zoukankan      html  css  js  c++  java
  • MXNET:监督学习

    线性回归

    给定一个数据点集合 X 和对应的目标值 y,线性模型的目标就是找到一条使用向量 w 和位移 b
    描述的线,来尽可能地近似每个样本X[i] 和 y[i]。

    数学公式表示为(hat{y}=Xw+b)

    目标函数是最小化所有点的平方误差 (sum_{i=1}^{n} (hat{y_i}-y_i)^2)

    ⼀个神经⽹络就是⼀个由节点(神经元)和有向边组成的集合。我们⼀ 般把⼀些节点组成层,每⼀层先从下⾯⼀层的节点获取输⼊,然后输出给上⾯的层使⽤。要计算⼀ 个节点值,我们需要将输⼊节点值做加权和(权数值即w),然后再加上⼀个激活函数(activation function)。这里的激活函数是(f(x)=x)

    创建数据集: (y=2*x[0] - 3.4*x[1] + 4.2 +noise)

    # -*- coding: utf-8 -*-
    from mxnet import ndarray as nd
    from mxnet import autograd
    
    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 += .01 * nd.random_normal(shape=y.shape)
    
    print 'dataset'
    
    import matplotlib.pyplot as plt
    plt.scatter(X[:, 1].asnumpy(),y.asnumpy())
    plt.show()
    

    当我们开始训练神经⽹络的时候,我们需要不断读取数据块。这⾥我们定义⼀个函数它每次返回 batch_size 个随机的样本和对应的⽬标。

    import random
    batch_size = 10
    def data_iter():
        # 产⽣⼀个随机索引
        idx = list(range(num_examples))
        random.shuffle(idx)
        for i in range(0, num_examples, batch_size):
            j = nd.array(idx[i:min(i+batch_size,num_examples)])
            yield nd.take(X, j), nd.take(y, j)
    
    for data, label in data_iter(): 
        print(data, label)
    

    随机初始化模型参数,之后训练时我们需要对这些参数求导来更新它们的值,使损失尽量减小;因此我们需要创建它们的梯度。

    w = nd.random_normal(shape=(num_inputs, 1))
    b = nd.zeros((1,))
    params = [w, b]
    
    for param in params:
        param.attach_grad()
    

    定义网络

    def net(X):
        return nd.dot(X, w) + b
    

    定义损失函数

    def square_loss(yhat, y):
        # 注意这⾥我们把 y 变形成 yhat 的形状来避免矩阵形状的⾃动转换
        return (yhat - y.reshape(yhat.shape)) ** 2
    

    定义优化方案,我们这⾥通过随机梯度下降来求解。每⼀步,我们将模型参数沿着梯度的反⽅向走特定距离,这个距离⼀般叫学习率(learning rate)lr

    def SGD(params, lr):
        for param in params:
            param[:] = param - lr * param.grad
    

    现在我们可以开始训练了。训练通常需要迭代数据数次,在这⾥使⽤ epochs表⽰迭代总次数; ⼀次迭代中,我们每次随机读取固定数个数据点,计算梯度并更新模型参数。

    epochs = 5
    learning_rate = .001
    niter = 0
    moving_loss = 0
    smoothing_constant = .01
    # 训练
    for e in range(epochs):
        total_loss = 0
        for data, label in data_iter():
            with autograd.record():
                output = net(data)
                loss = square_loss(output, label)
            loss.backward()
            SGD(params, learning_rate)
            total_loss += nd.sum(loss).asscalar()
            # 记录每读取⼀个数据点后,损失的移动平均值的变化;
            niter +=1
            curr_loss = nd.mean(loss).asscalar()
            moving_loss = (1 - smoothing_constant) * moving_loss + (smoothing_constant * curr_loss)
            if (niter + 1) % 100 == 0:
                print("Epoch %d, batch %d. Average loss: %f" % (
                    epochs, niter, moving_loss))
    print(params)
    # output
    [[ 1.99952257]
     [-3.39969802]]
    <NDArray 2x1 @cpu(0)>, 
    [ 4.19949913]
    <NDArray 1 @cpu(0)>
    

    线性回归-使用Gluon

    这里我们将使用MXNet提供的Gluon接口更方便地实现线性回归的训练。

    首先生成数据集

    num_inputs = 2
    num_examples = 1000
    true_w = [2, -3.4]
    true_b = 4.2
    features = nd.random_normal(scale=1, shape=(num_examples, num_inputs))
    labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
    labels += nd.random_normal(scale=0.01, shape=labels.shape)
    

    读取数据,使用Gluon提供的data模块来读取数据。在每一次迭代中,我们将随机读取包含10个数据样本的小批量。

    from mxnet.gluon import data as gdata
    batch_size = 10
    dataset = gdata.ArrayDataset(features, labels)
    data_iter = gdata.DataLoader(dataset, batch_size, shuffle=True)
    

    在前面我们需要定义模型参数,并使用它们一步步描述模型是怎样计算的。当模型结构变得更复杂时,这些步骤将变得更加繁琐。其实,Gluon提供了大量预定义的层,这使我们只需关注使用哪些层来构造模型。
    首先,导入nn模块。我们先定义一个模型变量net,它是一个Sequential实例。在Gluon中,Sequential实例可以看做是一个串联各个层的容器。在构造模型时,我们在该容器中依次添加层。当给定输入数据时,容器中的每一层将依次计算并将输出作为下一层的输入。
    线性回归的输出层又叫全连接层。在Gluon中,全连接层是一个Dense实例。我们定义该层输出个数为1。

    from mxnet.gluon import nn
    net = nn.Sequential()
    net.add(nn.Dense(1))
    

    值得一提的是,在Gluon中我们无需指定每一层输入的形状,例如线性回归的输入个数。当模型看见数据时,例如后面执行net(X)时,模型将自动推断出每一层的输入个数。

    初始化模型参数,从MXNet中导入init模块,并通过init.Normal(sigma=0.01)指定权重参数每个元素将在初始化时随机采样于均值为0标准差为0.01的正态分布。偏差参数全部元素初始化为零。

    from mxnet import init
    net.initialize(init.Normal(sigma=0.01))
    

    定义损失函数,从gluon引入loss模块

    from mxnet.gluon import loss as gloss
    loss = gloss.L2Loss()
    

    定义优化算法,在导入Gluon后,我们可以创建一个Trainer实例,并且将模型参数传递给它。

    from mxnet.gluon import Trainer
    trainer = Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.03})
    

    训练模型,我们通过调用step函数来迭代模型参数。由于变量l是batch_size维的NDArray,执行l.backward()等价于l.sum().backward()。按照小批量随机梯度下降的定义,我们在step函数中提供batch_size,以确保小批量随机梯度是该批量中每个样本梯度的平均。

    num_epochs = 3
    for epoch in range(1, num_epochs + 1):
        for X, y in data_iter:
            with autograd.record():
                l = loss(net(X), y)
            l.backward()
            trainer.step(batch_size)
        print("epoch %d, loss: %f"
              % (epoch, loss(net(features), labels).asnumpy().mean()))
    
    dense = net[0]
    print true_w, dense.weight.data()
    print true_b, dense.bias.data()
    

    可以从net获得需要的层,并访问其权重和位移。学到的和真实的参数很接近。

  • 相关阅读:
    关于web标准的理解(转)
    media type 与 media query
    HTML 5 学习 (1)
    jQuery的事件和动画
    jQuery操作Dom
    jQuery选择器的学习
    关于datetime和int 是否可为null的问题
    core animation (转)
    关于Navigation的BarButtonItem的
    iphone和ipad各控件大小
  • 原文地址:https://www.cnblogs.com/houkai/p/9519802.html
Copyright © 2011-2022 走看看