您的位置:首页 > 理论基础 > 计算机网络

BP神经网络入门级简介

2017-08-01 18:32 218 查看

1. BP神经网络概述

神经网络是一类能够模拟任何函数的一个非线性映射。先简单举个例子,假设有一个神经网络仅由一个神经元构成:



神经网络采用的是给每个X1,X2,X3,X4加上一定的权值W1,W2,W3,W4,因此组合的线性输出为:

hW,b(x)=WTXW+b

hW,b(x)是一个标量

因此无论网络如何复杂,输出都会是一个关于输出的现象组合。为了模拟好非线性函数,需要加上一个激活函数:

f(z)=11+e−z

则:

f′(z)=e−z(1+e−z)2=f(z)(1−f(z))

假设我们的训练数据集为:



此时fW,b(x)=f(WTX+b),令g(x)=11+e−z,此时的损失函数为:

J(W,b)=12∑i=1n(fW,b(x(i))−y(i))2++λ2K∑k∈Kw2ji

分别对W,b求偏导,得:

∂J∂wj∂f∂bj=∑i=1ng(wix(i)+b−y(i))g(wix(i)+b)(1−g(wix(i)+b))⋅x(i)j+λKwji=∑i=1ng(wix(i)+b−y(i))g(wix(i)+b)(1−g(wix(i)+b))

后面的正则项是求所有权值的平方和的均值,K为权值的总的数目,根据梯度下降算法:

wj=wj−α∂J∂wjbj=bj−α∂J∂bj

代码的简单实现为:

from numpy import exp, array, random, dot

class NeuralNetwork():
def __init__(self):
random.seed(1)
# gengerate initial random W
self.synaptic_weights = 2 * random.random((3, 1)) - 1

def _sigmoid(self, x):
return 1/(1+exp(-x))

# gradient of the sigmod curve
def _sigmoid_derivative(self, x):
return x * (1-x)

def train(self, training_set_inputs, train_set_outputs, number_of_training_iterations):
for iteration in range(number_of_training_iterations):
output = self.predict(training_set_inputs)
error = training_set_outputs - output
adjustment = dot(training_set_inputs.T, error * self._sigmoid_derivative(output))
# update the W value
self.synaptic_weights += adjustment

def predict(self, inputs):
return self._sigmoid(dot(inputs, self.synaptic_weights))

if __name__ == "__main__":
neural_network = NeuralNetwork()

print("Random starting synaptic weights:")
print(neural_network.synaptic_weights)

training_set_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
training_set_outputs = array([[1, 1, 1, 0]]).T

neural_network.train(training_set_inputs, training_set_outputs, 10000)

print("New synaptic weights after training")
print(neural_network.synaptic_weights)

print("predicting:")
print(neural_network.predict(array([1, 0, 0])))


以上就是BP神经网络的简单介绍。

2. BP神经网络里面的权值迭代

假设有下面这样一个4层的神经网络模型(作为多个隐藏层的代表):



先给定下面几个字母代号:

Ln表示第n层,如L1表示输入层。W(l)ij表示第l层的第j个节点到第l+1层的第i个节点之间的权值。zli表示第l层的第i个节点经过上层所有连向该节点的加权求和,a(l)i表示第l层的第i个节点经过Activationfunction之后的输出值,即:

a(l)i=f(z(l)i)=sigmod(z(l)i)

b(l)i表示第l=1层第i个节点的偏置,定义δ(l)i为以a(l)i作为输入的第l层的第i个节点对总体误差的影响,则有:

z(l)ia(l)i=∑j=1nw(l−1)ija(l−1)j+b(l−1)i=11+e−z(l)i

设最终的输出值为:h(W,b)(x),实际的值为y,则损失函数为:

J(W,b)=12(hW,b(x)−y)2+λ2K∑k∈Kw2ij

后面的为正则项,其中K表示所有权重的数目,正则项即时对所有权重求加权平方和的均值。

BP神经网络的步骤为:

1. 随机初始化权值W和b

2. 通过前向传播的网络,计算在当前权重和偏置的情况下的输出hw,b(x)以及中间每一层对应的输出a(l)

