14 | 构建网络:一站式实现模型搭建与训练
构建自己的模型
- 深入了解
- 翻译
- 解释
- 总结
本文详细介绍了如何使用PyTorch一站式实现模型搭建与训练。作者通过一个线性回归模型的例子引出了构建网络时的重要知识点,包括继承nn.Module类、重写__init__()方法和forward()方法。文章介绍了nn.Module模块的作用和使用方法,以及模型的训练过程,包括损失函数与优化方法的选择以及模型参数的更新。此外,作者还讨论了如何将重复的结构放在一个单独的module中,并在模型中调用这部分的实现方式。另外,文章介绍了两种方式来保存和加载模型参数,以及如何使用Torchvision中的模型进行微调。通过实例和代码演示,读者可以快速了解PyTorch中模型搭建与训练的流程,以及如何使用预训练模型进行微调。整体而言,本文对于想要快速了解PyTorch模型搭建与训练的读者来说,是一篇值得阅读的文章。
《PyTorch 深度学习实战》,新⼈⾸单¥59
全部留言(28)
- 最新
- 精选
- vcjmhgclass 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-16214 - Mr_李冲我在使用预训练好的alexnet-owt-7be5be79.pth模型,反复执行下面这段代码的时候 alexnet(input_tensor).argmax() 得到的结果并不总是263,而有时候会得到151和264或者其他的数值,请问我最终应该相信哪一个预测结果呢,是进行多次预测取预测次数最多的那个吗?还是有别的科学的方法呢?
作者回复: 你好,感谢你的留言。 如果保证输入一样,正常不会这样的。 你检查检查你的预处理的resize是不是会随机切割。 还是不行的话,可以把你的代码发给我看看。
2022-03-1582 - 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-162 - 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-1231 - 刘利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-0321 - 马克图布思考: 使用 `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-121 - 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归属地:北京