【问题标题】:Neural Net Back Propagation not training神经网络反向传播不训练
【发布时间】:2015-05-10 05:57:50
【问题描述】:

我做了一个神经网络,现在我正在尝试实现反向传播算法

我用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]

【问题讨论】:

    标签: python algorithm python-2.7 neural-network


    【解决方案1】:

    有很多事情会出错。

    首先,您没有正确初始化权重:

    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]。对于较大的值,sigmoid 函数返回的值非常接近 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

    【讨论】:

    • 感谢您的回复。我已经编辑了包括你的笔记在内的问题。它仍然没有学会如何解决。当我得到正确的数学时,我会尝试双曲正切。
    • @f.rodrigues 您的规范化代码错误。您应该对列而不是行取平均值和标准:self.input_values = (self.input_values - np.mean(self.input_values, axis=0)) / np.std(self.input_values, axis=0)。如果您只有一行(就像您似乎拥有的那样),这当然没有意义。在这种情况下,请尝试不进行标准化。
    • 另外,100k 轮次的训练听起来太多了。我建议将其保持在1000-5000 范围内并调整学习率。您还可以在每次迭代后打印其输出,以更好地了解您应该进行多少次迭代。另外,请研究动量技术。
    • 该死,我在 set_weight 方法中犯了一个愚蠢的错误。我没有将 (self.learning_rate * delta_change * result) 添加到权重,而是将权重更改为该值。我想我误解了 pdf 所说的将权重更新为新值,而这是对权重的增量更改。
    • 如果 w 和 x 形状不同(如 conv 层或其他层),因此 dw 和 dx 形状不同,我们如何按元素方式将顶层的 dx 与前一层的 dw 相乘影响上一层w的变化。
    猜你喜欢
    • 2011-11-20
    • 2018-08-04
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 2015-03-03
    • 2012-02-21
    • 2011-01-05
    • 1970-01-01
    相关资源
    最近更新 更多