- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊
1.检查GPU
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvisiondevice=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_datatotal_data.class_to_idxtrain_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_datasetbatch_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,0for 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/=sizetrain_loss/=num_batchesreturn train_acc,train_lossdef test(dataloader,model,loss_fn):size=len(dataloader.dataset)num_batches=len(dataloader)test_loss,test_acc=0,0with 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/=sizetest_loss/=num_batchesreturn test_acc,test_lossimport 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_accbest_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']=100epochs_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.98lr = start_lr * (0.92 ** (epoch // 2))for param_group in optimizer.param_groups:param_group['lr'] = lrlearn_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()