零、数据对象的操作
在pytorch中,数据对象基本都可以用张量(实际上就是一个n维矩阵)来表达。
常见函数/方法:
X.shape
:返回一个列表,表示张量每个维度的长度
X.numel
:返回张量中元素个数
X.reshape
:重新设置张量各个维度大小,可以通过指定某个维度大小为-1来自动计算
torch.zeros or torch.ones
:创建一个全零张量or创建一个全1张量
torch.zeros_like or torch.ones_like
:参数是一个张量,创建一个与参数大小同的全0张量或全1张量
torch.rand or torch.randn
:前者创建一个[0,1]均匀分布的张量,后者创建一个服从标准正态分布的张量
元素逐个操作
Python原生的加减乘除和求幂、判断语句运算都是对张量对应元素进行逐个运算。
torch.exp
:是指数运算的逐个运算
X.sum
:求和,可以带上参数,对某个维度求和,keepdim=True可以指定保持某个维度不被压缩
1 2
| X.sum(axis=[0,1]) X.sum(axis=0)
|
索引和切片
广播机制
当运算的矩阵维数不足时,pytorch会将矩阵的此维度复制,以满足运算要求。
索引和切片机制大致与python的列表相当,但是pytorch还支持用列表来当索引:
1 2 3 4
| X = torch.arange(12).reshape(3,4) X[[0,2],:]
|
矩阵操作
torch.dot
:点乘
torch.mv(A, x)
:矩阵-向量积
torch.mm(A, B)
:矩阵-矩阵积
torch.norm(u)
:求范数
一、微积分
梯度
梯度是对一个多元函数的各个变量求偏导数之后获得的n维向量。
∇xf(x)=[∂x1∂f(x),…,∂xn∂f(x)]
求梯度时常使用以下规则
-
∇xAx=AT
-
∇xxTA=A
-
∇xxTAx=(A+AT)x
-
∇x∥x∥=∇xxTx=2x
自动微分
在pytorch中,可以通过简单的函数调用完成复杂的梯度计算
1 2 3 4 5
| X = torch.arange(12,require_grad=True) # 或在之后显式地写X.require_grad(True) Y = f(X) # 对X进行一系列计算 Y.backward() x.grad
|
前提是y是一个标量,否则需要通过y.sum().backward()
来调用
梯度会自动累积,所以必要时需要调用X.grad.zero_()
来清空梯度
不需要梯度计算时,可以通过
1 2 3 4 5 6 7
| x.grad.zero_() y = x * x u = y.detach() z = u * x
z.sum().backward() x.grad == u
|
detach函数来将u当做一个常数,不参与梯度计算.
还可以通过with语句让某部分代码不计算梯度
with torch.no_grad():
二、线性回归
线性回归算是高中就接触的问题了,只不过现在将各个参数和自变量(特征)、因变量(标签)用向量来描述
y=Xw+b
我们假设一些标签和特征是存在线性关系的,我们希望拟合出的y^使得损失L最小
L(w,b)是关于两个参数的函数,在训练集上,通过调整w,b可以使损失达到满意的值,具体方法是对损失函数求梯度,通过梯度下降的方法来求得极小值。
然而线性回归作为回归问题的最简单的模型,是存在解析解的。
w∗=(XTX)−1XTy
实际上,代码中还是用求数值解的方法来一点一点逼近的
线性回归的机器学习代码可以分为大如下步骤:
- 设定一个待求参数的初始值,可以通过正态分布等方法获得,并定义超参数(学习率η,正则化常数λ等)。
- 获取训练集,使用当前模型计算估计值,与真实标签求损失(均方差、范数)。
- 求损失函数关于参数的梯度,利用梯度求出当前参数应当变化的方向,结合学习率对参数进行修正。
- 训练完毕后,利用测试集(验证集进行评估)
三、softmax回归
softmax是线性回归问题的一种,softmax回归将输出的标签规定为one-hot标签,即标签向量中只有一个维度是1,其他维度是0;同时对预测值(有正有负)计算softmax值,从而保证归一、非负的性质。
yj=∑ieoieoj
而损失函数也通过交叉熵损失来定义
l(y,y^)=−∑yjlogyj^
由于y是独热标签,所以损失函数的计算也较为简单。
代入后
l(y,y^)=logk=1∑qeok−j=1∑qyjoj
求梯度:
∂ojl(y,y^)=∑k=1qeokeoj−yj
四、利用pytorch框架
定义神经网络
nn.Sequential
初始化数据
此章节提及两种初始化方式
1 2 3 4 5 6 7 8 9 10
| net[0].weight.data.normal_(0, 0.01) net[0].bias.data.fill_(0)
def init_weight(m): if type(m) == nn.Linear: nn.init.normal(m.weight,std=0.01)
net.apply(init_weight)
|
定义损失函数
1 2 3
| loss = nn.MSELoss()
loss = nn.CrossEntropyLoss(reduction='none')
|
优化器(训练器)
1
| trainer = torch.optim.SGD(net.parameters(),0.1)
|
开始训练
1 2
| num_epochs = 10 d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
|