目录
前言
- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊
一、 前期准备
1. 设置GPU
import os,PIL,pathlib,warnings
warnings.filterwarnings("ignore")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
2.查看数据
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
import os,PIL,pathlib
data_dir="data/第8天/bird_photos"
data_dir=pathlib.Path(data_dir)
image_count = len(list(data_dir.glob('*/*')))
print("图片总数为:",image_count)
二、构建模型
1.划分数据集
batch_size = 8
img_height = 224
img_width = 224
import torchvision.transforms as transforms
import torchvision.datasets as datasets
transforms=transforms.Compose([
transforms.Resize([224,224]),
transforms.ToTensor(),
# transforms.Normalize(
# mean=[0.482,0.456,0.406],
# std=[0.229,0.224,0.225]
# )
])
total_data=datasets.ImageFolder("data/第8天/bird_photos",transform=transforms)
total_data
total_data.class_to_idx
train_size=int(0.8*len(total_data))
test_size=len(total_data)-train_size
train_data,test_data=torch.utils.data.random_split(total_data,[train_size,test_size])
train_data,test_data
batch_size=8
train_dl=torch.utils.data.DataLoader(train_data,batch_size,shuffle=True,num_workers=1)
test_dl=torch.utils.data.DataLoader(test_data,batch_size,shuffle=True,num_workers=1)
for X,y in train_dl:
print(X.shape)
print(y.shape)
break
2.划分标签
total_data.class_to_idx
3.编译及训练模型
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
optimizer = torch.optim.Adam(model.parameters(), lr= 1e-4)
loss_fn = nn.CrossEntropyLoss()
import copy
import torch
# Loss function and other initializations
loss_fn = nn.CrossEntropyLoss()
epochs = 20
train_loss = []
train_acc = []
test_loss = []
test_acc = []
best_acc = 0
best_loss = float('inf') # 初始化最优损失为正无穷
patience = 5 # 设置耐心值,即连续5轮损失不下降时停止训练
patience_counter = 0 # 用于记录损失不下降的轮数
# Training and testing loop
for epoch in range(epochs):
model.train()
epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)
model.eval()
epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
# Check if test loss improved
if epoch_test_loss < best_loss:
best_loss = epoch_test_loss
best_model = copy.deepcopy(model)
patience_counter = 0 # 重置耐心计数器
else:
patience_counter += 1 # 增加耐心计数器
# If patience is exceeded, stop training
if patience_counter >= patience:
print(f"Stopping early at epoch {epoch+1} due to no improvement in test loss for {patience} epochs.")
break
train_acc.append(epoch_train_acc)
train_loss.append(epoch_train_loss)
test_acc.append(epoch_test_acc)
test_loss.append(epoch_test_loss)
# Print the results for the current epoch
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))
# Save the best model
PATH = './best_model.pth'
torch.save(best_model.state_dict(), PATH)
print('Finished Training')
三、结果可视化
import matplotlib.pyplot as plt
import warnings
epochs = len(train_acc)
# 绘制准确率
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.plot(range(1, epochs + 1), train_acc, label='Train Accuracy', color='blue')
plt.plot(range(1, epochs + 1), test_acc, label='Test Accuracy', color='orange')
plt.title('Training and Test Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='best')
# 绘制损失
plt.subplot(1, 2, 2)
plt.plot(range(1, epochs + 1), train_loss, label='Train Loss', color='blue')
plt.plot(range(1, epochs + 1), test_loss, label='Test Loss', color='orange')
plt.title('Training and Test Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend(loc='best')
# 显示图形
plt.tight_layout()
plt.show()
Epoch: 1, Train_acc:34.3%, Train_loss:6.088, Test_acc:55.8%, Test_loss:5.442, Lr:1.00E-04 Epoch: 2, Train_acc:55.8%, Train_loss:4.859, Test_acc:56.6%, Test_loss:4.382, Lr:1.00E-04 Epoch: 3, Train_acc:60.8%, Train_loss:4.076, Test_acc:56.6%, Test_loss:3.759, Lr:1.00E-04 Epoch: 4, Train_acc:61.1%, Train_loss:3.380, Test_acc:61.1%, Test_loss:2.907, Lr:1.00E-04 Epoch: 5, Train_acc:60.2%, Train_loss:2.901, Test_acc:69.0%, Test_loss:2.309, Lr:1.00E-04 Epoch: 6, Train_acc:61.5%, Train_loss:2.361, Test_acc:64.6%, Test_loss:2.099, Lr:1.00E-04 Epoch: 7, Train_acc:62.4%, Train_loss:2.051, Test_acc:61.9%, Test_loss:1.911, Lr:1.00E-04 Epoch: 8, Train_acc:65.9%, Train_loss:1.718, Test_acc:69.0%, Test_loss:1.442, Lr:1.00E-04 Epoch: 9, Train_acc:68.1%, Train_loss:1.479, Test_acc:62.8%, Test_loss:1.540, Lr:1.00E-04 Epoch:10, Train_acc:68.1%, Train_loss:1.340, Test_acc:73.5%, Test_loss:1.332, Lr:1.00E-04 Epoch:11, Train_acc:67.5%, Train_loss:1.242, Test_acc:68.1%, Test_loss:1.071, Lr:1.00E-04 Epoch:12, Train_acc:70.6%, Train_loss:1.111, Test_acc:69.9%, Test_loss:1.219, Lr:1.00E-04 Epoch:13, Train_acc:68.4%, Train_loss:1.033, Test_acc:68.1%, Test_loss:1.286, Lr:1.00E-04 Epoch:14, Train_acc:69.9%, Train_loss:0.970, Test_acc:76.1%, Test_loss:0.925, Lr:1.00E-04 Epoch:15, Train_acc:76.1%, Train_loss:0.831, Test_acc:77.9%, Test_loss:0.654, Lr:1.00E-04 Epoch:16, Train_acc:77.0%, Train_loss:0.740, Test_acc:71.7%, Test_loss:0.926, Lr:1.00E-04 Epoch:17, Train_acc:72.8%, Train_loss:0.852, Test_acc:75.2%, Test_loss:0.708, Lr:1.00E-04 Epoch:18, Train_acc:76.1%, Train_loss:0.790, Test_acc:68.1%, Test_loss:0.741, Lr:1.00E-04 Epoch:19, Train_acc:77.7%, Train_loss:0.710, Test_acc:76.1%, Test_loss:0.765, Lr:1.00E-04 Epoch:20, Train_acc:77.0%, Train_loss:0.685, Test_acc:79.6%, Test_loss:0.645, Lr:1.00E-04 Finished Training
四、总结
模型的核心是一个结合 ResNet 和 DenseNet 的混合网络:
ResNet 残差块:通过残差连接解决了梯度消失问题,使得网络可以训练得更深。
DenseNet 密集块:通过密集连接实现了特征重用,提高了参数效率。
混合模型:先通过一个 ResNet 残差块 提取特征,然后通过一个 DenseNet 密集块 进一步提取和重用特征,最后通过全局平均池化和全连接层进行分类。