- 🍨 本文为 🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者: K同学啊
1.检查GPU
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
2.查看数据
import os,PIL,random,pathlib
data_dir = pathlib.Path('data/48-data')
data_dir=pathlib.Path(data_dir)
data_path=list(data_dir.glob("*"))
ClassNames=[str(path).split('\\')[2] for path in data_path]
ClassNames
3.划分数据集
train_trainsforms=transforms.Compose([
transforms.Resize([224,224]),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.486,0.456,0.406],
std=[0.229,0.224,0.225]
)
]
)
total_data=datasets.ImageFolder("data/48-data",transform=train_trainsforms)
total_data
total_data.class_to_idx
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
batch_size=32
train_dl=torch.utils.data.DataLoader(train_dataset,batch_size,shuffle=True,num_workers=1)
test_dl=torch.utils.data.DataLoader(test_dataset,batch_size,shuffle=True,num_workers=1)
for X,y in train_dl:
print(X.shape)
print(y.shape)
break
4.调用官方模型
from torchvision.models import vgg16
print("Using {} device".format(device))
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
5.动态调整学习率函数
#调用官方动态学习率接口
learning_rate = 1e-4
lambda1=lambda epoch:0.92**(epoch//4)
optimizer=torch.optim.SGD(model.parameters(),lr=learning_rate)
scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lr_lambda=lambda1)
6.编译及训练模型
def train(dataloader,model,loss_fn,optimizer):
size=len(dataloader.dataset)
num_batches=len(dataloader)
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)
#反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss+=loss.item()
train_acc+=(pred.argmax(1)==y).type(torch.float).sum().item()
train_acc/=size
train_loss/=num_batches
return train_acc,train_loss
def test(dataloader,model,loss_fn):
size=len(dataloader.dataset)
num_batches=len(dataloader)
test_loss,test_acc=0,0
with torch.no_grad():
for imgs,target in dataloader:
imgs,target=imgs.to(device),target.to(device)
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
import copy
loss_fn=nn.CrossEntropyLoss()
epochs=40
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_test_acc
best_model=copy.deepcopy(model)
train_acc.append(epoch_train_acc)
train_loss.append(epoch_train_loss)
test_acc.append(epoch_test_acc)
test_loss.append(epoch_test_loss)
lr=optimizer.state_dict()['param_groups'][0]['lr']
template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')
print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss,
epoch_test_acc*100, epoch_test_loss, lr))
PATH='./best_model.pth'
torch.save(best_model.state_dict(),PATH)
print('Finished Training')
7.结果可视化
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()
8.预测本地图片
from PIL import Image
classes=list(total_data.class_to_idx)
def predict_one_image(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=model.eval()
output=model(img)
_,pred=torch.max(output,1)
pred_class=classes[pred]
print('预测结果是:{pred_class}')
predict_one_image(image_path='data/48-data/Angelina Jolie/005_582c121a.jpg',
model=model,
transform=train_trainsforms,
classes=classes)
#查看最优损失及准确率
best_model.eval()
epoch_test_Acc,epoch_test_loss=test(test_dl,best_model,loss_fn)
epoch_test_Acc,epoch_test_loss
总结:
1.VGG-16
VGG-16(Visual Geometry Group-16)是由牛津大学视觉几何组(Visual Geometry Group)提出的一种深度卷积神经网络架构,用于图像分类和对象识别任务。VGG-16在2014年被提出,是VGG系列中的一种。VGG-16之所以备受关注,是因为它在ImageNet图像识别竞赛中取得了很好的成绩,展示了其在大规模图像识别任务中的有效性。
以下是VGG-16的主要特点:
- **深度:**VGG-16由16个卷积层和3个全连接层组成,因此具有相对较深的网络结构。这种深度有助于网络学习到更加抽象和复杂的特征。
- 卷积层的设计: VGG-16的卷积层全部采用
3x3
的卷积核和步长为1的卷积操作,同时在卷积层之后都接有ReLU激活函数。这种设计的好处在于,通过堆叠多个较小的卷积核,可以提高网络的非线性建模能力,同时减少了参数数量,从而降低了过拟合的风险。 - **池化层:**在卷积层之后,VGG-16使用最大池化层来减少特征图的空间尺寸,帮助提取更加显著的特征并减少计算量。
- **全连接层:**VGG-16在卷积层之后接有3个全连接层,最后一个全连接层输出与类别数相对应的向量,用于进行分类。
VGG-16结构说明:
- 13个卷积层(Convolutional Layer),分别用
blockX_convX
表示; - 3个全连接层(Fully connected Layer),用
classifier
表示; - 5个池化层(Pool layer)。
VGG-16****包含了16个隐藏层(13个卷积层和3个全连接层),故称为 VGG-16
2.设置动态学习率
#非官方设置动态学习率
def adjust_learning_rate(optimizer, epoch, start_lr):
# 每 2 个epoch衰减到原来的 0.98
lr = start_lr * (0.92 ** (epoch // 2))
for param_group in optimizer.param_groups:
param_group['lr'] = lr
learn_rate = 1e-4 # 初始学习率
optimizer = torch.optim.SGD(model.parameters(), lr=learn_rate)
#官方设置动态学习率
# 调用官方动态学习率接口时使用
lambda1 = lambda epoch: 0.92 ** (epoch // 4)
optimizer = torch.optim.SGD(model.parameters(), lr=learn_rate)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1) #选定调整方法
model = [torch.nn.Parameter(torch.randn(2, 2, requires_grad=True))]
optimizer = SGD(model, 0.1)
scheduler = ExponentialLR(optimizer, gamma=0.9)
for epoch in range(20):
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
scheduler.step()