基于TensorFlow实现mnist数据分类

基于TensorFlow实现mnist数据分类

mnist数据集

  MNIST数据集是机器学习领域中非常经典的一个数据集,由60000个训练样本和10000个测试样本组成,每个样本都是一张28 * 28像素的灰度手写数字图片。

一共4个文件依次分别为:测试集、测试集标签、训练集、训练集标签


读入数据

  使用TensorFlow中input_data.py脚本来读取数据及标签。

1
2
3
4
5
6
7
8
9
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('./data/', one_hot=True) #one_hot 表示采用one_hot的编码方式编码标签
# 分成训练以及测试数据
trX, trY, teX, teY = mnist.train.images, mnist.train.labels,mnist.test.images, mnist.test.labels

# ?个图片28 * 28 一个颜色通道,因为数据是一维的,需要转化成28*28的形式
trX = np.reshape(trX, [-1, 28, 28, 1])
teX = np.reshape(teX, [-1, 28, 28, 1])

数据可视化

  将前20个图像显示出来。

1
2
3
4
5
6
7
8
9
fig, ax = plt.subplots(nrows=4,ncols=5,sharex='all',sharey='all')#20个子图
ax = ax.flatten() #将(4,5)降成(1,20)这样可以更好的将子图添加进去
for i in range(20):
img = trX[i].reshape(28, 28)#将数据转化为(28,28)的形式
ax[i].imshow(img, cmap='Greys')
ax[0].set_xticks([])
ax[0].set_yticks([])
plt.tight_layout()
plt.show()

图像如下

准备搭建卷积神经网络

  本次采用3个卷积层和2个全连接层。

  • 卷积函数和最大池化函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #定义卷积函数
    def conv2d(x, w, b, k):
    x = tf.nn.conv2d(x, w, strides=[1, k, k, 1], padding='SAME')
    x = tf.add(x, b)
    return tf.nn.relu(x)

    #定义最大池化函数
    def maxPool(x, k, s):
    return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, s, s, 1], padding='SAME')
  • 权值以及偏差

    卷积核都是使用3*3。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    weights = {
    'w1': tf.Variable(tf.random_normal([3, 3, 1, 32]), name='w1'),
    'w2': tf.Variable(tf.random_normal([3, 3, 32, 64]), name='w2'),
    'w3': tf.Variable(tf.random_normal([3, 3, 64, 128]), name='w3'),
    'w4': tf.Variable(tf.random_normal([4*4*128, 625]), name='w4'),
    'out': tf.Variable(tf.random_normal([625, 10]), name='wout')
    }

    biases = {
    'b1': tf.Variable(tf.random_normal([32]), name='b1'),
    'b2': tf.Variable(tf.random_normal([64]), name='b2'),
    'b3': tf.Variable(tf.random_normal([128]), name='b3'),
    'b4': tf.Variable(tf.random_normal([625]), name='b4'),
    'out': tf.Variable(tf.random_normal([10]), name='bout')
    }
  • 占位符

    1
    2
    3
    4
    X = tf.placeholder(tf.float32, [None, 28, 28, 1], 'x')#输入
    Y = tf.placeholder(tf.float32, [None, 10], 'y')#输出
    p_conv = tf.placeholder(tf.float32, name='p_conv')#卷积层dropout的比例
    p_hidden = tf.placeholder(tf.float32, name='p_hidden')#全连接层dropout的比例
  • 损失函数、优化器以及评估模型

    1
    2
    3
    4
    5
    6
    7
    # 损失函数
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=Y))
    #优化器
    op = tf.train.AdamOptimizer(0.001).minimize(cost)
    #评估模型
    # argmax(array,axis) axis=1取每行最大值的索引,0为取每列最大值的索引。这里表示取每个样本的预测值
    predict_op = tf.argmax(out, 1, name='predict_op')

搭建卷积神经网络

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
def model(x, weight, biases, p_conv, p_hidden,):
#第一层
c1 = conv2d(x, weights['w1'], biases['b1'], 1)
# c1 = [?,28,28,32]
c1 = maxPool(c1, 2, 2)
# c1 = [?,14,14,32]

#第二层
c2 = conv2d(c1, weights['w2'], biases['b2'], 1)
# c2 = [?,14,14,64]
c2 = maxPool(c2, 2, 2)
# c2 = [?,7,7,64]
c2 = tf.nn.dropout(c2, p_conv)#按比例杀死一些神经防止过拟合

#第三层
c3_a = conv2d(c2, weights['w3'], biases['b3'], 1)
c3 = tf.nn.relu(c3_a)
# c3 = [?,7,7,128]
c3 = maxPool(c3, 2, 2)
# c3 = [?,4,4,128]

#全连接层
#转换数据 c3 = [?,4*4*128]
c3 = tf.reshape(c3, [-1, weights['w4'].get_shape().as_list()[0]])
c3 = tf.nn.dropout(c3, p_conv)

#全连接第一层
c4 = tf.add(tf.matmul(c3, weights['w4']), biases['b4'])
c4 = tf.nn.dropout(c4, p_hidden)

#输出层
outputs = tf.add(tf.matmul(c4, weights['out']), biases['out'], name='outputs')
return outputs

