利用Gluon实现简单的线性回归训练

前言

  上一篇文章只利用NDArray和autograd来实现一个线性回归的训练,现在我们可以使用MXNet提供的Gluon接口更方便地实现线性回归的训练。(和上一篇文章类似的代码就不在给出注释了)
  同样地,给了你许多满足y=w*x+b这一函数关系的x,y,通过训练,求出尽可能满足条件(误差尽可能小)的w和b。下面例子的函数为 y[i] = 2 * x[i][0] - 3.4 * x[i][1] + 4.2 + noise,即给出数据集x,y,求出w,b,使得w尽量接近[2,-3.4],b尽量接近4.2。

创建数据集

from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import gluon #导入Gluon接口

num_inputs = 2
num_examples = 1000

true_w = [2,-3.4]
true_b = 4.2

x = nd.random_normal(shape=(num_examples,num_inputs))
y = true_w[0] * x[:,0] + true_w[1] * x[:,1] + true_b
y += 0.01 * nd.random_normal(shape=y.shape)

数据读取

  此时不再需要data_iter()来进行数据的读取。

batch_size = 10
dataset = gluon.data.ArrayDataset(x,y)
data_iter = gluon.data.DataLoader(dataset,batch_size,shuffle=True) #shuffle表示是否随机打乱

for data,label in data_iter:
    print(data,label)
    break

[[-0.6128307  -0.13006628]
 [ 0.17985249  1.8944763 ]
 [-1.749226    0.12701914]
 [ 1.1370468  -0.24184602]
 [ 0.20744328 -0.5686463 ]
 [ 0.8463716  -0.6305023 ]
 [ 2.3007503  -0.89770544]
 [-0.2647494   0.06295237]
 [-0.9038635   0.6280921 ]
 [-0.2878615  -0.9035178 ]]
<NDArray 10x2 @cpu(0)> 
[ 3.4145176  -1.8604004   0.26332545  7.3125057   6.5659037   8.037142
 11.842436    3.4656026   0.2390664   6.7074056 ]
<NDArray 10 @cpu(0)>

  当不知道某个函数是如何定义时,在jupyter notebook中可以在函数后输入?和??来查询(不用加括号),比如:

gluon.data.ArrayDataset?

Init signature: gluon.data.ArrayDataset(*args)
Docstring:     
A dataset that combines multiple dataset-like objects, e.g.
Datasets, lists, arrays, etc.

The i-th sample is defined as `(x1[i], x2[i], ...)`.

Parameters
----------
*args : one or more dataset-like objects
    The data arrays.
File:           c:\users\szw\miniconda3\envs\gluon\lib\site-packages\mxnet\gluon\data\dataset.py
Type:           type
Subclasses:     

gluon.data.ArrayDataset??

Init signature: gluon.data.ArrayDataset(*args)
Source:        
class ArrayDataset(Dataset):
    """A dataset that combines multiple dataset-like objects, e.g.
    Datasets, lists, arrays, etc.

    The i-th sample is defined as `(x1[i], x2[i], ...)`.

    Parameters
    ----------
    *args : one or more dataset-like objects
        The data arrays.
    """
    def __init__(self, *args):
        assert len(args) > 0, "Needs at least 1 arrays"
        self._length = len(args[0])
        self._data = []
        for i, data in enumerate(args):
            assert len(data) == self._length, \
                "All arrays must have the same length; array[0] has length %d " \
                "while array[%d] has %d." % (self._length, i+1, len(data))
            if isinstance(data, ndarray.NDArray) and len(data.shape) == 1:
                data = data.asnumpy()
            self._data.append(data)

    def __getitem__(self, idx):
        if len(self._data) == 1:
            return self._data[0][idx]
        else:
            return tuple(data[idx] for data in self._data)

    def __len__(self):
        return self._length
File:           c:\users\szw\miniconda3\envs\gluon\lib\site-packages\mxnet\gluon\data\dataset.py
Type:           type
Subclasses:     

  都是英文看得有点晕晕的hhh,我现阶段还是知道函数的大概作用后先多用起来(可以多print看看效果),等以后可以再查查具体文档。

定义模型

  Gluon提供大量提前定制好的层,例如线性模型(单层网络,y=wx+b)就是使用对应的Dense层。
  构建模型最简单的方法就是利用Sequential来把所有层串起来。Sequential实例可以看作是一个串联各个层的容器。在构造模型时,我们在该容器中依次添加层。当给定输入数据时,容器中的每一层将依次计算并将输出作为下一层的输入

net = gluon.nn.Sequential()  #定义一个空的模型(nn = neural network)
net.add(gluon.nn.Dense(1)) )#加入一个Dense层,这个1表示输出节点个数
net

Sequential(
  (0): Dense(None -> 1, linear)
)

  加入Dense层时,唯一必须要定义的参数就是输出节点的个数,在线性模型中是1,这里不需定义输入节点是多少,之后真正给数据的时候系统会自动赋值,这一设计为模型开发会带来便利。

初始化模型参数

  在使用net前,我们需要初始化模型参数,如线性回归模型中的权重(weight)和偏差(bias)

net.initialize() #使用默认随机初始化方法

损失函数

square_loss = gluon.loss.L2Loss() #平方误差函数,平方损失又称L2范数损失

优化:随机梯度下降

  创建一个Trainer实例,并指定学习率为0.03的小批量随机梯度下降(sgd)为优化算法。该优化算法将用来迭代net实例所有通过add函数嵌套的层所包含的全部参数。

trainer = gluon.Trainer(net.collect_params(),'sgd',{'learning_rate':0.03})
#collect_params函数用于获取全部参数

训练

  我们不再是调用SGD,而是用trainer.step()来更新模型,来迭代模型参数。

epochs = 5
batch_size = 10
for e in range(epochs):
    total_loss = 0
    for data,label in data_iter: #读一组数据块(一组数据块包括10组数据),data是x,label是y(真实)
        with autograd.record(): #求导程序
            output = net(data) #通过Dense得到output,即通过net中的参数得到预测的y
            loss = square_loss(output,label) #利用预测y和真实y得到损失函数
        loss.backward() #对损失函数求导
        trainer.step(batch_size) #更新参数
        total_loss += nd.sum(loss).asscalar()
    print("Epoch %d , average loss: %f"%(e,total_loss/num_examples))

Epoch 0 , average loss: 2.819463
Epoch 1 , average loss: 0.007534
Epoch 2 , average loss: 0.000071
Epoch 3 , average loss: 0.000049
Epoch 4 , average loss: 0.000049

  trainer.step(batch_size, ignore_stale_grad=False)
-----进行一个参数更新步骤。应该在autograd.backward() 后以及record()外使用。
-----batch_size : 处理数据的批量大小。
-----ignore_stale_grad : 如果为真,则忽略具有陈旧梯度的参数(在上一步之后没有被’ backward '更新的梯度)并跳过更新。

检验

dense = net[0] #从net获得需要的层,即第一层
true_w,dense.weight.data() #权重(weight)

([2, -3.4], 
 [[ 1.9996018 -3.39955  ]]
 <NDArray 1x2 @cpu(0)>)

true_b, dense.bias.data()

(4.2, 
 [4.1994724]
 <NDArray 1 @cpu(0)>)

总结

  Gluon让我们能很简洁地实现模型,其中提供了数据处理的工具、定义好的神经网络层、损失函数、参数初始化方法等等,但直接上手可能会因为太简洁而觉得有些莫名,对一些函数的功能之类的不是很清楚,可以先手动试试搭个模型后再用Gluon。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值