利用mxnet的autograd和ndarry来实现线性回归的训练
所需要导入的包和模块:
import random
from IPython.display import set_matplotlib_formats
from matplotlib import pyplot as plt
from mxnet import autograd, nd
首先我们先生成数据集,假设数据集的样本数是1000,输入是2,则随机生成的批量样本特征 X∈ℝ1000×2
然后我们用公式:y=Xw+b+ϵ来生成标签,这里我设定线性回归模型真实权重 w=[2,−3.4]和偏差 b=4.2,ϵ是一个随机噪声项设定服从均值为0和标准差为0.01的正态分布
num_inputs = 2 #输入是2
num_examples = 1000 #样本数量
true_w = [2, -3.4] #真实的w
true_b = 4.2 #真实的b
features = nd.random.normal(scale=1, shape=(num_examples, num_inputs))
#样本特征服从均值为0,标准差为1的正态分布,是一个1000*2的ndarry
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
#求得标签
labels += nd.random.normal(scale=0.01, shape=labels.shape)
#加上一个随机噪声项,噪声项服从均值为0,标准差为0.01的正态分布和标签的shape相同
现在我们可以画出特征值与标签的散点图:
打印出散点图只是为了直观地看出特征值和标签的关系
def set_figsize(figsize=(3.5, 2.5)):
set_matplotlib_formats('retina') # 打印高清图。
plt.rcParams['figure.figsize'] = (3.5, 2.5) # 设置图的尺寸。
set_figsize()
plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1)
plt.show()
#打印出特征和标签的散点图
每次只读取batch_size个数据样本
batch_size = 10 # 每次读取的数据集大小
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# 生成索引
random.shuffle(indices)
# 样本的读取顺序是随机的。
for i in range(0, num_examples, batch_size):
j = nd.array(indices[i: min(i + batch_size, num_examples)])
# take 函数根据索引返回对应元素。
yield features.take(j), labels.take(j)
w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))
# w服从均值为0,标准差为0.01的正态分布
b = nd.zeros(shape=(1,))
# b初始化为0
params = [w, b]
for param in params: # 申请存储梯度所需要的内存
param.attach_grad()
线性回归的矢量计算表达式的实现,使用dot
函数做矩阵乘法:
def linreg(X, w, b):
return nd.dot(X, w) + b
这里我使用平方损失来定义线性回归的损失函数
def squared_loss(y_hat, y):
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
小批量随机梯度下降算法,通过不断更新模型参数来优化损失函数
这里的lr是学习率
def sgd(params, lr, batch_size):
for param in params:
param[:] = param - lr * param.grad / batch_size
训练时的迭代次数可以自己定义,由于收敛的比较快,所以10次就足够了
lr = 0.03 #学习率
num_epochs = 10 # 迭代次数
net = linreg
loss = squared_loss
# 训练模型一共需要 num_epochs 个迭代周期。
for epoch in range(1, num_epochs + 1):
# 在一个迭代周期中,使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。
# X 和 y 分别是小批量样本的特征和标签。
for X, y in data_iter(batch_size, features, labels):
with autograd.record():
# l 是有关小批量 X 和 y 的损失。
l = loss(net(X, w, b), y)
# 小批量的损失对模型参数求导。
l.backward()
# 使用小批量随机梯度下降迭代模型参数。
sgd([w, b], lr, batch_size)
print('epoch %d, loss %f' % (epoch, loss(net(features, w, b), labels).mean().asnumpy()))
训练完成之后,查看训练得到的参数和生成训练集的真实参数:
print("true_w:{}, w:{}" .format(true_w, w))
print("true_b:{}, b:{}" .format(true_b, b))
我得到的结果是:
用pip下载包的时候有时候会特别慢,可以考虑使用国内的镜像比如清华,ustc等等。。。
然后python路径最好是全英文,要不然可能会导致一些奇怪的问题
认真阅读代码,有问题的地方可以试着输出看看
线代+高数+概率论一定要学好。。。
附上完整的python代码:
import random
from IPython.display import set_matplotlib_formats
from matplotlib import pyplot as plt
from mxnet import autograd, nd
num_inputs = 2 #输入是2
num_examples = 1000 #样本数量
true_w = [2, -3.4] #真实的w
true_b = 4.2 #真实的b
features = nd.random.normal(scale=1, shape=(num_examples, num_inputs))
# 样本特征服从均值为0,标准差为1的正态分布,是一个1000*2的ndarry
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
# 求得标签
labels += nd.random.normal(scale=0.01, shape=labels.shape)
# 加上一个随机噪声项,噪声项服从均值为0,标准差为0.01的正态分布和标签的shape相同
def set_figsize(figsize=(3.5, 2.5)):
set_matplotlib_formats('retina') # 打印高清图。
plt.rcParams['figure.figsize'] = (3.5, 2.5) # 设置图的尺寸。
set_figsize()
plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1)
plt.show()
# 打印出特征和标签的散点图
batch_size = 10 # 每次读取的数据集大小
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# 生成索引
random.shuffle(indices)
# 样本的读取顺序是随机的。
for i in range(0, num_examples, batch_size):
j = nd.array(indices[i: min(i + batch_size, num_examples)])
# take 函数根据索引返回对应元素。
yield features.take(j), labels.take(j)
w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))
# w服从均值为0,标准差为0.01的正态分布
b = nd.zeros(shape=(1,))
# b初始化为0
params = [w, b]
for param in params: # 申请存储梯度所需要的内存
param.attach_grad()
def linreg(X, w, b):
return nd.dot(X, w) + b
def squared_loss(y_hat, y):
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
def sgd(params, lr, batch_size):
for param in params:
param[:] = param - lr * param.grad / batch_size
lr = 0.03 #学习率
num_epochs = 10 # 迭代次数
net = linreg
loss = squared_loss
# 训练模型一共需要 num_epochs 个迭代周期。
for epoch in range(1, num_epochs + 1):
# 在一个迭代周期中,使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。
# X 和 y 分别是小批量样本的特征和标签。
for X, y in data_iter(batch_size, features, labels):
with autograd.record():
# l 是有关小批量 X 和 y 的损失。
l = loss(net(X, w, b), y)
# 小批量的损失对模型参数求导。
l.backward()
# 使用小批量随机梯度下降迭代模型参数。
sgd([w, b], lr, batch_size)
print('epoch %d, loss %f' % (epoch, loss(net(features, w, b), labels).mean().asnumpy()))
print("true_w:{}, w:{}" .format(true_w, w))
print("true_b:{}, b:{}" .format(true_b, b))