动手学深度学习-Day3-深度学习基础

PS:最近一堆事儿,进度缓慢

李沐-动手学深度学习-Day3

线性回归实现

读取数据集

//返回batch_size(批量大小)个随机样本的特征和标签。
def data_iter(batch_size, features, labels):
    num_examples = len(features)     #features定义为1000*2,1000个样本,2个特征,len函数输出1000
    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)])
        yield features.take(j), labels.take(j)  # take函数根据索引返回对应元素
//调用函数,返回10组样本
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
    print(X, y)
    break

初始化模型参数

对于线性回归模型中的权重参数和偏差进行设置。

w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))  #权重参数是均值0,标差0.01的正态随机数,num_inputs=2
b = nd.zeros(shape=(1,))
//创建梯度
w.attach_grad()
b.attach_grad()

attach_grad()函数:将需要求梯度的参数附加上梯度信息,以便在模型训练过程中进行自动求导和参数更新。模型训练时,就可以自动地计算参数w和b的梯度,并进行参数更新。

定义模型、损失函数、优化算法

1、模型:即线性回归方法

def linreg(X, w, b):  # 函数输入参数为样本特征,权重和偏差
    return nd.dot(X, w) + b  #dot做矩阵乘法

2、损失函数:平方损失函数,reshape函数用于将实际的label变成预测的y_hat的形状。
1 2 ( y ^ − y ) 2 \frac{1}{2}(\hat{y}-y)^2 21(y^y)2

def squared_loss(y_hat, y):  # 输入参数为通过线性回归计算式得到的预测值和真实值
   return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  

3、优化算法:sgd函数,小批量(每轮迭代中随机均匀采样多个样本组成一个小批量)随机梯度下降算法

def sgd(params, lr, batch_size):  # params是模型中的参数,lr是学习率,batch_size是批量的大小
  for param in params:
      param[:] = param - lr * param.grad / batch_size 

训练模型

多次迭代模型参数
backward()函数:计算网络中变量的梯度。根据输出变量构建计算图,并计算每个变量的梯度。计算完成后,可以通过grad属性得到每个变量的梯度值。

lr = 0.03    #学习率
num_epochs = 3   #迭代周期
net = linreg   #模型
loss = squared_loss   #损失函数

for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
  # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
  # 和y分别是小批量样本的特征和标签
  for X, y in data_iter(batch_size, features, labels):
      with autograd.record():   #做前向计算,即得到损失函数
          l = loss(net(X, w, b), y)  # l是有关小批量X和y的损失
      l.backward()  # 小批量的损失对模型参数求梯度
      sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降迭代模型参数,每一轮迭代都会更新参数w和b
  train_l = loss(net(features, w, b), labels)
  print('epoch %d, loss %f' % (epoch + 1, train_l.mean().asnumpy()))

输出结果:
num: 1000
epoch 1, loss 0.054382
num: 1000
epoch 2, loss 0.000248
num: 1000
epoch 3, loss 0.000050
在训练完成后,可以观察迭代更新的参数和真实参数的区别。

true_w, w    #在生成数据集时设定了true_w的数值,用该数值得到labels,即y
true_b, b

输出真实w和训练后的w,两个参数
([2, -3.4],
[[ 1.9996792]
[-3.3996103]]
<NDArray 2x1 @cpu(0)>)
输出真实b和训练后的b
(4.2,
[4.1986103]
<NDArray 1 @cpu(0)>)

softmax回归实现理论过程

模型输出可以是一个离散值,使用softmax做分类,此时的输出单元变成多个。

关于softmax如何实现分类

首先,softmax回归跟线性回归一样将输入特征与权重做线性叠加,但是其输出量的个数是类别数。而线性回归中的输出是一个连续的数。如书中举例,假设有4个特征,可以决定三个类别,则此时的输出与特征之间的关系如下:
o 1 = x 1 w 11 + x 2 w 21 + x 3 w 31 + x 4 w 41 + b 1 , o 2 = x 1 w 12 + x 2 w 22 + x 3 w 32 + x 4 w 42 + b 2 , o 3 = x 1 w 13 + x 2 w 23 + x 3 w 33 + x 4 w 43 + b 3 . \begin{aligned} o_1 &= x_1 w_{11} + x_2 w_{21} + x_3 w_{31} + x_4 w_{41} + b_1,\\ o_2 &= x_1 w_{12} + x_2 w_{22} + x_3 w_{32} + x_4 w_{42} + b_2,\\ o_3 &= x_1 w_{13} + x_2 w_{23} + x_3 w_{33} + x_4 w_{43} + b_3. \end{aligned} o1o2o3=x1w11+x2w21+x3w31+x4w41+b1,=x1w12+x2w22+x3w32+x4w42+b2,=x1w13+x2w23+x3w33+x4w43+b3.
上式即可以看出每一个输出量和特征之间的关系依然是线性叠加。如果用神经网络图表示,可以表示如下:
在这里插入图片描述
其次,分类问题是需要得到离散的预测输出,上图中的输出o看作是某个类别的置信度,选择最大的即为所预测的类别。但是,线性叠加的输出范围不确定,因此,使用softmax晕眩解决这一问题,通过如下计算,将输出值变换为正且和为1的概率分布,即
y ^ 1 , y ^ 2 , y ^ 3 = softmax ( o 1 , o 2 , o 3 ) , \hat{y}_1, \hat{y}_2, \hat{y}_3 = \text{softmax}(o_1, o_2, o_3), y^1,y^2,y^3=softmax(o1,o2,o3),

