前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何用Python创建一个多层神经网络

如何用Python创建一个多层神经网络

作者头像
Stanley Sun
发布2019-09-23 15:24:39
1.2K0
发布2019-09-23 15:24:39
举报
文章被收录于专栏:思考是一种快乐

英文原文:https://medium.com/technology-invention-and-more/how-to-build-a-multi-layered-neural-network-in-python-53ec3d1d326a

问题

在之前的博文里, 我们学习了如何创建一个神经网络。不过,如果我们面临一个更复杂的问题,如何识别“?”是什么?

Input

output

Example 1

0 0 1

0

Example 2

0 1 1

1

Example 3

1 0 1

1

Example 4

0 1 0

1

Example 5

1 0 0

1

Example 6

1 1 1

0

Example 7

0 0 0

0

New situation

1 1 0

?

仔细观察会发现,input3是一个无关项。前两列通过“异或”运算后得到output。 因此,我们知道,“?”的值应该是0.

不过,单层神经网络已经处理不了这样的逻辑了。在input和output之间不存在“一对一”的关系,这种情况被称为“非线性模式”。

我们必须创建一个隐藏层,比如有4个神经元(Layer1)。这可以使得神经网络来思考input的组合情况。

蓝色线是神经元之间的链接。这个图是由 https://github.com/miloharper/visualise-neural-network 工具自动生成的。

图中可以看到,Layer1是Layer2的输入。现在,我们可以从训练数据中寻找Layer1和output的关系。在神经网络的训练过程中,通过调整两层的权重,相关性会得到放大。

实际上,图像识别跟这个很相似。像素和苹果之间没有直接的关联。但是,像素的组合与苹果存在一个直接的关联。

给神经网络增加更多层,它就会做更复杂的思考。

Python源码地址: https://github.com/miloharper/multi-layer-neural-network

这个神经网络是从之前文章中修改而来的。总和解释参见文章《Python代码搭建简单的神经网络》

不同之处是现在有多层。当神经网络计算Layer2的error时,它会反向把它传播回Layer1, 然后调整Layer1到权重。这被称为“反向传播(back propagation)”

运行代码

代码语言:javascript
复制
python main.py

结果

代码语言:javascript
复制
Stage 1) Random starting synaptic weights: 
    Layer 1 (4 neurons, each with 3 inputs): 
[[-0.16595599  0.44064899 -0.99977125 -0.39533485]
 [-0.70648822 -0.81532281 -0.62747958 -0.30887855]
 [-0.20646505  0.07763347 -0.16161097  0.370439  ]]
    Layer 2 (1 neuron, with 4 inputs):
[[-0.5910955 ]
 [ 0.75623487]
 [-0.94522481]
 [ 0.34093502]]
Stage 2) New synaptic weights after training: 
    Layer 1 (4 neurons, each with 3 inputs): 
[[ 0.3122465   4.57704063 -6.15329916 -8.75834924]
 [ 0.19676933 -8.74975548 -6.1638187   4.40720501]
 [-0.03327074 -0.58272995  0.08319184 -0.39787635]]
    Layer 2 (1 neuron, with 4 inputs):
[[ -8.18850925]
 [ 10.13210706]
 [-21.33532796]
 [  9.90935111]]
Stage 3) Considering a new situation [1, 1, 0] -> ?: 
[ 0.0078876]

首先,神经网络随机为神经链接分配权重,然后使用训练集进行训练。

然后,它会对之前没有遇到过到新情况 1, 1, 0进行思考,并做出预测。预测值是0.0078876。正确答案是0,已经非常接近。

很酷!不过计算机在背后做了很多看不见的矩阵运算。

代码解析

1.神经元层

代码语言:javascript
复制
#神经元层
class NeuronLayer():
    # number_of_neurons:神经元数量; number_of_inputs_per_neuron:每个神经元的输入数
    def __init__(self, number_of_neurons, number_of_inputs_per_neuron):
        self.synaptic_weights = 2 * random.random((number_of_inputs_per_neuron, number_of_neurons)) - 1

new 一个NeuronLayer会生成一层神经元。比如layer1 = NeuronLayer(4, 3)就是生成layer 1,有4个神经元,每个神经元有3个输入。实际上就是一个3行4列的数组。 注意,__init__的参数与random的参数顺序不一样。

2.神经网络

代码语言:javascript
复制
class NeuralNetwork():
    def __init__(self, layer1, layer2):
        self.layer1 = layer1
        self.layer2 = layer2

这是神经网络class。因为这个神经网络有两层,所以有2个参数layer1,layer2。它们是NeuronLayer类型。当然,这种写法扩展性并不好,如果需要三层网络,还需要修改代码。如果改成数组存储每一层神经元,会提高扩展性。不过那样可能性又会低一点。这里为了方便解释,这里就写4死layer1,layer2来存储每层网络。

3.思考

