TensorFlow练习1-前馈神经网络实现分类

文章目录
  1. 介绍
  2. 实现部分

开始学习TensorFlow, 看了一些文档以及教学视频,主要是周莫烦的TensorFlow入门视频 ,之前自己手写过BPNN,各种debug,费了很多事情,而且还有很多地方需要优化,想到自己还要用CNN, RNN等DNN,自己写的话, 可能性不大了,于是就打算使用深度学习框架了,准备多写几个例子加深印象。

介绍

TF属于google提出的一套graph计算框架,跟我们之前的思路不太一样,之前是导入数据,然后进行训练,测试等等,而TF事先设计好网络,然后再填充数据,这种方式的好处是设计与数据分离,不用针对具体数据,而坏处是不容易调试,因为network中的变量在没有数据之前,都还没有分配内存,还好有可视化工具tensorboard,可以很清楚的看到每个变量的shape。

TensorFlow的安装,上一篇博客已经记录了。 这一个博客主要是使用TensorFlow做一个mnist数据集的分类的例子。主要记录下,自己的学习流程。

实现部分

首先定义了添加层的函数。 每添加一个层,需要有输入, 参数权重,偏置,以及最后的输出, 当然还有激励函数。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def add_layer(inputs, in_size, out_size, layer_name, activity_func=None):
'''
args:
inputs: 层的输入
in_size: 输入的shape
out_size: 输出的shape, 与in_size共同决定了权重的shape
activity_fuc: 激活函数
'''
# 正太分布下,初始化权重W
W = tf.Variable(tf.random_uniform([in_size, out_size], -1.0, 1.0), name="W")
# 偏置一般用一个常数来初始化就行
bias = tf.Variable(tf.constant(0.1, shape=[out_size]), name="bias")
# Wx_Plus_b = tf.matmul(inputs, W) + bias 这种方式与下面的均可以
Wx_Plus_b = tf.nn.xw_plus_b(inputs, W, bias)
if activity_func is None:
outputs = Wx_Plus_b
else:
outputs = activity_func(Wx_Plus_b)
return outputs # 返回的是该层的输出

接着,开始构造神经网络。使用的数据集手写数字识别的mnist数据集,包含训练数据和测试数据,属于机器学习中的Hello World。数据的输入已经处理为了28*28的向量,标签是one-hot的10维的向量。 基于数据集,我们先定义一些参数:

1
2
3
4
5
hidden_layers = 1 # 一共有多少层,这里只用了一个隐层,多层一样
hidden_units = 200 # 每一层的隐层神经元的个数,实际上应该是一个列表,由于只有一个隐层,直接设置为了一个数字
n_input = 784 # 输入向量维度
n_classes = 10 # 最后一层的输出的维度,分类问题中就是类别的个数
learning_rate = 0.5 # 学习率,一般是梯度下降等优化算法的参数.

下面就可以定义网络的结构了,TF的特点就是先设计网络,无需实际的数据。先定义输入数据和输出数据:

1
2
xs = tf.placeholder(tf.float32, [None, n_input], name="input")
ys = tf.placeholder(tf.float32, [None, n_classes], name="output")

使用placeholder相当于给xs, ys 预留个位置,等后续填充数据,第二个参数是shape,其中None表示任何数都可以,一般是batch_size,就是训练的数据量。 有了输入数据,下面开始添加层,这里加入一个隐含层:

1
2
3
4
5
6
# 第一层,输入数据就是xs
l1 = add_layer(xs, n_input, hidden_units, 'hidden_layer_1', activity_func=tf.nn.tanh)
#l2 = add_layer(l1, in_size, out_size, .....) 类似可以定义多层
#定义隐层到输出层:, 输入是隐层的输出即: l1 , 最后使用一个softmax 分类
prediction = add_layer(l1, hidden_units, n_classes, 'prediction_layer', activity_func=tf.nn.softmax)

就上面的几行代码就可以构造好我们的神经网络了。 下面开始训练操作,一般神经网络是用BackProg来训练,然后SGD进行优化。 在TensorFlow里面,下面两行就可以了,手写的时候,写了一堆函数—:

1
2
3
4
5
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction))) 也可以用下面tf自带的计算交叉熵的函数
# 使用预测值与真实值,计算误差,不推荐平方误差
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(prediction, ys))
train_op = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy) # 直接指定学习率,最小化损失函数即可

