Pytorch入门实战第五周:运动鞋识别

目录

前言

1.1设置GPU

1.2.导入数据

二、构建CNN网络

2.1 网络结构图

2.2 代码实现

三、训练模型

3.1 训练函数

3.2测试函数

3.3 设置动态学习率

3.4 正式训练

四、结果可视化

4.1 Loss和Acuuracy图

4.2 指定图片进行预测

五、保存并加载模型

六、提高精度尝试

总结


前言

  • 🍨本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客
  • 🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)

说在前面:

本周学习目标:了解如何设置动态学习率(重点)、调整代码是测试集accuracy达到84%;拔高:保存训练过程中的最佳模型权重,调整代码使测试集accuracy到达86%
我的环境:Python3.8、Pycharm2020、torch1.12.1+cu113(数据来源——[K同学啊](https://mtyjkh.blog.csdn.net/))


一、前期准备

1.1设置GPU

(有GPU优先使用GPU,没有的话就使用CPU)

代码如下:

#一、前期准备
'''
1.1 设置GPU
'''
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib
import torch.nn.functional as F
import matplotlib.pyplot as plt
from PIL import Image

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

结果输出:cuda

1.2.导入数据

1.数据下载并设置相应的文件目录以便图片读取,将数据下载放在对应代码下目录下新建的data目录

  • 数据集介绍:预先划分了train和test数据集,每个数据集里都包含了两类图片,addidas和nike

导入数据的步骤

 1)使用函数将字符串类型的文件夹路径转换为pathlib.Path对象

 2)使用glob方法获取data_dir路径下的所有文件路径,并以列表的形式存储在data_paths中

 3)利用split()函数对data_paths中的每个文件路径执行分割操作,获取各个文件所属的类别名称并储存在classNames中

数据文件导入代码如下:

'''
1.2 导入数据
'''
data_dir = './data/'
data_dir = pathlib.Path(data_dir)           #使用pathlib.Path()函数将字符串类型的文件夹路径转换为pathlib.Path对象
data_paths = list(data_dir.glob('*'))       #使用glob()方法获取data_dir路径下的所有文件路径,并以列表形式存储在data_paths中
classNames = [str(path).split("\\")[1] for path in data_paths]   #使用data_paths中每个文件路径执行分割操作,获得各文件所属的类别名称
print(classNames)

打印结果为:

['test', 'train']

2.图片数据处理

torchvision.transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起 
1)Resize:将输入图片resize成统一尺寸
2)ToTensor:将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
3)Normalize:标准化处理-->转换为标准正态分布,使模型更容易收敛;其中mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的
ImageFolder类来创建一个数据集对象,total_data将是一个包含所有图像数据的数据集对象,可以用于训练神经网络模型

代码如下:

train_transforms = transforms.Compose([
    transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸
    # transforms.RandomHorizontalFlip(), # 随机水平翻转
    transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    transforms.Normalize(           # 标准化处理-->转换为标准正态分布(高斯分布),使模型更容易收敛
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])

test_transform = transforms.Compose([
    transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸
    transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])

train_dataset = datasets.ImageFolder("./data/train/", transform=train_transforms)
test_dataset = datasets.ImageFolder("./data/test/", transform=train_transforms)

print(train_dataset.class_to_idx)     #total_data.class_to_idx是一个存储了数据集类别和对于索引的字典

打印结果如下:

{'adidas': 0, 'nike': 1}

3.查看一个batch_size的数据结构

torch.utils.data.DataLoader():这是Pytorch中用于加载和管理数据的一个实用工具类,它允许以小批次的方式迭代数据集,这对于训练神经网络和其他机器学习任务非常有用。具体参数解释如下:

1)dataset(必需参数):这是你的数据集对象,通常是 torch.utils.data.Dataset 的子类,它包含了你的数据样本。

2)batch_size(可选参数):指定每个小批次中包含的样本数。默认值为 1。

3)shuffle(可选参数):如果设置为 True,则在每个 epoch 开始时对数据进行洗牌,以随机打乱样本的顺序。这对于训练数据的随机性很重要,以避免模型学习到数据的顺序性。默认值为 False。

4)num_workers(可选参数):用于数据加载的子进程数量。通常,将其设置为大于 0 的值可以加快数据加载速度,特别是当数据集很大时。默认值为 0,表示在主进程中加载数据。

5)pin_memory(可选参数):如果设置为 True,则数据加载到 GPU 时会将数据存储在 CUDA 的锁页内存中,这可以加速数据传输到 GPU。默认值为 False。

6)drop_last(可选参数):如果设置为 True,则在最后一个小批次可能包含样本数小于 batch_size 时,丢弃该小批次。这在某些情况下很有用,以确保所有小批次具有相同的大小。默认值为 False。

7)timeout(可选参数):如果设置为正整数,它定义了每个子进程在等待数据加载器传递数据时的超时时间(以秒为单位)。这可以用于避免子进程卡住的情况。默认值为 0,表示没有超时限制。

8)worker_init_fn(可选参数):一个可选的函数,用于初始化每个子进程的状态。这对于设置每个子进程的随机种子或其他初始化操作很有用

代码如下:

batch_size = 32
train_dl = torch.utils.data.DataLoader(train_dataset,
                                       batch_size=batch_size,
                                       shuffle=True,
                                       num_workers=0)
test_dl = torch.utils.data.DataLoader(test_dataset,
                                      batch_size=batch_size,
                                      shuffle=True,
                                      num_workers=0)
for X, y in test_dl:
    print("Shape of X [N, C, H, W]: ", X.shape)
    print("Shape of y: ", y.shape, y.dtype)
    break

打印结果如下:

Shape of X [N, C, H, W]:  torch.Size([32, 3, 224, 224])
Shape of y:  torch.Size([32]) torch.int64

二、构建CNN网络

2.1 网络结构图

2.2 代码实现

1.准备知识

nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中

在本次模型结构中一个卷积模块是由一个Conv2d、BN层、ReLu层构成,形成一个'卷积-BN-激活‘的结构

2.代码实现

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        #nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中
        #12*220*220
        self.conv1 = nn.Sequential(
            nn.Conv2d(3,12,kernel_size=5, padding=0),
            nn.BatchNorm2d(12),nn.ReLU())
        #12*216*216
        self.conv2 = nn.Sequential(
            nn.Conv2d(12,12,kernel_size=5, padding=0),
            nn.BatchNorm2d(12),nn.ReLU())
        #12*108*108
        self.pool3 =nn.Sequential(nn.MaxPool2d(2))
        #24*104*104
        self.conv4 = nn.Sequential(
            nn.Conv2d(12, 24, kernel_size=5, padding=0),
            nn.BatchNorm2d(24), nn.ReLU())
        #24*100*100
        self.conv5 = nn.Sequential(
            nn.Conv2d(24, 24, kernel_size=5, padding=0),
            nn.BatchNorm2d(24), nn.ReLU())
        #24*50*50
        self.pool6 = nn.Sequential(nn.MaxPool2d(2))
        self.dropout = nn.Sequential(nn.Dropout(0.2))     #设置p=0.2的正则化

        self.fc = nn.Sequential(nn.Linear(24*50*50, len(classNames)))

    def forward(self, x):

        batch_size = x.size(0)
        x = self.conv1(x)           #卷积-BN-激活
        x = self.conv2(x)
        x = self.pool3(x)
        x = self.conv4(x)
        x = self.conv5(x)
        x = self.pool6(x)
        x = self.dropout(x)
        # flatten 变成全连接网络需要的输入 (batch, 24*50*50) ==> (batch, -1), -1 此处自动算出的是24*50*50
        x = x.view(batch_size, -1)
        x = self.fc(x)

        return x

device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))
model = Model().to(device)
print(model)

模型打印结果如下:

Using cuda device
Model(
  (conv1): Sequential(
    (0): Conv2d(3, 12, kernel_size=(5, 5), stride=(1, 1))
    (1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
  )
  (conv2): Sequential(
    (0): Conv2d(12, 12, kernel_size=(5, 5), stride=(1, 1))
    (1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
  )
  (pool3): Sequential(
    (0): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (conv4): Sequential(
    (0): Conv2d(12, 24, kernel_size=(5, 5), stride=(1, 1))
    (1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
  )
  (conv5): Sequential(
    (0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1))
    (1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
  )
  (pool6): Sequential(
    (0): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (dropout): Sequential(
    (0): Dropout(p=0.2, inplace=False)
  )
  (fc): Sequential(
    (0): Linear(in_features=60000, out_features=2, bias=True)
  )
)

三、训练模型

3.1 训练函数

代码如下:

#三、训练模型
'''
3.1 训练函数
'''
def train(dataloader, model, loss_fn, optimier):
    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)
        #反向传播
        optimier.zero_grad()   #grad属性归零
        loss.backward()        #反向传播
        optimier.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

3.2测试函数

代码如下:

'''
3.2编写测试函数
'''
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)

            # 计算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.3 设置动态学习率

1. 预备知识

1)torch.optim.lr_scheduler.StepLR:等间隔动态调整方法,每经过step_size个epoch,做一次学习率decay,以gamma值为缩小倍数

torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)

  • optimizer(Optimizer):是之前定义好的需要优化的优化器的实例名
  • step_size(int):是学习率衰减的周期,每经过每个epoch,做一次学习率decay
  • gamma(float):学习率衰减的乘法因子。Default:0.1

示例代码:

optimizer = torch.optim.SGD(net.parameters(), lr=0.001 )
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)

2)lr_scheduler.LambdaLR:根据自己定义的函数更新学习率

torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1, verbose=False)

  • optimizer(Optimizer):是之前定义好的需要优化的优化器的实例名
  • lr_lambda(function):更新学习率的函数

示例代码:

lambda1 = lambda epoch: (0.92 ** (epoch // 2) # 第二组参数的调整方法
optimizer = torch.optim.SGD(model.parameters(), lr=learn_rate)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1) #选定调整方法

3)lr_scheduler.MultiStepLR:在特定的 epoch 中调整学习率

torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1, verbose=False)

  • optimizer(Optimizer):是之前定义好的需要优化的优化器的实例名
  • milestones(list):是一个关于epoch数值的list,表示在达到哪个epoch范围内开始变化,必须是升序排列
  • gamma(float):学习率衰减的乘法因子。Default:0.1

示例代码:

optimizer = torch.optim.SGD(net.parameters(), lr=0.001 )
scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, 
                                                 milestones=[2,6,15], #调整学习率的epoch数
                                                 gamma=0.1)

除了调用官方动态学习率接口,还可以自定义动态学习率变化函数(本文选用的自定义方法)

# # 调用官方动态学习率接口时使用
# lambda1 = lambda epoch: (0.92 ** (epoch // 2)
# optimizer = torch.optim.SGD(model.parameters(), lr=learn_rate)
# scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1) #选定调整方法

2.代码实现

先定义一个动态学习的函数,根据epoch的训练进度来动态的改变学习率,然后在训练的时候调用该函数来作为模型学习率

同时选择SGD作为优化器

'''
3.3 设置动态学习率
'''
#定义的根据epoch动态变化的学习率
def adjust_lr(optimizer, epoch, start_lr):
    # 每2个epoch衰减到原来的0.98
    lr = start_lr * (0.98 ** (epoch // 2))
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

lr = 1e-4   #初始学习率
optimizer = torch.optim.SGD(model.parameters(), lr=lr)

3.4 正式训练

损失函数选用的交叉熵函数,epoch设置为40

代码如下:

'''
3.4 正式训练
'''
loss_fn = nn.CrossEntropyLoss()    #交叉熵函数作为损失函数
epochs = 40

train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    # 更新学习率(使用自定义学习率时使用)
    adjust_lr(optimizer, epoch, lr)

    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)

    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))
print('Done')

训练过程结果如下:

Epoch: 1, Train_acc:50.4%, Train_loss:0.766, Test_acc:53.9%, Test_loss:0.692, Lr:1.00E-04
Epoch: 2, Train_acc:59.4%, Train_loss:0.676, Test_acc:56.6%, Test_loss:0.666, Lr:1.00E-04
Epoch: 3, Train_acc:63.1%, Train_loss:0.666, Test_acc:56.6%, Test_loss:0.686, Lr:9.80E-05
Epoch: 4, Train_acc:71.1%, Train_loss:0.570, Test_acc:69.7%, Test_loss:0.573, Lr:9.60E-05
Epoch: 5, Train_acc:73.3%, Train_loss:0.536, Test_acc:73.7%, Test_loss:0.573, Lr:9.22E-05
Epoch: 6, Train_acc:77.5%, Train_loss:0.504, Test_acc:77.6%, Test_loss:0.511, Lr:8.86E-05
Epoch: 7, Train_acc:76.9%, Train_loss:0.492, Test_acc:67.1%, Test_loss:0.544, Lr:8.34E-05
Epoch: 8, Train_acc:82.7%, Train_loss:0.438, Test_acc:78.9%, Test_loss:0.490, Lr:7.85E-05
Epoch: 9, Train_acc:78.7%, Train_loss:0.460, Test_acc:81.6%, Test_loss:0.499, Lr:7.24E-05
Epoch:10, Train_acc:83.5%, Train_loss:0.414, Test_acc:84.2%, Test_loss:0.465, Lr:6.68E-05
Epoch:11, Train_acc:83.3%, Train_loss:0.410, Test_acc:77.6%, Test_loss:0.495, Lr:6.03E-05
Epoch:12, Train_acc:85.9%, Train_loss:0.400, Test_acc:82.9%, Test_loss:0.477, Lr:5.45E-05
Epoch:13, Train_acc:86.3%, Train_loss:0.381, Test_acc:80.3%, Test_loss:0.452, Lr:4.83E-05
Epoch:14, Train_acc:87.1%, Train_loss:0.378, Test_acc:80.3%, Test_loss:0.481, Lr:4.28E-05
Epoch:15, Train_acc:88.0%, Train_loss:0.373, Test_acc:76.3%, Test_loss:0.474, Lr:3.72E-05
Epoch:16, Train_acc:88.0%, Train_loss:0.360, Test_acc:80.3%, Test_loss:0.506, Lr:3.23E-05
Epoch:17, Train_acc:88.8%, Train_loss:0.365, Test_acc:81.6%, Test_loss:0.482, Lr:2.74E-05
Epoch:18, Train_acc:89.6%, Train_loss:0.354, Test_acc:80.3%, Test_loss:0.456, Lr:2.33E-05
Epoch:19, Train_acc:89.2%, Train_loss:0.337, Test_acc:81.6%, Test_loss:0.477, Lr:1.95E-05
Epoch:20, Train_acc:89.8%, Train_loss:0.341, Test_acc:82.9%, Test_loss:0.454, Lr:1.62E-05
Epoch:21, Train_acc:90.2%, Train_loss:0.331, Test_acc:81.6%, Test_loss:0.468, Lr:1.33E-05
Epoch:22, Train_acc:89.0%, Train_loss:0.353, Test_acc:80.3%, Test_loss:0.462, Lr:1.08E-05
Epoch:23, Train_acc:90.6%, Train_loss:0.343, Test_acc:82.9%, Test_loss:0.442, Lr:8.68E-06
Epoch:24, Train_acc:90.6%, Train_loss:0.338, Test_acc:82.9%, Test_loss:0.489, Lr:6.95E-06
Epoch:25, Train_acc:90.6%, Train_loss:0.330, Test_acc:80.3%, Test_loss:0.490, Lr:5.45E-06
Epoch:26, Train_acc:90.4%, Train_loss:0.349, Test_acc:81.6%, Test_loss:0.464, Lr:4.28E-06
Epoch:27, Train_acc:92.6%, Train_loss:0.327, Test_acc:81.6%, Test_loss:0.446, Lr:3.29E-06
Epoch:28, Train_acc:91.0%, Train_loss:0.328, Test_acc:80.3%, Test_loss:0.473, Lr:2.53E-06
Epoch:29, Train_acc:91.2%, Train_loss:0.332, Test_acc:81.6%, Test_loss:0.468, Lr:1.91E-06
Epoch:30, Train_acc:91.6%, Train_loss:0.326, Test_acc:81.6%, Test_loss:0.486, Lr:1.44E-06
Epoch:31, Train_acc:91.0%, Train_loss:0.333, Test_acc:81.6%, Test_loss:0.434, Lr:1.06E-06
Epoch:32, Train_acc:91.2%, Train_loss:0.345, Test_acc:81.6%, Test_loss:0.470, Lr:7.84E-07
Epoch:33, Train_acc:89.8%, Train_loss:0.340, Test_acc:81.6%, Test_loss:0.466, Lr:5.67E-07
Epoch:34, Train_acc:91.4%, Train_loss:0.336, Test_acc:81.6%, Test_loss:0.484, Lr:4.11E-07
Epoch:35, Train_acc:90.2%, Train_loss:0.334, Test_acc:81.6%, Test_loss:0.437, Lr:2.91E-07
Epoch:36, Train_acc:90.2%, Train_loss:0.337, Test_acc:81.6%, Test_loss:0.449, Lr:2.07E-07
Epoch:37, Train_acc:89.0%, Train_loss:0.342, Test_acc:81.6%, Test_loss:0.450, Lr:1.44E-07
Epoch:38, Train_acc:91.2%, Train_loss:0.335, Test_acc:80.3%, Test_loss:0.468, Lr:9.98E-08
Epoch:39, Train_acc:89.8%, Train_loss:0.342, Test_acc:81.6%, Test_loss:0.459, Lr:6.80E-08
Epoch:40, Train_acc:90.4%, Train_loss:0.340, Test_acc:82.9%, Test_loss:0.453, Lr:4.63E-08
Done
预测结果是:adidas    

进程已结束,退出代码 0

最好的结果能达到84.2%这里

四、结果可视化

4.1 Loss和Acuuracy图

代码如下:

#四、结果可视化
'''
4.1 Loss和Accuracy图
'''
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()

打印输入如下图所示:

4.2 指定图片进行预测

代码如下:

'''
4.2 指定图片进行预测
'''
classes = list(train_dataset.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.eval()
    output = model(img)

    _, pred = torch.max(output, 1)
    pred_class = classes[pred]
    print(f'预测结果是:{pred_class}')

predict_one_image(image_path='./data/test/nike/10.jpg', model=model,
                  transform=train_transforms, classes=classes)

打印输出如下:预测结果是:adidas

很奇怪--这里我选用的照片一直是nike的,试了很多次还是打印的adidas的结果,就算在最好的模型参数下还是预测错误的

五、保存并加载模型

函数解释:

torch.save(obj, f, pickle_module=<module '...'>, pickle_protocol=2)
obj:保存对象

f:类文件对象 (必须实现写和刷新)或一个保存文件名的字符串

pickle_module:类文件对象 (必须实现写和刷新)或一个保存文件名的字符串

pickle_protocol:指定 pickle protocal 可以覆盖默认参数

代码如下:

PATH = './model5.pth'
torch.save(model.state_dict(), PATH)

#将参数加载到model放在
model.load_state_dict(torch.load(PATH, map_location=device))

六、提高精度尝试

由于初始设置的网络结果和超参数的结果运行效果并不是很好,所以这里设置了多组实验探究提升测试集Accuracy的方法——主要是通过修改优化器、修改学习率的初始值、修改学习率的衰减率、以及正则项的p几种组合来调整模型

0.SGD、P=0.2、初始学习率=0.0001、学习率衰减率=0.98

最佳结果为84.2%

1.修改优化器为Adam

运行下来并没有提升模型的结果,反而降低了

在test数据集上的acc最佳只能达到80.3%,没有SGD的效果好

2.在使用Adam的基础上,将正则项的P设置为0.5

相较与1情况下准确率有一点点提升不过提升不大

在test数据集上的acc最佳只能达到81.6%,没有SGD的效果好

3.修改优化器为SGD,P=0.2,学习率的衰减率为0.99

和2的结果相差不大,在epoch=22,test_acc就可以达到81.6%然后就一直不变了

4.优化器为SGD、P=0.2、初始学习率设置为0.001(原来为0.0001)

达到目前的最佳效果85.5%

说明了初始学习率对这个模型的accuracy还是由较大影响的

5.优化器为SGD、P=0.4、初始学习率为0.001、学习率衰减为0.98

test_acc的最佳结果为88.2%


总结

  • 本周重点学习了动态学习率的设置
  • 这次从学习率出发优化模型结果取得了较好的结果、同时可以发现正则项的参数对模型的性能影响也是较大的(动态学习率的初始值、衰减率对模型的优化都是十分关键的,我们在设置这些参数的时候需要格外的注意)
  • 但是本次选择指定图片预测结果一直是错的,没想太明白
  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值