四、tensor 的几种形状
- 由于要进行 tensor 的学习,因此,我们先导入我们需要的库。
import torch from torch import tensor
1. Scalar(标量)
- Scalar 通常就是一个数值。
- 我们可以先使用
tensor()
生成一个数。
x = tensor(42.) x #tensor(42.)
- 我们可以通过
dim()
查看他的维度。
x.dim() #0
- 我们可以通过
item()
将张量转变为元素。 - 就行 print(x) 和 print(x.item()) 值是不一样的,一个是打印张量,一个是打印元素。
x.item() #42.0
2. Vector(向量)
v = tensor([1.5, -0.5, 3.0]) v #tensor([ 1.5000, -0.5000, 3.0000])
- 示例 2:
v.dim() #1
- 示例 3:
v.size() #torch.Size([3]) • 1 • 2
3. Matrix(矩阵)
- Matrix 一般计算的都是矩阵,通常都是多维的。
- 关于矩阵的生成操作,与上述是大体一致的。
M = tensor([[1., 2.], [3., 4.]]) M #tensor([[1., 2.], # [3., 4.]])
- 我们可以使用
matmul()
进行矩阵的乘法运算。
M.matmul(M) #tensor([[ 7., 10.], # [15., 22.]])
- 也可以直接进行矩阵内元素的乘法运算。
M * M #tensor([[ 1., 4.], # [ 9., 16.]])
五、PyTorch 的 autograd 机制
1. autograd 机制
- PyTorch 框架最厉害的一件事就是帮我们把返向传播全部计算好了。
- 如果需要求导,我们可以手动定义:
- 示例 1:
x = torch.randn(3,4,requires_grad=True) x #tensor([[-0.4847, 0.7512, -1.0082, 2.2007], # [ 1.0067, 0.3669, -1.5128, -1.3823], # [ 0.8001, -1.6713, 0.0755, 0.9826]], requires_grad=True)
- 示例 2:
x = torch.randn(3,4) x.requires_grad=True x #tensor([[ 0.6438, 0.4278, 0.8278, -0.1493], # [-0.8396, 1.3533, 0.6111, 1.8616], # [-1.0954, 1.8096, 1.3869, -1.7984]], requires_grad=True)
- 示例 3:
b = torch.randn(3,4,requires_grad=True) t = x + b y = t.sum() y #tensor(7.9532, grad_fn=<SumBackward0>)
- 示例 4:(y.backward() 时,如果 y 是标量(scalar),则不需要为 backward() 传入任何参数;如果 y 是张量(tensor),需要传入一个与 y 同形的 tensor(张量))
y.backward() b.grad #tensor([[1., 1., 1., 1.], # [1., 1., 1., 1.], # [1., 1., 1., 1.]])
- 虽然我们没有指定 t 的 requires_grad 但是需要用到它,也会默认为 True 的。
x.requires_grad, b.requires_grad, t.requires_grad #(True, True, True)
2. 举例说明
- 整体的计算流程如下:
x = torch.rand(1) b = torch.rand(1, requires_grad = True) w = torch.rand(1, requires_grad = True) y = w * x z = y + b x.requires_grad, b.requires_grad, w.requires_grad, y.requires_grad#注意y也是需要的 #(False, True, True, True) x.is_leaf, w.is_leaf, b.is_leaf, y.is_leaf, z.is_leaf #(True, True, True, False, False)
- 返向传播计算。
z.backward(retain_graph=True)#如果不清空会累加起来 w.grad #tensor([0.7954]) b.grad #tensor([1.])
3. 一个简单的线性回归模型
- 我们构造一组输入数据 X 和其对应的标签 y。
x_values = [i for i in range(11)] x_train = np.array(x_values, dtype=np.float32) x_train = x_train.reshape(-1, 1) x_train.shape #(11, 1) y_values = [2*i + 1 for i in x_values] y_train = np.array(y_values, dtype=np.float32) y_train = y_train.reshape(-1, 1) y_train.shape #(11, 1)
- 导入线性回归模型需要的库。
import torch import torch.nn as nn
- 其实线性回归就是一个不加激活函数的全连接层。
class LinearRegressionModel(nn.Module): def __init__(self, input_dim, output_dim): super(LinearRegressionModel, self).__init__() self.linear = nn.Linear(input_dim, output_dim) def forward(self, x): out = self.linear(x) return out input_dim = 1 output_dim = 1 model = LinearRegressionModel(input_dim, output_dim) model #LinearRegressionModel( # (linear): Linear(in_features=1, out_features=1, bias=True) #)
- 指定好参数和损失函数。
epochs = 1000 learning_rate = 0.01 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) criterion = nn.MSELoss()
- 在指定好参数和损失函数后,就可以训练模型了。
for epoch in range(epochs): epoch += 1 # 注意转行成tensor inputs = torch.from_numpy(x_train) labels = torch.from_numpy(y_train) # 梯度要清零每一次迭代 optimizer.zero_grad() # 前向传播 outputs = model(inputs) # 计算损失 loss = criterion(outputs, labels) # 返向传播 loss.backward() # 更新权重参数 optimizer.step() if epoch % 50 == 0: print('epoch {}, loss {}'.format(epoch, loss.item())) #epoch 50, loss 0.22157077491283417 #epoch 100, loss 0.12637567520141602 #epoch 150, loss 0.07208002358675003 #epoch 200, loss 0.04111171141266823 #epoch 250, loss 0.023448562249541283 #epoch 300, loss 0.01337424572557211 #epoch 350, loss 0.007628156337887049 #epoch 400, loss 0.004350822884589434 #epoch 450, loss 0.0024815555661916733 #epoch 500, loss 0.0014153871452435851 #epoch 550, loss 0.000807293108664453 #epoch 600, loss 0.00046044986811466515 #epoch 650, loss 0.00026261876337230206 #epoch 700, loss 0.0001497901976108551 #epoch 750, loss 8.543623698642477e-05 #epoch 800, loss 4.8729089030530304e-05 #epoch 900, loss 1.58514467329951e-05 #epoch 950, loss 9.042541933013126e-06 #epoch 1000, loss 5.158052317710826e-06
- 得到测试模型的预测结果。
predicted = model(torch.from_numpy(x_train).requires_grad_()).data.numpy() predicted #array([[ 0.9957756], # [ 2.9963837], # [ 4.996992 ], # [ 6.9976 ], # [ 8.998208 ], # [10.9988165], # [12.999424 ], # [15.000032 ], # [17.00064 ], # [19.00125 ], # [21.001858 ]], dtype=float32)
- 将得到模型进行保存与读取。
torch.save(model.state_dict(), 'model.pkl') model.load_state_dict(torch.load('model.pkl')) #<All keys matched successfully>
- 如果使用 GPU 进行模型训练,只需要把数据和模型传入到 cuda 里面就可以了。
import torch import torch.nn as nn import numpy as np class LinearRegressionModel(nn.Module): def __init__(self, input_dim, output_dim): super(LinearRegressionModel, self).__init__() self.linear = nn.Linear(input_dim, output_dim) def forward(self, x): out = self.linear(x) return out input_dim = 1 output_dim = 1 model = LinearRegressionModel(input_dim, output_dim) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model.to(device) criterion = nn.MSELoss() learning_rate = 0.01 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) epochs = 1000 for epoch in range(epochs): epoch += 1 inputs = torch.from_numpy(x_train).to(device) labels = torch.from_numpy(y_train).to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() if epoch % 50 == 0: print('epoch {}, loss {}'.format(epoch, loss.item())) #epoch 50, loss 0.057580433785915375 #epoch 100, loss 0.03284168243408203 #epoch 150, loss 0.01873171515762806 #epoch 200, loss 0.010683886706829071 #epoch 250, loss 0.006093675270676613 #epoch 300, loss 0.0034756092354655266 #epoch 350, loss 0.0019823340699076653 #epoch 400, loss 0.0011306683300063014 #epoch 450, loss 0.0006449012435041368 #epoch 500, loss 0.0003678193606901914 #epoch 550, loss 0.0002097855758620426 #epoch 600, loss 0.00011965946032432839 #epoch 650, loss 6.825226591899991e-05 #epoch 700, loss 3.892400854965672e-05 #epoch 750, loss 2.2203324988367967e-05 #epoch 800, loss 1.2662595509027597e-05 #epoch 850, loss 7.223141892609419e-06 #epoch 900, loss 4.118806373298867e-06 #epoch 950, loss 2.349547230551252e-06 #epoch 1000, loss 1.3400465377344517e-06