即使是这么乱写也很准确准确率达到995这种程度的手写数字识别项目请看如下好家伙这破选题给我折腾了一整个小时手写数字识别增强MNIST加个平移旋转噪点完整源码链接https://pan.quark.cn/s/1e54aa2ae950先说数据这一块torchvision的datasets.MNIST倒是方便一行就下好了但他*的下到一半断了那个破进度条卡在67%一动不动我等了特么半小时才发现是yann.lecun那个老域名404了好在torchvision自己会切到aws的镜像不然我真想砸电脑数据增强这一块我用的transforms.Compose一条龙RandomAffine设了degrees15, translate(0.15,0.15)然后ToTensor之后再加一个Lambda层塞高斯噪声torch.randn_like出来的噪声乘0.15再clamp到0到1之间不然归一化之后有些像素直接变负数了踩过的坑def get_transform(augmentFalse): if not augment: return transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) return transforms.Compose([ transforms.RandomAffine(degrees15, translate(0.15, 0.15)), transforms.ToTensor(), transforms.Lambda(lambda x: torch.clamp( x torch.randn_like(x) * 0.15, 0.0, 1.0 )), transforms.Normalize((0.1307,), (0.3081,)) ])normalize那俩参数(0.1307,)和(0.3081,)是MNIST数据集的均值和标准差算出来的不是瞎编的这玩意儿要是搞错了模型收敛巨慢我之前直接拿(0.5,0.5)归一化结果loss跟心电图一样上下蹦然后说Dataloader那块的num_workerswindows下这玩意儿要是设大于0直接给你报错BrokenPipeError气得我直接设0拉倒linux下没问题但咱这破windows不配用多进程是吧CNN模型结构我就搞了两层卷积第一层32个3x3核第二层64个3x3核每层后面跟BatchNorm和MaxPool最后接一个128的全连接加Dropout(0.5)输出10类class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 nn.Conv2d(1, 32, kernel_size3, padding1) self.bn1 nn.BatchNorm2d(32) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.bn2 nn.BatchNorm2d(64) self.pool nn.MaxPool2d(2, 2) self.dropout1 nn.Dropout2d(0.25) self.dropout2 nn.Dropout(0.5) self.fc1 nn.Linear(64 * 7 * 7, 128) self.fc2 nn.Linear(128, 10) def forward(self, x): x self.pool(F.relu(self.bn1(self.conv1(x)))) x self.dropout1(x) x self.pool(F.relu(self.bn2(self.conv2(x)))) x self.dropout1(x) x x.view(-1, 64 * 7 * 7) x F.relu(self.fc1(x)) x self.dropout2(x) x self.fc2(x) return x我一开始没加BatchNorm结果训练到第三个epoch准确率就卡在93%上不去了加了bn之后直接冲到98%细节啊兄弟们bn的gamma和beta虽然多了点参数量但值Dropout的位置也讲究我放在pool后面而不是conv后面效果更好训练的时候有个坑就是增强过的数据训练集准确率看着没那么高第一轮才61.5%吓我一跳以为模型崩了后来一想不对啊增强之后样本更难了原始测试集反而一路飙到96%这就对了说明增强起到了正则化的作用def train_epoch(model, loader, optimizer, device): model.train() total_loss 0.0 correct 0 total 0 for data, target in loader: data, target data.to(device), target.to(device) optimizer.zero_grad() output model(data) loss F.cross_entropy(output, target) loss.backward() optimizer.step() total_loss loss.item() * data.size(0) pred output.argmax(dim1) correct pred.eq(target).sum().item() total target.size(0) return total_loss / total, correct / total学习率我设的0.001用Adam每5个epoch衰减一半最后一轮降到0.00025其实也可以直接用CosineAnnealing但我懒可视化那块才叫折腾matplotlib中文显示的问题我说了多少遍了每次都得配SimHei还特么得设axes.unicode_minusFalse不然负号显示成方块我直接把这两行扔文件开头plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False跑出来一看增强对比图原始数字整整齐齐增强之后歪七扭八的还带雪花噪点看着就真实随机平移了±15%旋转±15度再加高斯噪声σ0.15训练曲线那张图最能说明问题损失从1.1一路降到0.29训练集准确率从61.5%爬到91.1%测试集准确率从96.24%一路升到98.8%关键是训练和测试的差距在缩小说明增强确实有用没过拟合混淆矩阵那边我用的sklearn的confusion_matrix配合seaborn的热力图画的大部分数字都分得挺好就是4和9偶尔搞混还有3和8也有几回这特么也正常人类写潦草了也分不清我单独看了一下错误分类的样本图有些数字写得确实离谱7写得跟1一样5写得跟6似的这要是人能认错那也不能怪模型对吧训练结束后保存的模型才1.6MB放到手机上跑都没问题pth格式直接load就行torch.save(model.state_dict(), mnist_cnn_final.pth)最后跑一下main.py就全自动了数据增强→训练→保存→画图一条龙10个epoch在我这破i5笔记本cpu上跑了大概七八分钟要是能调cuda估计两三分钟搞定整体的目录结构也不复杂项目文件夹里五个py文件加一个data目录存MNIST数据再加一个pth模型和五张png图生成的05_错误分类.png里面能看到模型具体在哪些样本上翻车了这个对调试特别有用我看了下大部分错误样本本身就模糊到人眼都认不出那没辙总的来说这破项目就是MNIST数据增强加CNN的一套标准流程你要是毕设选这个切记三点一是数据增强的参数别设太猛不然模型学不动二是BatchNorm和Dropout一定要加三是matplotlib的SimHei赶紧配好不要等到画图才抓瞎最终测试集准确率98.8%马马虎虎吧要是调调超参数上99%也不难但我困了就这样吧非常不错了。
【免费】手写数字识别系统CNN增强版python源码分享,准确率提升巨大
发布时间:2026/6/1 4:48:09
即使是这么乱写也很准确准确率达到995这种程度的手写数字识别项目请看如下好家伙这破选题给我折腾了一整个小时手写数字识别增强MNIST加个平移旋转噪点完整源码链接https://pan.quark.cn/s/1e54aa2ae950先说数据这一块torchvision的datasets.MNIST倒是方便一行就下好了但他*的下到一半断了那个破进度条卡在67%一动不动我等了特么半小时才发现是yann.lecun那个老域名404了好在torchvision自己会切到aws的镜像不然我真想砸电脑数据增强这一块我用的transforms.Compose一条龙RandomAffine设了degrees15, translate(0.15,0.15)然后ToTensor之后再加一个Lambda层塞高斯噪声torch.randn_like出来的噪声乘0.15再clamp到0到1之间不然归一化之后有些像素直接变负数了踩过的坑def get_transform(augmentFalse): if not augment: return transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) return transforms.Compose([ transforms.RandomAffine(degrees15, translate(0.15, 0.15)), transforms.ToTensor(), transforms.Lambda(lambda x: torch.clamp( x torch.randn_like(x) * 0.15, 0.0, 1.0 )), transforms.Normalize((0.1307,), (0.3081,)) ])normalize那俩参数(0.1307,)和(0.3081,)是MNIST数据集的均值和标准差算出来的不是瞎编的这玩意儿要是搞错了模型收敛巨慢我之前直接拿(0.5,0.5)归一化结果loss跟心电图一样上下蹦然后说Dataloader那块的num_workerswindows下这玩意儿要是设大于0直接给你报错BrokenPipeError气得我直接设0拉倒linux下没问题但咱这破windows不配用多进程是吧CNN模型结构我就搞了两层卷积第一层32个3x3核第二层64个3x3核每层后面跟BatchNorm和MaxPool最后接一个128的全连接加Dropout(0.5)输出10类class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 nn.Conv2d(1, 32, kernel_size3, padding1) self.bn1 nn.BatchNorm2d(32) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.bn2 nn.BatchNorm2d(64) self.pool nn.MaxPool2d(2, 2) self.dropout1 nn.Dropout2d(0.25) self.dropout2 nn.Dropout(0.5) self.fc1 nn.Linear(64 * 7 * 7, 128) self.fc2 nn.Linear(128, 10) def forward(self, x): x self.pool(F.relu(self.bn1(self.conv1(x)))) x self.dropout1(x) x self.pool(F.relu(self.bn2(self.conv2(x)))) x self.dropout1(x) x x.view(-1, 64 * 7 * 7) x F.relu(self.fc1(x)) x self.dropout2(x) x self.fc2(x) return x我一开始没加BatchNorm结果训练到第三个epoch准确率就卡在93%上不去了加了bn之后直接冲到98%细节啊兄弟们bn的gamma和beta虽然多了点参数量但值Dropout的位置也讲究我放在pool后面而不是conv后面效果更好训练的时候有个坑就是增强过的数据训练集准确率看着没那么高第一轮才61.5%吓我一跳以为模型崩了后来一想不对啊增强之后样本更难了原始测试集反而一路飙到96%这就对了说明增强起到了正则化的作用def train_epoch(model, loader, optimizer, device): model.train() total_loss 0.0 correct 0 total 0 for data, target in loader: data, target data.to(device), target.to(device) optimizer.zero_grad() output model(data) loss F.cross_entropy(output, target) loss.backward() optimizer.step() total_loss loss.item() * data.size(0) pred output.argmax(dim1) correct pred.eq(target).sum().item() total target.size(0) return total_loss / total, correct / total学习率我设的0.001用Adam每5个epoch衰减一半最后一轮降到0.00025其实也可以直接用CosineAnnealing但我懒可视化那块才叫折腾matplotlib中文显示的问题我说了多少遍了每次都得配SimHei还特么得设axes.unicode_minusFalse不然负号显示成方块我直接把这两行扔文件开头plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False跑出来一看增强对比图原始数字整整齐齐增强之后歪七扭八的还带雪花噪点看着就真实随机平移了±15%旋转±15度再加高斯噪声σ0.15训练曲线那张图最能说明问题损失从1.1一路降到0.29训练集准确率从61.5%爬到91.1%测试集准确率从96.24%一路升到98.8%关键是训练和测试的差距在缩小说明增强确实有用没过拟合混淆矩阵那边我用的sklearn的confusion_matrix配合seaborn的热力图画的大部分数字都分得挺好就是4和9偶尔搞混还有3和8也有几回这特么也正常人类写潦草了也分不清我单独看了一下错误分类的样本图有些数字写得确实离谱7写得跟1一样5写得跟6似的这要是人能认错那也不能怪模型对吧训练结束后保存的模型才1.6MB放到手机上跑都没问题pth格式直接load就行torch.save(model.state_dict(), mnist_cnn_final.pth)最后跑一下main.py就全自动了数据增强→训练→保存→画图一条龙10个epoch在我这破i5笔记本cpu上跑了大概七八分钟要是能调cuda估计两三分钟搞定整体的目录结构也不复杂项目文件夹里五个py文件加一个data目录存MNIST数据再加一个pth模型和五张png图生成的05_错误分类.png里面能看到模型具体在哪些样本上翻车了这个对调试特别有用我看了下大部分错误样本本身就模糊到人眼都认不出那没辙总的来说这破项目就是MNIST数据增强加CNN的一套标准流程你要是毕设选这个切记三点一是数据增强的参数别设太猛不然模型学不动二是BatchNorm和Dropout一定要加三是matplotlib的SimHei赶紧配好不要等到画图才抓瞎最终测试集准确率98.8%马马虎虎吧要是调调超参数上99%也不难但我困了就这样吧非常不错了。