《动手学深度学习》组队学习——Task3打卡

一、线性回归

1.优化问题

(1)若样本量为 n n n,解释变量为 d d d,则线性回归模型为
y i = ∑ j = 1 d x i j w j + b + ϵ i   ⟺ y = X w + b + ϵ y_i=\sum_{j=1}^d x_i^j w_j+b+\epsilon_i\ \Longleftrightarrow \mathbf{y}=\mathbf{Xw}+\mathbf{b}+\mathbf{\epsilon} yi=j=1dxijwj+b+ϵi y=Xw+b+ϵ
其中, ϵ i ∼ N ( 0 , σ 2 ) \epsilon_i\sim\mathcal{N}(0,\sigma^2) ϵiN(0,σ2).令
X = [ 1 x 1 1 ⋯ x 1 d 1 x 2 1 ⋯ x 2 d ⋮ ⋮ ⋮ 1 x n 1 ⋯ x n d ] w = [ b w 1 ⋯ w d ] T \mathbf{X}=\begin{bmatrix} 1 & x_1^1 &\cdots & x_1^d\\ 1 & x_2^1 & \cdots& x_2^d\\ \vdots & \vdots & &\vdots\\ 1 & x_n^1 & \cdots & x_n^d \end{bmatrix}\quad \mathbf{w}=\begin{bmatrix} b & w_1 & \cdots & w_d\end{bmatrix}^T X= 111x11x21xn1x1dx2dxnd w=[bw1wd]T
则有
y = X w + ϵ \mathbf{y}=\mathbf{Xw}+\mathbf{\epsilon} y=Xw+ϵ
(2)优化问题
min ⁡ w , b L ( w , b ) = 1 2 ∥ y − X w − b 1 n ∥ 2 \min_{\mathbf{w},b} L(\mathbf{w},b)=\frac{1}{2}\|\mathbf{y}-\mathbf{Xw}-b\mathbf{1}_n\|^2 w,bminL(w,b)=21yXwb1n2
(3)随机梯度下降
通过计算目标函数的梯度更新参数,但由于更新参数前需要遍历整个数据集,其运行速度会很慢,故在每次需要计算更新的时候随机抽取一小批样本(小批量随机梯度下降)。

  1. 给出参数初始值;
  2. 从数据集中随机抽取小批量样本B;
  3. 计算小批量损失均值关于模型参数的梯度;
  4. 将梯度乘以学习率 η \eta η,从当前参数值中减去; ( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l i ( w , b ) (\mathbf{w},b)\leftarrow (\mathbf{w},b)-\frac{\eta}{|B|}\sum_{i\in B}\partial_{(\mathbf{w},b)}l^i(\mathbf{w},b) w,b(w,b)BηiB(w,b)li(w,b)
  5. 重复第2-4步。

2.代码实现

(1)生成小批量。输入批量大小、特征矩阵、标签向量,生成大小为batch_size的小批量。

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):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])
        yield features[batch_indices], labels[batch_indices]

此种方法在存储与运行速度方面不占优。
(2)随机梯度下降算法,每次迭代梯度需要手动设为0,才能使下一次和上一次不相关。

def sgd(params, lr, batch_size):  #@save
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size
            param.grad.zero_()

(3)学习率 η \eta η的选取,太小会使收敛速度较慢,太大可能使得梯度计算出现问题。

3.Pytorch版本的实现。

在PyTorch中,data模块提供了数据处理工具,nn模块定义了大量的神经网络层和常见损失函数。
(1)生成小批量:

def load_array(data_arrays, batch_size, is_train=True):  #@save
    """构造一个PyTorch数据迭代器"""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train) 

batch_size = 10
data_iter = load_array((features, labels), batch_size)

is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据。
(2)定义模型:

  • Sequential类将多个层串联在一起。 当给定输入数据时,Sequential实例将数据传入到第一层, 然后将第一层的输出作为第二层的输入,以此类推。
  • 在PyTorch中,全连接层在Linear类中定义。nn.Linear(input.size, output.size).
  • 通过net[0]选择网络中的第一个图层, 然后使用weight.data和bias.data方法访问参数。 还可使用替换方法normal_和fill_来重写参数值。
    net[0].weight.data.normal_(0, 0.01) net[0].bias.data.fill_(0)
    (3)定义优化算法(指定学习率=0.03)
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

(4)训练

num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y)
        trainer.zero_grad()   #优化器梯度清零
        l.backward()  #优化器已做sum处理
        trainer.step()  #模型更新
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')

