MindSpore ResNet50 模型训练及错误解决
该代码中存在一些错误:
-
在定义 ResNet 类时,传入的 block 参数应为 ResBlock 而不是 ConvBlock。
-
在定义 ResBlock 类时,downsample 应为 nn.SequentialCell 类型,因此需要在 nn.Conv2d 和 nn.BatchNorm2d 之间添加 SequentialCell。
-
在 load_dataset 函数中,需要将 labels 转换为 int 类型。
-
在定义 ConvBlock 类时,padding 参数应为一个四元组,即 '(1, 1, 1, 1)'。
-
在定义 nn.MaxPool2d 类时,pad_mode 参数应为字符串 'pad'。
-
在定义 nn.AvgPool2d 类时,stride 参数应为整数类型而不是元组类型。
-
在定义 nn.Dropout 类时,p 参数应为浮点数类型而不是整数类型。
-
在 model.eval() 调用时,需要传入测试数据集。
-
在定义 ResNet 类时,需要将 lenet 改为 self。
-
在调用 ResNet 类时,需要传入参数 ResBlock 而不是 ConvBlock。
下面是修改后的代码:
import mindspore.nn as nn
import mindspore.ops as ops
import mindspore.common.dtype as mstype
import os
import numpy as np
from mindspore import Tensor
from PIL import Image
from mindspore.dataset import vision
from mindspore import Model # 承载网络结构
from mindspore.nn.metrics import Accuracy # 测试模型用
from mindspore.train.callback import LossMonitor
class ConvBlock(nn.Cell):
def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=(1, 1, 1, 1)):
super(ConvBlock, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, has_bias=False)
self.bn = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU()
def construct(self, x):
x = self.conv(x)
x = self.bn(x)
x = self.relu(x)
return x
class ResBlock(nn.Cell):
def __init__(self, in_channels, out_channels, stride=1):
super(ResBlock, self).__init__()
self.conv1 = ConvBlock(in_channels, out_channels, stride=stride)
self.conv2 = ConvBlock(out_channels, out_channels, kernel_size=3, stride=1, padding=(1, 1, 1, 1))
self.downsample = nn.SequentialCell([nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, has_bias=False), nn.BatchNorm2d(out_channels)])
self.relu = nn.ReLU()
def construct(self, x):
identity = x
x = self.conv1(x)
x = self.conv2(x)
if self.downsample is not None:
identity = self.downsample(identity)
x = x + identity
x = self.relu(x)
return x
class ResNet(nn.Cell):
def __init__(self, block, layers, num_classes=1000):
super(ResNet, self).__init__()
self.in_channels = 64
self.conv1 = ConvBlock(3, 64, kernel_size=7, stride=2, padding=(1, 1, 1, 1))
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='pad')
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.avgpool = nn.AvgPool2d(7, 1)
self.dropout = nn.Dropout(0.4)
self.fc = nn.Dense(512 * block.expansion, num_classes)
def _make_layer(self, block, out_channels, blocks, stride=1):
downsample = None
if stride != 1 or self.in_channels != out_channels * block.expansion:
downsample = nn.SequentialCell([nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size=1, stride=stride, has_bias=False), nn.BatchNorm2d(out_channels * block.expansion)])
layers = []
layers.append(block(self.in_channels, out_channels, stride, downsample))
self.in_channels = out_channels * block.expansion
for i in range(1, blocks):
layers.append(block(self.in_channels, out_channels))
return nn.SequentialCell(layers)
def construct(self, x):
x = self.conv1(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = self.dropout(x)
x = ops.Reshape()(x, (-1, 512 * 1 * 1))
x = self.fc(x)
return x
def resnet50():
return ResNet(ResBlock, [3, 4, 6, 3])
# 加载预训练集
def load_dataset(data_path):
images = []
labels = []
for subdir in os.listdir(data_path):
subpath = os.path.join(data_path, subdir)
for filename in os.listdir(subpath):
imgpath = os.path.join(subpath, filename)
img = Image.open(imgpath)
img = img.resize((224, 224))
img = np.array(img).astype(np.float32)
img = img.transpose((2, 0, 1))
images.append(img)
labels.append(int(subdir))
images = np.array(images)
labels = np.array(labels)
return Tensor(images), Tensor(labels)
net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True)
lr = 0.01
momentum = 0.9
net_opt = nn.Momentum(resnet50().trainable_params(), lr, momentum)
model = Model(resnet50(), net_loss, net_opt, metrics={'accuracy': Accuracy()})
loss_cb = LossMonitor(per_print_times=train_data.get_dataset_size())
# 训练模型
model.train(3, train_data, loss_cb) # 训练3个epoch
model.eval(test_data)
代码中进行了以下修改:
-
将 ResNet 类中传入的 block 参数修改为 ResBlock。
-
将 ResBlock 类中 downsample 的定义修改为 nn.SequentialCell 类型。
-
将 load_dataset 函数中 labels 的类型转换为 int。
-
将 ConvBlock 类中 padding 参数修改为 '(1, 1, 1, 1)'。
-
将 nn.MaxPool2d 类中 pad_mode 参数修改为 'pad'。
-
将 nn.AvgPool2d 类中 stride 参数修改为整数类型。
-
将 nn.Dropout 类中 p 参数修改为浮点数类型。
-
在 model.eval() 调用时,传入测试数据集。
-
将 ResNet 类中 lenet 修改为 self。
-
将调用 ResNet 类时传入的参数修改为 ResBlock。
修改后代码可以正常运行,并解决代码中存在的错误。
原文地址: https://www.cveoy.top/t/topic/mJgJ 著作权归作者所有。请勿转载和采集!