最近在学习paddlepaddle,跟着官方文档在写最基础的"数字识别"。发现自己写的实现无法收敛,初步判断是写的 样本数据采集处理 逻辑有问题,因为我改用官方实现的样本数据采集就能正常收敛。
调试了半天还是没发现是什么差异导致。想求助各位佬 ![]()
下图是自己写的 样本数据采集get_MNIST_dataloader(dataFrom=“local”) 收敛日志
改用官方的样本数据采集get_MNIST_dataloader(dataFrom=“remote”) 收敛日志
以下是源码
import json
import gzip
import paddle
from paddle.vision.transforms import Normalize
from paddle.io import Dataset
import numpy as np
import paddle.nn.functional as F
from paddle.nn import Linear
from paddle.nn import Conv2D, MaxPool2D, Linear
class MNISTDataset(Dataset):
"""
步骤一:继承paddle.io.Dataset类
"""
def __init__(self, datafile, mode='train', transform = None):
"""
步骤二:实现构造函数
"""
super().__init__()
self.mode = mode
self.transform = transform
print('loading mnist dataset from {} ......'.format(datafile))
# 加载json数据文件
data = json.load(gzip.open(datafile))
print('mnist dataset load done')
# 读取到的数据区分训练集,验证集,测试集
train_set, val_set, eval_set = data
if mode=='train':
# 获得训练数据集
print("imgs",len(train_set[0][0]))
self.imgs, self.labels = train_set[0], train_set[1]
elif mode=='valid':
# 获得验证数据集
self.imgs, self.labels = val_set[0], val_set[1]
elif mode=='test':
# 获得测试数据集
self.imgs, self.labels = eval_set[0], eval_set[1]
else:
raise Exception("mode can only be one of ['train', 'valid', 'test']")
def __getitem__(self, index):
"""
步骤三:实现__getitem__方法,定义指定index时如何获取数据
"""
data, label = self.imgs[index], self.labels[index]
data = np.reshape(data, [28, 28]).astype("float32")
label = np.reshape(label,[1]).astype("int64")
return self.transform(data),label
def __len__(self):
"""
步骤四:实现__len__方法,返回数据集总数目
"""
return len(self.imgs)
def get_MNIST_dataloader(datafile = './dataset/mnist.json.gz',dataFrom = 'local'):
# 定义图像归一化处理方法,这里的CHW指图像格式需为 [C通道数,H图像高度,W图像宽度]
transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')
# 下载数据集并初始化 DataSet
if dataFrom == 'local' :
train_dataset = MNISTDataset(datafile, mode='train', transform=transform)
elif dataFrom == 'remote':
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
else:
raise Exception("data_format can only be one of ['local', 'remote']")
# 定义并初始化数据读取器
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True,drop_last=True)
return train_loader,''
# 定义多层全连接神经网络
class MNIST(paddle.nn.Layer):
def __init__(self):
super(MNIST, self).__init__()
# 定义卷积层,输出特征通道out_channels设置为20,卷积核的大小kernel_size为5,卷积步长stride=1,padding=2
self.conv1 = Conv2D(in_channels=1, out_channels=20, kernel_size=5, stride=1, padding=2)
# 定义池化层,池化核的大小kernel_size为2,池化步长为2
self.max_pool1 = MaxPool2D(kernel_size=2, stride=2)
# 定义卷积层,输出特征通道out_channels设置为20,卷积核的大小kernel_size为5,卷积步长stride=1,padding=2
self.conv2 = Conv2D(in_channels=20, out_channels=20, kernel_size=5, stride=1, padding=2)
# 定义池化层,池化核的大小kernel_size为2,池化步长为2
self.max_pool2 = MaxPool2D(kernel_size=2, stride=2)
# 定义一层全连接层,输出维度是10
self.fc = Linear(in_features=980, out_features=10)
# 定义网络前向计算过程,卷积后紧接着使用池化层,最后使用全连接层计算最终输出
# 卷积层激活函数使用Relu,全连接层不使用激活函数
def forward(self, inputs):
x = self.conv1(inputs)
x = F.relu(x)
x = self.max_pool1(x)
x = self.conv2(x)
x = F.relu(x)
x = self.max_pool2(x)
x = paddle.reshape(x, [x.shape[0], 980])
x = self.fc(x)
return x
#网络结构部分之后的代码,保持不变
def train(model,train_loader):
model.train()
learning_rate = 0.001
# 使用SGD优化器,设置learning_rate
opt = paddle.optimizer.SGD(learning_rate=learning_rate, parameters=model.parameters())
# 训练5轮
EPOCH_NUM = 10
# MNIST图像高和宽
IMG_ROWS, IMG_COLS = 28, 28
loss_list = []
for epoch_id in range(EPOCH_NUM):
for batch_id, data in enumerate(train_loader()):
#准备数据
images, labels = data
images = paddle.to_tensor(images)
labels = paddle.to_tensor(labels)
#前向计算的过程
predicts = model(images) # [batch_size, 1]
#计算损失,使用交叉熵损失函数,取一个批次样本损失的平均值
loss = F.cross_entropy(predicts, labels)
avg_loss = paddle.mean(loss)
#每训练200批次的数据,打印下当前Loss的情况
if batch_id % 200 == 0:
loss_list.append(avg_loss.numpy())
print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
#后向传播,更新参数的过程
avg_loss.backward()
# 最小化loss,更新参数
opt.step()
# 清除梯度
opt.clear_grad()
#保存模型参数
paddle.save(model.state_dict(), 'mnist.pdparams')
return loss_list
def do_train():
# 训练模型
model = MNIST()
params_info = paddle.summary(model, (1, 1, 28, 28))
print(params_info)
train_loader,_ = get_MNIST_dataloader(dataFrom="local") # local-本地采集器,remote-官方实现的采集器
loss_list_conv = train(model,train_loader)
do_train()
以下是官方demo中样本数据集,我放wormhole上了,在24小时候或被下载100次后会被删除,如果过期了,还有需要的佬可以回复一下,我再补一个

