本主题使用Tensorflow的高级API Keras实现Le-Net5卷积神经网络;
备注:在Keras之前,Tensorflow提供layers包提供了层的封装,并提供对应的函数实现层的快捷创建方式。
备注:训练结果是MNIST手写数字的部分
样本进行训练与测试。
使用的包
%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import math
一、输入层
# 1.1 训练集输入
input_layer_x = tf.keras.layers.Input(
shape=(28, 28, 1),
batch_size=None,
dtype=tf.float32)
# 1.2 训练集标签
input_layer_y = tf.keras.layers.Input(
shape=(10,),
batch_size=None,
dtype=tf.float32)
二、卷积层
# 2. 卷积层,池化层,dropout层
# 2.1 第一层 28*28*1->14*14*6
convolved_layer_28_28_6 = tf.keras.layers.Conv2D(
filters=6,
kernel_size=5, # 也可以元组,分别指定高宽(5, 5),
strides=1, # 也可以元组,分别指定高宽(1, 1),
padding='same',
data_format='channels_last', # 元组最后一个是通道数
activation=tf.nn.relu # 激活函数
)(input_layer_x)
pooled_layer_14_14_6 = tf.keras.layers.MaxPool2D(
pool_size=2, # 池化核大小,可以使用元组(2,2)
strides=2, # 步长,可以使用元组(2,2)
padding='valid', # 数据不足,是否补边
data_format='channels_last'
)(convolved_layer_28_28_6)
# 2.2 第二层 14*14*6 -> 5*5*16
convolved_layer_10_10_16 = tf.keras.layers.Conv2D(
filters=16,
kernel_size=5, # 也可以元组,分别指定高宽(5, 5),
strides=1, # 也可以元组,分别指定高宽(1, 1),
padding='valid',
data_format='channels_last', # 元组最后一个是通道数
activation=tf.nn.relu # 激活函数
)(pooled_layer_14_14_6)
pooled_layer_5_5_6 = tf.keras.layers.MaxPool2D(
pool_size=2, # 池化核大小,可以使用元组(2,2)
strides=2, # 步长,可以使用元组(2,2)
padding='valid', # 数据不足,是否补边
data_format='channels_last'
)(convolved_layer_10_10_16)
# 2.3 第三层 5*5*16 -> 1*1*120
convolved_layer_1_1_120 = tf.keras.layers.Conv2D(
filters=120,
kernel_size=5, # 也可以元组,分别指定高宽(5, 5),
strides=1, # 也可以元组,分别指定高宽(1, 1),
padding='valid',
data_format='channels_last', # 元组最后一个是通道数
activation=tf.nn.relu # 激活函数
)(pooled_layer_5_5_6)
三、卷积层到全连接层格式转换
fc_120 = tf.keras.layers.Flatten(
data_format='channels_last'
)(convolved_layer_1_1_120)
四、全连接层
# 3. 全连接层
# 3.2 第一层 120->84
fc_84 = tf.keras.layers.Dense(
units=84,
activation=tf.nn.relu
)(fc_120)
# 3.3 第二层 84->10
fc_10 = tf.keras.layers.Dense(
units=10,
activation=None, # 最后不需要激活函数,使用的是f(x)=x恒等激活函数
)(fc_84)
五、损失函数与优化器
# 4. 损失函数与优化器
# 预测模型
o_predict = tf.nn.sigmoid(fc_10)
# 损失函数
loss = tf.losses.sigmoid_cross_entropy(input_layer_y, fc_10)
optimizer = tf.train.AdamOptimizer(0.0001)
opt_op = optimizer.minimize(loss)
print('Le-Net5神经网络模型定义完毕!')
六、模型训练
- 这里训练采用了原始的方式(Tensorflow提供了更好的封装)
# 5. 数据加载-------------------------------------------------------
SAMPLE_PATH = 'samples/'
# 加载训练标签
result = np.loadtxt(SAMPLE_PATH + "train.txt", np.int)
NUM = 2000 # 训练集60000个,为了速度取一部分
result = result[0:NUM]
labels = np.zeros((len(result), 10), dtype=np.int)
for i in range(len(result)):
lb = result[I]
labels[i][lb] = 1
# 加载图像数据
# 把图像数据转换成需要的格式
data = np.zeros((len(result), 28, 28, 1), np.float32)
for i in range(len(result)):
# print('加载图像:%d' % I )
img = np.array([plt.imread(SAMPLE_PATH + "train/TrainImage_%05d.bmp" % (i + 1))])
data[i, :, :, 0] = img
print("加载完毕训练样本,个数:(%d)" % len(result))
# 加载测试集
# 加载测试标签
test_result = np.loadtxt(SAMPLE_PATH + "test.txt", np.int)
NUM = 200 # 测试集10000个,为了速度取一部分
test_result = test_result[0:NUM]
test_labels = np.zeros((len(test_result), 10), dtype=np.int)
for i in range(len(test_result)):
lb = test_result[I]
test_labels[i][lb] = 1
# 加载测试数据
test_data = np.zeros((len(test_result), 28, 28, 1), np.float32)
for i in range(len(test_result)):
# print('加载图像:%d' % I )
img = np.array([plt.imread(SAMPLE_PATH + "test/TestImage_%05d.bmp" % (i + 1))])
test_data[i, :, :, 0] = img
print("加载完毕测试样本,个数:(%d)" % len(test_result))
# 6. 训练--------------------------------------------------------
# 定义准确率
correct = tf.equal(tf.argmax(o_predict, 1), tf.argmax(input_layer_y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, 'float'))
# 执行训练
session = tf.Session()
session.run(tf.global_variables_initializer())
# 训练相关线束
TIMES = 1000
batch_size = 200
batch = int(math.ceil(len(data) / batch_size))
correct_rates = [] # 记录准确率,用于可视化。
is_over = False
for t in range(TIMES):
loss_result = 0.0
for idx in range(batch):
_, loss_result = session.run([opt_op, loss], # 边训练,边计算损失值。
feed_dict={
input_layer_x: data[idx * batch_size:(idx + 1) * batch_size],
input_layer_y: labels[idx * batch_size:(idx + 1) * batch_size]})
if loss_result < 0.000000001:
is_over = True
break
# 没一轮训练就评估效果
if t % 50 == 0:
# 评估准确率
correct_rate = session.run(accuracy, feed_dict={input_layer_x: test_data, input_layer_y: test_labels})
# 输出
print('测试集正确率: %5.2f%%,损失度:%f' % (correct_rate * 100.0, loss_result))
correct_rates.append(correct_rate)
if is_over:
break
print('训练完毕')
七、训练结果可视化
# 7. 可视化训练过程中的准确率
# 可视化一下训练过程
figure = plt.figure(figsize=(8, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(range(len(correct_rates)), correct_rates, color=(0, 0, 1, 1), marker='.', label='正确率曲线',
markerfacecolor=(1, 0, 0, 1), markeredgecolor=(1, 0, 0, 1), markersize=3)
ax.set_xbound(lower=-1, upper=len(correct_rates))
ax.set_ybound(lower=0, upper=1)
plt.annotate(s='最高识别率:%5.2f%%' % (max(correct_rates) * 100.0), xy=(60, 0.5))
plt.legend()
# plt.grid(b=True)
plt.show()
输出结果
- 运行输出
Le-Net5神经网络模型定义完毕!
加载完毕训练样本,个数:(2000)
加载完毕测试样本,个数:(200)
测试集正确率: 13.00%,损失度:0.702731
测试集正确率: 94.00%,损失度:0.017105
测试集正确率: 95.50%,损失度:0.002867
测试集正确率: 96.00%,损失度:0.000916
测试集正确率: 96.00%,损失度:0.000415
测试集正确率: 97.00%,损失度:0.000220
测试集正确率: 97.00%,损失度:0.000128
测试集正确率: 97.00%,损失度:0.000080
测试集正确率: 97.50%,损失度:0.000052
测试集正确率: 97.50%,损失度:0.000035
测试集正确率: 98.00%,损失度:0.000024
测试集正确率: 98.00%,损失度:0.000017
测试集正确率: 98.00%,损失度:0.000012
测试集正确率: 98.00%,损失度:0.000009
测试集正确率: 98.50%,损失度:0.000006
测试集正确率: 98.50%,损失度:0.000005
测试集正确率: 98.50%,损失度:0.000003
测试集正确率: 98.50%,损失度:0.000002
测试集正确率: 98.50%,损失度:0.000002
测试集正确率: 98.50%,损失度:0.000001
训练完毕
-
可视化输出