y ^ 1 = exp ⁡ ( o 1 ) ∑ i = 1 3 exp ⁡ ( o i ) , y ^ 2 = exp ⁡ ( o 2 ) ∑ i = 1 3 exp ⁡ ( o i ) , y ^ 3 = exp ⁡ ( o 3 ) ∑ i = 1 3 exp ⁡ ( o i ) . \hat{y}_1 = \frac{ \exp(o_1)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}_2 = \frac{ \exp(o_2)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}_3 = \frac{ \exp(o_3)}{\sum_{i=1}^3 \exp(o_i)}. y^1=i=13exp(oi)exp(o1),y^2=i=13exp(oi)exp(o2),y^3=i=13exp(oi)exp(o3).

显然, y ^ 1 + y ^ 2 + y ^ 3 = 1 \hat{y}_1 + \hat{y}_2 + \hat{y}_3 = 1 y^1+y^2+y^3=1,且, 0 ≤ y ^ 1 , y ^ 2 , y ^ 3 ≤ 1 0 \leq \hat{y}_1, \hat{y}_2, \hat{y}_3 \leq 1 0y^1,y^2,y^31
argmax ⁡ i o i = argmax ⁡ i y ^ i , \operatorname*{argmax}_i o_i = \operatorname*{argmax}_i \hat y_i, iargmaxoi=iargmaxy^i,
最后,我们将上述的运算表示成矢量计算的形式。仍然假设有4个特征,3个输出,因此权重和偏差可以表示成如下的矩阵形式
W = [ w 11 w 12 w 13 w 21 w 22 w 23 w 31 w 32 w 33 w 41 w 42 w 43 ] , b = [ b 1 b 2 b 3 ] , \boldsymbol{W} = \begin{bmatrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \\ w_{31} & w_{32} & w_{33} \\ w_{41} & w_{42} & w_{43} \end{bmatrix},\quad \boldsymbol{b} = \begin{bmatrix} b_1 & b_2 & b_3 \end{bmatrix}, W= w11w21w31w41w12w22w32w42w13w23w33w43 ,b=[b1b2b3],
对第 i i i个样本而言,其输入特征表示为
x ( i ) = [ x 1 ( i ) x 2 ( i ) x 3 ( i ) x 4 ( i ) ] , \boldsymbol{x}^{(i)} = \begin{bmatrix}x_1^{(i)} & x_2^{(i)} & x_3^{(i)} & x_4^{(i)}\end{bmatrix}, x(i)=[x1(i)x2(i)x3(i)x4(i)],
线性加权后的输出表示为
o ( i ) = [ o 1 ( i ) o 2 ( i ) o 3 ( i ) ] , \boldsymbol{o}^{(i)} = \begin{bmatrix}o_1^{(i)} & o_2^{(i)} & o_3^{(i)}\end{bmatrix}, o(i)=[o1(i)o2(i)o3(i)],
经过softmax运算后的预测类别的概率表示为
y ^ ( i ) = [ y ^ 1 ( i ) y ^ 2 ( i ) y ^ 3 ( i ) ] . \boldsymbol{\hat{y}}^{(i)} = \begin{bmatrix}\hat{y}_1^{(i)} & \hat{y}_2^{(i)} & \hat{y}_3^{(i)}\end{bmatrix}. y^(i)=[y^1(i)y^2(i)y^3(i)].
因此,上述对于第 i i i个样本分类的矢量计算可以表示为
o ( i ) = x ( i ) W + b , y ^ ( i ) = softmax ( o ( i ) ) . \begin{aligned} \boldsymbol{o}^{(i)} &= \boldsymbol{x}^{(i)} \boldsymbol{W} + \boldsymbol{b},\\ \boldsymbol{\hat{y}}^{(i)} &= \text{softmax}(\boldsymbol{o}^{(i)}). \end{aligned} o(i)y^(i)=x(i)W+b,=softmax(o(i)).
当然,我们也可以得到小批量样本分类的矢量计算表达式,假设批量大小为 n n n,特征数为 d d d,输出的类别数为 q q q
假设,一批样本的特征表示为 X ∈ R n × d \boldsymbol{X} \in \mathbb{R}^{n \times d} XRn×d,回归表达式中的权重和偏差表示为 W ∈ R d × q \boldsymbol{W} \in \mathbb{R}^{d \times q} WRd×q b ∈ R 1 × q \boldsymbol{b} \in \mathbb{R}^{1 \times q} bR1×q。则可以得到
O = X W + b , Y ^ = softmax ( O ) , \begin{aligned} \boldsymbol{O} &= \boldsymbol{X} \boldsymbol{W} + \boldsymbol{b},\\ \boldsymbol{\hat{Y}} &= \text{softmax}(\boldsymbol{O}), \end{aligned} OY^=XW+b,=softmax(O),

关于交叉熵损失函数

定义为
H ( y ( i ) , y ^ ( i ) ) = − ∑ j = 1 q y j ( i ) log ⁡ y ^ j ( i ) , H\left(\boldsymbol y^{(i)}, \boldsymbol {\hat y}^{(i)}\right ) = -\sum_{j=1}^q y_j^{(i)} \log \hat y_j^{(i)}, H(y(i),y^(i))=j=1qyj(i)logy^j(i),
假设训练数据集的样本数为 n n n,交叉熵损失函数定义为
ℓ ( Θ ) = 1 n ∑ i = 1 n H ( y ( i ) , y ^ ( i ) ) , \ell(\boldsymbol{\Theta}) = \frac{1}{n} \sum_{i=1}^n H\left(\boldsymbol y^{(i)}, \boldsymbol {\hat y}^{(i)}\right ), (Θ)=n1i=1nH(y(i),y^(i)),

softmax回归的实现

关于本书中用到的数据集

这里综合两个文件:
chapter_deep-learning-basics/fashion-mnist.ipynb,—专门讲这个数据集
chapter_deep-learning-basics/softmax-regression-scratch.ipynb ----上面的数据集实际已经封装到了load_data_fashion_mnist函数中,可以直接调用读取数据集。
1、获取数据集
导入必要的包及模块

%matplotlib inline
import d2lzh as d2l
from mxnet.gluon import data as gdata  --gluon提供了data包来读取数据,将导入的data模块用gdata代替
import sys
import time 
//获取训练数据和测试数据
mnist_train = gdata.vision.FashionMNIST(train=True)   ---参数train
mnist_test = gdata.vision.FashionMNIST(train=False)
//训练集样本60000,测试集10000,共10个类别,每个类别是6000和1000
len(mnist_train), len(mnist_test)

导入后的结果
在这里插入图片描述

// 通过[]访问任何一个样本
feature, label = mnist_train[0]   --获取第一个训练样本的图像及标签
//feature表征图像,示例是一个28像素的图像,像素数值是0-255之间的数表示,灰度图像,则通道数为1
feature.shape, feature.dtype

得到结果为((28, 28, 1), numpy.uint8)
图像的类别是用文本表示的,还需要有数字标签。

# 本函数已保存在d2lzh包中方便以后使用
def get_fashion_mnist_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
//下面定义的是可以在一行中画出多个图像和对应标签的函数
def show_fashion_mnist(images, labels):   #输入参数是图像及标签
    d2l.use_svg_display()
    # 这里的_表示我们忽略(不使用)的变量
    _, figs = d2l.plt.subplots(1, len(images), figsize=(12, 12))    #画子图的方式
    for f, img, lbl in zip(figs, images, labels):
        f.imshow(img.reshape((28, 28)).asnumpy())
        f.set_title(lbl)
        f.axes.get_xaxis().set_visible(False)
        f.axes.get_yaxis().set_visible(False)
X, y = mnist_train[0:9]   #取前9个样本的图像和标签
show_fashion_mnist(X, get_fashion_mnist_labels(y))    #调用显示函数画出图

在这里插入图片描述
2、利用封装好的函数读取数据集
在d2lzh.load_data_fashion_mnist函数中直接获取数据集,返回train_iter和test_iter两个变量。

%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, nd
//读数据
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)    ---这个函数内部就是上面显示的获取数据的过程,且直接得到小批量数据

