6.构建神经网络
前言
我们已经知道,深度学习一词,最早是在2006~2007年,由Geoffrey Hinton 在《Science》上发表的文章开始被提出和逐步兴起的。深度学习是在机器学习的基础上发展的,神经网络的层级比机器学习的多而复杂。
生物学领域神经网络中的单个神经元 ↑神经网络结构,正是受到生物学领域中的神经网络的启发,才有了今天机器学习、深度学习中的神经网络的结构。
今天我们就利用谷歌的深度学习框架TensorFlow,来搭建一个自己的简单的神经网络。
上面是一个3层的神经网络,其中:每一个⭕️代表一个神经元,也可以叫做神经节点、神经结点,每个神经元有一个偏置bias。每一条线,有一个权重weight。
神经网络学习的目标:就是通过减少损失loss或cost,来确定权重和偏置。理论上,如果有足够多的隐藏层和足够大的训练集,则可以模拟出任何方程。
搭建一个简单的神经网络
搭建一个简单的神经网络的基本思路:
1.准备数据
2.搭建模型
3.训练模型
4.使用模型
先来搭建一个只有两层(不包含输入层)的神经网络,也即:输入层--隐藏层--输出层。
为了方便层的添加,我们把添加层,抽到一个方法中add_layer(inputs, input_size, output_size, activation_func)
,参数解释如下:
inputs: 输入的数据
input_size: 输入的size
output_size: 输出的size
activation_func: 激励函数
完整的添加层,代码如下所示:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 添加一层
def add_layer(inputs, input_size, output_size, activation_func):
"""
:param inputs: 输入的数据
:param input_size: 输入的size
:param output_size: 输出的size
:param activation_func: 激励函数
:return:
"""
weights = tf.Variable(tf.random_normal([input_size, output_size], seed=1024))
bias = tf.Variable(tf.zeros([1, output_size]))
w_x_plus_b = tf.matmul(inputs, weights) + bias
if activation_func is None:
outputs = w_x_plus_b
else:
outputs = activation_func(w_x_plus_b)
return outputs
说明:
1.权重weights的初始化,通常是通过生产随机数作为权重的初始化值。
2.偏置bias的初始化,通常是将偏置初始化为0。
神经元3.我们已经知道,每一个⭕️代表着一个神经元,也可以叫做神经节点、神经结点,每个神经元有一个偏置bias。每一条线,有一个权重weight。如上图所示。神经网络学习的目标:就是通过减少损失loss或cost,来确定权重和偏置,所以权重和偏置都是用tensorflow
中的tf.Variable()
来创建的。tf.Variable()
有一个很重要的特性,是可被训练。
4.w_x_plus_b = tf.matmul(inputs, weights) + bias
整体表示:权重 * 自变量 + 偏置,也就是通常我们见到的线性函数y = a * x + b;权重即这里的a,偏置即这里的b。在tensorflow
中,tf.matmul(inputs, weights)
表示矩阵相乘。
5.通常,一层中的神经元经过加权求和,然后再经过非线性方程得到的结果转化为输出,或者作为下一层的输入。注意:非线性方程,即是通常所说的激励函数。
常见的激励函数:sigmoid函数、tanh函数、ReLu函数、SoftMax函数等等。这里我们设计的函数需要调用者传入一个激励函数,如果不穿入,则按照线性处理。
补充:tensor flow中的随机数
tensor flow中的随机数,常用的有两种:正态分布的随机数和均匀分布随机数。
正态分布随机数:
tf.random_normal(shape, mean=平均值,stddev=标准差,seed=随机种子)
均匀分布随机数:
tf.random_uniform(shape,minval=下边界,maxval=上边界,dtype=数据类型,seed=随机种子)
每个参数的含义,都在上面写明了。其中,随机种子是产生伪随机数的一种,当设置了相同的随机种子后,每次运行得到的随机数都相同。
准备数据
通过准备x数据,y数据,其中为了数据的略显杂乱,加入了一些噪音数据,也即噪点。
# 上接
# 1.准备数据
x_data = np.linspace(-2.0, 2.0, 50)[:, np.newaxis]
# 添加一些噪点
noise = np.random.normal(0.0, 0.1, x_data.shape)
y_data = x_data ** 2 + noise
搭建模型
按照预先设计的神经网络:输入层 --- 隐藏层(1层)--- 输出层,所以搭建模型这一步骤中,我们加入了:
一个隐藏层hidden_layer1 = add_layer(xs, 1, 20, activation_func=tf.nn.sigmoid)
,这一层有20个神经元,且这一层使用的激励函数为tf.nn.sigmoid
。当然,你也可以使用其他激励函数tf.nn.tanh
或者tf.nn.reLu
,来对比下他们的拟合效果。
一个输出层prediction = add_layer(hidden_layer1, 20, 1, activation_func=None)
,这一层只有一个神经元,即:预测值。另外,这一层没有使用激励函数。
神经网络学习的目标:就是通过减少损失loss或cost: loss = tf.reduce_mean(tf.reduce_sum(tf.square(prediction - ys), reduction_indices=[1]))
使用均方误差来计算的损失函数。
提示:均方误差是指参数估计值与参数真值之差平方的期望值; 可以评价数据的变化程度,其值越小,说明预测模型描述实验数据具有更好的精确度。
本步骤的完整代码如下:
# 上接
# 2.搭建模型
xs = tf.placeholder(dtype=tf.float32, shape=[None, 1])
ys = tf.placeholder(dtype=tf.float32, shape=[None, 1])
# 隐藏层:这一层有20个神经元
hidden_layer1 = add_layer(xs, 1, 20, activation_func=tf.nn.sigmoid)
# 输出层:这一层只有一个神经元,即:预测值
prediction = add_layer(hidden_layer1, 20, 1, activation_func=None)
# 损失函数
loss = tf.reduce_mean(tf.reduce_sum(tf.square(prediction - ys), reduction_indices=[1]))
# 假设学习率为: 0.1
learning_rate = 0.1
# 梯度下降优化器,让损失最小化
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
# 初始化tensor flow中的变量
init = tf.global_variables_initializer()
# 画图
figure = plt.figure()
ax = figure.add_subplot(1, 1, 1)
ax.scatter(x_data, y_data)
plt.grid(True)
# 连续画图像
plt.ion()
plt.show()
注意:
- 本示例,采用的是梯度下降优化器,让损失最小化:
tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
。传入的学习率,通常是个小数,通常不同的学习率对最终的学习效果是有影响的,且不同的模型影响不同。开发过程中,可以修改学习率的大小,来看看具体的影响。
2.tensorflow中必须对变量进行显示初始化:tf.global_variables_initializer()
,否则在会话中运行会报错。
3.由于x、y的值需要根据后面的值来确定,所以用了tensorflow中的占位。
训练模型
训练模型,必须在tensorflow中的Session会话的上下文中进行。因为涉及多次训练,我们设计了一个循环。每学习200次后打印一下损失值,并且更新拟合的图像。
# 3.训练模型
with tf.Session() as sess:
sess.run(init)
for i in range(2000):
sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
if i % 200 == 0:
# 打印一下损失值
print(sess.run(loss, feed_dict={xs: x_data, ys: y_data}))
# 拿到预测值,方便后面画图像
prediction_value = sess.run(prediction, feed_dict={xs: x_data})
# 异常处理
try:
ax.lines.remove(lines[0])
except Exception as result:
print(result)
pass
# 用实线画出拟合结果
lines = ax.plot(x_data, prediction_value, color="red", linewidth=2)
plt.pause(0.2)
运行结果如下:
name 'lines' is not defined
0.4657365
0.10333648
0.061281133
0.04103751
0.03180971
0.026741847
0.023417206
0.021100197
0.019451708
学习效果图
说明:
1.name 'lines' is not defined
是捕捉到的异常。因为第一次删除实线的图像时,我们还没有绘制,所以有异常抛出,被我们捕捉到了。
2.打印剩余的信息,就是每学习200次后打印一下损失值。可见,损失是由最初的0.4657365逐渐降到了0.019451708。
3.通过学习效果图,可以看到,最初偏离数据很多,随着学习次数增多,拟合的效果也越来越好。
小结
本文通过谷歌的深度学习框架TensorFlow,来搭建一个自己的简单的神经网络。
更多了解,可关注微信公众号:人人懂编程
微信公众号:人人懂编程