神经网络反向传播不训练
Neural Net Back Propagation not training
我制作了一个神经网络,现在我正在尝试实施反向传播算法
我已经使用 this diagram(pdf 文件)来帮助记下背后的数学,因为我不是工程师,所以可能使用不当,但我想要一些见解。
神经网络的大小是固定的(2个输入,2个隐藏层,每个3个隐藏节点,2个输出节点),但我打算稍后更改它。我主要关注反向传播算法。
问题是:反向传播似乎对最终结果没有影响,即使权重在算法的每一步都在改变。
import numpy as np
import math
class NeuralNetwork:
def __init__(self, learning_rate=0.0001):
self.learning_rate = learning_rate
self.weights_hidden_1 = np.arange(0.1, 0.7, 0.1).reshape((2, 3))
self.weights_hidden_2 = np.arange(0.7, 1.6, 0.1).reshape((3, 3))
self.weights_output = np.arange(1.6, 2.11, 0.1).reshape(3, 2)
self.input_values = None
self.results_hidden_1 = None
self.results_hidden_2 = None
self.results_output = None
@staticmethod
def activation(x):
"""Sigmoid function"""
try:
return 1 / (1 + math.e ** -x)
except OverflowError:
return 0
def delta_weights_output(self, expected_results):
errors = []
for k, result in enumerate(self.results_output):
error = result * (1 - result) * (result - expected_results[k])
errors.append(error)
errors = np.array(errors)
return errors
@staticmethod
def delta_weights_hidden(next_layer_results, next_layer_weights, next_layer_errors):
errors = []
for j, next_layer_result in enumerate(next_layer_results):
error_differences = []
for n, next_layer_error in enumerate(next_layer_errors):
error_difference = next_layer_weights[j][n] * next_layer_error
error_differences.append(error_difference)
error = next_layer_result * (1 - next_layer_result) * sum(error_differences)
errors.append(error)
return errors
def set_weight(self, weights, errors, results):
for j, result in enumerate(results):
for n, error in enumerate(errors):
new_weight = - self.learning_rate * error * result
weights[j][n] = new_weight
def back_propagate(self, expected_results):
output_error = self.delta_weights_output(expected_results)
self.set_weight(
self.weights_output,
output_error,
self.results_hidden_2
)
error_hidden_layer_2 = self.delta_weights_hidden(self.results_hidden_2,
self.weights_output,
output_error)
self.set_weight(
self.weights_hidden_2,
error_hidden_layer_2,
self.results_hidden_1
)
error_hidden_layer_1 = self.delta_weights_hidden(self.results_hidden_1,
self.weights_hidden_2,
error_hidden_layer_2)
self.set_weight(
self.weights_hidden_1,
error_hidden_layer_1,
self.input_values)
def feed_forward(self):
self.results_hidden_1 = np.array(
map(self.activation, self.input_values.dot(self.weights_hidden_1))
)
self.results_hidden_2 = np.array(
map(self.activation, self.results_hidden_1.dot(self.weights_hidden_2))
)
self.results_output = np.array(
map(self.activation, self.results_hidden_2.dot(self.weights_output))
)
def start_net(self, input_values):
self.input_values = np.array(input_values)
self.feed_forward()
return self.results_output
ANN = NeuralNetwork()
for n in xrange(10):
result = ANN.start_net([1, 2])
print result # should output [0.4, 0.6] after fixing the weights
ANN.back_propagate([0.4, 0.6])
编辑 1:
以下 IVlad 答案:
class NeuralNetwork:
def __init__(self, learning_rate=0.0001):
self.learning_rate = learning_rate
self.weights_hidden_1 = np.random.random((2,3))
self.weights_hidden_2 = np.random.random((3, 3))
self.weights_output = np.random.random((3, 2))
# ...
def start_net(self, input_values):
self.input_values = np.array(input_values)
self.input_values = (self.input_values - np.mean(self.input_values)) / np.std(self.input_values)
# ...
但还是没有变化。即使经过 100000 轮学习。我得到 [0.49999953 0.50000047]
很多事情都可能出错。
首先,您没有正确初始化权重:
self.weights_hidden_1 = np.arange(0.1, 0.7, 0.1).reshape((2, 3))
self.weights_hidden_2 = np.arange(0.7, 1.6, 0.1).reshape((3, 3))
self.weights_output = np.arange(1.6, 2.11, 0.1).reshape(3, 2)
你应该随机初始化权重,它们应该在[0, 1]
。对于较大的值,S 型函数 returns 的值非常接近 1
,因此由于您的权重较大,您将继续获得该值。它的导数将非常小,这就是您学习缓慢的原因。
之后好像只学了十遍?你应该做更多,可能超过 100,甚至可能超过 2000 与基本梯度下降。
然后,确保通过减去平均值并将每个特征除以标准差来标准化输入数据(但前提是您有多个训练实例):
self.input_values = (self.input_values - np.mean(self.input_values, axis=0)) / np.std(self.input_values, axis=0)
我没有在公式中发现错误,所以我猜这可能是您初始化权重的方式。
也可以考虑使用双曲正切激活函数。根据我的经验,它表现得更好。你可以像numpy中的np.tanh(x)
一样使用,它的导数是1 - result ** 2
.
我制作了一个神经网络,现在我正在尝试实施反向传播算法
我已经使用 this diagram(pdf 文件)来帮助记下背后的数学,因为我不是工程师,所以可能使用不当,但我想要一些见解。
神经网络的大小是固定的(2个输入,2个隐藏层,每个3个隐藏节点,2个输出节点),但我打算稍后更改它。我主要关注反向传播算法。
问题是:反向传播似乎对最终结果没有影响,即使权重在算法的每一步都在改变。
import numpy as np
import math
class NeuralNetwork:
def __init__(self, learning_rate=0.0001):
self.learning_rate = learning_rate
self.weights_hidden_1 = np.arange(0.1, 0.7, 0.1).reshape((2, 3))
self.weights_hidden_2 = np.arange(0.7, 1.6, 0.1).reshape((3, 3))
self.weights_output = np.arange(1.6, 2.11, 0.1).reshape(3, 2)
self.input_values = None
self.results_hidden_1 = None
self.results_hidden_2 = None
self.results_output = None
@staticmethod
def activation(x):
"""Sigmoid function"""
try:
return 1 / (1 + math.e ** -x)
except OverflowError:
return 0
def delta_weights_output(self, expected_results):
errors = []
for k, result in enumerate(self.results_output):
error = result * (1 - result) * (result - expected_results[k])
errors.append(error)
errors = np.array(errors)
return errors
@staticmethod
def delta_weights_hidden(next_layer_results, next_layer_weights, next_layer_errors):
errors = []
for j, next_layer_result in enumerate(next_layer_results):
error_differences = []
for n, next_layer_error in enumerate(next_layer_errors):
error_difference = next_layer_weights[j][n] * next_layer_error
error_differences.append(error_difference)
error = next_layer_result * (1 - next_layer_result) * sum(error_differences)
errors.append(error)
return errors
def set_weight(self, weights, errors, results):
for j, result in enumerate(results):
for n, error in enumerate(errors):
new_weight = - self.learning_rate * error * result
weights[j][n] = new_weight
def back_propagate(self, expected_results):
output_error = self.delta_weights_output(expected_results)
self.set_weight(
self.weights_output,
output_error,
self.results_hidden_2
)
error_hidden_layer_2 = self.delta_weights_hidden(self.results_hidden_2,
self.weights_output,
output_error)
self.set_weight(
self.weights_hidden_2,
error_hidden_layer_2,
self.results_hidden_1
)
error_hidden_layer_1 = self.delta_weights_hidden(self.results_hidden_1,
self.weights_hidden_2,
error_hidden_layer_2)
self.set_weight(
self.weights_hidden_1,
error_hidden_layer_1,
self.input_values)
def feed_forward(self):
self.results_hidden_1 = np.array(
map(self.activation, self.input_values.dot(self.weights_hidden_1))
)
self.results_hidden_2 = np.array(
map(self.activation, self.results_hidden_1.dot(self.weights_hidden_2))
)
self.results_output = np.array(
map(self.activation, self.results_hidden_2.dot(self.weights_output))
)
def start_net(self, input_values):
self.input_values = np.array(input_values)
self.feed_forward()
return self.results_output
ANN = NeuralNetwork()
for n in xrange(10):
result = ANN.start_net([1, 2])
print result # should output [0.4, 0.6] after fixing the weights
ANN.back_propagate([0.4, 0.6])
编辑 1:
以下 IVlad 答案:
class NeuralNetwork:
def __init__(self, learning_rate=0.0001):
self.learning_rate = learning_rate
self.weights_hidden_1 = np.random.random((2,3))
self.weights_hidden_2 = np.random.random((3, 3))
self.weights_output = np.random.random((3, 2))
# ...
def start_net(self, input_values):
self.input_values = np.array(input_values)
self.input_values = (self.input_values - np.mean(self.input_values)) / np.std(self.input_values)
# ...
但还是没有变化。即使经过 100000 轮学习。我得到 [0.49999953 0.50000047]
很多事情都可能出错。
首先,您没有正确初始化权重:
self.weights_hidden_1 = np.arange(0.1, 0.7, 0.1).reshape((2, 3))
self.weights_hidden_2 = np.arange(0.7, 1.6, 0.1).reshape((3, 3))
self.weights_output = np.arange(1.6, 2.11, 0.1).reshape(3, 2)
你应该随机初始化权重,它们应该在[0, 1]
。对于较大的值,S 型函数 returns 的值非常接近 1
,因此由于您的权重较大,您将继续获得该值。它的导数将非常小,这就是您学习缓慢的原因。
之后好像只学了十遍?你应该做更多,可能超过 100,甚至可能超过 2000 与基本梯度下降。
然后,确保通过减去平均值并将每个特征除以标准差来标准化输入数据(但前提是您有多个训练实例):
self.input_values = (self.input_values - np.mean(self.input_values, axis=0)) / np.std(self.input_values, axis=0)
我没有在公式中发现错误,所以我猜这可能是您初始化权重的方式。
也可以考虑使用双曲正切激活函数。根据我的经验,它表现得更好。你可以像numpy中的np.tanh(x)
一样使用,它的导数是1 - result ** 2
.