回到首页

linear regression basic realization

Keys in ML are training data, loss function, optimization algrithm and model

import library

%matplotlib inline
import random
from mxnet import np, npx, autograd
from d2l import mxnet as d2l

npx.set_np()
With common ml framework mxnet, corresponding code is as follows(add some supplementary code), and later sections are alike.
from mxnet import gluon

generate training data

def synthetic_data(w, b, num_examples):
    # y = Xw+b+noise
    X = np.random.normal(0,1,(num_examples, len(w)))
    y=np.dot(X, w)+b
    y+=np.random.normal(0, 0.01, y.shape)
    return X, y.reshape((-1,1))

true_w = np.array([2, -3.4])
true_b=4.2
features, labels = synthetic_data(true_w, true_b, 1000)
This module is changeless either with or without framework. Data is independent to code.

define model

def linreg(X, w, b):
    # linear regression model
    return np.dot(X, w)+b
mxnet version:
from mxnet.gluon import nn

net = nn.Sequential()
net.add(nn.Dense(1))

define loss function

def squared_loss(y_hat, y):
    # squared_loss
    return (y_hat - y.reshape(y_hat.shape))**2/2
mxnet version:
loss = gluon.loss.L2Loss()

define optimization algrithm

def sgd(params, lr, batch_size):
    # mini-batch stochastic gradient descent
    for param in params:
        param[:] = param - lr*param.grad/batch_size
mxnet version:
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate':0.03})

generate mini-batch data

def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # randomly-read samples
    random.shuffle(indices)
    for i in range(0, num_examples, batch_size):
        batch_indices = np.array(indices[i:min(i+batch_size, num_examples)])
        yield features[batch_indices], labels[batch_indices]
mxnet version:
def load_array(data_arrays, batch_size, is_train=True):
    # construct a Gluon data iterator
    dataset = gluon.data.ArrayDataset(*data_arrays)
    return gluon.data.DataLoader(dataset, batch_size, shuffle=is_train)

train to estimate parameters

w =np.random.normal(0, 0.01, (2,1))
b = np.zeros(1)
w.attach_grad()
b.attach_grad()

lr = 0.03
num_epochs=3
net=linreg
loss=squared_loss
batch_size=10

for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):
        with autograd.record():
            l=loss(net(X, w, b), y) # X and y's mini-batch loss
        # calculate l's gradient on (w, b)
        l.backward()
        sgd([w, b], lr, batch_size)
    train_l = loss(net(features, w, b), labels)
    print(f'epoch {epoch+1}, loss {float(train_l.mean()):f}')

print(f'w\'s evaluated error: {true_w-w.reshape(true_w.shape)}')
print(f'b\'s evaluated error: {true_b-b}')
mxnet version:
from mxnet import init

net.initialize(init.Normal(sigma=0.01))
        
batch_size=10
num_epochs=3

for epoch in range(num_epochs):
    for X, y in load_array((features, labels), batch_size):
        with autograd.record():
            l=loss(net(X), y) # X and y's mini-batch loss
        # calculate l's gradient on (w, b)
        l.backward()
        trainer.step(batch_size)
    l = loss(net(features), labels)
    print(f'epoch {epoch+1}, loss {l.mean().asnumpy():f}')

w = net[0].weight.data()
print(f'w\'s evaluated error: {true_w-w.reshape(true_w.shape)}')
b = net[0].bias.data()
print(f'b\'s evaluated error: {true_b-b}')

running result

print is

epoch 1, loss 0.042583
epoch 2, loss 0.000160
epoch 3, loss 0.000050
w's evaluated error: [-0.00063181 -0.00097275]
b's evaluated error: [0.00130653]

mxnet库的wheel文件从此处下载

参考链接:3.2. 线性回归的从零开始实现
3.3. 线性回归的简洁实现

本文创建于2022.2.22/17.36,修改于2022.3.7/14.19

#ml #linear_regression #code #mxnet