VGG13到VGG19代码。
怎么用paddlepaddle写
本项目是百度AI Studio上图像分类课程的一个内容,之前使用ResNet101网络完成,现在用VGG-16网络实现同样的任务。数据集可以在AI Studio上搜索Butterfly20下载,如果下载不到,可用下面网盘链接。
Butterfly20数据集下载链接:
链接:https://pan.baidu.com/s/19Fqsg_rUAQi9nvf3vLhI9w
提取码:qdkx
这次使用其他网络完成同一任务,所以程序大体变化不大,数据预处理、训练测试、模型保存等都变化不大,所以更详细的分步解释见上一篇文章:
https://blog.csdn.net/weixin_43848436/article/details/114669737
我可以提供使用PaddlePaddle编写VGG16模型的代码,与此相关的VGG13到VGG19的代码与VGG16类似,仅需要更改部分网络块和参数配置即可。以下是代码和相关注释:
import paddle
# 定义网络块:卷积+池化
class ConvPool(paddle.nn.Layer):
def __init__(self, num_channels, num_filters):
super(ConvPool, self).__init__()
# 定义卷积层
self.conv2d = paddle.nn.Conv2D(in_channels=num_channels,
out_channels=num_filters,
kernel_size=3,
stride=1,
padding=1)
# 定义批归一化层
self.batch_norm = paddle.nn.BatchNorm2D(num_filters)
# 定义ReLU激活函数
self.relu = paddle.nn.ReLU()
# 定义最大池化层
self.pool2d = paddle.nn.MaxPool2D(kernel_size=2, stride=2)
def forward(self, inputs):
x = self.conv2d(inputs)
x = self.batch_norm(x)
x = self.relu(x)
x = self.pool2d(x)
return x
# 定义VGG网络结构:由多个网络块组成
class VGG16(paddle.nn.Layer):
def __init__(self, num_classes):
super(VGG16, self).__init__()
# 定义网络块
self.block1 = ConvPool(3, 64)
self.block2 = ConvPool(64, 128)
self.block3 = paddle.nn.Sequential(
ConvPool(128, 256),
ConvPool(256, 256)
)
self.block4 = paddle.nn.Sequential(
ConvPool(256, 512),
ConvPool(512, 512)
)
self.block5 = paddle.nn.Sequential(
ConvPool(512, 512),
ConvPool(512, 512)
)
# 定义全连接层
self.fc1 = paddle.nn.Linear(in_features=512 * 7 * 7, out_features=4096)
self.fc2 = paddle.nn.Linear(in_features=4096, out_features=4096)
self.fc3 = paddle.nn.Linear(in_features=4096, out_features=num_classes)
def forward(self, inputs):
x = self.block1(inputs)
x = self.block2(x)
x = self.block3(x)
x = self.block4(x)
x = self.block5(x)
x = paddle.flatten(x, start_axis=1, stop_axis=-1)
x = self.fc1(x)
x = paddle.nn.functional.relu(x)
x = paddle.nn.functional.dropout(x, p=0.5, training=self.training)
x = self.fc2(x)
x = paddle.nn.functional.relu(x)
x = paddle.nn.functional.dropout(x, p=0.5, training=self.training)
x = self.fc3(x)
return x
# 参数配置
train_parameters = {
"input_size": [3, 224, 224],
"class_dim": 1000,
"lr": 0.005,
"epoch_num": 100,
"batch_size": 64,
"step_size": 30,
"gamma": 0.1,
"optimizer_type": "momentum",
"momentum": 0.9,
"l2_decay": 5e-4,
"save_interval_epochs": 10,
"early_stop_epochs": 4,
"resume_epoch": 90,
"resume_dir": "./checkpoints/vgg16_epoch_90.pdparams"
}
# 定义训练函数
def train(model, train_loader, valid_loader, optimizer, loss_fn, train_parameters):
# 开始训练
for epoch in range(train_parameters['epoch_num']):
model.train()
for batch_id, data in enumerate(train_loader()):
x_data = data[0]
y_data = data[1]
logits = model(x_data)
loss = loss_fn(logits, y_data)
loss.backward()
optimizer.step()
optimizer.clear_grad()
if batch_id % 10 == 0:
print('epoch: {}, batch_id: {}, loss is: {}'.format(epoch, batch_id, loss.numpy()))
# 验证模型
model.eval()
accuracies = []
losses = []
for batch_id, data in enumerate(valid_loader()):
x_data = data[0]
y_data = data[1]
# 这里需要显式地告诉 PaddlePaddle 不需要计算梯度,以免浪费内存
with paddle.no_grad():
logits = model(x_data)
loss = loss_fn(logits, y_data)
acc = paddle.metric.accuracy(input=logits, label=y_data)
accuracies.append(acc.numpy())
losses.append(loss.numpy())
avg_acc, avg_loss = np.mean(accuracies), np.mean(losses)
print("[Validation] accuracy/loss: {}/{}".format(avg_acc, avg_loss))
# 保存模型
if (epoch % train_parameters['save_interval_epochs'] == 0) or (epoch == train_parameters['epoch_num'] - 1):
model_save_dir = "./checkpoints"
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
model_save_path = os.path.join(model_save_dir, "vgg16_epoch_{}.pdparams".format(epoch))
paddle.save(model.state_dict(), model_save_path)
# 主函数
if __name__ == '__main__':
# 数据准备
train_dataset = paddle.vision.datasets.Cifar10(mode='train', transform=paddle.vision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]))
valid_dataset = paddle.vision.datasets.Cifar10(mode='test', transform=paddle.vision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]))
train_loader = paddle.io.DataLoader(train_dataset,
batch_size=train_parameters['batch_size'],
shuffle=True,
num_workers=0,
drop_last=True)
valid_loader = paddle.io.DataLoader(valid_dataset,
batch_size=train_parameters['batch_size'],
shuffle=False,
num_workers=0,
drop_last=True)
# 模型训练
paddle.set_device('gpu' if paddle.fluid.is_compiled_with_cuda() else 'cpu')
model = VGG16(num_classes=train_parameters['class_dim'])
# 加载已训练好的模型
if 'resume_dir' in train_parameters.keys():
assert os.path.exists(train_parameters['resume_dir']), "The resume_dir does not exist."
model_state_dict = paddle.load(train_parameters['resume_dir'])
model.set_dict(model_state_dict)
loss_fn = paddle.nn.CrossEntropyLoss()
optimizer = paddle.optimizer.Momentum(learning_rate=train_parameters['lr'],
momentum=train_parameters['momentum'],
weight_decay=paddle.regularizer.L2Decay(train_parameters['l2_decay']))
train(model=model,
train_loader=train_loader,
valid_loader=valid_loader,
optimizer=optimizer,
loss_fn=loss_fn,
train_parameters=train_parameters)