简单神经网络 "calibration" (python)
Simple neural network "calibration" (python)
我开始使用神经网络和这类东西,我了解 perceptron
的工作原理以及 feed-forward and backpropagation
机制背后的逻辑,我现在正在尝试编写一个简单的多-具有 3 个神经元的层网络(隐藏层中有 2 个,输出层中有 1 个)应该 足以执行 xor operation
.
我在 Python(现在使用 v3.6.1)中是这样实现的:
import numpy as np
class Neuron():
def __init__(self, n, w = None, b = None):
#np.random.seed(46144492)
#np.random.seed(23)
self.weights = 2 * np.random.random((n)) - 1 if w == None else np.array(w)
self.bias = 2 * np.random.random() - 1 if b == None else b
self.learning_rate = 0.1
self.weights_error = []
for i in range(n):
self.weights_error.append(0)
self.bias_error = 0
def learning_factor(self, output):
return output * (1 - output)
def fire(self, x):
return 1 / (1 + np.exp(-x))
def __call__(self, inputs):
weighted = []
for i in range(len(inputs)):
weighted.append(inputs[i] * self.weights[i])
weighted = np.array(weighted)
return self.fire(weighted.sum() + self.bias)
def adjust(self, n_weights):
for i in range(n_weights):
self.weights[i] -= self.weights_error[i]
self.bias -= self.bias_error
class HiddenNeuron(Neuron):
def calc_error(self, inputs, output, next_layer, number_in_layer):
error = 0
for n in range(len(next_layer)):
error += next_layer[n].delta * next_layer[n].weights[number_in_layer - 1]
derivative = self.learning_factor(output)
self.delta = error * derivative
self.weights_error = []
for i in range(len(inputs)):
self.weights_error.append(self.delta * inputs[i] * self.learning_rate)
self.bias_error = self.delta * self.learning_rate
class OutputNeuron(Neuron):
def calc_error(self, inputs, output, expected):
error = output - expected
derivative = self.learning_factor(output)
self.delta = error * derivative
self.weights_error = []
for i in range(len(inputs)):
self.weights_error.append(self.delta * inputs[i] * self.learning_rate)
self.bias_error = self.delta * self.learning_rate
# Network
n1, n2 = HiddenNeuron(2), HiddenNeuron(2)
n3 = OutputNeuron(2)
# Training data
training_set_in = [[0, 0], [0, 1], [1, 0], [1, 1]]
training_set_out = [0, 1, 1, 0]
# Training cycles
for i in range(10000):
for i in range(len(training_set_in)):
# Feed-forward
n1_out = n1(training_set_in[i])
n2_out = n2(training_set_in[i])
n3_in = [n1_out, n2_out]
n3_out = n3(n3_in)
# Backpropagation
n3.calc_error(n3_in, n3_out, training_set_out[i])
n2.calc_error(training_set_in[i], n2_out, [n3], 2)
n1.calc_error(training_set_in[i], n1_out, [n3], 1)
n1.adjust(2)
n2.adjust(2)
n3.adjust(2)
# "New" cases (test)
for new in [[0, 0], [0, 1], [1, 0], [1, 1]]:
print(n3([n1(new), n2(new)]))
如您所见,我使用 sigmoid 函数作为激活函数,但我还没有实现动量(我仍然需要了解它是如何工作的)。
在大多数情况下,网络工作正常。但我发现在某些情况下它会输出一些奇怪的值(例如,参见我在 Neuron class 构造函数中评论的两个随机种子)。如果我增加 Neuron.learning_rate(例如将其设置为 10),这两种情况就可以解决,但仍然会出现其他一些异常(找不到这些种子,对不起......但是他们是要求频繁,只需 运行 代码 10 或 20 次,你就会看到一些)。
问题是:为什么会这样?是不是我的网络太"small"/简单了?我认为 3 个神经元就足够了。还是只是"calibration"的问题(不知道怎么称呼,我指的是调整学习率因子和动量的过程,这里没有)?或者我什至犯了什么错误?我真的想不通。
编辑: 我正在用所有可能的情况训练网络,然后在相同的情况下尝试它只是为了验证它是否正常工作。
我觉得没关系,因为神经网络的性能取决于它的初始状态,即权重和偏差。在您的情况下,权重和偏差开始时是随机的,因此取决于种子。甚至还有专门的techniques1 to reduce this effect, such as weight normalisation(还有google这个,有一些关于这个话题的有趣论文)。
我开始使用神经网络和这类东西,我了解 perceptron
的工作原理以及 feed-forward and backpropagation
机制背后的逻辑,我现在正在尝试编写一个简单的多-具有 3 个神经元的层网络(隐藏层中有 2 个,输出层中有 1 个)应该 足以执行 xor operation
.
我在 Python(现在使用 v3.6.1)中是这样实现的:
import numpy as np
class Neuron():
def __init__(self, n, w = None, b = None):
#np.random.seed(46144492)
#np.random.seed(23)
self.weights = 2 * np.random.random((n)) - 1 if w == None else np.array(w)
self.bias = 2 * np.random.random() - 1 if b == None else b
self.learning_rate = 0.1
self.weights_error = []
for i in range(n):
self.weights_error.append(0)
self.bias_error = 0
def learning_factor(self, output):
return output * (1 - output)
def fire(self, x):
return 1 / (1 + np.exp(-x))
def __call__(self, inputs):
weighted = []
for i in range(len(inputs)):
weighted.append(inputs[i] * self.weights[i])
weighted = np.array(weighted)
return self.fire(weighted.sum() + self.bias)
def adjust(self, n_weights):
for i in range(n_weights):
self.weights[i] -= self.weights_error[i]
self.bias -= self.bias_error
class HiddenNeuron(Neuron):
def calc_error(self, inputs, output, next_layer, number_in_layer):
error = 0
for n in range(len(next_layer)):
error += next_layer[n].delta * next_layer[n].weights[number_in_layer - 1]
derivative = self.learning_factor(output)
self.delta = error * derivative
self.weights_error = []
for i in range(len(inputs)):
self.weights_error.append(self.delta * inputs[i] * self.learning_rate)
self.bias_error = self.delta * self.learning_rate
class OutputNeuron(Neuron):
def calc_error(self, inputs, output, expected):
error = output - expected
derivative = self.learning_factor(output)
self.delta = error * derivative
self.weights_error = []
for i in range(len(inputs)):
self.weights_error.append(self.delta * inputs[i] * self.learning_rate)
self.bias_error = self.delta * self.learning_rate
# Network
n1, n2 = HiddenNeuron(2), HiddenNeuron(2)
n3 = OutputNeuron(2)
# Training data
training_set_in = [[0, 0], [0, 1], [1, 0], [1, 1]]
training_set_out = [0, 1, 1, 0]
# Training cycles
for i in range(10000):
for i in range(len(training_set_in)):
# Feed-forward
n1_out = n1(training_set_in[i])
n2_out = n2(training_set_in[i])
n3_in = [n1_out, n2_out]
n3_out = n3(n3_in)
# Backpropagation
n3.calc_error(n3_in, n3_out, training_set_out[i])
n2.calc_error(training_set_in[i], n2_out, [n3], 2)
n1.calc_error(training_set_in[i], n1_out, [n3], 1)
n1.adjust(2)
n2.adjust(2)
n3.adjust(2)
# "New" cases (test)
for new in [[0, 0], [0, 1], [1, 0], [1, 1]]:
print(n3([n1(new), n2(new)]))
如您所见,我使用 sigmoid 函数作为激活函数,但我还没有实现动量(我仍然需要了解它是如何工作的)。
在大多数情况下,网络工作正常。但我发现在某些情况下它会输出一些奇怪的值(例如,参见我在 Neuron class 构造函数中评论的两个随机种子)。如果我增加 Neuron.learning_rate(例如将其设置为 10),这两种情况就可以解决,但仍然会出现其他一些异常(找不到这些种子,对不起......但是他们是要求频繁,只需 运行 代码 10 或 20 次,你就会看到一些)。
问题是:为什么会这样?是不是我的网络太"small"/简单了?我认为 3 个神经元就足够了。还是只是"calibration"的问题(不知道怎么称呼,我指的是调整学习率因子和动量的过程,这里没有)?或者我什至犯了什么错误?我真的想不通。
编辑: 我正在用所有可能的情况训练网络,然后在相同的情况下尝试它只是为了验证它是否正常工作。
我觉得没关系,因为神经网络的性能取决于它的初始状态,即权重和偏差。在您的情况下,权重和偏差开始时是随机的,因此取决于种子。甚至还有专门的techniques1 to reduce this effect, such as weight normalisation(还有google这个,有一些关于这个话题的有趣论文)。