- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍦 参考文章地址: 365天深度学习训练营-第P6周:好莱坞明星识别
- 🍖 作者:K同学啊
一、前期准备
1.设置GPU
-
import torch
-
from torch
import nn
-
import torchvision
-
from torchvision
import transforms,datasets,models
-
import matplotlib.pyplot
as plt
-
import os,PIL,pathlib
-
device = torch.device(
"cuda"
if torch.cuda.is_available()
else
"cpu")
-
device
device(type='cuda')
2.导入数据
-
data_dir =
'./49-data/'
-
data_dir = pathlib.Path(data_dir)
-
-
data_paths =
list(data_dir.glob(
'*'))
-
classNames = [
str(path).split(
'\\')[
1]
for path
in data_paths]
-
classNames
['Dark', 'Green', 'Light', 'Medium']
-
train_transforms = transforms.Compose([
-
transforms.Resize([
224,
224]),
# resize输入图片
-
transforms.ToTensor(),
# 将PIL Image或numpy.ndarray转换成tensor
-
transforms.Normalize(
-
mean = [
0.485,
0.456,
0.406],
-
std = [
0.229,
0.224,
0.225])
# 从数据集中随机抽样计算得到
-
])
-
-
test_transforms = transforms.Compose([
-
transforms.Resize([
224,
224]),
# resize输入图片
-
transforms.ToTensor(),
# 将PIL Image或numpy.ndarray转换成tensor
-
transforms.Normalize(
-
mean = [
0.485,
0.456,
0.406],
-
std = [
0.229,
0.224,
0.225])
# 从数据集中随机抽样计算得到
-
])
-
-
total_data = datasets.ImageFolder(data_dir,transform=train_transforms)
-
total_data
Dataset ImageFolder Number of datapoints: 1200 Root location: 49-data StandardTransform Transform: Compose( Resize(size=[224, 224], interpolation=PIL.Image.BILINEAR) ToTensor() Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) )
total_data.class_to_idx
{'Dark': 0, 'Green': 1, 'Light': 2, 'Medium': 3}
3.数据集划分
-
train_size =
int(
0.8*
len(total_data))
-
test_size =
len(total_data) - train_size
-
train_dataset, test_dataset = torch.utils.data.random_split(total_data,[train_size,test_size])
-
train_dataset,test_dataset
train_size,test_size
(960, 240)
-
batch_size =
32
-
train_dl = torch.utils.data.DataLoader(train_dataset,
-
batch_size=batch_size,
-
shuffle=
True,
-
num_workers=
1)
-
test_dl = torch.utils.data.DataLoader(test_dataset,
-
batch_size=batch_size,
-
shuffle=
True,
-
num_workers=
1)
-
imgs, labels =
next(
iter(train_dl))
-
imgs.shape
torch.Size([32, 3, 224, 224])
-
import numpy
as np
-
-
# 指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch)
-
plt.figure(figsize=(
20,
5))
-
for i, imgs
in
enumerate(imgs[:
20]):
-
npimg = imgs.numpy().transpose((
1,
2,
0))
-
npimg = npimg * np.array((
0.229,
0.224,
0.225)) + np.array((
0.485,
0.456,
0.406))
-
npimg = npimg.clip(
0,
1)
-
# 将整个figure分成2行10列,绘制第i+1个子图。
-
plt.subplot(
2,
10, i+
1)
-
plt.imshow(npimg)
-
plt.axis(
'off')
-
for X,y
in test_dl:
-
print(
'Shape of X [N, C, H, W]:', X.shape)
-
print(
'Shape of y:', y.shape)
-
break
Shape of X [N, C, H, W]: torch.Size([32, 3, 224, 224]) Shape of y: torch.Size([32])
二、构建简单的CNN网络
1. 搭建模型
-
import torch.nn.functional
as F
-
-
# class vgg16(nn.Module):
-
-
# def __init__(self):
-
# super(vgg16,self).__init__()
-
-
# self.block1 = nn.Sequential(
-
# nn.Conv2d(3,64,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(64,64,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))
-
# )
-
-
# self.block2 = nn.Sequential(
-
# nn.Conv2d(64,128,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(128,128,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))
-
# )
-
-
# self.block3 = nn.Sequential(
-
# nn.Conv2d(128,256,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(256,256,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(256,256,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))
-
# )
-
-
# self.block4 = nn.Sequential(
-
# nn.Conv2d(256,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(512,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(512,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))
-
# )
-
-
# self.block5 = nn.Sequential(
-
# nn.Conv2d(512,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(512,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.Conv2d(512,512,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
-
# nn.ReLU(),
-
# nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))
-
# )
-
-
# self.classifier = nn.Sequential(
-
# nn.Linear(in_features=512*7*7, out_features=4096),
-
# nn.ReLU(),
-
# nn.Linear(in_features=4096,out_features=4096),
-
# nn.ReLU(),
-
# nn.Linear(in_features=4096,out_features=4)
-
# )
-
-
# def forward(self,x):
-
-
# x = self.block1(x)
-
# x = self.block2(x)
-
# x = self.block3(x)
-
# x = self.block4(x)
-
# x = self.block5(x)
-
# x = torch.flatten(x, start_dim=1)
-
# x = self.classifier(x)
-
-
# return x
-
-
-
# model = vgg16().to(device)
-
# model
-
from torchvision.models
import vgg16
-
-
model = vgg16(pretrained =
True).to(device)
-
for param
in model.parameters():
# 只训练输出层
-
param.requires_grad =
False
-
-
model.classifier._modules[
'6'] = nn.Linear(
4096,
len(classNames))
-
model.to(device)
-
model
VGG( (features): Sequential( (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU(inplace=True) (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU(inplace=True) (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (6): ReLU(inplace=True) (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (8): ReLU(inplace=True) (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (11): ReLU(inplace=True) (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (13): ReLU(inplace=True) (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (15): ReLU(inplace=True) (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (18): ReLU(inplace=True) (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (20): ReLU(inplace=True) (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (22): ReLU(inplace=True) (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (25): ReLU(inplace=True) (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (27): ReLU(inplace=True) (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (29): ReLU(inplace=True) (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (avgpool): AdaptiveAvgPool2d(output_size=(7, 7)) (classifier): Sequential( (0): Linear(in_features=25088, out_features=4096, bias=True) (1): ReLU(inplace=True) (2): Dropout(p=0.5, inplace=False) (3): Linear(in_features=4096, out_features=4096, bias=True) (4): ReLU(inplace=True) (5): Dropout(p=0.5, inplace=False) (6): Linear(in_features=4096, out_features=4, bias=True) ) )
2.查看模型详情
-
import torchsummary
as summary
-
summary.summary(model,(
3,
224,
224))
---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Conv2d-1 [-1, 64, 224, 224] 1,792 ReLU-2 [-1, 64, 224, 224] 0 Conv2d-3 [-1, 64, 224, 224] 36,928 ReLU-4 [-1, 64, 224, 224] 0 MaxPool2d-5 [-1, 64, 112, 112] 0 Conv2d-6 [-1, 128, 112, 112] 73,856 ReLU-7 [-1, 128, 112, 112] 0 Conv2d-8 [-1, 128, 112, 112] 147,584 ReLU-9 [-1, 128, 112, 112] 0 MaxPool2d-10 [-1, 128, 56, 56] 0 Conv2d-11 [-1, 256, 56, 56] 295,168 ReLU-12 [-1, 256, 56, 56] 0 Conv2d-13 [-1, 256, 56, 56] 590,080 ReLU-14 [-1, 256, 56, 56] 0 Conv2d-15 [-1, 256, 56, 56] 590,080 ReLU-16 [-1, 256, 56, 56] 0 MaxPool2d-17 [-1, 256, 28, 28] 0 Conv2d-18 [-1, 512, 28, 28] 1,180,160 ReLU-19 [-1, 512, 28, 28] 0 Conv2d-20 [-1, 512, 28, 28] 2,359,808 ReLU-21 [-1, 512, 28, 28] 0 Conv2d-22 [-1, 512, 28, 28] 2,359,808 ReLU-23 [-1, 512, 28, 28] 0 MaxPool2d-24 [-1, 512, 14, 14] 0 Conv2d-25 [-1, 512, 14, 14] 2,359,808 ReLU-26 [-1, 512, 14, 14] 0 Conv2d-27 [-1, 512, 14, 14] 2,359,808 ReLU-28 [-1, 512, 14, 14] 0 Conv2d-29 [-1, 512, 14, 14] 2,359,808 ReLU-30 [-1, 512, 14, 14] 0 MaxPool2d-31 [-1, 512, 7, 7] 0 AdaptiveAvgPool2d-32 [-1, 512, 7, 7] 0 Linear-33 [-1, 4096] 102,764,544 ReLU-34 [-1, 4096] 0 Dropout-35 [-1, 4096] 0 Linear-36 [-1, 4096] 16,781,312 ReLU-37 [-1, 4096] 0 Dropout-38 [-1, 4096] 0 Linear-39 [-1, 4] 16,388 ================================================================ Total params: 134,276,932 Trainable params: 16,388 Non-trainable params: 134,260,544 ---------------------------------------------------------------- Input size (MB): 0.57 Forward/backward pass size (MB): 218.77 Params size (MB): 512.23 Estimated Total Size (MB): 731.57 ----------------------------------------------------------------
三、训练模型
-
# 设置优化器
-
optimizer = torch.optim.Adam(model.parameters(), lr=
1e-4)
#要训练什么参数/
-
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=
5, gamma=
0.92)
#学习率每5个epoch衰减成原来的1/10
-
loss_fn = nn.CrossEntropyLoss()
1. 编写训练函数
-
# 训练循环
-
def
train(
dataloader, model, loss_fn, optimizer):
-
size =
len(dataloader.dataset)
# 训练集的大小,一共900张图片
-
num_batches =
len(dataloader)
# 批次数目,29(900/32)
-
-
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)
# 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
-
-
# 反向传播
-
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
2.编写测试函数
-
def
test (dataloader, model, loss_fn):
-
size =
len(dataloader.dataset)
# 测试集的大小,一共10000张图片
-
num_batches =
len(dataloader)
# 批次数目,8(255/32=8,向上取整)
-
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
3、正式训练
-
epochs =
20
-
train_loss = []
-
train_acc = []
-
test_loss = []
-
test_acc = []
-
best_acc =
0
-
-
for epoch
in
range(epochs):
-
model.train()
-
epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)
-
-
scheduler.step()
#学习率衰减
-
-
model.
eval()
-
epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
-
-
# 保存最优模型
-
if epoch_test_acc > best_acc:
-
best_acc = epoch_train_acc
-
state = {
-
'state_dict': model.state_dict(),
#字典里key就是各层的名字,值就是训练好的权重
-
'best_acc': best_acc,
-
'optimizer' : optimizer.state_dict(),
-
}
-
-
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(
'Done')
-
print(
'best_acc:',best_acc)
Epoch:18, Train_acc:93.5%, Train_loss:0.270, Test_acc:95.4%,Test_loss:0.223 Epoch:19, Train_acc:94.5%, Train_loss:0.241, Test_acc:95.8%,Test_loss:0.223 Epoch:20, Train_acc:94.4%, Train_loss:0.243, Test_acc:96.2%,Test_loss:0.207 Done best_acc: 0.94375
四、结果可视化
1.Loss与Accuracy图
-
import matplotlib.pyplot
as plt
-
#隐藏警告
-
import warnings
-
warnings.filterwarnings(
"ignore")
#忽略警告信息
-
plt.rcParams[
'font.sans-serif'] = [
'SimHei']
# 用来正常显示中文标签
-
plt.rcParams[
'axes.unicode_minus'] =
False
# 用来正常显示负号
-
plt.rcParams[
'figure.dpi'] =
100
#分辨率
-
-
epochs_range =
range(epochs)
-
-
plt.figure(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 Validation Loss')
-
plt.show()
2.指定图片进行预测
-
from PIL
import Image
-
-
classes =
list(total_data.class_to_idx)
-
-
def
predict_one_img(
image_path,model,transform,classes):
-
test_img = Image.
open(image_path).convert(
'RGB')
-
plt.imshow(test_img)
-
test_img = transform(test_img)
-
img = test_img.to(device).unsqueeze(
0)
-
model.
eval()
-
output = model(img)
-
-
_,pred = torch.
max(output,
1)
-
pred_class = classes[pred]
-
print(
f'预测结果是:{pred_class}')
predict_one_img('./49-data/Dark/dark (1).png', model, train_transforms, classNames)
预测结果是:Dark
转载:https://blog.csdn.net/suic009/article/details/128499622
查看评论