实现一个简单的神经网络
前向传播算法
假设存在如下图所示的三层神经网络:
前向传播可以表示成矩阵乘法。将输入$x_1$、$x_2$组织成一个$1\times2$的矩阵,而$W^{(1)}$组织成一个$2\times3$的矩阵:
$$
W^{(1)}=\begin{bmatrix}
W^{(1)}{1,1}&W^{(1)}{1,2}&W^{(1)}{1,3}\
W^{(1)}{2,1}&W^{(1)}{2,2}&W^{(1)}{2,3}\
\end{bmatrix}
$$
这样通过矩阵乘法可以得到隐藏层三个节点所组成的向量取值:
[这里之前出了点公式的问题,原因是 mathjax 解析中括号改了。。]
$$
a^{(1)}=[a_{11},a_{12},a_{13}]=xW^{(1)}=[x1,x2]\begin{bmatrix}
W^{(1)}{1,1}&W^{(1)}{1,2}&W^{(1)}{1,3}\
W^{(1)}{2,1}&W^{(1)}{2,2}&W^{(1)}{2,3}\
\end{bmatrix}\
=[W^{(1)}{1,1}x_1+W^{(1)}{2,1}x_2+W^{(1)}{1,2}x_1+W^{(1)}{2,2}x_2+W^{(1)}{1,3}x_1+W^{(1)}{2,3}x_2]
$$
类似的输出层可以表示为:
$$
y=a^{(1)}W^{(2)}=[a_{11},a_{12},a_{13}]\begin{bmatrix}W^{(2)}{1,1}\W^{(2)}{2,1}\
W^{(2)}{3,1}\
\end{bmatrix}=[W^{(2)}{1,1}a_{11}+W^{(2)}{2,1}a{12}+W^{(2)}{3,1}a{13}]
$$
这样就将前向传播的算法通过矩阵的乘法表示出来了。在TensorFlow中提供了一个函数直接可以进行这样的矩阵计算。
1 | a = tf.matmul(x, w1) |
神经网络的参数
- 下面给出在TensorFlow中声明了一个$2*3$的矩阵变量的方法:
1 | weights = tf.Variable(tf.random_normal([2, 3], stddev=2)) |
tf.random_normal
正态分布,参数为:平均值、标准差、取值类型
官方API:tf.random_normaltf.truncated_normal
正态分布,但如果随机出来的值偏离平均值超过两2个标准差,重新随机
官方API:tf.truncated_normaltf.random_uniform
平均分布,参数为:最小、最大取值、取值类型
官方API:tf.random_uniformtf.random_gamma
Gamma分布,参数为:形状参数alpha、尺度参数beta、取值类型
官方API:tf.random_gamma
- NN中通常会使用常数初始化bias
1 | biases = tf.Variable(tf.zeros([3])) |
- TensorFlow中也支持使用其他变量初始值来初始化新变量:
1 | w2 = tf.Variable(weights.initialized_value()) |
- 将前向传播过程写成代码:
1 | import tensorflow as tf |
如果存在很多变量,再对每个变量初始化会导致很麻烦,TensorFlow提供了一种便捷的方式初始化:
1 | init_w = global_variables_initializer() |
简单的监督学习
使用监督学习的方式设置神经网络参数需要有标注好的训练数据集。
之前所有的变量的取值都是随机的,但是在实际过程中,可能需要更好的设置参数的值,这时就需要一种优化算法。而神经网络优化算法中最常用的方法是反向传播算法。
反向传播算法实现了一个迭代的过程,在每次迭代的开始,首先需要选取一小部分训练数据,这部分的叫做batch。然后,这个batch的样例会通过前向传播算法得到预测结果,因为训练数据都有标注,所以计算出当前计算的值和真实值之间的差距,反向传播算法会更新神经网络参数的取值,使得在这个batch上神经网络模型的预测结果和真实答案更接近。
这里要注意,如果每轮迭代中选取的数据都要通过常量来表示,那么TensorFlow的计算图将会太大。因为每生成一个常量,TensorFlow将会在计算图中增加一个节点。一般来说一个神经网络的训练要经过非常多次的迭代,这样就会产生非常大的计算图,利用率很低。为了避免这个问题,TensorFlow提供了placeholder机制用于提供输入数据,而只需要将数据通过placeholder传入计算图。
1 | import tensorflow as tf |
如果需要一次性计算多个样例前向传播结果。
1 | x = tf.placeholder(tf.float32, shape=(3, 2), name="input") |
利用损失函数反向传播调整参数
之后详细介绍
1 | # 损失函数 |
完整神经网络样例
- 这是一个完整程序训练二分类问题
1 | import tensorflow as tf |