代码语言:javascript
复制
    # The neural network thinks.
    def think(self, inputs):
        output_from_layer1 = self.__sigmoid(dot(inputs, self.layer1.synaptic_weights))
        output_from_layer2 = self.__sigmoid(dot(output_from_layer1, self.layer2.synaptic_weights))
        return output_from_layer1, output_from_layer2

第一层的输出=输入*layer1的权重 (NX3的矩阵 * 3X4的矩阵=NX4的矩阵)

第二层的输出=第一层的输出*layer2的权重 (NX4的矩阵 * 4X1的矩阵 = NX1的矩阵)

输出每一层的输出值

注:NXK的矩阵表示N个样本,每个样本输出K个值。

4.训练

代码语言:javascript
复制
    # We train the neural network through a process of trial and error.
    # Adjusting the synaptic weights each time.
    def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
        for iteration in range(number_of_training_iterations):
            # Pass the training set through our neural network
            output_from_layer_1, output_from_layer_2 = self.think(training_set_inputs)

            # Calculate the error for layer 2 (The difference between the desired output
            # and the predicted output).
            layer2_error = training_set_outputs - output_from_layer_2
            layer2_delta = layer2_error * self.__sigmoid_derivative(output_from_layer_2)

            # Calculate the error for layer 1 (By looking at the weights in layer 1,
            # we can determine by how much layer 1 contributed to the error in layer 2).
            layer1_error = layer2_delta.dot(self.layer2.synaptic_weights.T)
            layer1_delta = layer1_error * self.__sigmoid_derivative(output_from_layer_1)

            # Calculate how much to adjust the weights by
            layer1_adjustment = training_set_inputs.T.dot(layer1_delta)
            layer2_adjustment = output_from_layer_1.T.dot(layer2_delta)

            # Adjust the weights.
            self.layer1.synaptic_weights += layer1_adjustment
            self.layer2.synaptic_weights += layer2_adjustment

训练中迭代number_of_training_iterations次,每一次都会:

代码语言:txt
复制
1. 思考,把训练集作为输入,用神经网络思考,得出输出(output\_from\_layer\_1, output\_from\_layer\_2)。output\_from\_layer\_1是NX4的矩阵,**output\_from\_layer\_2是NX1的矩阵。**
代码语言:txt
复制
2.  比较layer2的输出和期望输出,得出layer2输出误差(layer2\_error)。**layer2\_error是NX1的矩阵。**
代码语言:txt
复制
3. 计算layer2输出的S梯度值self.\_\_sigmoid\_derivative(output\_from\_layer\_2),得出置信程度。对于置信程度低的权重,调整程度也大。
代码语言:txt
复制
 误差越大,权重调整程度也大。所以要再乘以误差(layer2\_error)。即
代码语言:javascript
复制
layer2_delta=layer2_error * self.__sigmoid_derivative(output_from_layer_2)

layer2_delta就是layer2的输出需要调整的步长。layer2_delta是NX1的矩阵。

  1. layer2有1个神经元,每个神经元有4个输出。layer2.synaptic_weights是一个4X1的矩阵。它的转置矩阵layer2.synaptic_weights.T是一个1X4的矩阵。

layer1_error = layer2_delta.dot(self.layer2.synaptic_weights.T)

layer2的输出要调整,比如要调整layer1的输出。layer2需要调整的值(layer2_delta)越大,就说明layer1的输出有误差(layer1_error)应该越大。乘正比关系;另外,与layer2的权重也乘正比关系,因为layer2的输出是layer1输出.dot.layer2.synaptic_weights。

layer1_error是一个NX4的矩阵。它表示layer1输出的4个值,每个值的误差。

  1. layer1_delta与layer2_delta的计算方法一样。
代码语言:javascript
复制
layer1_delta = layer1_error * self.__sigmoid_derivative(output_from_layer_1)

layer1_delta是一个NX4的矩阵,表示每一个输出值在本次iteration需要调整的步长。

6.

代码语言:javascript
复制
layer1_adjustment = training_set_inputs.T.dot(layer1_delta)
layer2_adjustment = output_from_layer_1.T.dot(layer2_delta)

training_set_inputs 是一个NX3的矩阵;training_set_inputs.T是一个3XN的矩阵。layer1_delta是一个NX3的矩阵。因此layer1_adjustment是一个3X4的矩阵。

layer1.synaptic_weights也是一个3X4的矩阵。layer1_adjustment就是每个权重需要调整的值。

同理,layer2_adjustment是layer2.synaptic_weights中每个权重需要调整的值。layer2_adjustment和layer2.synaptic_weights都是4X1的矩阵。

  1. 调整权重
代码语言:javascript
复制
self.layer1.synaptic_weights += layer1_adjustment
self.layer2.synaptic_weights += layer2_adjustment

继续下一个迭代的训练

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 运行代码
  • 结果
  • 代码解析
    • 1.神经元层
      • 2.神经网络
        • 3.思考
          • 4.训练
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档