python - 神经网络反向传播不训练

标签 python algorithm python-2.7 neural-network

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

我用过 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 型函数返回的值非常接近于 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

关于python - 神经网络反向传播不训练,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30134429/

相关文章:

python - 在 URL 中使用查询字符串对 Pyramid/Cornice 资源进行单元测试

python - 扩展/ reshape Pandas 系列列的尺寸

c++ - 两个包的背包算法

python - 如何让 pip 指向更新版本的 Python

python - 如何在不同的进程python中增加计数器?

linux - 在 Ubuntu 上使用 python 2.7 和 pyglet 的 Mp3 播放器

Python 使用 webbrowser、urllib 和 CookieJar 验证并启动私有(private)页面

python - 在tensorflow docker-compose中没有贴切?

algorithm - oracle生成16位随机数

algorithm - 分割双标签数组