李沐-动手学深度学习-Day2
自动求梯度
/chapter_prerequisite/autograd.ipynb
// 导入
from mxnet import autograd, nd
//示例
x = nd.arange(4).reshape((4, 1)) --产生4个元素的一维向量,在整形成4行1列
x
//Out
[[0.]
[1.]
[2.]
[3.]]
<NDArray 4x1 @cpu(0)>
//调用attach_grad函数来申请存储梯度所需要的内存
x.attach_grad()
//调用record函数来要求MXNet记录与求梯度有关的计算。
with autograd.record():
y = 2 * nd.dot(x.T, x) ---做矩阵X的转置和X的dot运算,1行4列*4行1列,得到一个标量
//调用backward函数自动求梯度
y.backward() ---对标量求梯度,见数学基础部分A.2.4梯度的验证部分
//验证
assert (x.grad - 4 * x).norm().asscalar() == 0
x.grad
//Out x.grad
[[ 0.]
[ 4.]
[ 8.]
[12.]]
<NDArray 4x1 @cpu(0)>
assert语句用于在代码中进行判断,若为False时,程序会引发AssertionError错误
asscalar() 将向量转换成标量,且向量只能为一维含单个元素的向量
训练模式和预测模式
通过调用is_training函数来查看
作用是什么?后续在学习过程中在来回答这一点
// 查看模式
print(autograd.is_training()) ---预测
with autograd.record():
print(autograd.is_training()) ---训练
对Python控制流求梯度
控制流:程序中包含的一些控制语句,比如循环,条件等。
在运算过程中,需要对变量求梯度
// 如何实现,通过输入a确定后续所有操作
def f(a): ---定义函数f,其变量为a
b = a * 2 ----函数的实现
while b.norm().asscalar() < 1000: ---while语句中,b的范数在转成标量是否小于1000
b = b * 2 ---如果是,计算b*2并赋值给b,并循环
if b.sum().asscalar() > 0: --如果b求和后为正,执行下面的操作
c = b
else:
c = 100 * b
return c
//
a = nd.random.normal(shape=1) ---产生一个随机的a,标量
a.attach_grad() ---分配内存
print("a grad:",a.grad)
with autograd.record(): --保留计算记录
c = f(a) --调用函数
c.backward()
print("c:",c)
print("c:",c / a) ---可以看出函数f(a)实际就是2*a
线性回归
基本要素
1、构建模型
线性回归,就是将要预测的输出与各因素之间是线性关系。假设有两个特征,则模型可以定义为
y
ˆ
=
x
1
w
1
+
x
2
w
2
+
b
.
\^{y} = x_1w_1+x_2w_2+b.
yˆ=x1w1+x2w2+b.
𝑤1和 𝑤2是权重(weight), 𝑏是偏差(bias)
2、模型训练
- 训练数据
training set, sample,label,feature - 损失函数
衡量预测值与真实值之间的误差。 常用的是平房函数,假设对于第i个样本来说,该样本的误差可以表示为平方损失
l ( i ) ( w 1 , w 2 , b ) = 1 2 ( y ˆ ( i ) − y ( i ) ) 2 l^{(i)}(w_1,w_2,b) = \frac{1}{2}(\^{y}^{(i)}-{y}^{(i)})^2 l(i)(w1,w2,b)=21(yˆ(i)−y(i))2
常数项是为了在求导后的常数系数为1.这一损失函数应该越小越好。显然,这个函数只与模型中的参数有关,因此可以记为“以模型参数为参数的函数”。
对所有样本的误差函数做平均
l ( w 1 , w 2 , b ) = 1 n ∑ i = 1 n l ( i ) ( w 1 , w 2 , b ) l(w_1,w_2,b)=\frac{1}{n}\sum_{i=1}^{n} l^{(i)}(w_1,w_2,b) l(w1,w2,b)=n1i=1∑nl(i)(w1,w2,b)
训练的目的,是系统找出一组最优的模型参数,可以记为
w 1 ∗ , w 2 ∗ , b ∗ = arg min w 1 , w 2 , b l ( w 1 , w 2 , b ) w_1^*,w_2^*,b^*=\mathop{\arg\min}\limits_{w_1,w_2,b}l(w_1,w_2,b) w1∗,w2∗,b∗=w1,w2,bargminl(w1,w2,b) - 优化算法
有解析解(可以用公式表示),数值解(优化算法有限次迭代模型参数来尽可能降低损失函数的值),在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)是一种常用的方法,即随机选择参数的初始值,在每次迭代中降低损失函数。每次迭代中,随机均匀采样小批量(mini-batch)B的训练数据,通过对这一小批量数据集中的参数梯度乘以学习率,作为调整量。如下所示:
w 1 ← = w 1 − η ∣ B ∣ ∑ i ∈ B ∂ l ( i ) ( w 1 , w 2 , b ) ∂ w 1 w_1 \leftarrow =w_1-\frac{\eta}{| \mathcal{B}|}\sum_{i\in\mathcal{B}}\frac{\partial{l^{(i)}(w_1,w_2,b) }}{\partial{w_1}} w1←=w1−∣B∣ηi∈B∑∂w1∂l(i)(w1,w2,b)
通过链式求导法则,既可以得到上式的对w1求导后的结论为
x 1 ( i ) ( x 1 ( i ) w 1 + x 2 ( i ) w 2 + b − y ( i ) ) x_1^{(i)}(x_1^{(i)}w_1+x_2^{(i)}w_2+b-y^{(i)}) x1(i)(x1(i)w1+x2(i)w2+b−y(i))
在更新参数过程中, η \eta η称为学习率, ∣ B ∣ | \mathcal{B}| ∣B∣是批量大小,这两个参数都称为超参数(hyperparameter)。
线性回归表示方法
神经网络图
线性回归是一个单层神经网络,输入层即输入特征,这里假定有两个特征,即特征向量维度为2.输出层就是线性回归的输出,负责计算的单元o称为神经元。输出层和两个输入特征均连接,因此也称为全连接层(fully-connected layer)或稠密层(dense layer)。
矢量计算表达式
矢量计算避免了用for循环做多次逐个元素运算,更节省时间。矢量的表达式为
y
ˆ
=
X
w
+
b
\boldsymbol{\^y} =\mathbf{X}\boldsymbol{w} +b
yˆ=Xw+b
假设数据样本个数为n,特征维度为d,此时
y
ˆ
∈
R
n
×
1
\boldsymbol{\^y}\in\mathbb{R}^{n\times1}
yˆ∈Rn×1,样本
X
∈
R
n
×
d
\mathbf{X}\in\mathbb{R}^{n\times d}
X∈Rn×d,权重
w
∈
R
d
×
1
\boldsymbol{w}\in\mathbb{R}^{d\times1}
w∈Rd×1,偏置
b
∈
R
b\in\mathbb{R}
b∈R,对应的样本标签(即真实值)
y
∈
R
n
×
1
\boldsymbol{y}\in\mathbb{R}^{n\times1}
y∈Rn×1。模型参数也用矢量表示为
θ
=
[
w
1
,
w
2
,
b
]
T
\boldsymbol{\theta}=[w_1,w_2,b]^T
θ=[w1,w2,b]T。损失函数如下
l
(
w
1
,
w
2
,
b
)
=
1
n
∑
i
=
1
n
l
(
i
)
(
w
1
,
w
2
,
b
)
l(w_1,w_2,b)=\frac{1}{n}\sum_{i=1}^{n} l^{(i)}(w_1,w_2,b)
l(w1,w2,b)=n1i=1∑nl(i)(w1,w2,b)
l
(
i
)
(
w
1
,
w
2
,
b
)
=
1
2
(
y
ˆ
(
i
)
−
y
(
i
)
)
2
l^{(i)}(w_1,w_2,b) = \frac{1}{2}(\^{y}^{(i)}-{y}^{(i)})^2
l(i)(w1,w2,b)=21(yˆ(i)−y(i))2
当用矢量表示时,可以记为
l
(
θ
)
=
1
2
n
(
y
ˆ
−
y
)
T
(
y
ˆ
−
y
)
l(\boldsymbol{\theta})=\frac{1}{2n}(\boldsymbol{\^y}-\boldsymbol{y})^T(\boldsymbol{\^y}-\boldsymbol{y})
l(θ)=2n1(yˆ−y)T(yˆ−y)
小批量随机梯度下降的迭代步骤将相应地改写为
θ
←
θ
−
η
∣
B
∣
∑
i
∈
B
∇
θ
ℓ
(
i
)
(
θ
)
,
\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \nabla_{\boldsymbol{\theta}} \ell^{(i)}(\boldsymbol{\theta}),
θ←θ−∣B∣ηi∈B∑∇θℓ(i)(θ),
关于损失函数对参数求导表示为
线性回归实现
/chapter_deep-learning-basics/linear-regression-scratch.ipynb
导入本节需要的一些包及模块
%matplotlib inline
from IPython import display
from matplotlib import pyplot as plt
from mxnet import autograd, nd
import random
生成数据集样本
假设样本数n=1000,特征维度d=2,因此可以得到 X ∈ R 1000 × 2 \mathbf{X}\in\mathbb{R}^{1000\times 2} X∈R1000×2,线下回归中的参数为 θ = [ w 1 , w 2 , b ] T = [ 2 , − 3.4 , 4.2 ] T \boldsymbol{\theta}=[w_1,w_2,b]^T=[2,-3.4,4.2]^T θ=[w1,w2,b]T=[2,−3.4,4.2]T,定义一个随机噪声 ϵ ∼ N ( μ = 0 , σ 2 = 0.01 ) \epsilon\sim\mathcal{N}(\mu = 0, \sigma^2 =0.0 1) ϵ∼N(μ=0,σ2=0.01)生成标签(label),即真实值 y = X w + b + ϵ \boldsymbol{y} =\mathbf{X}\boldsymbol{w} +b+\epsilon y=Xw+b+ϵ.
num_inputs = 2 ---特征维度
num_examples = 1000 ---样本数
true_w = [2, -3.4] ---权重w
true_b = 4.2 ---偏差
features = nd.random.normal(scale=1, shape=(num_examples, num_inputs)) ---随机产生1000行2列的特征矩阵,标准差为1
print("feature_1:",features[:,:])
print("feature_1:",features[:, 0]) ----第一个特征,即特征矩阵中的第一列
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b ---每一行是一个长度为1的向量(标量),得到一个1000*1的列向量
labels += nd.random.normal(scale=0.01, shape=labels.shape) ---加随机误差
features[0], labels[0] ---观测特征矩阵的第一行,即第一个样本的两个特征,观测labels矩阵的第一行,即第一个样本的真实值
上述代码运行后,可以看到特征矩阵,样本标签的数值
// 通过生成第二个特征features[:, 1]和标签 labels 的散点图,直观观察两者间的线性关系
def use_svg_display():
# 用矢量图显示,使⽤svg格式在Jupyter中显⽰绘图
display.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):
use_svg_display()
# 设置图的尺寸
plt.rcParams['figure.figsize'] = figsize
set_figsize()
plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1); #asnumpy()将MXNet数组转换成NumPy数组
PS:今天干了点其他事儿,学的较少。
另:我是用的MXNET版本的,新的是用pytorch版本,但是看了很多博客,貌似安装环境很麻烦,暂时就不用新版本了额,内容都是一样的,重点是学会方法么。我也没有去听李沐的课。