3. 对于输出层,定义

δ(L)i=∑j=1m∂12(a(L)i−y)2∂aLi=a(L)i−y

后文中,为了方便书写,去掉了求和符号,均假设只有一个样本。多个样本的话,只需叠加即可。

4,对于第L−1层,有:

δ(L−1)i=∂Jw,b(z(L−1)i)∂a(L−1)i=∑k=1m∑j=1n∂Jjw,b(aL−1i)∂aL−1i=∑k=1m∑j=1n∂[12(f(w(L−1)ijaL−1i+b(L)j+⋯)−yj]2∂a(L−1)i=∑k=1m∑j=1n[f(w(L−1)ijaL−1i+b(L)j+⋯)−y]⋅∂[f(w(L−1)ijaL−1i+b(L)j+⋯)−y]∂a(L−1)i=∑k=1m∑j=1n(a(L)j−yj)⋅f′(a(L)j)⋅w(L−1)ij=∑k=1m∑j=1n(a(L)j−yj)⋅a(L)j⋅(1−a(L)j)⋅wL−1ij=∑k=1m∑j=1nδ(L)j⋅a(L)j⋅(1−a(L)j)⋅wL−1ij

5, 更新第L−1层到第L层的权重w(L−1)

∂Jw,b(a(L−1)i)∂wji加上正则项以后的偏导数为:∂Jw,b(a(L−1)i)∂wjiw(L−1)ji=∑k=1n∂Jjw,b(a(L−1)i)∂a(L)j⋅∂a(L)j∂wji=(a(L)j−y)⋅a(L)j⋅(1−a(L)j)⋅a(L−1)i注意这里去掉了求和符号=δ(L)j⋅a(L)j⋅(1−a(L)j)⋅a(L−1)i=δ(L)j⋅a(L)j⋅(1−a(L)j)⋅a(L−1)i+λKwji=w(L−1)ji−α⋅∂Jw,b(a(L−1)i)∂wji

6,对于第l层和第l+1层之间:

∂J∂a(l)i=∑j=1n∂J∂a(l+1)j⋅∂a(l+1)j∂a(l)i



a(l+1)j=f(wjia(l)i+bj+...)=f(z(l+1)j+⋯)

因此

∂a(l+1)j∂a(l)i=f(z(l+1)j+⋯)⋅(1−f(z(l+1)j+⋯))⋅wji=a(l+1)j⋅(1−a(l+1)j)⋅wji

因此:

δ(L)i=∂J∂a(l)i=∑j=1n[∂J∂a(l+1)j⋅a(l+1)j⋅(1−a(l+1)j)⋅wji]=∑j=1n[δ(L+1)i⋅a(l+1)j⋅(1−a(l+1)j)⋅wji]

而对于最后一层:

∂J∂a(L)i=a(L)i−yii表示输出层的第i个节点

故:

∂J∂w(l)ji∂J∂b(l)iwjib(l)i=∂J∂a(l+1)j⋅a(l+1)j(1−a(l+1)j)a(l)i+λKwji=δ(l+1)j⋅a(l+1)j(1−a(l+1)j)a(l)i+λKwji=∂J∂a(l+1)j⋅a(l+1)j(1−a(l+1)j)=δ(l+1)j⋅a(l+1)j(1−a(l+1)j)=wji−α⋅∂J∂wji=b(l)i−α⋅∂J∂b(l)i

注意,这里:

δ(l)j=∂J∂a(l)j

由此可以看出,要想求出每一层的权重的偏导数∂J∂wji,需要先求出误差对于后面一层所有节点的的输出值a(l+1)j的偏导数,因此总共需要3个变量来分别存储a(l)i、∂J∂a(l)i、w(l)ji,其中a(l)i、∂J∂a(l)i需要一个2维数组来存,w(l)ji需要一个3维度数组来存。

这里有一个简单的例子,很直观。

4. TensorFlow搭建一个简单的BP神经网络

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
n_nodes_hl1 = 500
n_nodes_hl2 = 500
n_nodes_hl3 = 500

n_classes = 10
batch_size = 100

x = tf.placeholder("float", [None, 784])
y = tf.placeholder("float", [None, n_classes])

def neural_network_model(data):
# 创建第一个隐藏层节点500个
hidden_1_layer = {"weight": tf.Variable(tf.random_normal([784, n_nodes_hl1])),
"biases": tf.Variable(tf.random_normal([n_nodes_hl1]))}
# 创建第二个隐藏层节点500个
hidden_2_layer = {"weight": tf.Variable(tf.random_normal([n_nodes_hl1, n_nodes_hl2])),
"biases": tf.Variable(tf.random_normal([n_nodes_hl2]))}
# 创建第三个隐藏层节点500个
hidden_3_layer = {"weight": tf.Variable(tf.random_normal([n_nodes_hl2, n_nodes_hl3])),
"biases": tf.Variable(tf.random_normal([n_nodes_hl3]))}
# 创建输出层节点10个
output_layer = {"weight": tf.Variable(tf.random_normal([n_nodes_hl3, n_classes])),
"biases": tf.Variable(tf.random_normal([n_classes]))}

# 连接输入层
l1 = tf.add(tf.matmul(data, hidden_1_layer["weight"]), hidden_1_layer["biases"])
l1 = tf.nn.relu(l1)

# 连接hidden layer 1和hidden layer 2
l2 = tf.add(tf.matmul(l1, hidden_2_layer["weight"]), hidden_2_layer["biases"])
l2 = tf.nn.relu(l2)

# 连接hidden layer 2和hidden layer 3
l3 = tf.add(tf.matmul(l2, hidden_3_layer["weight"]), hidden_3_layer["biases"])
l3 = tf.nn.relu(l3)

# 连接hidden layer 3和output layer
output = tf.add(tf.matmul(l3, output_layer["weight"]), output_layer["biases"])
# output = tf.nn.softmax(output)

return output

def train(x):
# 获取输出值
predict = neural_network_model(x)
# 定义对数损失函数
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=predict, labels=y))
# 定义最优化损失的计算方法
optimizer = tf.train.AdamOptimizer().minimize(cost)

