????欢迎莅临我的个人主页????????这里是我专注于深度学习领域、用心分享知识精粹与智慧火花的独特角落!????
????如果大家喜欢文章,欢迎:关注????+点赞????????+评论✍????+收藏????,如有错误敬请指正!????
????“请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信生活中总有美好值得我们全力以赴,哪怕粉身碎骨!”????
前言
????模式识别导论课程编程实践作业????
目录
任务说明
数据文件
编辑程序实现思路
数据处理
自定义神经网络
1️⃣整体网络架构
2️⃣特征提取部分
3️⃣全局平均池化
4️⃣分类器部分
5️⃣参数量
数据划分及打包
模型训练
模型测试
性能评估结果分析
任务说明
使用MNIST手写数据集,设计神经网络结构以实现字符识别,网络结构可采用多层感知器或卷积神经网络
数据文件
????下载地址:Minst数据集
????文件内容
程序实现思路
该项目的完整资源我已经上传GitHub,有需要的可自取
GitHub地址:https://github.com/Rostiute-W/Minst_recogntion-Pytorch/tree/main
????项目目录
数据处理
由于Minst数据集是以二进制的形式存储的,为了便于后续处理,我将其由二进制转为了PNG图片形式,并分为train和test文件夹(train含60000张图像,test含1000张图像)
# convert2img.py
import os
import idx2numpy
from PIL import Image
from tqdm import tqdm
# --------------------------------------------------------------#
# 将IDX文件转换为图片
# --------------------------------------------------------------#
# -------------------------设置IDX文件的路径---------------------#
train_images_path = 'test3/dataset/MNIST/train-images.idx3-ubyte'
train_labels_path = 'test3/dataset/MNIST/train-labels.idx1-ubyte'
test_images_path = 'test3/dataset/MNIST/t10k-images.idx3-ubyte'
test_labels_path = 'test3/dataset/MNIST/t10k-labels.idx1-ubyte'
# -------------------------保存图片根目录------------------------#
output_dir = 'test3/dataset'
# -------------------------检查文件是否存在----------------------#
for path in [train_images_path, train_labels_path, test_images_path, test_labels_path]:
if not os.path.exists(path):
raise FileNotFoundError(f"文件未找到: {path}")
os.makedirs(output_dir, exist_ok=True)
# ---------------------------保存为PNG格式----------------------#
def save_images(images, labels, dataset_type='train'):
for label in range(10):
label_dir = os.path.join(output_dir, dataset_type, str(label))
os.makedirs(label_dir, exist_ok=True)
num_samples = images.shape[0]
print(f"\033[31m保存 {dataset_type} 集中的 {num_samples} 张图片\033[0m")
for idx in tqdm(range(num_samples)):
image = images[idx]
label = labels[idx]
# -----------------转换为PIL图像-------------------#
img = Image.fromarray(image).convert('L')
img_name = f"{idx}.png"
img_path = os.path.join(output_dir, dataset_type, str(label), img_name)
img.save(img_path)
if __name__ == '__main__':
# ---------------------------加载训练集图像和标签----------------------------#
train_images = idx2numpy.convert_from_file(train_images_path)
train_labels = idx2numpy.convert_from_file(train_labels_path)
# ---------------------------加载测试集图像和标签----------------------------#
test_images = idx2numpy.convert_from_file(test_images_path)
test_labels = idx2numpy.convert_from_file(test_labels_path)
# -------------------------------保存训练集图像------------------------------#
save_images(train_images, train_labels, 'train')
# -------------------------------保存测试集图像------------------------------#
save_images(test_images, test_labels, 'test')
print("\033[31mMNIST数据集已成功转换为PNG格式图片\033[0m")
????目录结构
自定义神经网络
注:我使用的深度学习框架是Pytorch
# -------------------------------------------------------------#
# 自定义网络结构
# -------------------------------------------------------------#
class MinstNet(nn.Module):
def __init__(self, num_classes=10):
super(MinstNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
)
self.global_pool = nn.AdaptiveAvgPool2d((1, 1))
self.classifier = nn.Sequential(
nn.Linear(128, 128),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(128, num_classes),
)
def forward(self, x):
x = self.features(x)
x = self.global_pool(x)
x = torch.flatten(x, start_dim=1)
x = self.classifier(x)
return x
1️⃣整体网络架构
这个神经网络是一个用于图像分类任务的卷积神经网络(CNN),主要由特征提取部分、全局平均池化层和分类器部分组成。
2️⃣特征提取部分
由一系列卷积层、批量归一化层和激活函数层组成。
- 首先,使用三个卷积模块进行特征提取。每个卷积模块包含一个卷积层、一个批量归一化层和一个 ReLU 激活函数。这种组合有助于加速网络的训练收敛速度,并提高模型的泛化能力。
- 卷积层的参数设置如下:
- 第一个卷积层将输入的三通道图像转换为 32 通道的特征图,卷积核大小为 3x3,步长为 1,填充为 1,这可以保持输入图像的尺寸不变。
- 第二个卷积层将 32 通道的特征图进一步转换为 64 通道,参数设置与第一个卷积层类似。
- 第三个卷积层将 64 通道的特征图转换为 128 通道。
- 每个卷积模块之后跟着一个最大池化层,池化核大小为 2x2,步长为 2,用于降低特征图的空间尺寸,减少计算量和参数数量,同时提取更抽象的特征。
3️⃣全局平均池化
使用自适应平均池化层将特征图的空间尺寸压缩为 1x1,即每个通道的特征被压缩为一个值。这一步的作用是将不同大小的输入图像转换为固定长度的特征向量,方便后续的分类操作。
4️⃣分类器部分
由两个全连接层、一个 Dropout 层和最后的输出层组成。
- 第一个全连接层将全局平均池化后的 128 维特征向量映射到 128 维的隐藏层。
- 接着使用 ReLU 激活函数增加模型的非线性表达能力。
- Dropout 层以 0.5 的概率随机丢弃神经元的输出,有助于防止过拟合。
- 最后一个全连接层将 128 维的隐藏层映射到指定数量的类别(由参数
num_classes
决定,默认为 10),输出每个类别的预测概率。
5️⃣参数量
可以看到哈,这个网络其实是非常简单的,参数量也相对少很多(只有11万左右),但是对于Minst数据集这种分类任务来说还是绰绰有余的
数据划分及打包
这个部分我使用的是B站博主霹雳吧啦Wz的代码,并对其进行了部分修改以适应本次的分类任务。最终可以得到类别标签的txt、测试集的txt文件(最终测试的文本数据集),我的训练集又划分为了训练集和验证集,二者的比例是8:2,也就是最终进行训练的图像有48004张,验证的图像有11996张,测试的图像有10000张。
代码我就不放了,具体可以看utils.py和dataloader.py
模型训练
训练流程没啥好说的,就是正常的训练即可。不懂的看这儿!
参数需要注意的是,本次训练采用了AMP(自动混合精度)、优化器是Adam、损失函数是交叉熵,我没有设置按照轮数的模型保存,直接存储的就是性能最佳的模型,同时训练过程中的损失和准确率曲线也进行了绘制(含训练和验证),这些均存储在logs文件夹下
具体可以看train.py和callbacks.py
模型测试
这个部分参考了B站博主Bubbliiiing的代码,然后我自己重新写了一遍,现在可以通过输入文本数据的txt文件来测试模型在整个数据集上的性能,并且添加了一些其它的可视化效果,如混淆矩阵、Recall和Precision条形图等
具体可以看infer.py和eval.py
性能评估结果分析
这个网络我只训练了50轮,但是效果还是挺不错的
????损失曲线和准确率曲线
可以明显看到,模型在20轮左右的时候就开始收敛了,并且根据得到的文本数据来看,整个过程验证损失最低达到了0.1073,准确率达到了96.61%,数据已经相当可观了
????混淆矩阵
大部分的数据还是能够正确分类的,少部分数据出现误识别,其中5的识别错误率最高
????测试集指标
可以看到哈,无论是准确率、精确率、召回率还是F1分数,指标均达到了97%以上,并且对于单张图片的预测(手动测试)准确率非常高,可以说该模型在Minst数据分类任务上表现得十分出色
????总结
总的来说,此次分类任务完成的效果还是比较不错的,对于这样一个简单的项目十分推荐用于上手深度学习,我在GitHub上传的每一个代码均写了非常详尽的注释,即便是小白也能轻松上手噢!至此,综合编程实践项目算是全部完成了,非常感谢您能够看到这里,有任何疑问可以随时私信或评论留言噢!????