34- PyTorch数据增强和迁移学习 (PyTorch系列) (深度学习)

知识要点

  •  对vgg  模型进行迁移学习
  • 定义数据路径: train_dir = os.path.join(base_dir, 'train')     # base_dir = './dataset'
  • 定义转换格式:

transform = transforms.Compose([transforms.Resize((96, 96)),  # 统一缩放
                                transforms.ToTensor(),        # 转换为tensor
                                transforms.Normalize(mean=[0.5, 0.5, 0.5],  # 正则化
                                                     std=[0.5, 0.5, 0.5])])
  • 数据转换: train_ds = torchvision.datasets.ImageFolder(train_dir, transform=transform)
  • train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size, shuffle=True, drop_last=True)   # 定义数据训练格式
  • 修改结果特征, 4分类: model.classifier[-1].out_features = 4   # 调整输出层
  • 数据位置调整: device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
  • 定义优化器: optimizer = optim.Adam(model.parameters(), lr=0.001)
  • 定义损失: loss_fn = nn.CrossEntropyLoss()
  • 梯度归零: optimizer.zero_grad()
  • loss.backward()
  • 梯度更新: optimizer.step()
  • 查看模型: model.parameters
  • 图示: plt.plot(range(1, epochs+1), train_loss, label='train_loss')
  • 图例显示: plt.legend()
  • 模型参数: model.state_dict()
  • 保存参数: torch.save(model.state_dict(), './vgg16.pth')
  • 给模型传参: new_model.load_state_dict(torch.load('./vgg16.pth'))
  • 测试数据预测:
# 测试过程
test_correct = 0
test_total = 0
new_model.eval()  # eval  评价, 评估

with torch.no_grad():
    for x, y in test_d1:
        x, y = x.to(device), y.to(device)
        y_pred = new_model(x)
        y_pred = torch.argmax(y_pred, dim=1)
        test_correct += (y_pred == y).sum().item()
        test_total += y.size(0)
        
epoch_test_acc = test_correct / test_total
print(epoch_test_acc)    # 0.9644444444444444
  • 保存最佳参数:
model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

import copy
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 没有训练前的初始化参数
best_model_weight = model.state_dict()
best_acc = 0.0
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        # 更新参数, 保存最佳参数
        best_model_weight = copy.deepcopy(model.state_dict())

# 把最好的参数加载到模型
model.load_state_dict(best_model_weight)
  • 保存完整模型: torch.save(model, './my_whole_model.pth')
  • 加载完整模型: new_model2 = torch.load('./my_whole_model.pth')

跨设备保存模型及加载:

  • model.load_state_dict(torch.load('./my_best_weight', map_location=device))
# 把刚才保存的模型映射到GPU
torch.save(model.state_dict(), './my_best_weight')

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 下载完模型后, 执行了model.to(device), 默认在CPU上
model.load_state_dict(torch.load('./my_best_weight', map_location=device))
  • 学习率衰减: step_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)  # step_lr_scheduler.step()   # from torch.optim import lr_scheduler
  • 数据加强处理:
# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])


一 天气图片分类

1.1 简介

数据四分类: Rain, sunshine, sunrise, cloudy.

1.2 导包

# vgg 
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
import torchvision
from torchvision import transforms

1.3 导入数据

import os
base_dir = './dataset'
train_dir = os.path.join(base_dir, 'train')
test_dir = os.path.join(base_dir, 'test')
  • 图片数据转换方式: 图片尺寸统一, 数据转换为tensor, 数据正则化
transform = transforms.Compose([transforms.Resize((96, 96)),  # 统一缩放
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化
                                transforms.Normalize(mean=[0.5, 0.5, 0.5],
                                                     std=[0.5, 0.5, 0.5])])
  • 图片数据导入
train_ds = torchvision.datasets.ImageFolder(train_dir, transform=train_transform)
test_ds = torchvision.datasets.ImageFolder(test_dir, transform=test_transform)

