本文为🔗小白入门Pytorch内部限免文章
参考本文所写记录性文章,请在文章开头注明以下内容,复制粘贴即可
- 🍨 本文为🔗小白入门Pytorch中的学习记录博客
- 🍦 参考文章:【小白入门Pytorch】教案一
- 🍖 原作者:K同学啊
PyTorch是一个开源的深度学习框架。它的自动求导功能也使得实现反向传播算法变得简单,是训练深度学习模型的关键组件,本节主要分为如下两个主要内容:
- 创建张量:学会如何创建空张量、随机张量、全零张量以及使用已有数据创建张量。
- 张量的操作:学会如何对张量进行操作,包括张量的加减乘除运算、shape变换、转置、索引与切片以及数组、列表与张量之间的互转。
- 自动求导原理与实现:自动求导是一个关键的功能,它允许我们自动计算梯度,从而进行反向传播和优化。
- 反向传播:反向传播是深度学习中的关键概念之一,它是训练神经网络模型的基础。
笔记和想法
重点内容
本周教程分为两个部分来进行讲解:
- 第一部分为张量的创建以及运算操作
- 第二部分设计自动求导以及反向传播的原理
第一部分
- 张量的创立:torch.tensor( ) ,使用
torch.tensor
函数从Python列表或NumPy数组创建张量,也可以使用其他创建函数,torch.zeros
、torch.ones
、torch.rand
分别创建全0,全1,随机张量。其中()内传入张量的形状。 - 张量操作:可以对张量执行各种数学运算和操作,如加法、减法、乘法、除法、矩阵乘法等。例如 tensor1+tensor2,tensor1-tensor2,tensor1*tensor2
- 张量索引和切片:可以使用索引和切片操作来访问张量中的特定元素或子张量。同numpy中切片,[:],前面是行号后面是列号。
- 张量的GPU加速 在PyTorch中,可以将张量存储在CPU或GPU上。cpu转到GPU torch.to(“cuda“)。
- 张量转化为numpy和list列表:分别用 array = tensor.numpy(),list=tensor.tolist()来完成。
第二部分
- 梯度计算:每个张量都有一个属性requires_grad,默认为False。如果我们希望计算某个张量的梯度,需要将requires_grad设置为True,那么就会开始追踪在该变量上的所有操作,而完成计算后,可以调用 .backward() 并自动计算所有的梯度,得到的梯度都保存在属性 .grad 中。
- 反向传播:使用梯度下降法来最小化损失函数。首先对输入样本进行前向传播计算出预测结果,将预测值与真实值比较,得到损失函数,利用求梯度对损失函数进行优化,时损失函数最小,在此过程中更新各参数的值。
疑难重点
求梯度时,先执行y.sum()再求导的目的是为了计算一个标量值(scalar)的梯度。PyTorch的自动微分机制是基于标量值的,因此我们需要确保我们要计算的梯度是一个标量。具体解释如下:
y是一个张量,它可能包含多个元素,例如[y1, y2, …],每个元素都与x相关。如果我们直接调用y.backward(),PyTorch会尝试计算y中每个元素对应的梯度,这将得到一个与x具有相同形状的梯度张量。这在某些情况下可能是有用的,但通常我们更关心的是一个标量目标函数的梯度。
通过执行y.sum(),我们将y中的所有元素相加,得到一个标量值(单个数字)。然后,我们对这个标量值执行反向传播,计算相对于x的梯度。这确保了我们计算的是整个目标函数相对于x的梯度,而不是每个元素的梯度。
重点代码复现
创建张量
# 导入PyTorch库
import torch
#创建0维
tensor = torch.tensor(5)
print(tensor.shape)
torch.Size([])
#创建1维
tensor = torch.tensor([1, 2, 3, 4, 5])
print(tensor.shape)
torch.Size([5])
利用zeros和ones和rand
# 创建一个形状为(2, 3)的零张量
zeros_tensor = torch.zeros((2, 3))
print(zeros_tensor)
tensor([[0., 0., 0.],
[0., 0., 0.]])
# 创建一个形状为(2, 4)的一张量
one_tensor=torch.ones((2,4))
print(one_tensor)
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.]])
# 创建一个形状为(3, 3)的随机张量
rand_tensor = torch.rand((3, 3))
print(rand_tensor)
tensor([[0.5825, 0.4410, 0.6772],
[0.5829, 0.1274, 0.7013],
[0.8257, 0.9574, 0.7388]])
加减乘除
import torch
tensor1 = torch.tensor([1, 2, 3])
tensor2 = torch.tensor([4, 5, 6])
result = tensor1 + tensor2
print(result)
result = tensor1 * tensor2
print(result)
result = tensor2 - tensor1
print(result)
result = tensor2 / tensor1
print(result)
tensor([5, 7, 9])
tensor([ 4, 10, 18])
tensor([3, 3, 3])
tensor([4, 2, 2])
张量索引和切片
import torch
# 创建一个形状为(3, 3)的张量
tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 访问第一个元素
print(tensor[0, 0]) # 输出: tensor(1)
# 切片操作
print(tensor[:, 1]) # 输出: tensor([2, 5, 8])
tensor(1)
tensor([2, 5, 8])
张量的GPU与CPU切换
import torch
tensor = torch.tensor([[1, 2], [3, 4]])
tensor = tensor.to('cuda')
tensor
tensor = tensor.to('cpu')
tensor
tensor([[1, 2],
[3, 4]], device='cuda:0')
张量形状变换
import torch
# 改变张量的形状
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
b = a.reshape(3, 2) # 改变为3x2的张量
b
tensor([[1, 2],
[3, 4],
[5, 6]])
# 改变张量的形状(与reshape()功能相同)
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
b = a.view(3, 2) # 改变为3x2的张量
b
tensor([[1, 2],
[3, 4],
[5, 6]])
# 转置张量
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
b = a.transpose(0, 1) # 转置为3x2的张量
b
tensor([[1, 4],
[2, 5],
[3, 6]])
张量转化为数组
import torch
import numpy as np
# 创建一个PyTorch张量
tensor = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 将张量转换为NumPy数组
array = tensor.numpy()
# 现在,`array`就是一个NumPy数组,你可以使用NumPy的功能来操作它
print(array)
[[1 2 3]
[4 5 6]
[7 8 9]]
张量转化为列表
import torch
# 创建一个PyTorch张量
tensor = torch.tensor([[1, 2, 3],
[4, 5, 6]])
# 将张量转换为Python列表
tensor_list = tensor.tolist()
print(tensor_list)
[[1, 2, 3], [4, 5, 6]]
请注意,.tolist()
方法只能用于包含标量元素的张量,例如整数或浮点数。如果张量包含其他张量或复杂数据类型,则不能直接使用.tolist()
。在这种情况下,你需要先将内部的张量或复杂数据类型转换为Python列表。
自动求导综合代码案例
🚩示例 1:线性回归
考虑一个简单的线性回归模型,我们的目标是找到一条直线,以最小化预测值与真实值之间的平方误差。我们可以使用梯度下降算法来更新直线的参数。
import torch
# 创建训练数据
x_train = torch.tensor([[1.0], [2.0], [3.0]])
y_train = torch.tensor([[2.0], [4.0], [6.0]])
# 定义模型参数
w = torch.tensor([[0.0]], requires_grad=True)
b = torch.tensor([[0.0]], requires_grad=True)
# 定义模型
def linear_regression(x):
return torch.matmul(x, w) + b
# 定义损失函数
def loss_fn(y_pred, y):
return torch.mean((y_pred - y)**2)
# 定义优化器
optimizer = torch.optim.SGD([w, b], lr=0.01)
# 训练模型
for epoch in range(100):
# 前向传播
y_pred = linear_regression(x_train)
# 计算损失
loss = loss_fn(y_pred, y_train)
# 反向传播
loss.backward()
# 更新参数
optimizer.step()
# 清零梯度
optimizer.zero_grad()
反向传播代码案例
import torch
import torch.nn as nn
import torch.optim as optim
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1) # 输入维度为1,输出维度为1
def forward(self, x):
return self.linear(x)
model = LinearRegression()
criterion = nn.MSELoss() # 均方误差损失函数
# 随机梯度下降优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 生成样本数据
x_train = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_train = torch.tensor([[2.0], [4.0], [6.0], [8.0]])
# 训练模型
for epoch in range(100):
optimizer.zero_grad() # 梯度清零
# 前向传播
y_pred = model(x_train)
# 计算损失
loss = criterion(y_pred, y_train)
# 反向传播
loss.backward()
# 参数更新
optimizer.step()
闯关练习
👉练习1:请创建一个形状为 2x3 的全零张量,然后加上标量2,将结果赋予answer1
import torch
tensor = torch.zeros((2,3));
answer = tensor+2;
answer
tensor([[2., 2., 2.],
[2., 2., 2.]])
👉练习2:请创建一个形状为 2x3 的全零张量a,一个形状为 2x3 的全1张量b,a与b相乘后,再乘以标量3,将结果赋予answer2
import torch
tensor1 = torch.zeros((2,3))
tensor2 = torch.ones((2,3))
tensor3 = tensor1 * tensor2
tensor3 = tensor3 *3
tensor3
tensor([[0., 0., 0.],
[0., 0., 0.]])