Reference:TensorFlow中文文档(文档是Python2.7,在博客里将代码改为3.7可用的了)
Github:代码与数据集都在这里
需要的基础知识:
00 Intro | 01 INTRO_MNIST | 02 CONV_MNIST |
---|---|---|
无 | 神经网络基础 | CNN基础 |
00 Intro
基本概念
TensorFlow 是一个编程系统, 使用图来表示计算任务。 图中的节点被称之为 op (operation 的缩写)。 一个 op 获得 0 个或多个 Tensor, 执行计算, 产生 0 个或多个 Tensor。
TF中重要的类:
- 使用图 (graph) 来表示计算任务.
- 在被称之为 会话 (Session) 的上下文 (context) 中执行图.
- 使用 tensor 表示数据.
- 通过 变量 (Variable) 维护状态.
- 使用 feed 和 fetch 可以为任意的操作(arbitrary operation) 赋值或者从其中获取数据.
构建图
举个构建一个默认图的例子,constant与matmul都是op节点
import tensorflow as tf
# 创建一个常量 op, 产生一个 1x2 矩阵. 这个 op 被作为一个节点加到默认图中
# 构造器的返回值代表该常量 op 的返回值.
matrix1 = tf.constant([[3., 3.]])
# 创建另外一个常量 op, 产生一个 2x1 矩阵.
matrix2 = tf.constant([[2.],[2.]])
# 创建一个矩阵乘法 matmul op , 把 'matrix1' 和 'matrix2' 作为输入.
# 返回值 'product' 代表矩阵乘法的结果.
product = tf.matmul(matrix1, matrix2)
构造完成以后,需要用Session会话来启动图,run()的参数传入的即是我们需要取回的op
with tf.Session() as sess:
result = sess.run(product)
print(result)
[[12.]]
变量
# 创建一个变量, 初始化为标量 0.
state = tf.get_variable("counter", initializer=0)
# 创建一个 op(update), 其作用是使 state 增加 1
one = tf.constant(1)
new_value = tf.add(state, one)
update = tf.assign(state, new_value)
上面就是图的构建,assgin()用于赋值给state。
# 启动图后, 变量必须先经过`初始化` (init) op 初始化,
# 首先必须增加一个`初始化` op 到图中.
init_op = tf.initialize_all_variables()
# 启动图, 运行 op
with tf.Session() as sess:
# 运行 'init' op
sess.run(init_op)
# 打印 'state' 的初始值
print(sess.run([state, one]))
# 运行 op, 更新 'state', 并打印 'state'
for _ in range(3):
sess.run(update)
print(sess.run(state))
且从第十行可以看出,还能多个值同时取出。
[0, 1]
1
2
3
占位符Feed
这个跟Python的argumentParser很像,他的作用很简单,将input每一轮feed入占位符中进行图运行,这对之后分批训练很有用。
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
会话
进行所有操作的地方。
with tf.Session() as sess:
print(sess.run([output], feed_dict={input1:[1.,2.,3.], input2:[4.,5.,6.]}))
[ 4. 10. 18.]
01 INTRO_MNIST
如果要亲手下载数据集你可以在这里下,数据集的内容里面有写,首先先读取数据集,由于tensorflow为了入门做了点操作方便了很多在读MNIST数据上,不过其他的就要自己动手分batch分test/train等等了。
载入数据
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/mnist-data/", one_hot=True)
定义输入
# x,y_分别装载真实输入的样本与样本label
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
模型本体
# 784 -> 10
w = tf.get_variable('w', [x.shape[-1], 10])
b = tf.get_variable('b', initializer=0.)
y = tf.nn.softmax(tf.matmul(x, w) + b)
像之前那样,需要构建模型,这里做一个简单的到不能再简单的神经网络,用无初始化的参数w与偏差b,和深度学习经典激励函数softmax
优化函数
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
y_为真实label,用真实值与得出值做交叉熵作为损失函数,并用经典的梯度下降优化以0.01学习率学习…就这么一个train_op完成了。
模型评估
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
用平均数来评测模型…然后就可以直接拿去运行了。
运行
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_op, feed_dict={x: batch_xs, y_: batch_ys})
if i % 100 == 0:
result = sess.run([cross_entropy, accuracy],
feed_dict={x: mnist.test.images, y_:mnist.test.labels})
print("batch:",i," loss:",result[0],"accuracy:",result[1])
print("accuracy:",sess.run(accuracy,
feed_dict={x: mnist.test.images, y_:mnist.test.labels}))
batch: 0 loss: 34787.844 accuracy: 0.1037
batch: 100 loss: 3675.5537 accuracy: 0.8891
batch: 200 loss: 3767.2817 accuracy: 0.881
batch: 300 loss: 3358.4658 accuracy: 0.9035
batch: 400 loss: 3790.03 accuracy: 0.8845
batch: 500 loss: 3279.187 accuracy: 0.9035
batch: 600 loss: 3204.0613 accuracy: 0.9058
batch: 700 loss: 3137.3442 accuracy: 0.912
batch: 800 loss: 3353.4536 accuracy: 0.9027
batch: 900 loss: 3239.4736 accuracy: 0.9058
accuracy: 0.9104
自此一个神经网络已经做完了(其实很像是用了普通的线性回归)准确度到91%左右就收敛了,似乎效果并不是特别的好。
02 CONV_MNIST
加入卷积吧!这里只写与之前不一样的了。
定义卷积层
# 定义步长为1的SAME类型Conv层
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
# 定义步长为2的MaxPooling层
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
这样提前定义了方便之后使用。
定义输入
# x要转换成[number, height, width, channel]的格式才能进一步完成卷积
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
x_image = tf.reshape(x, [-1, 28, 28, 1])
第一层卷积
# 28*28*1 -> 14*14*32
# 对Conv的过滤器的参数和偏差值都做了点初始化
W_conv1 = tf.get_variable('W_conv1', shape=[5, 5, 1, 32], initializer=tf.truncated_normal_initializer(stddev=0.1))
b_conv1 = tf.get_variable('b_conv1', shape=[32], initializer=tf.constant_initializer(0.1))
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
第二层卷积
# 14*14*32 -> 7*7*64
W_conv2 = tf.get_variable('W_conv2', shape=[5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=0.1))
b_conv2 = tf.get_variable('b_conv2', shape=[64], initializer=tf.constant_initializer(0.1))
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
第三层全连接
# 3136 -> 1024
W_fc1 = tf.get_variable('W_fc1', shape=[7 * 7 * 64, 1024], initializer=tf.truncated_normal_initializer(stddev=0.1))
b_fc1 = tf.get_variable('b_fc1', shape=[1024], initializer=tf.constant_initializer(0.1))
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
# 并加入Dropout,提高性能加快速度
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
第四层输出层
这一层跟之前的一层网络的就基本一样了。
# 1024 -> 10
W_fc2 = tf.get_variable('W_fc2', shape=[1024, 10], initializer=tf.truncated_normal_initializer(stddev=0.1))
b_fc2 = tf.get_variable('b_fc2', shape=[10], initializer=tf.constant_initializer(0.1))
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
算法优化与模型评估
# 将GD换成了Adam优化器,又快又好
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_op = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
运行
sess = tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(1600):
batch = mnist.train.next_batch(50)
if i % 100 == 0:
train_accuracy = sess.run(accuracy, feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0})
print("step %d, training accuracy %g"%(i, train_accuracy))
sess.run(train_op, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print("test accuracy %g"%sess.run(accuracy, feed_dict={
x:mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
step 0, training accuracy 0.1
step 100, training accuracy 0.84
step 200, training accuracy 0.9
step 300, training accuracy 0.94
step 400, training accuracy 0.88
step 500, training accuracy 0.98
step 600, training accuracy 0.94
step 700, training accuracy 0.98
step 800, training accuracy 0.96
step 900, training accuracy 0.96
step 1000, training accuracy 1
step 1100, training accuracy 0.98
step 1200, training accuracy 0.94
step 1300, training accuracy 1
step 1400, training accuracy 0.96
step 1500, training accuracy 0.94
test accuracy 0.9706
这下效果还蛮不错的,而且只学了1600次就有97%准确率了,实测这个模型学大概五六千就能达到99.1%的准确率的,这里就不写了。