【深度学习笔记03】线性回归与Softmax回归及其损失函数
一、线性模型
1.1 模型的数学表示
- 输入:$\textbf x=[x_1,x_2,\dots,x_n]^T$
- 权重:$\textbf w=[w_1, w_2, \dots, w_n]^T$,决定每个特征对预测值的英雄
- 偏差:$b$,决定特征都为0时,预测值应为多少。
- 输出为输入的加权和:$y=w_1x_1+w_2x_2+\dots+w_nx_n+b$
- 向量形式的输出:$y=<\textbf w,\textbf x>+b$
线性模型可以看作单层神经网络。
1.2 衡量预估质量
衡量预估的质量就是比较真实值和预估值,假设$y$是真实值,$\hat y$是估计值,可以有多种形式衡量两者的差距,例如平方损失:$l(y,\hat y)=\frac{1}{2}(y-\hat y)^2$
1.3 训练数据的表示
通常我们会收集一些数据点包括训练样本和对应的真实值,记为:
$\textbf X=[\textbf x_1,\textbf x_2,\cdots,\textbf x_n]^T$
$\textbf y=[y_1,y_2,\cdots,y_n]^T$
其中$\textbf x_n$是列向量,代表每一个样本数据。这样$\textbf X$的每一行就是一个样本。
这样所有样本的预测值就可以表示为:
$\hat{\textbf y}=\textbf X\textbf w+b$
1.4 参数学习
训练的损失带入1.2中提到的平方损失公式。
$l(\textbf w,b)=\frac{1}{2}(y-\hat y)^2=\frac{1}{2}\left(\mathbf{w}^\top \mathbf{x} + b - \hat y\right)$
$L(\mathbf{w}, b) =\frac{1}{n}\sum_{i=1}^n l^{(i)}(\mathbf{w}, b) =\frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2.$
通过令$L(\textbf w,b)$最小,找到对应的参数$\textbf w$和$b$。
1.5 线性模型求解
为了便于计算,令$\textbf X=[\textbf X, 1]$,$\textbf w=[\textbf w, b]^T$,在$\textbf X$的最右侧添加全一的列,在$\textbf w$的下面添加标量$b$。这样就可以直接计算$\textbf y = \textbf X \textbf w$
带入损失函数:
$l(\textbf X,\textbf y,\textbf w)=\frac{1}{2n}||\textbf y-\textbf X \textbf w||^2$
$\frac{\partial}{\partial \textbf w}l(\textbf X,\textbf y,\textbf w)=\frac{1}{n}(\textbf y-\textbf X \textbf w)^T\textbf X$
由于损失函数是凸函数,所以最优解满足梯度为0,可以解得
$\textbf w^*=(\textbf X^T\textbf X)^{-1}\textbf X\textbf y$
1.6 线性回归的从零实现
(1)导入包
1 | import random |
(2)构造数据集
创建一个带有噪声的人造数据集,使用真实的$w$和$b$生成数据集及标签。
1 | def synthetic_data(w, b, num_examples): |
features的每一行都包含一个二维数据样本,labels中的每一行都包含一个标签值。
(3)读取批量
1 | def data_iter(batch_size, features, labels): |
(4)初始化模型参数
1 | w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True) |
(5)定义模型
1 | def linreg(X, w, b): |
(6)定义损失函数
1 | def squared_loss(y_hat, y): |
(7)定义优化算法
1 | def sgd(params, lr, batch_size): |
(8)训练过程
1 | lr = 0.03 |
1.7 线性回归的简单实现
(1)导入包
1 | import numpy as np |
(2)调用框架中现有的API读取数据
1 | def load_array(data_arrays, batch_size, is_train=True): |
(3)定义模型
1 | from torch import nn |
(4)均方误差
1 | loss = nn.MSELoss() |
(5)随机梯度下降
1 | trainer = torch.optim.SGD(net.parameters(), lr=0.03) |
(6)训练过程
1 | num_epochs = 3 |
二、基础优化方法——梯度下降
当一个模型没有显式解时,一般通过这种方法求解。
- 挑选一个初始值$w_0$
- 在训练中重复迭代参数:$w_t=w_{t-1}-\eta\frac{\partial l}{\partial w_{t-1}}$($\eta$:学习率)
也就是说让$w$沿梯度方向(数值下降最快的方向)进行参数更新来找到最优解。类似于下山时一直找坡度最陡的方向走,最终到达山脚(最优解)。
(1)超参数1:学习率
其中的学习率代表每一次参数更新的大小,学习率太小参数更新很慢,学习率太大模型会震荡找不到最优解。
(2)超参数2:批量大小
由于在整个训练集上计算梯度时间消耗太大,可能需要数分钟乃至数个小时。
因此通常随机采样$b$个样本来近似训练集的损失。
同样批量大小不能太大,也不能太小。如果批量太小,不适合并行计算利用GPU资源,如果批量太大,内存消耗增加,浪费计算。
三、Softmax回归
上面提到的回归,目的是估计一个连续值。而分类问题是用来预测一个离散类别。Softmax回归虽然名字叫回归,但其实是一个分类问题。
常见的分类问题包括:手写数字识别、自然物体分类、蛋白质显微镜图片分类、恶意软件分类、恶意评论分类。
对比回归与分类
回归 | 分类 |
---|---|
单连续值数值输出 | 多个输出 |
跟真实值的区别作为损失 | 输出i是预测i的置信度 |
1.1 如何将分类问题转化为回归问题
(1)类别编码
对于n个类别,可以用一维有效编码来编码。那么标号就是长为n的向量,每个类别的标号向量分别是$\textbf y_1,\textbf y_2\dots \textbf y_n$。
其中第i个类别的标号是$\textbf y_i=[0,0,1,0\dots 0]$,其中只有第i个元素是1,其余元素都是0。
(2)确定损失函数
在Softmax中可以选择使用均方损失函数训练。
(3)进行预测
$\hat y=argmax\ o_i$
其中$o_i$是每个类别的置信度,$argmax\ o_i$是置信度最大的类别的索引。这样就能找到置信度最大的那个类别。
进行检测的关键是使对于正确类的置信度远大于其它类别。通常需要保证$o_y-o_i\ge\Delta(y,i)$
(4)置信度转换为概率
我们获得了所有类别的置信度$\textbf o=[o_1,o_2,\dots,o_n]$。
但是置信度只是预测的物体与每个类别的匹配程度,而非识别为该物体的概率,具体转换方法如下:
$\hat{\textbf y}=softmax(\textbf o)$
$\hat y_i=\frac{exp(o_i)}{\sum_k exp(o_k)}$
这样就实现了置信度$\textbf o$的所有元素非负,且和为1。
然后将真实的概率$\textbf y$与$\hat {\textbf y}$的区别作为损失。