目录
一、前期准备
1、数据集CIFAR10
2、判断自己的设备,是否可以使用GPU运行。
3、下载数据集,划分好训练集和测试集
4、加载训练集、测试集
5、取一个批次查看下
6、数据可视化
二、搭建简单的CNN网络模型
三、训练模型
1、设置超参数
2、编写训练函数
3、编写测试函数
4、正式训练
四、模型训练结果可视化
五、模型训练结果:
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊 | 接辅导、项目定制
这周的实战内容,主要使用的数据集是CIFAR10数据集。用来验证彩色图片的识别。
一、前期准备
1、数据集CIFAR10
我们使用的数据集的文档地址:Datasets — Torchvision 0.17 documentation
简单介绍下CIFAR10数据集:
CIFAR-10数据集由60000张32 × 32彩色图像组成,分为10个类,每个类有6000张图像。
有50000张训练图像和10000张测试图像。
2、判断自己的设备,是否可以使用GPU运行。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
3、下载数据集,划分好训练集和测试集
import torchvision.datasets
# 下载训练集
train_ds = torchvision.datasets.CIFAR10('data',
train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
# 下载测试集
test_ds = torchvision.datasets.CIFAR10('data',
train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
4、加载训练集、测试集
# 使用dataloader加载数据集,并设置好batch_size
batch_size = 32
train_dl = torch.utils.data.DataLoader(train_ds,
shuffle=True,
batch_size=batch_size)
test_dl = torch.utils.data.DataLoader(test_ds,
batch_size=batch_size)
5、取一个批次查看下
# 取一个批次,查看下数据
imgs,labels = next(iter(train_dl))
print(imgs.shape) # 数据的shape为:[batch_size,channel,height,weight]
'''
对于CIFAR10,这里的shape是 [32,3,32,32],即 因为取得是train_dl的数据,batch_size为32;
channel为3是因为,是彩色图片RGB的3通道,如果是黑白图片,则channel为1;剩下的32x32是高度和宽度;
'''
6、数据可视化
即:展示下取到的数据。
# 数据可视化
plt.figure(figsize=(20,5))
for i, imgs in enumerate(imgs[:20]):
npimg = imgs.numpy().transpose((1,2,0))
#.numpy()用于将Tensor转换为一个Numpy数组。transpose是Numpy数组的一个方法,用于重新排列数组的维度。
plt.subplot(2, 10, i+1)
plt.imshow(npimg, cmap=plt.cm.binary)
plt.axis('off')
plt.show()
运行结果展示:
二、搭建简单的CNN网络模型
CNN(卷积神经网络),需要注意其结构、层与层之间的连接关系以及各层的功能。
①卷积层:负责提取特征。(通常使用局部连接和权值共享方式,这有助于减少网络的参数数量和计算复杂度。)
②池化层:负责降低数据的空间尺寸和计算复杂度。
③全连接层:负责将提取的特征映射到输出类别。
# 构建简单的CNN网络
num_classes = 10
class Model(nn.Module):
def __init__(self):
super().__init__()
# 特征提取
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
self.pool1 = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(64, 64, kernel_size=3)
self.pool2 = nn.MaxPool2d(2)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3)
self.pool3 = nn.MaxPool2d(2)
# 分类网络
self.fc1 = nn.Linear(512, 256)
self.fc2 = nn.Linear(256, num_classes)
# 前向传播
def forward(self,x):
x = self.pool1(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x)))
x = self.pool3(F.relu(self.conv3(x)))
x = torch.flatten(x, start_dim=1) # 线性层+激活函数 是构建复杂模型的基础
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
# 打印并加载模型
model = Model().to(device)
print(model)
三、训练模型
1、设置超参数
# 1、设置超参数
loss_fn = nn.CrossEntropyLoss() # 创建损失函数
learn_rate = 1e-2 #学习率
opt = torch.optim.SGD(model.parameters(), lr=learn_rate) # 定义一个随机梯度下降优化器,即SGD优化器。
# model.parameters() 返回模型中所有可训练的参数(通常是权重和偏置)
2、编写训练函数
# 2、编写训练函数
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset) # 数据集的大小,一共60000张图片
num_batches = len(dataloader) # 批次数目 1875 (60000/32 = 1875)
train_loss, train_acc = 0, 0 # 初始化训练的损失和正确率
for X,y in dataloader: # 获取图片及其标签
X, y = X.to(device), y.to(device)
# 计算预测误差
pred = model(X) # 网络输出
loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距,y为真实值,计算二者差值,即为损失。
# 反向传播
optimizer.zero_grad() # grad属性归零
loss.backward() # 反向传播
optimizer.step() # 每一步自动更新
# 记录acc与loss
train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
train_loss += loss.item()
train_acc /= size
train_loss /= num_batches
return train_acc, train_loss
3、编写测试函数
# 3、编写测试函数
# 测试函数和训练函数大致相同,但是由于不进行梯度下降对网络权重进行更新,所以不需要传入优化器。
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset) # 数据集的大小,共10000张
num_batches = len(dataloader) # 批次数目 ,313( 10000/32 = 321.5 ,向上取整)
test_loss, test_acc = 0, 0 # 初始化测试的损失和精确
# 不进行训练时,停止梯度下降,节省计算内存消耗
with torch.no_grad():
for imgs, target in dataloader:
imgs, target = imgs.to(device), target.to(device)
# 计算loss
target_pred = model(imgs)
loss = loss_fn(target_pred, target)
test_loss += loss.item()
test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()
test_acc /= size
test_loss /= num_batches
return test_acc, test_loss
4、正式训练
# 4、正式训练
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []
'''
model.train()和model.eval() 是深度学习中常见的两个方法,它们用于设置模型的训练模式和评估模式。
①当你调用model.train()时,你正在告诉模型你即将进入训练阶段。通常意味着模型中的某些层(如Dropout层和BatchNormalization层)会改变它们的行为以适应训练过程。
Dropout层:在训练模式下,Dropout层会随机将一部分神经元的输出设置为0,有助于防止过拟合。
BatchNormalization层:在训练模式下,BatchNoralization层会使用当前批次的数据来更新其运行均值和方差,并应用这些统计量来标准化输入。
②当你调用model.eval()时,你正在告诉模型你即将进入评估或推断阶段。在这种模式下,模型的某些层会改变它们的行为,以确保在评估时模型给出一致的结果。
'''
for epoch in range(epochs):
model.train() # 进入训练阶段
epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
model.eval()
epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
train_acc.append(epoch_train_acc)
train_loss.append(epoch_train_loss)
test_acc.append(epoch_test_acc)
test_loss.append(epoch_test_loss)
template = 'Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}'
print(template.format(epoch+1, epoch_train_acc*100,epoch_train_loss, epoch_test_acc*100, epoch_test_loss))
print('Finish')
四、模型训练结果可视化
# 四、结果可视化
warnings.filterwarnings('ignore') # 忽略警告信息
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100 # 分辨率
epochs_range = range(epochs) # 生成从0到epoches-1的整数序列
plt.figure(figsize=(12,3)) # figsize=(12,3) 包含两个元素的元组,分别代表图形的宽度和高度,单位是英寸。
plt.subplot(1,2,1)
plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1,2,2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validataion Loss')
# 在远程服务器上面跑代码,想要保存下,plt.show()的结果,打下下面的注释
# plt.savfig('想要保存的服务器的地址+图片的名称.png/jpg自行定义即可')
# eg:plt.savefig('/data/jupyter/deepinglearning/resultImg.jpg')
plt.show()
print("画图结束。。。")
五、模型训练结果:
这周和上周的代码类似,但是,比起刚开始的时候,好多代码都清晰了很多。