画一个函数图像:
#以RELU为例
%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, nd
def xyplot(x_vals, y_vals, name):
d2l.set_figsize(figsize=(5, 2.5))
d2l.plt.plot(x_vals.asnumpy(), y_vals.asnumpy())
d2l.plt.xlabel('x')
d2l.plt.ylabel(name + '(x)')
x = nd.arange(-8.0, 8.0, 0.1)
x.attach_grad()
with autograd.record():
y = x.relu()
xyplot(x, y, 'relu')
#先对参数attach_grad(),然后with autogard_record():,下面写计算loss的过程,最后对loss做
#backward(),参数的grad就自动在参数这个对象中生成了,调用参数.grad即可
y.backward()
xyplot(x, x.grad, 'grad of relu')
结果:
image.png
image.png
画一组features和labels的散点图
import d2lzh
plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1);
image.png
细节:在做loss的时候记得reshape,因为label通常是一个vector,但net的输出经常是一个batch_size*1的矩阵
image.png
def squared_loss(y_hat, y): # 本函数已保存在d2lzh包中方便以后使用
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
丢弃法:避免过拟合的办法
思想是在计算的时候有一定的几率将部分单元暂时丢弃,使得最后的输出不能总是依赖于个别单元,从而实现正则化(?)
import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import loss as gloss, nn
def dropout(X, drop_prob):
assert 0 <= drop_prob <= 1
keep_prob = 1 - drop_prob
# 这种情况下把全部元素都丢弃
if keep_prob == 0:
return X.zeros_like()
mask = nd.random.uniform(0, 1, X.shape) < keep_prob
print(mask)
return mask * X / keep_prob
def net(X):
X = X.reshape((-1, num_inputs))
H1 = (nd.dot(X, W1) + b1).relu()
if autograd.is_training(): # 只在训练模型时使用丢弃法
H1 = dropout(H1, drop_prob1) # 在第一层全连接后添加丢弃层
H2 = (nd.dot(H1, W2) + b2).relu()
if autograd.is_training():
H2 = dropout(H2, drop_prob2) # 在第二层全连接后添加丢弃层
return nd.dot(H2, W3) + b3
生成掩码(mask)的办法:将随机生成的标准正态矩阵与0-1数值作比较从而生成0或1的对应矩阵
mask = nd.random.uniform(0, 1, X.shape) < keep_prob
简洁实现即添加dropout层:
net = nn.Sequential()
net.add(nn.Dense(256, activation="relu"),
nn.Dropout(drop_prob1), # 在第一个全连接层后添加丢弃层
nn.Dense(256, activation="relu"),
nn.Dropout(drop_prob2), # 在第二个全连接层后添加丢弃层
nn.Dense(10))
net.initialize(init.Normal(sigma=0.01))
weigh-decay:避免过拟合的另一个方法
思想是对于绝对值较大的参数值,它们的影响力太大了因而做一定的惩罚,在损失函数上增加norm()
简洁实现:
def fit_and_plot_gluon(wd):
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize(init.Normal(sigma=1))
# 对权重参数衰减。权重名称一般是以weight结尾
trainer_w = gluon.Trainer(net.collect_params('.*weight'), 'sgd',
{'learning_rate': lr, 'wd': wd})
# 不对偏差参数衰减。偏差名称一般是以bias结尾
trainer_b = gluon.Trainer(net.collect_params('.*bias'), 'sgd',
{'learning_rate': lr})
train_ls, test_ls = [], []
for _ in range(num_epochs):
for X, y in train_iter:
with autograd.record():
l = loss(net(X), y)
l.backward()
# 对两个Trainer实例分别调用step函数,从而分别更新权重和偏差
trainer_w.step(batch_size)
trainer_b.step(batch_size)
train_ls.append(loss(net(train_features),
train_labels).mean().asscalar())
test_ls.append(loss(net(test_features),
test_labels).mean().asscalar())
d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
range(1, num_epochs + 1), test_ls, ['train', 'test'])
print('L2 norm of w:', net[0].weight.data().norm().asscalar())
一般使用模型训练的步骤:
#读取数据
from mxnet.gluon import data as gdata
batch_size = 10
# 将训练数据的特征和标签组合
dataset = gdata.ArrayDataset(features, labels)
# 随机读取小批量
data_iter = gdata.DataLoader(dataset, batch_size, shuffle=True)
#定义模型
from mxnet.gluon import nn
net = nn.Sequential()
net.add(nn.Dense(1))
#初始化
from mxnet import init
net.initialize(init.Normal(sigma=0.01))
#损失函数
from mxnet.gluon import loss as gloss
loss = gloss.L2Loss() # 平方损失又称L2范数损失
#训练
from mxnet import gluon
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.03})
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)
l = loss(net(features), labels)
print('epoch %d, loss: %f' % (epoch, l.mean().asnumpy()))
总结一下:读取数据用到gluon中data包的ArrayDataset和DataLoader、模型用了gluon中的nn包中Sequential和Dense、初始化、训练是先拿到trainer再对每个epoch:反复取batch大小的数据做迭代(trainer.step(batch_size)),取完输出一下结果。
注意:这里的step过程中内部对loss做了项数为batch_size的平均,也就是说不需要再在计算loss的时候做平均。如果loss已经做平均了,则应为trainer.step(batch_size)
softmax:
对于简单的情况,softmax是对于一张图片的长宽像素做flatten然后与矩阵相乘加上bias得到输出,再加上softmax函数得到概率:
image.png
上图其中的w的每一列代表一个类别
在softmax问题中就不好用L2Loss做,应该用cross_entropy,因为实际上不需要预测概率值与真实概率值(?)接近,只需要预测结果与真实一样就行了
image.png
其中j就是那个label中标定为真的类别,也就是说loss唯一的项其实是那个label中为真的那一项在模型参数中取log的值,这个值越大也就是预测的越准
例子: image.png
一个数组存着index,在一个数组中的每个子数组存着内容,怎么用index取出对应子数组中的元素值:nd.pick()
image.png
则cross_entropy:
def cross_entropy(y_hat, y):
return -nd.pick(y_hat, y).log()
网友评论