初始化模型参数

num_inputs = 784    #本示例中的图像是28*28,一个像素就是一个特征,因此共有784个特征
num_outputs = 10   #共10个类别

W = nd.random.normal(scale=0.01, shape=(num_inputs, num_outputs))  #随机产生标差为0.01,均值为0的权重参数,该矩阵大小为784*10
b = nd.zeros(num_outputs)   #产生偏差矩阵,10*1大小
//附上梯度
W.attach_grad()
b.attach_grad()

实现softmax运算

定义softmax函数,参数X是一个矩阵,其行数是样本数,列是输出的个数

def softmax(X):
    X_exp = X.exp()    #对矩阵中的每个元素做指数
    partition = X_exp.sum(axis=1, keepdims=True)    #参照前面的 softmax理论运算的表达式,先对每个元素秋指数,在都同行元素求和
    return X_exp / partition  # 令矩阵每行元素与改行元素的和相除。

下面用一个示例看softmax()的运算

X = nd.random.normal(shape=(2, 5))
print("X:",X)
X_prob = softmax(X)
X_prob, X_prob.sum(axis=1)

输出如下:
X: 这是随机生成的符合正态分布的矩阵X,2行5列
[[ 1.6839303 1.2573646 0.13123232 1.6403018 -1.2138013 ]
[ 2.3999705 -0.38509098 -0.98780406 0.95858884 -1.4976466 ]]
<NDArray 2x5 @cpu(0)>
下面是经过softmax运算后,对每一个元素求指数,将其变为正数,且小于1
(
[[0.34759867 0.22689399 0.07357834 0.33275956 0.01916943]
[0.73942626 0.0456413 0.02498061 0.1749487 0.01500311]]
<NDArray 2x5 @cpu(0)>,
对每一行求和,会发现和为1
[1. 1.]
<NDArray 2 @cpu(0)>)