# dataloader
batch_size = 32  # batch 批次
train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size,
                                       shuffle=True, drop_last=True)
test_d1 = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

1.4 导入模型 (迁移学习)

# 加载预训练模型
model = torchvision.models.vgg16(pretrained=True)
model 

for param in model.features.parameters():
    param.requires_grad = False
  • 定义输出类别
# 修改结果特征, 4分类
model.classifier[-1].out_features = 4
model.classifier[-1]    # Linear(in_features=4096, out_features=4, bias=True)

# 另一种修改方式  # 直接替换最后一层
# model.classifier[-1] = torch.nn.Linear(model.classifier[-1], 4)
  • 数据拷贝到 GPU
# 训练  # 拷贝到GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)

1.5 定义训练

# 继续训练
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()

# 定义训练过程
def fit(epoch, model, train_loader, test_loader):
    correct = 0
    total = 0
    running_loss = 0
    
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()
            
    epoch_loss = running_loss / len(train_loader.dataset)
    epoch_acc = correct / total
    
    # 测试过程
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    test_epoch_loss = test_running_loss / len(test_loader.dataset)
    test_epoch_acc = test_correct /test_total
    
    print('epoch', epoch,
          'loss', round(epoch_loss, 3),
          'accuracy', round(epoch_acc, 3),
          'test_loss', round(test_epoch_loss, 3),
          'test_accuracy', round(test_epoch_acc, 3))
    return epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc
  • 指定训练
# 指定训练次数
epochs = 20
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc = fit(epoch, model,
                                                                 train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(test_epoch_loss)
    test_acc.append(test_epoch_acc)

model.parameters     # 查看模型结构

1.6 结果展示

plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss')
plt.legend()

plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc')
plt.legend()

二 保存模型

2.1 保存参数

  • state_dict 是一个字典, 保存了训练模型
model.state_dict()   # 保存位置

# 保存参数
path = './vgg16.pth'
torch.save(model.state_dict(), path)

2.2 恢复模型

  • 先创建模型, 然后通过模型加载参数

new_model = torchvision.models.vgg16(pretrained=False)
new_model.classifier[-1].out_features = 4

# 传参
new_model.load_state_dict(torch.load('./vgg16.pth'))
new_model.state_dict()   # 保存位置

2.3 模型预测

# 把模型拷贝到数据所在的位置(GPU/ CPU)
new_model.to(device)

# 测试过程
test_correct = 0
test_total = 0
new_model.eval()  # eval  评价, 评估

with torch.no_grad():
    for x, y in test_d1:
        x, y = x.to(device), y.to(device)
        y_pred = new_model(x)
        y_pred = torch.argmax(y_pred, dim=1)
        test_correct += (y_pred == y).sum().item()
        test_total += y.size(0)
        
epoch_test_acc = test_correct / test_total
print(epoch_test_acc)    # 0.9644444444444444

2.4 保存参数最佳的模型

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 传参
# model.load_state_dict(torch.load('./vgg16.pth'))
import copy
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 没有训练前的初始化参数
best_model_weight = model.state_dict()
best_acc = 0.0
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        # 更新参数, 保存最佳参数
        best_model_weight = copy.deepcopy(model.state_dict())

  •  加载最佳参数模型
# 把最好的参数加载到模型
model.load_state_dict(best_model_weight)

2.5 保存完整模型和参数

  • 保存模型参数
torch.save(model, './my_whole_model.pth')
  • 加载模型及参数
new_model2 = torch.load('./my_whole_model.pth')
# 查看保存参数
new_model2.state_dict()
new_model2

2.6 跨设备的模型保存和加载

# GPU和cpu
device    # device(type='cpu')
  • 把刚才保存的模型映射到GPU 
# 把刚才保存的模型映射到GPU
torch.save(model.state_dict(), './my_best_weight')   # 保存参数

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 下载完模型后, 执行了model.to(device), 默认在CPU上
model.load_state_dict(torch.load('./my_best_weight', map_location=device))

三 学习率衰减

3.1 导入模型

# 加载预训练模型
model = torchvision.models.vgg16(pretrained=True)

for param in model.features.parameters():
    param.requires_grad = False

# 修改结果特征, 4分类
model.classifier[-1].out_features = 4

# 拷贝到GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)

# 继续训练
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()

3.2 学习率衰减

from torch.optim import lr_scheduler

# 学习率衰减
step_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
  • 模型训练
# 定义训练过程
def fit(epoch, model, train_loader, test_loader):
    correct = 0
    total = 0
    running_loss = 0
    
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()
            
    # 衰减学习率
    step_lr_scheduler.step()
    epoch_loss = running_loss / len(train_loader.dataset)
    epoch_acc = correct / total
    
    # 测试过程
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    test_epoch_loss = test_running_loss / len(test_loader.dataset)
    test_epoch_acc = test_correct /test_total
    
    print('epoch', epoch,
          'loss', round(epoch_loss, 3),
          'accuracy', round(epoch_acc, 3),
          'test_loss', round(test_epoch_loss, 3),
          'test_accuracy', round(test_epoch_acc, 3))
    return epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc
# 指定训练次数
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(test_epoch_loss)
    test_acc.append(test_epoch_acc)

四  数据增强

4.1 数据输入

数据增强

  • transforms.RandomCrop     # 随机位置裁剪
  • transforms.RandomRotation     # 随机旋转
  • transforms.RandomHorizontalFlip     # 水平翻转
  • transforms.RandomVerticalFlip     # 垂直翻转
  • transforms.ColorJitter(brightness)      # 亮度
  • transforms.ColorJitter(contrast)       # 对比度
  • transforms.ColorJitter(saturation)       # 饱和度
  • transforms.ColorJitter(hue)        # 色调
  • transforms.RandomGrayscale      # 随机灰度化
import os
base_dir = './dataset'
train_dir = os.path.join(base_dir, 'train')
test_dir = os.path.join(base_dir, 'test')
# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])
train_ds = torchvision.datasets.ImageFolder(train_dir, transform=train_transform)
test_ds = torchvision.datasets.ImageFolder(test_dir, transform=test_transform)

# dataloader
batch_size = 32  # batch 批次
train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size,
                                       shuffle=True, drop_last=True)