训练以及评估

  因为数据量过大,所以采用分批训练。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
saver = tf.train.Saver()
for i in range(5):
#分批训练
training_batch = zip(range(0, len(trX), batch_size), range(batch_size, len(trX)+1, batch_size))
for start, end in training_batch:
sess.run(op, feed_dict={X: trX[start:end], Y:trY[start:end], p_conv: 0.8, p_hidden: 0.5})
test_indices = np.arange(len(teX))
np.random.shuffle(test_indices)#随机打乱
test_indices = test_indices[0:test_size]#获取评估数据
print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
sess.run(predict_op, feed_dict={X: teX[test_indices], p_conv: 1.0, p_hidden: 1.0})))
#保存训练的模型
saver.save(sess, 'model/mnist/mnist', global_step=1)

结果如下:


完整代码

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('./data/', one_hot=True) #one_hot 表示采用one_hot的编码方式编码标签
# 分成训练以及测试数据
trX, trY, teX, teY = mnist.train.images, mnist.train.labels,mnist.test.images, mnist.test.labels
weights = {
'w1': tf.Variable(tf.random_normal([3, 3, 1, 32]), name='w1'),
'w2': tf.Variable(tf.random_normal([3, 3, 32, 64]), name='w2'),
'w3': tf.Variable(tf.random_normal([3, 3, 64, 128]), name='w3'),
'w4': tf.Variable(tf.random_normal([4*4*128, 625]), name='w4'),
'out': tf.Variable(tf.random_normal([625, 10]), name='wout')
}

biases = {
'b1': tf.Variable(tf.random_normal([32]), name='b1'),
'b2': tf.Variable(tf.random_normal([64]), name='b2'),
'b3': tf.Variable(tf.random_normal([128]), name='b3'),
'b4': tf.Variable(tf.random_normal([625]), name='b4'),
'out': tf.Variable(tf.random_normal([10]), name='bout')
}

# ?个图片28 * 28 一个颜色通道
trX = np.reshape(trX, [-1, 28, 28, 1])
teX = np.reshape(teX, [-1, 28, 28, 1])

X = tf.placeholder(tf.float32, [None, 28, 28, 1], 'x')#输入
Y = tf.placeholder(tf.float32, [None, 10], 'y')#输出
p_conv = tf.placeholder(tf.float32, name='p_conv')#卷积层dropout的比例
p_hidden = tf.placeholder(tf.float32, name='p_hidden')#全连接层dropout的比例

#定义卷积函数
def conv2d(x, w, b, k):
x = tf.nn.conv2d(x, w, strides=[1, k, k, 1], padding='SAME')
x = tf.add(x, b)
return tf.nn.relu(x)

#定义最大池化函数
def maxPool(x, k, s):
return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, s, s, 1], padding='SAME')


def model(x, weight, biases, p_conv, p_hidden,):
#第一层
c1 = conv2d(x, weights['w1'], biases['b1'], 1)
# c1 = [?,28,28,32]
c1 = maxPool(c1, 2, 2)
# c1 = [?,14,14,32]

#第二层
c2 = conv2d(c1, weights['w2'], biases['b2'], 1)
# c2 = [?,14,14,64]
c2 = maxPool(c2, 2, 2)
# c2 = [?,7,7,64]
c2 = tf.nn.dropout(c2, p_conv)

#第三层
c3_a = conv2d(c2, weights['w3'], biases['b3'], 1)
c3 = tf.nn.relu(c3_a)
# c3 = [?,7,7,128]
c3 = maxPool(c3, 2, 2)
# c3 = [?,4,4,128]

#全连接层
#转换数据 c3 = [?,4*4*128]
c3 = tf.reshape(c3, [-1, weights['w4'].get_shape().as_list()[0]])
c3 = tf.nn.dropout(c3, p_conv)

#全连接第一层
c4 = tf.add(tf.matmul(c3, weights['w4']), biases['b4'])
c4 = tf.nn.dropout(c4, p_hidden)

#输出层
outputs = tf.add(tf.matmul(c4, weights['out']), biases['out'], name='outputs')
return outputs

batch_size = 128
test_size = 512
if __name__ == "__main__":
out = model(X, weights, biases, p_conv, p_hidden)
# 损失函数
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=Y))
#优化器
op = tf.train.AdamOptimizer(0.001).minimize(cost)
#评估模型
# argmax(array,axis) axis=1取每行最大值的索引,0为取每列最大值的索引。这里表示取每个样本的预测值
predict_op = tf.argmax(out, 1, name='predict_op')
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
saver = tf.train.Saver()
for i in range(5):
#分批训练
training_batch = zip(range(0, len(trX), batch_size), range(batch_size, len(trX)+1, batch_size))
for start, end in training_batch:
sess.run(op, feed_dict={X: trX[start:end], Y:trY[start:end], p_conv: 0.8, p_hidden: 0.5})
test_indices = np.arange(len(teX))
np.random.shuffle(test_indices)#随机打乱
test_indices = test_indices[0:test_size]#获取评估数据
print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
sess.run(predict_op, feed_dict={X: teX[test_indices], p_conv: 1.0, p_hidden: 1.0})))
saver.save(sess, 'model/mnist/mnist', global_step=1)
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×