定义模型及损失函数

定义模型:此处定义net,参数为输入的特征矩阵,返回的是经过softmax运算后的每个类别的概率输出预测。

def net(X):
   return softmax(nd.dot(X.reshape((-1, num_inputs)), W) + b)  --reshape函数将图像改为长度为784的向量

定义损失函数:

def cross_entropy(y_hat, y):
    return -nd.pick(y_hat, y).log()
 //定义准确率
 def accuracy(y_hat, y):
    return (y_hat.argmax(axis=1) == y.astype('float32')).mean().asscalar()

这样就可以确定定义的模型在数据集上的准确率。

多层感知机MLP中的激活函数

ReLU函数

ReLU ( x ) = max ⁡ ( x , 0 ) . \text{ReLU}(x) = \max(x, 0). ReLU(x)=max(x,0).

// 定义绘图函数xyplot
%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)')
//画ReLu
x = nd.arange(-8.0, 8.0, 0.1)   --得到一个从-8到8,步长0.1的向量
x.attach_grad()
with autograd.record():
    y = x.relu()
xyplot(x, y, 'relu')
//负数时,ReLU函数的导数为0;当输入为正数时,ReLU函数的导数为1
y.backward()
xyplot(x, x.grad, 'grad of relu')

在这里插入图片描述在这里插入图片描述

sigmoid函数

对同一个矩阵观察其sigmoid函数,将元素的值变换到0和1之间:
sigmoid ( x ) = 1 1 + exp ⁡ ( − x ) . \text{sigmoid}(x) = \frac{1}{1 + \exp(-x)}. sigmoid(x)=1+exp(x)1.
对该函数求导,显然
sigmoid ′ ( x ) = sigmoid ( x ) ( 1 − sigmoid ( x ) ) . \text{sigmoid}'(x) = \text{sigmoid}(x)\left(1-\text{sigmoid}(x)\right). sigmoid(x)=sigmoid(x)(1sigmoid(x)).

with autograd.record():
    y = x.sigmoid()
xyplot(x, y, 'sigmoid')
y.backward()
xyplot(x, x.grad, 'grad of sigmoid')

在这里插入图片描述在这里插入图片描述

多层感知机的实现

导入需要的包及模块

%matplotlib inline
import d2lzh as d2l
from mxnet import nd
from mxnet.gluon import loss as gloss

获取同样的数据

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

定义特征数,输出类别数及隐藏层的单元个数

num_inputs, num_outputs, num_hiddens = 784, 10, 256
//随机产生参数
W1 = nd.random.normal(scale=0.01, shape=(num_inputs, num_hiddens))   ---从输入到隐藏层的参数,784*256
b1 = nd.zeros(num_hiddens)
W2 = nd.random.normal(scale=0.01, shape=(num_hiddens, num_outputs))  --从隐藏层到输出层的参数,256*10
b2 = nd.zeros(num_outputs)
params = [W1, b1, W2, b2]

for param in params:
    param.attach_grad()

用max函数定义ReLU

def relu(X):
    return nd.maximum(X, 0)

定义模型,首先用reshape将原始图像变为长度为784的向量,在利用dot做线性加权求和运算,即得到隐藏层的输出,对该数值进行非线性的relu变换,将数值限定为正,再将隐藏层的输出进行线性加权得到输出

def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(nd.dot(X, W1) + b1)
    return nd.dot(H, W2) + b2

定义损失函数

loss = gloss.SoftmaxCrossEntropyLoss()

定义训练模型,迭代次数为5,学习率为0.5

num_epochs, lr = 5, 0.5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,
              params, lr)
  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值