神经网络

神经网络 (Neural Network) 是机器学习的一个分支,全称人工神经网络(Artificial Neural Network,缩写 ANN),是一种模仿生物神经网络的结构和功能的数学模型或计算模型,用于对函数进行估计或近似。

Perceptron (感知器)

一个典型的神经网络由输入层、一个或多个隐藏层以及输出层组成,其中箭头代表着数据流动的方向,而圆圈代表激活函数(最常用的激活函数为 Sigmoid 函数).

最简单的神经网络为感知器,它只有输入层和输出层:

$$z = g(a_{0} + w_1a_1 + w_2a_2 + w_3*a_3)$$

一般地,

$$L_n = \sum\limits_{i=0}^{N_{pixels}}{W_{ni}.X_i} + b_n = X.W+b$$

Tensorflow 中可用 tf.nn.softmax

Y = tf.nn.softmax(tf.malmul(X, W) + b)

感知器只能解决简单的线性可分问题,而无法解决非线性可分问题,比如连 XOR(异或)这种最简单的分类问题都无法解决。

交叉熵

对于 sigmoid 激活函数,交叉熵比二次代价函数有两个显著的优势:

mini-batch

当然可以每次只用一个训练图像来计算梯度并且立即更新权重和偏置,但在 100 个样本上都这样做可以得到一个更好地表示由不同样本图像施加约束的梯度并且可能更快地朝着解决方案收敛。mini-batch 的大小是可调整的参数。另外一个显著的好处是使用批处理也意味着使用较大的矩阵,而这些通常更容易在 GPU 上优化。

示例

import tensorflow as tf

X = tf.placeholder(tf.float32, [None, 28, 28, 1])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
init = tf.initialize_all_variables()

# model
Y=tf.nn.softmax(tf.matmul(tf.reshape(X,[-1, 784]), W) + b)
# placeholder for correct answers
Y_ = tf.placeholder(tf.float32, [None, 10])
# loss function
cross_entropy = -tf.reduce_sum(Y_ * tf.log(Y))

# % of correct answers found in batch
is_correct = tf.equal(tf.argmax(Y,1), tf.argmax(Y_,1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))

optimizer = tf.train.GradientDescentOptimizer(0.003)
train_step = optimizer.minimize(cross_entropy)

sess = tf.Session()
sess.run(init)

for i in range(10000):
    # load batch of images and correct answers
    batch_X, batch_Y = mnist.train.next_batch(100)
    train_data={X: batch_X, Y_: batch_Y}

    # train
    sess.run(train_step, feed_dict=train_data)

    	# success ? add code to print it
    a,c = sess.run([accuracy, cross_entropy], feed=train_data)

    	# success on test data ?
    test_data={X:mnist.test.images, Y_:mnist.test.labels}
    a,c = sess.run([accuracy, cross_entropy], feed=test_data)

FNN (前馈神经网络)

前馈神经网络一般指拥有一个或多个隐含层的神经网络(如典型神经网络图示):各神经元从输入层开始,接收前一级输入,并输入到下一级,直至输出层。整个网络中无反馈,可用一个有向无环图表示。

只要拥有足够多的隐含层,前馈神经网络能以任意精读逼近任意复杂的连续函数。然而,如何设计隐含层的个数依然是一个未决问题,业界一般是根据经验来设置。较好的方法就是预先设定几个可选值,通过切换这几个值来看整个模型的预测效果,选择效果最好的值作为最终选择。这种方法又叫做 Grid Search(网格搜索)。

典型的前馈神经网络包括:

RELU

在深度网络里,sigmoid 激活函数确实能带来很多问题。它把所有的值都挤到了 0 到 1 之间,而且当你重复做的时候,神经元的输出和它们的梯度都归零了。值得一提的是,出于历史原因,一些现代神经网络使用了 ReLU(修正线性单元),它大致是如下这个样子:

对于偏置值,如果用 ReLU 的话,最好的办法就是把它们都初始化成小的正值,这样神经元一开始就会工作在 ReLU 的非零区域内。

示例

K = 200
L = 100
M = 60
N = 30

W1 = tf.Variable(tf.truncated_normal([28*28, K] ,stddev=0.1))
B1 = tf.Variable(tf.zeros([K]))
W2 = tf.Variable(tf.truncated_normal([K, L], stddev=0.1))
B2 = tf.Variable(tf.zeros([L]))
W3 = tf.Variable(tf.truncated_normal([L, M], stddev=0.1))
B3 = tf.Variable(tf.zeros([M]))
W4 = tf.Variable(tf.truncated_normal([M, N], stddev=0.1))
B4 = tf.Variable(tf.zeros([N]))
W5 = tf.Variable(tf.truncated_normal([N, 10], stddev=0.1))
B5 = tf.Variable(tf.zeros([10]))

X = tf.reshape(X, [-1, 28*28])

Y1 = tf.nn.sigmoid(tf.matmul(X, W1) + B1)
Y2 = tf.nn.sigmoid(tf.matmul(Y1, W2) + B2)
Y3 = tf.nn.sigmoid(tf.matmul(Y2, W3) + B3)
Y4 = tf.nn.sigmoid(tf.matmul(Y3, W4) + B4)
Y = tf.nn.relu(tf.matmul(Y4, W5) + B5)

TensorFlow 有一个非常方便的函数可以在单步内计算 softmax 和交叉熵,它是以一种数值上较为稳定的方式实现的。如果要使用它,你需要在应用 softmax 之前将原始的权重和加上你最后一层的偏置隔离开来(在神经网络的术语里叫「logits」)。比如,可以把 Y = tf.nn.softmax(tf.matmul(Y4, W5) + B5) 替换为

Ylogits = tf.matmul(Y4, W5) + B5
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(Ylogits, Y_)

RNN(Recurrent Neural Networks,递归神经网络)

递归神经网络(RNN)是两种人工神经网络的总称:时间递归神经网络(recurrent neural network)和结构递归神经网络(recursive neural network)。时间递归神经网络的神经元间连接构成有向图,而结构递归神经网络利用相似的神经网络结构递归构造更为复杂的深度网络。RNN 一般指代时间递归神经网络。单纯递归神经网络因为无法处理随着递归,权重指数级爆炸或消失的问题(Vanishing gradient problem),难以捕捉长期时间关联;而结合不同的 LSTM 可以很好解决这个问题。时间递归神经网络可以描述动态时间行为,因为和前馈神经网络(feedforward neural network)接受较特定结构的输入不同,RNN 将状态在自身网络中循环传递,因此可以接受更广泛的时间序列结构输入。

深度神经网络

隐含层较多的神经网络一般称为深度神经网络,比如