项目组经过我和大师兄一个月的Coding,目前基本开发进度告一段落。可以沉下心来搞一搞机器学习相关的东西了。实际上,一开始进项目组的时候就想尝试采用机器学习(更具体的说是深度学习)的方式来做点不一样的事情,而不是纯数学的东西。当然,数学有数学的优势,机器学习有机器学习的优势。
扯得有点远,回到主题,这是最近学习CNN入门的时候练手用的,也应该算是我的第一个机器学习程序吧。记得做出来的时候,还是有点小小的激动,毕竟人生中第一次也不多,哈哈哈 。中间也踩了不少坑,总结一下,整理成文,供后来者参考。
CNN是什么
卷积神经网络(英语:convolutional neural network,缩写:CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。
卷积神经网络由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网络能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网络在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网络,卷积神经网络需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。
卷积神经网络的灵感来自于动物视觉皮层组织的神经连接方式。单个神经元只对有限区域内的刺激作出反应,不同神经元的感知区域相互重叠从而覆盖整个视野。
以上内容来自于维基百科 ,如果第一次接触的话,肯定是看的一脸懵。有机会我开个坑,尝试用大白话讲一讲。这里有个gif图,形象的展现了卷积的过程:
MNIST数据集
MNIST数据集是一个手写数字识别数据集,常用于机器学习和深度学习的训练与测试。这个数据集包含了大量的手写数字图像,包括0到9的数字。这些图像都是28x28像素的灰度图像,每个图像都对应着一个标签,表示图像中所包含的数字。
MNIST手写数据集👉:官网 。官网中数据集一共分成了四个部分:
官网上提供了数据集的下载,主要包括四个文件:
文件下载 | 文件用途 |
---|---|
train-images-idx3-ubyte.gz | 训练集图像 |
train-labels-idx1-ubyte.gz | 训练集标签 |
t10k-images-idx3-ubyte.gz | 测试集图像 |
t10k-labels-idx1-ubyte.gz | 测试集标签 |
在上述文件中,训练集一共包含了 60,000 张图像和标签,而测试集一共包含了 10,000 张图像和标签。测试集中前5000个来自最初NIST项目的训练集.,后5000个来自最初NIST项目的测试集。前5000个比后5000个要规整,这是因为前5000个数据来自于美国人口普查局的员工,而后5000个来自于大学生。
这里有一版整合了四个部分的数据集,推荐用这个,我已经上传至网盘,可以直接下载,我的代码也是基于这个整合后的数据集,下载解压即可✌️: 蓝奏云
加载数据集
这里默认已经准备好所有环境,推荐使用Anaconda
和PyCharm
,新手友好。
加载数据集有两种方式,第一种是直接无需下载MNIST数据集,因为在Tensorflow中自带了,不过任然需要下载,且下载地址在海外,有可能会出现下载失败的情况,所以不推荐。代码如下,如果没有下载会自动下载:
from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
下载的数据集路径位于:C:\Users\{用户名}\.keras
。目前我还没有找到指定下载路径的方法,默认都放在了C盘下。
第二种方式是手动加载,把下载好的数据集文件放在项目目录下,编写加载数据集代码:
# 加载Mnist数据集
def load_mnist():
with np.load('mnist.npz', allow_pickle=True) as data:
return (data['x_train'], data['y_train']), (data['x_test'], data['y_test'])
这里说明一下各个变量:
- x_train:训练集手写数据图像
- y_train:训练集手写数据图像对应的标签
- x_test:测试集手写数据图像
- y_test:测试集手写数据图像对应的标签
我们可以通过下面函数的打印出形状:
# 主函数
def main():
mnist = load_mnist()
print_shape(mnist)
# 打印形状
def print_shape(data):
x_train, x_label = data[0]
y_train, y_label = data[1]
print(x_train.shape)
print(x_label.shape)
print(y_train.shape)
print(y_label.shape)
预览数据集
上一步我们以及实现加载数据集,这里我们要看看这个数据集里的内容的真面貌。比如预览前25个图像,这里用到了matplotlib
绘图库,如果没有安装,记得安装一下。
import matplotlib.pyplot as plt
# 主函数
def main():
mnist = load_mnist()
view_image(mnist[0])
# 预览前25个图像
def view_image(data):
x_train, y_train = data
fig, ax = plt.subplots(nrows=5, ncols=5, sharex='all', sharey='all')
ax = ax.flatten()
for i in range(25):
img = x_train[i].reshape(28, 28)
ax[i].set_title(y_train[i])
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
ax[0].set_xticks([])
ax[0].set_yticks([])
plt.tight_layout()
plt.show()
预览结果:
可以看到某些数字好像写的我自己都不认识,但是以标签为准,这也是机器学习的魅力。
训练数据集并保存
这一步就是最核心的部分了。编写训练部分的代码,然后将训练好的模型保存下来,这样以后直接加载这个模型就可以了,不用再次训练。
由于MNIST数据集比较简单,我这里没有用到CNN卷积神经网络的卷积层和池化层,只进行了全连接层搭建。激活函数选择了relu,优化器选择Adam:
# 训练并保存为SaveModel
def train_model(mnist):
x_train, y_train = mnist[0]
x_test, y_test = mnist[1]
# 归一化
x_train = x_train / 255.0
x_test = x_test / 255.0
model = keras.Sequential([
layers.Flatten(input_shape=(28, 28)),
layers.Dense(128, activation='relu'),
layers.Dense(10)
])
model.summary()
model.compile(optimizer=keras.optimizers.Adam(),
loss=losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=10)
model.save('success')
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print('\nTest accuracy:', test_acc)
print('Test loss', test_loss)
等待10轮训练完成,可以看到loss在不断降低,accuracy在不断提高。最终可以达到97.7%的准确率 。
注意:这里都是通过CPU进行训练的,没有用到GPU,Tensorflow 2.10
是Windows本地支持 GPU 的最后一个版本。从2.11
开始,你就需要在WSL2
上安装Tensorflow,或者使用TensorFlow-DirectML-Plugin
。
我用的是2.15版本,不过好在这个数据集并不大,CPU已经完全够用了,整个过程不到20秒就训练结束。训练完成后,会把模型保存在项目文件夹下的success
文件夹。
加载模型并可视化验证结果
训练完毕后,我们可以加载保存好的模型,并进行验证。我这里就直接从测试集中随机选取10张图像来进行验证。有能力的小伙伴完全可以自己手写好数字,压缩成28*28的图像并用模型验证。
# 加载模型并可视化验证结果
def load_model_check(mnist):
matplotlib.rc("font", family='YouYuan')
x_test1, y_test = mnist[1]
# 归一化
x_test = x_test1 / 255.0
# 加载模型
model = keras.models.load_model('success')
model.summary()
plt.figure()
for i in range(10):
num = np.random.randint(1, 10000)
plt.subplot(2, 5, i + 1)
plt.axis('off')
plt.imshow(x_test1[num], cmap='gray')
demo = tf.reshape(x_test[num], (1, 28, 28))
y_pred = np.argmax(model.predict(demo))
plt.title('标签值:' + str(y_test[num]) + '\n预测值:' + str(y_pred))
plt.show()
注意,matplotlib库显示中文有可能会出现方框,记得指定一下字体(代码第二行),我这里就使用幼圆了。
可以看到预测结果还是很不错的,也给出了预测的时间,基本上都是在20ms范围内。
总结
到此,Tensorflow2实现MNIST手写数据识别就结束了。有的人肯定会问我为啥不用pytorch,因为Tensorflow最大的优势是能够把模型迁移到各种位置,嵌入式、web都可以,而且还能够压缩模型,详情可看:https://tensorflow.google.cn/lite?hl=zh-cn。
来学习
最近刚好在学习这个
不愧是研究生
组里面都是用pytorch写的,说是大部分学术论文都是用这个写的,方便学习