hm_epochs = 10

with tf.Session() as sess:  # 真正运行在这里面
sess.run(tf.initialize_all_variables())

for epoch in range(hm_epochs):
epoch_loss = 0
for _ in range(int(mnist.train.num_examples / batch_size)):
epoch_x, epoch_y = mnist.train.next_batch(batch_size)
_, c = sess.run([optimizer, cost], feed_dict={x: epoch_x, y: epoch_y})
epoch_loss += c  # 叠加所有样本的损失
print("Epoch", epoch, "completed out of ", hm_epochs, "loss: ", epoch_loss)

correct = tf.equal(tf.arg_max(predict, 1), tf.arg_max(y, 1))

accuracy = tf.reduce_mean(tf.cast(correct, "float"))  # 所有元素取均值
print("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))

train(x)


注意事项:

1. 初始化权重和偏置的时候,不能都设为一样的,应该要随机初始化,否则可能造成权重完全相同,例如:



这是截取的网络的一部分,此时如果输出层的两个神经元相等,则以后的迭代过程当中,这两个神经元相连的前面一层的权值也相等,如果往前回溯,由于:

∂J∂w(l)ji=δ(l+1)ja(l+1)j(1−a(l+1)j)a(l)i

会造成偏导相等,从而权值也会呈现对称的特征,因此可能导致网络性能受到影响。

2. 对于求导的检查

神经网络的计算过程中,求导过程比较复杂,为了检验是否出错,可以用如下方法检验:



对于其上某点(xi,yi)点的导数近似等于:

∂f(x)∂x≈f(x+ϵ)−f(x−ϵ)2ϵ

此处ϵ取尽可能小的值,例如10−6。因此对于神经网络,可以:

∂J(wji)∂wji≈J(wji+ϵ)−J(wji−ϵ)2ϵϵ=10−6

当发现精确值和近似值相近时,说明导数计算正确,解除检验操作即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: