PyTorch 深度学习实战
方远
LINE China 数据科学家
10381 人已学习
新⼈⾸单¥59
登录后,你可以任选3讲全文学习
课程目录
已完结/共 32 讲
开篇词 (1讲)
PyTorch 深度学习实战
15
15
1.0x
00:00/00:00
登录|注册

14 | 构建网络:一站式实现模型搭建与训练

你好,我是方远。
前面我们花了不少时间,既学习了数据部分的知识,还研究了模型的优化方法、损失函数以及卷积计算。你可能感觉这些知识还有些零零散散,但其实我们不知不觉中,已经拿下了模型训练的必学内容。
今天这节课,也是一个中期小练习,是我们检验自己学习效果的好时机。我会带你使用 PyTorch 构建和训练一个自己的模型。
具体我是这么安排的,首先讲解搭建网络必备的基础模块——nn.Module 模块,也就是如何自己构建一个网络,并且训练它,换句话说,就是搞清楚 VGG、Inception 那些网络是怎么训练出来的。然后我们再看看如何借助 Torchvision 的模型作为预训练模型,来训练我们自己的模型。

构建自己的模型

让我们直接切入主题,使用 PyTorch,自己构建并训练一个线性回归模型,来拟合出训练集中的走势分布。
我们先随机生成训练集 X 与对应的标签 Y,具体代码如下:
import numpy as np
import random
from matplotlib import pyplot as plt
w = 2
b = 3
xlim = [-10, 10]
x_train = np.random.randint(low=xlim[0], high=xlim[1], size=30)
y_train = [w * x + b + random.randint(0,2) for x in x_train]
plt.plot(x_train, y_train, 'bo')
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文详细介绍了如何使用PyTorch一站式实现模型搭建与训练。作者通过一个线性回归模型的例子引出了构建网络时的重要知识点,包括继承nn.Module类、重写__init__()方法和forward()方法。文章介绍了nn.Module模块的作用和使用方法,以及模型的训练过程,包括损失函数与优化方法的选择以及模型参数的更新。此外,作者还讨论了如何将重复的结构放在一个单独的module中,并在模型中调用这部分的实现方式。另外,文章介绍了两种方式来保存和加载模型参数,以及如何使用Torchvision中的模型进行微调。通过实例和代码演示,读者可以快速了解PyTorch中模型搭建与训练的流程,以及如何使用预训练模型进行微调。整体而言,本文对于想要快速了解PyTorch模型搭建与训练的读者来说,是一篇值得阅读的文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《PyTorch 深度学习实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(28)

  • 最新
  • 精选
  • vcjmhg
    class MyCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, kernel_size=3) # conv1输出的特征图为222x222大小 self.fc = nn.Linear(16 * 222 * 222, 10) def forward(self, input): x = self.conv1(input) # 进去全连接层之前,先将特征图铺平 x = x.view(x.shape[0], -1) x = self.fc(x) return x # 尽量使用gpu进行训练,如果没有cpu则使用gpu来训练 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") cnn = MyCNN().to(device) transform = transforms.Compose([ # 修改裁剪图片的尺寸 transforms.RandomResizedCrop((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) cifar10_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, transform=transform, target_transform=None, download=True) dataloader = DataLoader(dataset=cifar10_dataset, # 传入的数据集, 必须参数 batch_size=32, # 输出的batch大小 shuffle=True, # 数据是否打乱 num_workers=2) # 进程数, 0表示只有主进程 # 定义优化器 optimizer = torch.optim.SGD(cnn.parameters(), lr=1e-4, weight_decay=1e-2, momentum=0.9) steps = 0 for epoch in range(16): for item in dataloader: steps += 1 output = cnn(item[0].to(device)) target = item[1].to(device) # 使用交叉熵损失函数 loss = nn.CrossEntropyLoss()(output, target) # 每100步打印一次loss if steps % 100 == 0: print('Epoch {}, Loss {}'.format(epoch + 1, loss)) cnn.zero_grad() loss.backward() optimizer.step() # 测试分类结果 im = Image.open('data/img.png') input_tensor = transform(im).unsqueeze(0) result = cnn(input_tensor.to(device)).argmax() print(result) # tensor(3, device='cuda:0')

    作者回复: 👍🏻👍🏻 ^^

    2021-11-16
    2
    14
  • Mr_李冲
    我在使用预训练好的alexnet-owt-7be5be79.pth模型,反复执行下面这段代码的时候 alexnet(input_tensor).argmax() 得到的结果并不总是263,而有时候会得到151和264或者其他的数值,请问我最终应该相信哪一个预测结果呢,是进行多次预测取预测次数最多的那个吗?还是有别的科学的方法呢?

    作者回复: 你好,感谢你的留言。 如果保证输入一样,正常不会这样的。 你检查检查你的预处理的resize是不是会随机切割。 还是不行的话,可以把你的代码发给我看看。

    2022-03-15
    8
    2
  • clee
    调整之后,可以正常训练了,但是测试数据的时候我发现有些图片分类会有问题,比如狗和猫,鹿和马就容易分类错误,这是因为欠拟合吗?应该如何优化?

    作者回复: hi。 CIFAR10的图片比较小,猫和狗、鹿和马比较像,一部分图片预测错误是可以接受的。可以在下面尝试1之后,用验证集评估一下模型精确与召回,看看是否为一个可接受的结果,如果是的话,那部分图片分错是没问题的。 可以做如下尝试: 1. 把train=Fasle改为True。我为了讲解方便直接使用验证集训练的。 cifar10_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, transform=transform, target_transform=None, download=True) 2. 把学习率调小一点试试。^^

    2021-11-16
    2
  • zhangting
    老师请教个问题,为什么改全连接后,训练出来的模型,总是输出的是5。而未做改动前,预测出来的是263.源码如下: alexnet = models.alexnet() alexnet.load_state_dict(torch.load('./model/alexnet-owt-7be5be79.pth')) fc_in_features = alexnet.classifier[6].in_features alexnet.classifier[6] = torch.nn.Linear(fc_in_features, 10) print(alexnet) transform = transforms.Compose([ transforms.RandomResizedCrop((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) cifar10_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, transform=transform, target_transform=None, download=False) dataloader = DataLoader(dataset=cifar10_dataset, batch_size=32, shuffle=True, num_workers=4) optimizer = torch.optim.SGD(alexnet.parameters(), lr=1e-4, weight_decay=1e-2, momentum=0.9) for epoch in range(3): for item in dataloader: output = alexnet(item[0]) target = item[1] loss = nn.CrossEntropyLoss()(output, target) print('Epoch {}, Loss {}'.format(epoch + 1 , loss)) alexnet.zero_grad() loss.backward() optimizer.step() im = Image.open('dog.jpg') transform = transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) input_tensor = transform(im).unsqueeze(0) alexnet.eval() print(alexnet(input_tensor).argmax())

    作者回复: 你好,感谢你的留言。 输出5不是正确的吗? cifar10里dog就是5啊

    2022-05-12
    3
    1
  • 刘利
    hi,老师,微调的时候,如果这样写,参数都不更新了,那还有哪部分参数会被训练呢?是需要再接一层全连接层么? alexnet = models.alexnet() alexnet.load_state_dict(torch.load('./model/alexnet-owt-4df8aa71.pth')) for param in alexnet.parameters(): param.requires_grad = False

    作者回复: 你好,刘利,感谢留言。 就只训练全连接层了。 finetune的时候会根据你的分类任务,新加一个全连接层(而不是使用原模型的)

    2022-05-03
    2
    1
  • 马克图布
    思考: 使用 `nn.CrossEntropyLoss` 作为 loss function 时,会自动在网络最后添加 `nn.LogSoftmax` 和 `nn.nLLLos`,因此不用再在 fc 层后面手动添加 Softmax 层; 问题: transform 中,标准化的 mean 和 std 是如何确定的(我们需要使用均值为[0.485, 0.456, 0.406],标准差为[0.229, 0.224, 0.225]对数据进行正规化)?

    作者回复: 你好,马克图布,感谢你的留言。 对,内置了Softmax。 均值[0.485, 0.456, 0.406],标准差[0.229, 0.224, 0.225] 是ImageNet的均值与标准差。torchvision中的模型都是在ImageNet上训练的。

    2021-11-12
    1
  • Monroe He
    老师请教一个问题,在梯度清零代码中 13 节课用的是优化器 optimizer.zero_grad() 这节课用的是模型 alexnet.zero_grad() 这两行代码有什么区别吗?

    作者回复: 抱歉,回复的太迟了。本质上没有太大区别。 但optimizer可以优化多个模型的参数。alexnet. zero_grad()指定只对alexnet的梯度进行清零。 例如,下面的代码。 # 创建多个模型 model1 = torch.nn.Linear(10, 5) model2 = torch.nn.Linear(10, 3) # 将模型的参数合并 all_parameters = list(model1.parameters()) + list(model2.parameters()) # 创建优化器,同时优化多个模型的参数 optimizer = optim.SGD(all_parameters, lr=0.01) # 在训练迭代中使用优化器来更新模型参数 for _ in range(num_epochs): optimizer.zero_grad()

    2023-03-19归属地:北京
  • 杨杰
    import torchvision.models as models from PIL import Image import torchvision import torchvision.transforms as transforms alexnet = models.alexnet(pretrained=True) im = Image.open('./data/dog.jpg') transform = transforms.Compose([ transforms.RandomResizedCrop((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) input_tensor = transform(im).unsqueeze(0) print(alexnet(input_tensor).argmax()) 以上代码输出的不一定是264,这个是啥情况?

    作者回复: 你好,因为使用了随机剪裁。 transforms.RandomResizedCrop((224,224))。 并且没有加alexnet.eval()

    2022-10-04归属地:北京
  • Geek_827444
    老师您好:我一步一步按照咱们那个步骤来的,为什么代码运行不了那?谢谢您! import torch import torch.nn as nn import torch.optim as optim import torchvision.models as models import torchvision.models as models alexnet = models.alexnet(pretrained=True) import torchvision.transforms as transforms transform = transforms.Compose([ transforms.RandomResizedCrop((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225]) ]) import torchvision cifar10_dataset = torchvision.datasets.CIFAR10(root='./data',#注:这里是存在 pycharm文件当中的data文件夹里 train=False, transform=transform, target_transform=None, download=True) from torch.utils.data import DataLoader dataloader = DataLoader(dataset=cifar10_dataset, batch_size=32, shuffle=True, num_workers=2) fc_in_features = alexnet.classifier[6].in_features alexnet.classifier[6] = torch.nn.Linear(fc_in_features,10) optimizer = torch.optim.SGD(alexnet.parameters(), lr=1e-4, weight_decay=1e-2, momentum=0.9) for epoch in range(3): # ↓定义比对的元素 for item in dataloader: output = alexnet(item[0]) target = item[1] # ↓使用损失函数 loss = nn.CrossEntropyLoss()(output, target) print('Epoch{},Loss{}'.format(epoch + 1, loss)) # ↓更新损失函数和优化函数 alexnet.zero_grad() loss.backward() optimizer.step()

    作者回复: 抱歉,回复迟了。 我执行了你的代码,并没有报错。你提示什么错误呢?

    2022-08-09归属地:北京
    2
  • John(易筋)
    巨人肩膀@马克图库 import torch import torch.nn as nn import torchvision import torchvision.transforms as transforms from PIL import Image transform = transforms.Compose([ transforms.RandomResizedCrop((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) cifar10_train_dataset = torchvision.datasets.CIFAR10(root='./data',train=True,transform=transform,target_transform=None) train_loader = torch.utils.data.DataLoader(dataset=cifar10_train_dataset,batch_size=32,shuffle=True,num_workers=2) classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') n_total_steps = len(train_loader) class MyCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, kernel_size=3) self.fc = nn.Linear(16 * 222 * 222, 10) def forward(self, input): x = self.conv1(input) x = x.view(x.shape[0], -1) x = self.fc(x) return x device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') model = MyCNN().to(device) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, weight_decay=1e-2, momentum=0.9) print('Start training...') for epoch in range(4): for i, (images, labels) in enumerate(train_loader): images = images.to(device) labels = labels.to(device) labels_pred = model(images) loss = criterion(labels_pred, labels) optimizer.zero_grad() loss.backward() optimizer.step if (i+1) % 100 == 0: print(f'Epoch [{epoch+1}/{4}], Step [{i+1:5d}/{n_total_steps}], Loss={loss.item():.4f}') print('Training complete!') with torch.no_grad(): im = Image.open('./images/dog.jpg') input_tensor = transform(im).unsqueeze(0).to(device) label_pred = model(input_tensor).argmax() print(f'Your label predicted: {classes[label_pred]}')

    作者回复: 👍🏻

    2022-08-07归属地:北京
收起评论
显示
设置
留言
28
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部