【Mxnet】Dataset和DataLoader模块(四)

导语

在gluon接口中,通过Dataset和DataLoader来对数据集进行循环遍历,并返回batch大小的数据,其中Dataset对象用于数据的收集、加载和变换,而DataLoader对象用于返回batch大小的数据。

Dataset

所有Dataset类中,都有以下四个方法:

  • getitem(idx): 数据加载,用于返回第idx个样本
  • len(): 用于返回数据集的样本的数量
  • transform(fn, lazy = True): 数据变换,用于返回对每个样本利用fn函数进行数据变换(增广)后的Dataset
  • transform_first(fn, lazy = True): 数据变换,用于返回对每个样本的特征利用fn函数进行数据变换(增广)后的Dataset,而不对label进行数据增广
import mxnet as mx
mx.random.seed(42) # 固定随机数种子,以便能够复现
X = mx.random.uniform(shape = (10, 3))
y = mx.random.uniform(shape = (10, 1))
dataset = mx.gluon.data.ArrayDataset(X, y) # ArrayDataset不需要从硬盘上加载数据
print(dataset[5])						  # 将返回第6个样本的特征和标签,(特征,标签)
转换数据(和数据增广)

模型训练的时候对于数据的格式有一定的要求(channel,height,width)并且要求数据是浮点类型。所以,我们还需要对之前的数据做一些转换。利用transforms可以很方便的实现数据的转换
通过ToTensor方法可以将图片数据转为(channel,height,width)的float类型的数据,通过Normalize方法可以设置数据的均值和标准差,这里将图片的均值设置为0.13,标准差设置为0.30,最后再通过Compose将这些数据转换过程组合成一个链式的处理。

#transforms链式转换数据
transformer = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(0.13,0.30)])
#转换数据
fashion_data = fashion_train_data.transform_first(transformer)
-------------------------------------------------------------------------------------------------
from mxnet.gluon import data as gdata
train= gdata.vision.ImageFolderDataset("path", flag=1)
print train[0] #变换之前的数据
## 数据变换定义
transform_train = gdata.vision.transforms.Compose([  # Compose将这些变换按照顺序连接起来
        # 将图片放大成高和宽各为 40 像素的正方形。
        gdata.vision.transforms.Resize(40),
        # 随机对高和宽各为 40 像素的正方形图片裁剪出面积为原图片面积 0.64 到 1 倍之间的小正方
        # 形,再放缩为高和宽各为 32 像素的正方形。
        gdata.vision.transforms.RandomResizedCrop(32, scale=(0.64, 1.0),
                                                  ratio=(1.0, 1.0)),
        # 随机左右翻转图片。
        gdata.vision.transforms.RandomFlipLeftRight(),
        # 将图片像素值按比例缩小到 0 和 1 之间,并将数据格式从“高 * 宽 * 通道”改为“通道 * 高 * 宽”。
        gdata.vision.transforms.ToTensor(),
        # 对图片的每个通道做标准化。
        gdata.vision.transforms.Normalize([0.4914, 0.4822, 0.4465],
                                          [0.2023, 0.1994, 0.2010])
    ])

train_ds_transformed = train_ds.transform_first(train)
print  train_ds_transformed[0] #变换之后的数据

DataLoader

由于内存的限制,在训练模型的时候通常都是指定一个batch的数据进行迭代训练,所以我们还需要将整个数据转成一个batch迭代器,每次从这个迭代器中取一个batch数据进行训练,gluon提供了一个DataLoader可以实现,而且通过num_workers参数来设置多个线程进行并行处理,但是在windows上测试的时候请将这个参数设置为0,避免线程错误问题

#设置batch的大小
batch_size = 256
#在windows系统上,请将num_workers设置为0,否则会导致线程错误
train_data = gluon.data.DataLoader(fashion_data ,batch_size=batch_size,shuffle=True,num_workers=0)
#每次从tran_data中取出一个batch大小的数据
for data,label in train_data:
    print(data.shape,label.shape)		#(256, 3, 28, 28) (256,)

模型训练和保存

使用gluon来构建一个LeNet的网络结构,然后利用MXNet提供的GPU加速来训练模型。

#加载验证数据
fashion_val_data = gluon.data.vision.FashionMNIST(train=False)
val_data = gluon.data.DataLoader(fashion_val_data.transform_first(transformer),
                                   batch_size=batch_size,num_workers=0)
