简单神经网络 "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这个,有一些关于这个话题的有趣论文)。


  1. link 摘自 http://neuralnetworksanddeeplearning.com/chap5.html