到这里,我们的网络以及训练都完成了,可以把数据传进去,进行训练了,不过,在这之前,最好是加入一下测试,每轮训练完了,看看测试数据集的正确率。 也很简单,直接看看预测与实际的偏差,然后构造一个Tensor即可:

1
2
3
4
5
## accuracy
# 数据集是10维的, 只需要选出最大作为识别的类别即可。
correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(ys, 1))
# TensorFlow里面运算均是 float32,因此这里有个强制转化
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

到此,所有事情准备完毕,开始装数据!直接看完整的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python
# encoding: utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import time
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
def add_layer(inputs, in_size, out_size, layer_name, activity_func=None):
''''''
W = tf.Variable(tf.random_uniform([in_size, out_size], -1.0, 1.0), name="W")
bias = tf.Variable(tf.constant(0.1, shape=[out_size]), name="bias")
# Wx_Plus_b = tf.matmul(inputs, W) + bias
Wx_Plus_b = tf.nn.xw_plus_b(inputs, W, bias)
# Wx_Plus_b = tf.nn.dropout(Wx_Plus_b, keep_prob)
if activity_func is None:
outputs = Wx_Plus_b
else:
outputs = activity_func(Wx_Plus_b)
return outputs
## para
hidden_layers = 1
hidden_units = 200
n_input = 784
n_classes = 10
learning_rate = 0.8
## define network
xs = tf.placeholder(tf.float32, [None, n_input], name="input")
ys = tf.placeholder(tf.float32, [None, n_classes], name="output")
keep_prob = tf.placeholder(tf.float32)
l1 = add_layer(xs, n_input, hidden_units, 'hidden_layer_1', activity_func=tf.nn.tanh)
prediction = add_layer(l1, hidden_units, n_classes, 'prediction_layer', activity_func=tf.nn.softmax)
## coss and train step
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction)))
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(prediction, ys))
train_op = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy)
tf.summary.scalar('loss', cross_entropy)
## accuracy
correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(ys, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
init = tf.global_variables_initializer()
# para
n_epochs = 40
batch_size = 100
with tf.Session() as sess:
st = time.time()
write = tf.summary.FileWriter('logs/', sess.graph)
sess.run(init)
for epoch in range(n_epochs):
n_batch = mnist.train.num_examples / batch_size
for i in range(n_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
sess.run(train_op, feed_dict={xs: batch_xs, ys: batch_ys, keep_prob:1.0})
print 'epoch', epoch, 'accuracy:', sess.run(accuracy, feed_dict={keep_prob:1.0, xs: mnist.test.images, ys: mnist.test.labels})
end = time.time()
print '*' * 30
print 'training finish. cost time:', int(end-st) , 'seconds; accuracy:', sess.run(accuracy, feed_dict={keep_prob:1.0, xs: mnist.test.images, ys: mnist.test.labels})

最终的结果,正确率到了94%:

1
2
3
4
5
6
7
8
9
epoch 34 accuracy: 0.9424
epoch 35 accuracy: 0.9426
epoch 36 accuracy: 0.9429
epoch 37 accuracy: 0.9433
epoch 38 accuracy: 0.9438
epoch 39 accuracy: 0.9437
******************************
training finish. cost time: 34 seconds; accuracy: 0.9437

因为网络的初始值都是随机的, 因此结果肯定不一样,有时候,初始值好的话, 可能很快就可以收敛,有时候运气不好,可能很多轮很慢,到百分之七八十,这个时候,就需要尝试了,调整学习率什么的,或者加大迭代的轮数,比如我增加到100轮,正确率到了95.2%。 最后说一个加快训练并且避免过拟合的方式: Dropout, 道理简单来说,就是每次训练随机性的忽略一些节点的贡献,将一些节点权重设置为0,这样就会避免特别依赖某些神经元,减少过拟合。DropOut在TF里面很容易实现,在add_layer里面加入一句话即可:

1
Wx_Plus_b = tf.nn.dropout(Wx_Plus_b, keep_prob)

其中keep_prob是要保留训练的比重,一般设置0.6,0.75等等,也是一个placeholder:

1
2
3
xs = tf.placeholder(tf.float32, [None, n_input], name="input")
ys = tf.placeholder(tf.float32, [None, n_classes], name="output")
keep_prob = tf.placeholder(tf.float32)

在训练的时候,传入进去就ok了。 这篇主要记录了在用TensorFlow做神经网络的时候,一个大概的流程,其余基本很类似。下面的训练也会基于这样的流程。