#定义使用的GPU,使用GPU加速训练,如果有多个GPU,可以定义多个
gpu_devices = [mx.gpu(0)]
#定义网络结构
LeNet = nn.Sequential()
#构建一个LeNet的网络结构
LeNet.add(
    nn.Conv2D(channels=6,kernel_size=5,activation="relu"),
    nn.MaxPool2D(pool_size=2,strides=2),
    nn.Conv2D(channels=16,kernel_size=3,activation="relu"),
    nn.MaxPool2D(pool_size=2,strides=2),
    nn.Flatten(),
    nn.Dense(120,activation="relu"),
    nn.Dense(84,activation="relu"),
    nn.Dense(10)
)

#初始化神经网络的权重参数,使用GPU来加速训练
LeNet.collect_params().initialize(force_reinit=True,ctx=gpu_devices)
#定义softmax损失函数
softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()
#设置优化算法,使用随机梯度下降sgd算法,学习率设置为0.1
trainer = gluon.Trainer(LeNet.collect_params(),"sgd",{"learning_rate":0.1})
#计算准确率
def acc(output,label):
    return (output.argmax(axis=1) == label.astype("float32")).mean().asscalar()

#设置迭代的轮数
epochs = 10
#训练模型
for epoch in range(epochs):
    train_loss,train_acc,val_acc = 0,0,0
    epoch_start_time = time.time()
    for data,label in train_data:
        #使用GPU来加载数据加速训练
        data_list = gluon.utils.split_and_load(data,gpu_devices)
        label_list = gluon.utils.split_and_load(label,gpu_devices)
        #前向传播
        with autograd.record():
            #获取多个GPU上的预测结果
            pred_Y = [LeNet(x) for x in data_list]
            #计算多个GPU上预测值的损失
            losses = [softmax_cross_entropy(pred_y,Y) for pred_y,Y in zip(pred_Y,label_list)]
        #反向传播更新参数
        for l in losses:
            l.backward()
        trainer.step(batch_size)
        #计算训练集上的总损失
        train_loss += sum([l.sum().asscalar() for l in losses])
        #计算训练集上的准确率
        train_acc += sum([acc(output_y,y) for output_y,y in zip(pred_Y,label_list)])

    for data,label in val_data:
        data_list = gluon.utils.split_and_load(data,ctx_list=gpu_devices)
        label_list = gluon.utils.split_and_load(label,ctx_list=gpu_devices)
        #计算验证集上的准确率
        val_acc += sum(acc(LeNet(val_X),val_Y) for val_X,val_Y in zip(data_list,label_list))

    print("epoch %d,loss:%.3f,train acc:%.3f,test acc:%.3f,in %.1f sec"%
          (epoch+1,train_loss/len(labels),train_acc/len(train_data),val_acc/len(val_data),time.time()-epoch_start_time))
#保存模型参数
LeNet.save_parameters("LeNet.params")

加载预训练模型

在上面介绍了如何来训练模型,并且保存模型文件,我们可以利用已经保存好的模型文件来做很多事情,如直接加载好训练好的模型文件来预测数据、利用模型文件来进行微调等。

from mxnet.gluon import nn
from mxnet.gluon.data.vision import datasets,transforms
from IPython import display
import matplotlib.pyplot as plt

#构建模型
LeNet = nn.Sequential()
#注意模型的结果必须与训练时的模型结构一模一样
LeNet.add(
    nn.Conv2D(channels=6,kernel_size=5,activation="relu"),
    nn.MaxPool2D(pool_size=2,strides=2),
    nn.Conv2D(channels=16,kernel_size=3,activation="relu"),
    nn.MaxPool2D(pool_size=2,strides=2),
    nn.Flatten(),
    nn.Dense(units=120,activation="relu"),
    nn.Dense(84,activation="relu"),
    nn.Dense(10)
)
#加载模型
LeNet.load_parameters("LeNet.params")
#构建一个数据转换器
transformer = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(0.13,0.30)
])
#获取数据
mnist_valid = datasets.FashionMNIST(train=False)
X,Y = mnist_valid[:10]
preds = []
for x in X:
    x = transformer(x).expand_dims(axis=0)
    #获取预测结果
    pred = LeNet(x).argmax(axis=1)
    preds.append(pred.astype("int32").asscalar())

_,figs = plt.subplots(1,10,figsize=(15,15))
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
               'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
display.set_matplotlib_formats("svg")
for f,x,y,pred_y in zip(figs,X,Y,preds):
    f.imshow(x.reshape((28,28)).asnumpy())
    ax = f.axes
    #显示图片的真实标签和预测标签
    ax.set_title(text_labels[y]+"\n"+text_labels[pred_y])
    #设置字体
    ax.title.set_fontsize(14)
    #隐藏坐标轴
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
plt.show()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值