test_d1 = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

4.2 减弱数据增强

# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                # transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                # transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化    # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化    # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迁移学习中,过拟合是一个常见的问题。过拟合指的是模型在训练集上表现良好,但在测试集或新数据上表现不佳的情况。 以下是一些可以应对过拟合问题的常见方法: 1. 数据增强(Data Augmentation):通过对训练数据进行随机变换(如旋转、翻转、裁剪等),增加数据的多样性,从而使模型更加泛化。 2. 正则化(Regularization):通过在损失函数中添加正则化项,限制模型的复杂度。常用的正则化方法有L1正则化和L2正则化。 3. 早停(Early Stopping):在训练过程中,监控模型在验证集上的性能。当验证集上的性能不再提升时,及时停止训练,以防止过拟合。 4. Dropout:在模型的隐藏层中引入Dropout层,随机丢弃一部分神经元的输出。这样可以减少神经网络的复杂度,提高模型泛化能力。 5. 模型复杂度控制:通过调整模型的大小、深度或宽度等参数,限制模型的容量。如果模型过于复杂,容易过拟合。 6. 增加训练数据量:通过收集更多的训练数据,可以帮助模型更好地学习数据的分布,减少过拟合的可能性。 7. 使用预训练模型的特征提取部分:在迁移学习中,通常可以冻结预训练模型的特征提取部分,只训练新添加的全连接层。这样可以减少模型的参数量,降低过拟合的风险。 以上方法可以单独或组合使用,具体的选择取决于你的任务和数据。通过使用这些方法,可以减轻模型的过拟合问题,提高模型在测试集或新数据上的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值