前言
用了太多的现成的网络结构,感觉自己在深度学习这一块只会用别人的结构,对模型的搭建啥的这一块都没多大经验,所以写下这篇博客,记录下自己尝试搭建模型的开始。
代码解析
1.我们用的是pytorch深度学习框架,数据集就用经典的mnist数据集。首先导入包
import numpy as np
import torch
#导入pytorch内置mnist数据
from torchvision.datasets import mnist
#导入数据预处理模块
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
#导入nn及优化器
import torch.nn.functional as F
import torch.optim as optim
from torch import nn
import matplotlib.pyplot as plt
#这是可视化模型结构的
from fvcore.nn import parameter_count_table
2.定义一些超参数
#定义超参数
#批次量
train_batch_size=64
test_batch_size=128
num_epoches=50
#学习率
lr=0.01
#动量
momentum=0.5
3.加载mnist数据集,笔者这里已经下载过mnist数据集,所以download设置为False,没有下载的话要改成True先下载数据集。
#下载数据和预处理
#定义预处理函数,预处理依次放在compose函数里
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
#下载数据,并且预处理
train_dataset=mnist.MNIST('./data',train=True,transform=transform,download=False)
test_dataset=mnist.MNIST('./data',train=False,transform=transform)
#dataloader是一个可迭代对象,像迭代器一样使用
train_loader=DataLoader(train_dataset,batch_size=train_batch_size,shuffle=True)
test_loader=DataLoader(test_dataset,batch_size=test_batch_size,shuffle=False)
4.搭建模型,这里的使用的是卷积神经网络,笔者定义了两种卷积,一种是普通的卷积层,一种是深度可分离卷积。深度可分离卷积简单来说就是先用一个和普通卷积层同样大小的卷积核,保持通道数不变,然后再用一个1*1的卷积进行通道数的调整,。这样使用深度可分离卷积不仅可以保存良好的特征提取效果,还能大大减少参数量。不过这好像对于笔者这里搭建的小网络结构影响也不是很大,使用深度可分离卷积也只是笔者的情怀。这里笔者也给出了使用普通卷积层和深度可分离卷积层的模型参数情况供大家参考。
#定义普通3*3卷积模块
def conv2d_dn(inp,out,s=1):
return nn.Sequential(
nn.Conv2d(inp,out,3,s,1,bias=False),
nn.BatchNorm2d(out),
nn.ReLU6()
)
# | name | #elements or shape |
# |:-------------------|:---------------------|
# | model | 0.4M |
# | layer1 | 0.4K |
# | layer1.0 | 0.4K |
# | layer1.0.0 | 0.3K |
# | layer1.0.1 | 64 |
# | layer2 | 18.6K |
# | layer2.0 | 18.6K |
# | layer2.0.0 | 18.4K |
# | layer2.0.1 | 0.1K |
# | layer3 | 0.4M |
# | layer3.0 | 0.4M |
# | layer3.0.weight | (128, 3136) |
# | layer3.0.bias | (128,) |
# | layer4 | 1.3K |
# | layer4.0 | 1.3K |
# | layer4.0.weight | (10, 128) |
# | layer4.0.bias | (10,) |
#定义深度可分离卷积模块
def conv2d_dw(inp,out,s=1):
return nn.Sequential(nn.Conv2d(inp,inp,3,s,groups=inp,bias=False,padding=1),
nn.BatchNorm2d(inp),
nn.ReLU6(),
nn.Conv2d(inp,out,1,1,0,bias=False),
nn.BatchNorm2d(out),
nn.ReLU6())
# | name | #elements or shape |
# |:-------------------|:---------------------|
# | model | 0.4M |
# | layer1 | 0.1K |
# | layer1.0 | 0.1K |
# | layer1.0.0 | 9 |
# | layer1.0.1 | 2 |
# | layer1.0.3 | 32 |
# | layer1.0.4 | 64 |
# | layer2 | 2.5K |
# | layer2.0 | 2.5K |
# | layer2.0.0 | 0.3K |
# | layer2.0.1 | 64 |
# | layer2.0.3 | 2.0K |
# | layer2.0.4 | 0.1K |
# | layer3 | 0.4M |
# | layer3.0 | 0.4M |
# | layer3.0.weight | (128, 3136) |
# | layer3.0.bias | (128,) |
# | layer4 | 1.3K |
# | layer4.0 | 1.3K |
# | layer4.0.weight | (10, 128) |
# | layer4.0.bias | (10,) |
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.layer1=nn.Sequential(conv2d_dn(1,32,1),nn.MaxPool2d((2,2),2),nn.Dropout(0.3))
self.layer2=nn.Sequential(conv2d_dn(32,64,1),nn.MaxPool2d((2,2),2),nn.Dropout(0.3))
self.layer3=nn.Sequential(nn.Linear(3136,128))
self.layer4 = nn.Sequential(nn.Linear(128, 10))
def forward(self,x):
x=self.layer1(x)
x=self.layer2(x)
x=x.view(-1,7*7*64)
x=self.layer3(x)
x=F.relu(x)
x=self.layer4(x)
return x
5.下面进行训练
#实例化网络
#检测是否有可用的GPU,有则使用,否则使用cpu
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
#实例化网络
model=Net()
model.to(device)
#可视化模型参数
# print(parameter_count_table(model))
#定义损失函数和优化器
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=lr,momentum=momentum)
#训练模型
#开始训练
losses=[]
acces=[]
eval_losses=[]
eval_acces=[]
for epoch in range(num_epoches):
print("开始第{}批次".format(epoch+1))
train_loss=0
train_acc=0
model.train()
#动态修改学习参数学习率
if epoch%5==0:
optimizer.param_groups[0]['lr']*=0.1
print("学习率:{}".format(optimizer.param_groups[0]['lr']))
for img,label in train_loader:
img=img.to(device)
label=label.to(device)
#前向传播
out=model(img)
loss=criterion(out,label)
#反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
#记录误差
train_loss+=loss.item()
#计算分类的准确率
_,pred=out.max(1)
num_correct=(pred==label).sum().item()
acc=num_correct/img.shape[0]
train_acc+=acc
losses.append(train_loss/len(train_loader))
acces.append(train_acc/len(train_loader))
# 在测试集上检验效果
eval_loss = 0
eval_acc = 0
# 将模型改为预测模式
model.eval()
for img, label in test_loader:
img = img.to(device)
label = label.to(device)
out = model(img)
loss = criterion(out, label)
# 记录误差
eval_loss += loss.item()
# 记录准确率
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
eval_acc += acc
eval_losses.append(eval_loss / len(test_loader))
eval_acces.append(eval_acc / len(test_loader))
print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'.format(epoch+1,
train_loss / len(
train_loader),
train_acc / len(
train_loader),
eval_loss / len(
test_loader),
eval_acc / len(
test_loader)))
6.可视化损失和准确率
#可视化化训练及测试损失值
fig1=plt.figure()
plt.plot(np.arange(num_epoches),losses)
plt.legend(['Train Loss'],loc='upper right')
fig2=plt.figure()
plt.plot(np.arange(num_epoches),acces)
plt.legend(['Train ACC'],loc='upper right')
fig3=plt.figure()
plt.plot(np.arange(num_epoches),eval_losses)
plt.legend(['Test Loss'],loc='upper right')
fig4=plt.figure()
plt.plot(np.arange(num_epoches),eval_acces)
plt.legend(['Test ACC'],loc='upper right')
plt.show()