二、softmax回归(用于分类问题)

1.softmax函数与交叉熵损失

(1)softmax函数定义
y ^ = s o f t m a x ( o ) , w i t h y ^ j = exp ⁡ ( o j ) ∑ k exp ⁡ ( o k ) \hat{\mathbf{y}}=softmax(\mathbf{o}),\quad with\quad \hat{y}_j=\frac{\exp(o_j)}{\sum_{k}\exp(o_k)} y^=softmax(o),withy^j=kexp(ok)exp(oj)
可见, ∑ j y j = 1 \sum_j y_j=1 jyj=1.
(2)交叉熵,用于衡量分布之间的差异
H ( p , q ) = − ∑ i p i log ⁡ ( q i ) H(\mathbf{p},\mathbf{q})=-\sum_{i}p_i\log(q_i) H(p,q)=ipilog(qi)
(3)损失函数及其导数
损失函数:
l ( y , y ^ ) = − ∑ j = 1 q y j log ⁡ y ^ j = − ∑ j = 1 q y j log ⁡ exp ⁡ ( o j ) + log ⁡ ( ∑ k = 1 q exp ⁡ ( o k ) ) ∑ j = 1 q y j = log ⁡ ∑ k = 1 q exp ⁡ ( o k ) − ∑ j = 1 q y j o j \begin{align*}l(\mathbf{y},\hat{\mathbf{y}})&=-\sum_{j=1}^q y_j\log{\hat{y}_j}\\ &=-\sum_{j=1}^q y_j\log{\exp(o_j)}+\log\left(\sum_{k=1}^q \exp(o_k)\right)\sum_{j=1}^q y_j\\ &=\log\sum_{k=1}^q \exp(o_k)-\sum_{j=1}^q y_j o_j \end{align*} l(y,y^)=j=1qyjlogy^j=j=1qyjlogexp(oj)+log(k=1qexp(ok))j=1qyj=logk=1qexp(ok)j=1qyjoj
关于任意为规范化的预测 o j o_j oj的导数
∂ o j l ( y , y ^ ) = s o f t m a x ( o ) j − y j \partial_{o_j} l(\mathbf{y},\hat{\mathbf{y}})=softmax(\mathbf{o})_j-y_j ojl(y,y^)=softmax(o)jyj

2.代码实现

(1)图像数据
图片转张量代码,且其值均在0~1之间。

trans = transforms.ToTensor()

在调用 d2l.load_data_fashion_mnist(batch_size) 时出现报错 name ‘transforms’ is not defined,在torch.py中对应函数中代码改成

trans = torchvision.transforms.ToTensor()

问题得到解决。
(2)根据公式定义softmax

def softmax(X):
    X_exp = torch.exp(X)
    partition = X_exp.sum(1, keepdim=True)  #保持维度不变
    return X_exp / partition  # 这里应用了广播机制

(3)定义softmax回归模型

def net(X):
    return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)

将原始图像展平为向量。

(4)根据公式定义损失函数

def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])

(5)分类精度
argmax可以获得每行中最大元素的索引。
(6)训练
updater 中可定义优化算法,可供调参的变量时迭代次数(num_epochs)和学习率(lr)。
(7)预测

3.简洁实现

(1)初始化模型参数
需在Sequential中添加一个带有10个输出的全连接层

net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))

(2)softmax的实现
前面定义的softmax函数代码,从计算角度来看,其中的指数可能会造成数值稳定性问题(溢出),故变化为
log ⁡ ( y ^ j ) = log ⁡ ( exp ⁡ ( o j − max ⁡ ( o k ) ) ∑ k exp ⁡ ( o j − max ⁡ ( o k ) ) ) = o j − max ⁡ ( o k ) − log ⁡ ( ∑ k exp ⁡ ( o j − max ⁡ ( o k ) ) ) \begin{align*} \log(\hat{y}_j)&=\log\left(\frac{\exp(o_j-\max(o_k))}{\sum_k \exp(o_j-\max(o_k))}\right)\\ &=o_j-\max(o_k)-\log\left(\sum_k \exp(o_j-\max(o_k))\right) \end{align*} log(y^j)=log(kexp(ojmax(ok))exp(ojmax(ok)))=ojmax(ok)log(kexp(ojmax(ok)))

loss = nn.CrossEntropyLoss(reduction='none')

(3)优化算法
torch内置的小批量随机梯度下降算法

trainer = torch.optim.SGD(net.parameters(), lr=0.1)

参考文献

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值