Task01:线性回归|Softmax与分类模型|多层感知机
Torch 操作
-
torch 乘法
torch.mm(a, b)
- mm只能进行矩阵乘法,不可以是tensor,也就是输入的两个tensor维度只能是 $(n\times m)$ 和 $(m\times p)$
torch.mul(a, b)
- 是矩阵a和b对应位相乘,a和b的维度必须相等,比如a的维度是(1, 2),b的维度是(1, 2),返回的仍是(1, 2)的矩阵
torch.matmul(a,b)
- 可以进行张量乘法, 输入可以是高维
torch.bmm(a,b)
- 是两个三维张量相乘, 两个输入tensor维度是 $(b\times n\times m)$ 和 $(b\times m\times p)$ , 第一维b代表batch size,输出为 $(b\times n \times p)$
-
torch 加法
- 第一种
x + y
- 第二种
torch.add(x, y)
- 第三种
torch.add(x, y, out=result)
- 第四种
y.add_(x)
- 第一种
-
查看 torch 的大小
torch.size()
torch.shape
torch.view()
用来改变 torch 的 shapetorch.item()
查看tensor
的 data 值
-
Tensor
和其他类型相互转换Tensor
转NumPy:a = torch.ones(5).numpy()
使用的相同的内存
- NumPy数组转
Tensor
:b = torch.from_numpy(np.ones(5))
使用的相同的内存c = torch.tensor(a)
进行数据拷贝,返回的Tensor
和原来的数据不再共享内存
-
常数初始化:
torch.empty(size)
返回形状为size的空tensortorch.zeros(size)
全部是0的tensortorch.zeros_like(input)
返回跟input的tensor一个size的全零tensortorch.ones(size)
全部是1的tensortorch.ones_like(input)
返回跟input的tensor一个size的全一tensortorch.arange(start=0, end, step=1)
返回一个从start到end的序列,可以只输入一个end参数,就跟python的range()一样了。实际上PyTorch也有range(),但是这个要被废掉了,替换成arange了torch.full(size, fill_value)
这个有时候比较方便,把fill_value这个数字变成size形状的张量
- 随机抽样(随机初始化):
torch.rand(size)
[0,1)内的均匀分布随机数torch.rand_like(input)
返回跟input的tensor一样size的0-1随机数torch.randn(size)
返回标准正太分布N(0,1)的随机数torch.normal(mean, std, out=None)
正态分布。这里注意,mean和std都是tensor,返回的形状由mean和std的形状决定,一般要求两者形状一样。如果,mean缺失,则默认为均值0,如果std缺失,则默认标准差为1.
-
自动求梯度
-
Tensor
是这个包的核心类,如果将其属性.requires_grad
设置为True
,它将开始追踪(track)在其上的所有操作。完成计算后,可以调用.backward()
来完成所有梯度计算。此Tensor
的梯度将累积到.grad
属性中。 -
反向传播更新参数 以下三句话一句也不能少:
- 将上次迭代计算的梯度值清0
optimizer.zero_grad()
- 反向传播,计算梯度值
loss.backward()
- 更新权值参数
optimizer.step()
- 将上次迭代计算的梯度值清0
-
直接调用backward()方法,会计算对计算图叶节点 x 的导数。
-
如果你要求导的是一个标量,那么gradients默认为None,所以前面可以直接调用
J.backward()
就行了 -
如果你要求导的是一个张量,那么gradients应该传入一个Tensor
-
-
一个计算图只能backward一次:计算图在进行反向求导之后,为了节省内存,就会销毁了。
-
中断梯度追踪:
with torch.no_grad():
-
-
奇技淫巧
-
torch.manual_seed(1)
利用随机数种子来使pytorch中的结果可以复现
-
Torch 复杂函数理解
-
torch.gather()
-
函数
torch.gather(input, dim, index, out=None) → Tensor
沿给定轴 dim ,将输入索引张量 index 指定位置的值进行聚合. -
应用:softmax+交叉熵损失
-
dim = 1 按列聚合
import torch a = torch.randint(0, 30, (2, 3, 5)) print(a) ''' tensor([[[ 18., 5., 7., 1., 1.], [ 3., 26., 9., 7., 9.], [ 10., 28., 22., 27., 0.]], [[ 26., 10., 20., 29., 18.], [ 5., 24., 26., 21., 3.], [ 10., 29., 10., 0., 22.]]]) ''' index = torch.LongTensor([[[0,1,2,0,2], [0,0,0,0,0], [1,1,1,1,1]], [[1,2,2,2,2], [0,0,0,0,0], [2,2,2,2,2]]]) print(a.size()==index.size()) b = torch.gather(a, 1,index) print(b) ''' True tensor([[[ 18., 26., 22., 1., 0.], [ 18., 5., 7., 1., 1.], [ 3., 26., 9., 7., 9.]], [[ 5., 29., 10., 0., 22.], [ 26., 10., 20., 29., 18.], [ 10., 29., 10., 0., 22.]]]) 可以看到沿着dim=1,也就是列的时候。输出tensor第一页内容, 第一行分别是 按照index指定的, input tensor的第一页 第一列的下标为0的元素 第二列的下标为1元素 第三列的下标为2的元素,第四列下标为0元素,第五列下标为2元素 index-->0,1,2,0,2 output--> 18., 26., 22., 1., 0. '''
-
dim =2 按行聚合
c = torch.gather(a, 2,index) print(c) ''' tensor([[[ 18., 5., 7., 18., 7.], [ 3., 3., 3., 3., 3.], [ 28., 28., 28., 28., 28.]], [[ 10., 20., 20., 20., 20.], [ 5., 5., 5., 5., 5.], [ 10., 10., 10., 10., 10.]]]) dim = 2的时候就安装 行 聚合了。参照上面的举一反三。 '''
-
dim = 0 按批量batch_size聚合
index2 = torch.LongTensor([[[0,1,1,0,1], [0,1,1,1,1], [1,1,1,1,1]], [[1,0,0,0,0], [0,0,0,0,0], [1,1,0,0,0]]]) d = torch.gather(a, 0,index2) print(d) ''' tensor([[[ 18., 10., 20., 1., 18.], [ 3., 24., 26., 21., 3.], [ 10., 29., 10., 0., 22.]], [[ 26., 5., 7., 1., 1.], [ 3., 26., 9., 7., 9.], [ 10., 29., 22., 27., 0.]]]) 这个有点特殊,dim = 0的时候(三维情况下),是从不同的页收集元素的。 这里举的例子只有两页。所有index在0,1两个之间选择。 输出的矩阵元素也是按照index的指定。分别在第一页和第二页之间跳着选的。 index [0,1,1,0,1]的意思就是。 在第一页选这个位置的元素,在第二页选这个位置的元素,在第二页选,第一页选,第二页选。 '''
-
-
nn.Linear
-
SOURCE
class Linear(Module):
class Linear(Module): r"""Applies a linear transformation to the incoming data: :math:`y = xA^T + b` Args: in_features: size of each input sample out_features: size of each output sample bias: If set to ``False``, the layer will not learn an additive bias. Default: ``True`` Examples:: >>> m = nn.Linear(20, 30) >>> input = torch.randn(128, 20) >>> output = m(input) >>> print(output.size()) torch.Size([128, 30]) """ __constants__ = ['bias', 'in_features', 'out_features'] def __init__(self, in_features, out_features, bias=True): super(Linear, self).__init__() self.in_features = in_features self.out_features = out_features self.weight = Parameter(torch.Tensor(out_features, in_features)) if bias: self.bias = Parameter(torch.Tensor(out_features)) else: self.register_parameter('bias', None) self.reset_parameters() def forward(self, input): return F.linear(input, self.weight, self.bias)
-
Linear Regression
-
线性回归:均方误差 + mini-batch SGD
-
-
初始化模型参数
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32) b = torch.zeros(1, dtype=torch.float32) w.requires_grad_(requires_grad=True) b.requires_grad_(requires_grad=True)
-
定义模型
def linreg(X, w, b): return torch.mm(X, w) + b
-
定义损失函数
def squared_loss(y_hat, y): return (y_hat - y.view(y_hat.size())) ** 2 / 2
-
定义优化算法
def sgd(params, lr, batch_size): for param in params: param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data
-
训练模型
for epoch in range(num_epochs): for X, y in data_iter(batch_size, features, labels): l = loss(net(X, w, b), y).sum() l.backward() sgd([w, b], lr, batch_size) w.grad.data.zero_() b.grad.data.zero_() train_l = loss(net(features, w, b), labels) print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))
-
-
- 定义模型
class LinearNet(nn.Module): def __init__(self, n_feature): super(LinearNet, self).__init__() self.linear = nn.Linear(n_feature, 1) def forward(self, x): y = self.linear(x) return y net = LinearNet(num_inputs)
-
初始化模型参数
from torch.nn import init init.normal_(net[0].weight, mean=0.0, std=0.01) init.constant_(net[0].bias, val=0.0)
-
定义损失函数
loss = nn.MSELoss()
-
定义优化算法
import torch.optim as optim optimizer = optim.SGD(net.parameters(), lr=0.03)
-
训练模型
for epoch in range(1, num_epochs + 1): for X, y in data_iter: output = net(X) l = loss(output, y.view(-1, 1)) optimizer.zero_grad() l.backward() optimizer.step() print('epoch %d, loss: %f' % (epoch, l.item()))
- 定义模型
softmax和分类模型
-
softmax和分类模型:输出层加 softmax + 交叉熵损失
-
-
定义模型
def softmax(X): X_exp = X.exp() partition = X_exp.sum(dim=1, keepdim=True) return X_exp / partition # 这里应用了广播机制
def net(X): return softmax(torch.mm(X.view((-1, num_inputs)), W) + b)
-
定义损失函数
def cross_entropy(y_hat, y): return - torch.log(y_hat.gather(1, y.view(-1, 1)))
-
-
-
定义模型
class FlattenLayer(nn.Module): def __init__(self): super(FlattenLayer, self).__init__() def forward(self, x): # x shape: (batch, *, *, ...) return x.view(x.shape[0], -1) from collections import OrderedDict net = nn.Sequential( # FlattenLayer(), # nn.Linear(num_inputs, num_outputs) OrderedDict([ ('flatten', FlattenLayer()), ('linear', nn.Linear(num_inputs, num_outputs))]) )
-
softmax与交叉熵损失函数
loss = nn.CrossEntropyLoss()
-
优化算法
optimizer = torch.optim.SGD(net.parameters(), lr=0.1)
-
多层感知机
-
多层感知机:隐层加激活函数 -》全连接层+relu+全连接层
-
-
定义模型
def relu(X): return torch.max(input=X, other=torch.tensor(0.0)) def net(X): X = X.view((-1, num_inputs)) H = relu(torch.matmul(X, W1) + b1) return torch.matmul(H, W2) + b2
-
-
-
模型定义
num_inputs, num_outputs, num_hiddens = 784, 10, 256 net = nn.Sequential( d2l.FlattenLayer(), nn.Linear(num_inputs, num_hiddens), nn.ReLU(), nn.Linear(num_hiddens, num_outputs), ) for params in net.parameters(): init.normal_(params, mean=0, std=0.01)
-