基于CIFAR10数据集的CNN
摘要
本日志记录我初次用pytorch搭建卷积神经网络,参考了很多别人的经验和代码,主要是根据https://blog.csdn.net/jining11/article/details/89114502这篇博客,按照博客上的内容一步步弄下来的,加强了我对CNN的理解,并明白了如何使用torch搭建神经网络。(在这里十分建议看懂之后在自己写代码,而不是直接ctrl+c/ctrl+v)
CNN
卷积神经网络之前学习的时候就接触过,在图像识别领域用的比较频繁。之前上数字图像处理课程的时候,最后一个实验是识别麻将和交通标志。如果使用卷积神经网络进行训练识别,会要比简单的对比准确率高。为了熟悉CNN。特意从csdn上找了一篇博客进行仿写。博客链接: 原博客地址。
数据集介绍
CIFAR-10数据集可以在官网下载链接: link不过网速很慢,我会附上我下载好的python版本。CIFAR中50000个作为train数据,10000作为test数据。这些图片中不存在类的重叠。更加详细的介绍上链接。官网介绍的很详细。
CIFAR有10个类别,60000个32*32像素的图片,如下图为部分展示
代码实现
代码可以分为搭建神经网络,写fit函数,读取数据集合3个部分,下面将分别介绍
读取数据集合
关于数据读取之后,转换成torch的张量形式,和超参数的选择代码。
cifar10_mean = (0.49,0.48,0.45)
cifar10_std = (0.25,0.24,0.26)
#define transform operations
train_transform = transforms.Compose([
#data augmentation
transforms.Pad(4),
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(32),
transforms.ToTensor(),
transforms.Normalize(cifar10_mean,cifar10_std)
])
test_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(cifar10_mean,cifar10_std)
])
#load data读取数据
train_dataset = torchvision.datasets.CIFAR10(root='./data/',
train=True,
transform=train_transform,
download=True)
test_dataset = torchvision.datasets.CIFAR10(root='./data',
train=False,
transform=test_transform,
)
#将训练集分为校验和训练
num_train = int(0.9*len(train_dataset))
num_val = int(0.1*len(train_dataset))
train_dataset,val_dataset=random_split(train_dataset,[num_train,num_val])
train_loader = Data.DataLoader(dataset=train_dataset,
batch_size=100,
shuffle=True)
val_loader = Data.DataLoader(dataset=val_dataset,
batch_size=100,
shuffle=True)
test_loader = Data.DataLoader(dataset=test_dataset,
batch_size=100,
shuffle=True)
""" 超参数选择 epochs:迭代次数 image_size:图片大小 num_classes分类数 lr:学习率 """
num_epochs = 10
image_size=32
num_classes=10
lr = 0.01
搭建CNN网络
CNN分为卷积–>池化–>再卷积–>再池化–>全连接层组成。由于输入是3通道的32*32像素的图片,因此第一个卷积层为3输入,我看的那篇博客使用的是16输出,代表16个隐层。(原理未知)。再加上归一化函数BatchNorm2d(16)。归一化函数原理见链接: link.后接上激活函数nn.ReLU()。和池化层。这里使用的是最大池化。通过2个这样的过程最后连接上全连接层。总体代码如下:
""" 搭建MyCNN网络 """
class MyCNN(nn.Module):
def __init__(self,image_size,num_classes):
super(MyCNN,self).__init__()
self.conv1=nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=16,kernel_size=3,stride=1,padding=1),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2,stride=2),
)
self.conv2=nn.Sequential(
nn.Conv2d(in_channels=16,out_channels=32,kernel_size=3,stride=1,padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2,stride=2),
)
self.fc=nn.Linear(32*(image_size//4)*(image_size//4),num_classes)
def forward(self, x):
""" Parameters ---------- x : N*3*image_size*image_size Returns:N*num_classes ------- """
x=self.conv1(x)
x=self.conv2(x)
x=x.view(x.size(0),-1)
output=self.fc(x)
return output
def save_model(model,save_path):
torch.save(model.state_dict(),save_path)
fit函数
fit函数分为train过程和val过程,采用校验集的方法对数据进行训练。代码如下:
""" 训练评估模型 """
def fit(model,train_loader,test_loader,num_epochs,optimizer,device):
loss_function=nn.CrossEntropyLoss()
model.to(device)
loss_function.to(device)
losses=[]
accs=[]
for epoch in range(num_epochs):
print('Epoch {}/{}:'.format(epoch + 1, num_epochs))
"训练模型"
loss = train(model,train_loader,loss_function,optimizer,device)
losses.append(loss)
"评估模型"
accuracy=evaluate(model, test_loader, device)
accs.append(accuracy)
show_cruve(losses,"train loss in every epoch")
show_cruve(accs,"test accuracy")
""" 训练模型 """
def train(model,train_loader,loss_function,optimizer,device):
total_loss = 0
for i,(images,targets) in enumerate(train_loader):
images=images.to(device)
targets=targets.to(device)
#前向传播
output = model(images)
loss = loss_function(output,targets)
#反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss +=loss.item()
#打印损失
if (i+1)%100==0:
print("step[{}/{}]Train Loss:{:.4f}".format(i+1,len(train_loader),loss.item()))
return total_loss/len(train_loader)
""" 评估模型 """
def evaluate(model,test_loader,device):
model.eval()
with torch.no_grad():
correct = 0
total = 0
for i,(images,targets) in enumerate(test_loader):
images = images.to(device)
targets = targets.to(device)
output = model(images)
_,predicted=torch.max(output.data,dim=1)
correct += (predicted==targets).sum().item()
total += targets.size(0)
accuracy = correct/total
print('Accuracy on Test Set:{:.4f}%'.format(100*accuracy))
return accuracy
""" 显示损失曲线 """
def show_cruve(ys,title):
x = np.array(range(len(ys)))
y = np.array(ys)
plt.plot(x,y,c='b')
plt.axis()
plt.title("{} curve".format(title))
plt.xlabel('epochs')
plt.ylabel('{}'.format(title))
plt.show()
总结
由于只是进一步熟悉神经网络的搭建,所以并未在改善模型上下功夫,通过自己动手搭建模型。加深了对神经网络和其应用的理解。完整代码和CAFAR数据由于太大不能上传,需要的话再说。