# CNN神经网络实验报告
## 问题描述
以MNIST手写数据集划分训练集和验证集,将自己手写拍照上传的数字图片作为测试样本,训练卷积神经网络分类器识别0-9的手写数字。
## 数据集说明
MNIST手写数字数据集包含60000张用于训练的手写数字图片和10000张用于测试的手写数字图片。所有的图片具有相同的尺寸(28x28 pixels),数字均位于图片中央。
数据集链接地址如下:
原训练集各类别分布和示例样本如下图所示:
![](https://www.writebug.com/myres/static/uploads/2022/9/26/61c3acf2b66aec1dd54053a6deabe33d.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/9/26/86bd9eef1988bb77ebd7123365f653fa.writebug)
图 1 训练集图片示例 图 2 训练集样本分布
在本实验中,原数据集中训练集被划分为训练集和验证集,其中验证集占比0.2,训练集占比0.8。原数据集的测试集作为测试集使用,用于评估模型性能。
在上述的分布图中不难发现,原数据集中的训练集基本上是类别均衡的;为了不破坏原数据集的类别均衡性,在划分训练集和验证集时,采用分类别抽样(stratified sampling)划分的方法。
![](https://www.writebug.com/myres/static/uploads/2022/9/26/b10fe6ef578f350dbe8dac2b37d438fa.writebug)
图 3 TensorBoard makegrid看到的输入图片
## 算法代码
算法概述:
模型架构:resnet18修改了第一个卷积层使其接受 BW 格式图片;修改了fc层使其输出10个类别的概率分布。未使用预先训练的权重。
数据处理:图片转换为 Tensor;按照 imagenet 图片第一个通道的均值和方差标准化处理。
权重更新:采用带动量的随机梯度下降法,初始学习率为 1e-3,动量参数为0.9;学习率每7个epoch缩小为0.1倍
损失计算:softmax + crossentropy loss
其他设置:batch_size=128, epoch_num = 24
使用说明: 训练模块设置了五个命令行参数,用户可自行决定数据文件夹位置,日志存放位置,模型保存位置,模型接受图片大小,训练集验证集的划分比例。
第三方包安装:
```c++
Pytorch
Tensorboard
Sk-learn
Numpy
Matplotlib
```
Seaborn(代码中没用上)
导入库
```python
# import necessary packages
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import Dataset, DataLoader, TensorDataset, Subset
import torchvision
from torchvision import transforms,utils,models
import argparse
import seaborn as sns
from collections import Counter
import time
import copy
from torch.utils.tensorboard import SummaryWriter
from sklearn.metrics import confusion_matrix, accuracy_score
```
可视化数据模块
```c++
def dataVisualization(x_train,y_train,x_test,y_test):
'''return null
visualing first nine images
save it as a image
then visualize distribution of training set
save it as a image
'''
plt.figure(figsize=(9, 9))
for i in range(9):
plt.subplot(331 + i)
plt.imshow(x_train[i], cmap=plt.get_cmap('gray'))
plt.savefig('sample.png', bbox_inches='tight', dpi=300)
print(f'训练集的样本数:{x_train.shape[0]},测试集的样本数:
{x_test.shape[0]}')
print(f'输入图像的大小:{x_train.shape[1]}*{x_train.shape[2]}')
y_train = np.array(y_train)
label_cnt = Counter(y_train) # 统计每个类别的样本数
print('训练集的图像类别分布:', label_cnt)
# 可视化图像类别分布
plt.figure(figsize=(9,9))
plt.pie(x=label_cnt.values(), labels=label_cnt.keys(), autopct='%.2f%%')
plt.savefig('label_distribution.png', bbox_inches='tight', dpi=300)
```
Stratified sampling 将原训练集分为训练集和验证集,先用自定义函数选择索引,再通过 torch.utils.Subset函数划分训练集和验证集。
```c++
def stratified_sampling(ds,k):
'''return trainset,validset
sampling from ds while maintaining data balance
acoss different classes.
k is the number of samples in each class in trainset.
'''
class_counts = {}
train_indices = []
test_indices = []
for i, (data, label) in enumerate(ds):
c = label
class_counts[c] = class_counts.get(c, 0) + 1
if class_counts[c] <= k:
train_indices.append(i)
else:
test_indices.append(i)
print('stratified sampling done')
return (train_indices,test_indices)
```
```python
# transform data and generate data loader to create batches
raw_trainset = torchvision.datasets.MNIST(args.datasetPath, train=True, download=False,
transform=data_transforms['train'])
train_indices, valid_indices = stratified_sampling(trainset, 0.8*len(trainset)/10)
trainset = Subset(raw_trainset,train_indices)
validset = Subset(raw_trainset,valid_indices)
train_data_loader = DataLoader(trainset,batch_size=128,shuffle=True,drop_last=False)
valid_data_loader = DataLoader(validset,batch_size=128,shuffle=False,drop_last=False)
```
构建网络模型并检查
```python
def my_model():
model_body = models.resnet18(pretrained=False)
num_ftrs = model_body.fc.in_features
# Here the size of each output sample is set to 2.
# Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).
model_body.fc = nn.Linear(num_ftrs, 10)
# modify first conv to accept bw img
# weight = copy.deepcopy(model_body.conv1.weight)
# new_weight = (torch.sum(weight,dim = 1)/3).unsqueeze(1)
model_body.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2,2), padding=(3, 3), bias=False)
# model_body.conv1.weight.data = new_weight
return model_body
def check_model(trainloader,net):
# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()
images = images.to(device)
labels = labels.to(device)
# create grid of images
img_grid = torchvision.utils.make_grid(images)
# write to tensorboard
writer.add_image('four_mnist_images', img_grid)
writer.add_graph(net, images)
writer.close()
```
训练模型
```python
def train_model(model, dataloaders,
writer, criterion, optimizer, sched uler,
device, args, num_epochs = 25, save =
True):
''
'return model
load input model as last best model,
begin trainning
for num_epochs
''
'
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
best_epoch = 0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch,
num_epochs - 1))
print('-' * 10)# Each epoch has a training and validation phase
for phase in ['train', 'val']:
if phase == 'train':
model.train()# Set model to training mode
else :
model.eval()# Set model to evaluate mode
running_loss = 0.0
running_corrects = 0# Iterate over data
.
count = 0
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)# print(
inputs.shape)# print(labels.shape)# zero the parameter gradients
optimizer.zero_grad()# forward# track history
if only in train
with torch.set_grad_enabled(phase ==
'train'):
outputs = model(inputs)# print(f "outputs done:{outputs.shape}")
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)# backward +
optimize only
if intraining phase
if phase == 'train':
loss.backward()
optimizer.step()# statistics
running_loss += loss.item() * inputs.size(
0)
running_corrects += torch.sum(preds ==
labels.data)
count += inputs.size(0)
epoch_loss = running_loss / count
epoch_acc = running_corrects.double() /
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
资源包含文件:课程论文报告word+源码 将自己手写拍照上传的数字图片作为测试样本,训练卷积神经网络分类器识别0-9的手写数字。详细介绍参考:https://biyezuopin.blog.csdn.net/article/details/127060029
资源推荐
资源详情
资源评论
收起资源包目录
基于Python的卷积神经网络分类器识别0-9的MNIST手写数据集.zip (6个子文件)
test.ipynb 310KB
基于Python的卷积神经网络分类器识别0-9的MNIST手写数据集.docx 365KB
LICENSE 1KB
基于Python的卷积神经网络分类器识别0-9的MNIST手写数据集.pdf 865KB
train.py 13KB
README.md 29KB
共 6 条
- 1
资源评论
shejizuopin
- 粉丝: 1w+
- 资源: 1300
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功