本文又是一篇基于Minist数据集的手写数字识别。
首先,mnist数据集:
链接:https://pan.baidu.com/s/1z7R7_jnDKZm9F7M6n8hiIw
提取码:rn8z
首先将二维的28*28的照片一维化成1*784的向量,搭建了一个784->128->10三个全连接层构成的网络,输出了分类结果。Dense层用了0.2的dropout。
首先对文章代码进行分块介绍,然后给出运行过程和运行结果,再对调试过程中遇到的一些问题进行简要说明,最后粘贴全部代码。
目录
一、代码分块介绍
三、调试中遇到的问题
1. 版本不兼容问题
2. history=model.fit()
3. fit和evaluate中的verbose
4. 关于执行问题
5. fit和evaluate的区别
四、代码
总结:
一、代码分块介绍
导入库:
import tensorflow as tf import matplotlib.pyplot as plt import numpy as np import os
第一个是深度学习框架的库
第二个是绘图库
第三个是数据分析库
第四个是操作系统功能接口库
获取Minist数据集
data = tf.keras.datasets.mnist (train_images,train_labels),(test_images,test_labels) = data.load_data()
获取数据集有很多种方法,比如下载下来保存到路径下,或者直接在tensorflow的库里加载。后文总结了获取数据集的方法,需要参考你的tensorflow版本,1.X和2.X不填一样。
#归一化 train_images = train_images/255.0 test_images = test_images/255.0
#这一部分是为了测试显示样例所用
#为了产生5*5大小的框框,可以修改
plt.figure(figsize=(5,5))
class_name = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
#下面这段也可以不要,为了显示照片
for i in range(25):
plt.subplot(5,5,i+1) #画图函数,代表将图按照5行5列的方式显示,i+1表示图存放的位置)
plt.xticks([])#坐标轴
plt.yticks([])
plt.grid(True,axis='x')#网格
plt.imshow(train_images[i],cmap=plt.cm.binary)#下面详细说说
plt.xlabel(class_name[train_labels[i]])#去对应的标签
plt.show()#显示图片
plt.imshow(train_images[i],cmap=plt.cm.binary)
第一个参数表示第几张照片,第二个参数cmap=colormap。
设置cmap参数有以下几种方式:
plt.imshow(image, cmap=plt.get_cmap('gray_r'))
plt.imshow(image, cmap='gray_r')
plt.imshow(image, cmap=plt.cm.binary)
参数作用
# 训练和保存模型
if os.path.exists('./model.h5'): #如果该路径下存在该模块,则加载模块,否则训练模型并保存
model = tf.keras.models.load_model('./model.h5')
else:
model = tf.keras.models.Sequential([ #搭建网络结构
tf.keras.layers.Flatten(input_shape=(28,28)),#拉直层可以变换张量的尺寸,把输入特征拉直为一维数组==1*784维向量
tf.keras.layers.Dense(128,activation='relu'),#第一个参数神经元个数,第二个参数‘激活函数’
tf.keras.layers.Dropout(0.2), #dropout丢失率设置为0.2
tf.keras.layers.Dense(10,activation='softmax') # 输出层,10分类,10个神经元,多分类采用softmax分类器
])
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.fit(train_images,train_labels,epochs=10)
model.save('model.h5') #保存模型,命名为model.h5,以后运行直接调用模型,不必训练
使用tf.keras.model.Sequential搭建分类模型主要包括七个步骤:(1)导入包模块;(2)加载数据集;(3)切分训练集和验证集;(4)对数据进行归一化处理;(5)搭建分类模型;(6)训练模型;(7)将模型应用于测试集。
前面4个之前已做,上面的代码就是搭建分类模型的代码。首先将输入的28*28照片拉成一维的1*784的向量作为输入,然后经过一个128个神经元的全连接层Dense,其dropout设置为0.2,最后连接到10个神经元的输出层作为分类结果。Dense层的激活函数为relu,输出层多分类,激活函数使用softmax。
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
optimizer:优化器设置为Adam;
loss:损失函数为交叉熵损失;
metrics: 列表,包含评估模型在训练和测试时的性能的指标,典型用法是metrics=[‘accuracy’];
history = model.fit(train_images,train_labels,epochs=10) loss = history.history['loss'] acc = history.history['accuracy']
model.fit:返回训练时的情况,返回的是一个History对象,可以通过History.history来查看训练过程,loss值等等,作为列表被保存了下来,方便后面画epoch的图用。epoch设为10。
plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.title('Training Accuracy')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.title('Training Loss')
plt.legend()
plt.show()
画出loss和accuracy随着epoch变化的图。
print('在测试集上评估')
test_loss,test_acc = model.evaluate(test_images,test_labels,verbose=1)
print('看看测试及测试结果')
predictions = model.predict(test_images)
for i in range(10):
print('预测值 = %i;正确值 = %i' % (np.argmax(predictions[i]),test_labels[i]))
model.evaluate():返回的是损失值和你指定的指标值。本例中你的目标是准确率accuracy,即model.compile(metric["accuracy"])。此处返回测试集的Loss和acc。只返回一个值。
model.predict将测试集照片进行预测,输出的是一个列表,保存对每个对应的test_images的预测。每个预测结果predict[i]都是一个长度为10的一维数组(十分类问题),哪个值最大就属于哪个分类结果。所以predeicts是一个test_size*10的二维数组。
ef preprocess_image(image):
image = tf.image.decode_jpeg(image,channels=1)
image = tf.image.resize(image,[28,28])
image = image/255.0
image = tf.reshape(image,[28,28])
return image
将输入的照片剪裁成合适尺寸,并归一化,最后改变形状。
def load_and_preprocess_image(path):
image = tf.io.read_file(path)
return preprocess_image(image)
读一个路径下的图片。
filepath = './3.jpg'
test_my_image = load_and_preprocess_image(filepath)
test_my_image = (np.expand_dims(test_my_image,0))
my_result = model.predict(test_my_image)
print('自己的图片预测值 = %i ; 文件名 = ', (np.argmax(my_result[0]), filepath))
测试:加载本文件同路径下的照片,reshape后进行预测。
二、运行过程和结果
整篇代码没有什么错误,下载所需的库就可以直接运行。
运行结果:
(1)显示的图片库中的一些图片:
(2)model.fit模型训练时,画的loss和acc随epoch变化图:
(3)model.fit模型训练时的日志信息,包括loss和acc:
训练模型: 2021-10-05 15:33:45.436902: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN)to use the following CPU instructions in performance-critical operations: AVX AVX2 To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags. Epoch 1/10 1875/1875 [==============================] - 1s 792us/step - loss: 0.2952 - accuracy: 0.9153 Epoch 2/10 1875/1875 [==============================] - 2s 874us/step - loss: 0.1424 - accuracy: 0.9578 Epoch 3/10 1875/1875 [==============================] - 2s 858us/step - loss: 0.1068 - accuracy: 0.9672 Epoch 4/10 1875/1875 [==============================] - 2s 824us/step - loss: 0.0890 - accuracy: 0.9728 Epoch 5/10 1875/1875 [==============================] - 2s 1ms/step - loss: 0.0750 - accuracy: 0.9772 Epoch 6/10 1875/1875 [==============================] - 2s 831us/step - loss: 0.0656 - accuracy: 0.9792 Epoch 7/10 1875/1875 [==============================] - 2s 816us/step - loss: 0.0587 - accuracy: 0.9811 Epoch 8/10 1875/1875 [==============================] - 2s 835us/step - loss: 0.0547 - accuracy: 0.9821 Epoch 9/10 1875/1875 [==============================] - 2s 929us/step - loss: 0.0468 - accuracy: 0.9845 Epoch 10/10 1875/1875 [==============================] - 2s 833us/step - loss: 0.0454 - accuracy: 0.9847
(4)model.evaluate评估训练完的模型的结果(用测试集):
在测试集上评估 313/313 [==============================] - 0s 775us/step - loss: 0.0717 - accuracy: 0.9790
(5)该路径下图片的预测结果:
开始预测: 自己的图片预测值 = %i ; 文件名 = (5, './3.jpg')
三、调试中遇到的问题
1. 版本不兼容问题
tensorflow1.X和2.X版本不兼容,找到的代码里边有些是1.X的语法,在导入库时用以下代码:
把 import tensorflow as tf 改成: import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
例如,在使用sess=tf.Session时,不能使用,就需要如下方式改:
import tensorflow as tf tf.compat.v1.disable_eager_execution() matrix1 = tf.constant([[3,3]]) matrix2 = tf.constant([[2],[2]]) product = tf.matmul(matrix1,matrix2) print(matrix1) print(matrix2) print(product) # method 1 sess = tf.compat.v1.Session() result = sess.run(product) print(result) sess.close() # method 2 # with tf.compat.v1.Session() as sess: # result2 = sess.run(product) # print(result2)
2. history=model.fit()
history = model.fit(train_images,train_labels,epochs=10)
loss = history.history['loss']
acc = history.history['accuracy']
model.fit()保存了模型训练时训练集loss、验证集loss、训练集准确率数据,作为字典保存了下来。但不同方法种调用loss和acc的数据不一样。本例中key的名字分别为loss和accuracy。
其他的方法可能不一样,如:
acc = history.history['sparse_categorical_accuracy'] val_acc = history.history['val_sparse_categorical_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss']
3. fit和evaluate中的verbose
其作用为记录训练日志。
verbose = 0 为不在标准输出流输出日志信息,verbose = 1 为输出进度条记录,verbose = 2 为每个epoch输出一行记录。
4. 关于执行问题
有的同学可能注意到,别的网络代码都有session作为模型调用的开始执行,但本例里面没用,难道它是直接执行的吗?
是的。因为别的代码用了session都是将模型写成了一个函数,封装在里面,函数是不会执行的,函数只有被调用了才可以执行。所以需要建立session对象来执行。
但是本例的模型执行直接在if-else里面,构建了model后,执行到model.fit时就开始执行了。
5. fit和evaluate的区别
fit():用于使用给定输入训练模型;
predict():用于实际预测,它为输入样本生成输出预测;
evaluate():用于评估已经训练过的模型,返回损失值&模型的度量值。
同时,模型的BatchNormalization,Dropout,LayerNormalization等优化手段只在fit时,对训练集有用;在进行evaluate()的时候,这些优化都会失效,因此,再次进行evaluate(x_train,y_train),就算添加了batchsize,也不能达到相同的评估计算结果。
四、代码
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import os
data = tf.keras.datasets.mnist
(train_images,train_labels),(test_images,test_labels) = data.load_data()
train_images = train_images/255.0 #归一化
test_images = test_images/255.0
plt.figure(figsize=(5,5))
class_name = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(True,axis='x')
plt.imshow(train_images[i],cmap=plt.cm.binary)
plt.xlabel(class_name[train_labels[i]])
# plt.ylabel(class_name[train_labels[i]])
plt.show()
#训练和保存模型
if os.path.exists('./model.h5'):
print('直接加载模型:')
model = tf.keras.models.load_model('./model.h5')
else:
print('训练模型:')
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28,28)),
tf.keras.layers.Dense(128,activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10,activation='softmax')
])
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
history = model.fit(train_images,train_labels,epochs=10)
loss = history.history['loss']
acc = history.history['accuracy']
plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.title('Training Accuracy')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.title('Training Loss')
plt.legend()
plt.show()
model.save('model.h5')
print('在测试集上评估')
test_loss,test_acc = model.evaluate(test_images,test_labels,verbose=1)
print('看看测试及测试结果')
predictions = model.predict(test_images)
print('预测值 = %i;正确值 = %i' % (np.argmax(predictions[0]),test_labels[0]))
# 图片进行预处理,reshape后进行归一化
def preprocess_image(image):
image = tf.image.decode_jpeg(image,channels=1)
image = tf.image.resize(image,[28,28])
image = image/255.0
image = tf.reshape(image,[28,28])
return image
# 加载图片路径,将图片进行预处理后输出
def load_and_preprocess_image(path):
image = tf.io.read_file(path)
return preprocess_image(image)
print('开始预测:')
filepath = './3.jpg'
test_my_image = load_and_preprocess_image(filepath)
test_my_image = (np.expand_dims(test_my_image,0))
my_result = model.predict(test_my_image)
print('自己的图片预测值 = %i ; 文件名 = ',(np.argmax(my_result[0]), filepath))
总结:
(1)显然,这份代码有点憨批,照片识别没有用CNN。直接将二维的照片一维化成784的向量,搭建了一个784->128->10三个全连接层构成的网络,输出了分类结果。
(2)同时,本文在fit时没有用batchsize,所以训练时有点慢,且准确率达到98.10%。加上batchsize后,如设置为1000,每1000个才进行一次更新,快了很多,但准确率下降到96%。
有了batchsize=1000:
没有batchsize:
不过作为新手还是推荐学习的,学习一下整个神经网络的训练和学习过程。



