PyTorch 基本使用学习笔记

1. PyTorch 简介
-
基于 Python 的深度学习框架,核心数据抽象是 张量(Tensor)。
-
特点:类似 NumPy 的张量计算、自动微分、动态计算图、GPU 加速(CUDA)、跨平台。
-
安装:
bashpip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple
2. 张量的创建
2.1 基本创建方式
| 方法 | 说明 |
|---|---|
torch.tensor(data) |
根据指定数据创建张量 |
torch.Tensor(shape) |
根据形状创建张量,也可传入数据 |
torch.IntTensor / FloatTensor / DoubleTensor |
创建指定类型的张量 |
python
import torch
import numpy as np
# 标量
data = torch.tensor(10)
# 从 numpy 数组创建
data = np.random.randn(2, 3)
data = torch.tensor(data)
# 从列表创建,默认 float32
data = [[10., 20., 30.], [40., 50., 60.]]
data = torch.tensor(data)
# 根据形状创建
data = torch.Tensor(2, 3) # 2行3列,默认 float32
data = torch.Tensor([10]) # tensor([10.])
data = torch.Tensor([10, 20]) # tensor([10., 20.])
# 指定类型
data = torch.IntTensor(2, 3) # int32
data = torch.IntTensor([2.5, 3.3]) # 类型转换 → tensor([2, 3], dtype=torch.int32)
data = torch.ShortTensor() # int16
data = torch.LongTensor() # int64
data = torch.FloatTensor() # float32
data = torch.DoubleTensor() # float64
2.2 线性张量与随机张量
python
# 线性张量
torch.arange(0, 10, 2) # tensor([0, 2, 4, 6, 8])
torch.linspace(0, 9, 10) # 在 [0,9] 上等距生成 10 个数
# 随机种子
torch.initial_seed() # 查看当前随机种子
torch.manual_seed(100) # 设置随机种子
# 随机浮点张量
torch.randn(2, 3) # 标准正态分布
# 随机整数张量
torch.randint(low, high, size=())
2.3 0、1、指定值张量
python
torch.zeros(2, 3) # 全 0
torch.zeros_like(data) # 按 data 形状创建全 0
torch.ones(2, 3) # 全 1
torch.ones_like(data) # 按 data 形状创建全 1
torch.full([2, 3], 10) # 全为指定值
torch.full_like(data, 20) # 按 data 形状创建指定值
2.4 张量元素类型转换
python
data.type(torch.DoubleTensor) # 转为 float64
data.half() # float16
data.double() # float64
data.float() # float32
data.short() # int16
data.int() # int32
data.long() # int64
3. 张量与 NumPy 的转换
3.1 张量 → NumPy 数组
Tensor.numpy():共享内存,修改一个会影响另一个。Tensor.numpy().copy():避免共享内存。
python
data_tensor = torch.tensor([2, 3, 4])
data_numpy = data_tensor.numpy() # 共享内存
data_numpy = data_tensor.numpy().copy() # 不共享内存
3.2 NumPy 数组 → 张量
torch.from_numpy(ndarray):共享内存。torch.tensor(ndarray):不共享内存。
python
data_numpy = np.array([2, 3, 4])
data_tensor = torch.from_numpy(data_numpy) # 共享内存
data_tensor = torch.tensor(data_numpy) # 不共享内存
3.3 标量张量 → 数字
python
data = torch.tensor(30)
data.item() # 30
4. 张量数值计算
4.1 基本运算
python
data = torch.randint(0, 10, [2, 3])
data.add(10) # 不修改原数据
data.add_(10) # 修改原数据(带下划线)
data.sub(100)
data.mul(100)
data.div(100)
data.neg()
4.2 点乘(Hadamard 积)
相同形状张量对应位置相乘:
python
data1 = torch.tensor([[1, 2], [3, 4]])
data2 = torch.tensor([[5, 6], [7, 8]])
torch.mul(data1, data2) # 或 data1 * data2
# tensor([[ 5, 12],
# [21, 32]])
4.3 矩阵乘法
要求:第一个矩阵 shape (n, m),第二个矩阵 shape (m, p),结果 shape (n, p)。
python
data1 = torch.tensor([[1, 2], [3, 4], [5, 6]])
data2 = torch.tensor([[5, 6], [7, 8]])
data1 @ data2 # 运算符 @
torch.matmul(data1, data2) # torch.matmul
5. 张量运算函数
python
data = torch.randint(0, 10, [2, 3], dtype=torch.float64)
data.mean() # 均值
data.mean(dim=0) # 按列
data.mean(dim=1) # 按行
data.sum() # 总和
data.sum(dim=0)
data.sum(dim=1)
torch.pow(data, 2) # 平方
data.sqrt() # 平方根
data.exp() # e^n
data.log() # 以 e 为底
data.log2() # 以 2 为底
data.log10() # 以 10 为底
注意:mean() 要求张量为 Float 或 Double 类型。
6. 张量索引操作
python
data = torch.randint(0, 10, [4, 5])
data[0] # 第 0 行
data[:, 0] # 第 0 列
data[[0, 1], [1, 2]] # 返回 (0,1)、(1,2) 两个元素
data[[0, 1], [1, 2]] # 返回 0、1 行的 1、2 列共 4 个元素
data[:, :2] # 前 2 列
data[2:, :2] # 第 2 行到最后的前 2 列
data[data[:, 2] > 5] # 布尔索引:第三列大于 5 的行
data[:, data[1] > 5] # 布尔索引:第二行大于 5 的列
多维索引:
python
data = torch.randint(0, 10, [3, 4, 5])
data[0, :, :] # 0 轴第一个数据
data[:, 0, :] # 1 轴第一个数据
data[:, :, 0] # 2 轴第一个数据
7. 张量形状操作
| 函数 | 说明 |
|---|---|
reshape() |
改变形状,数据不变 |
squeeze() |
删除形状为 1 的维度 |
unsqueeze(dim) |
添加形状为 1 的维度 |
transpose(dim0, dim1) |
交换两个维度 |
permute(dims) |
一次交换多个维度 |
view() |
改变形状,要求内存连续 |
contiguous() |
将张量变为连续,配合 view 使用 |
python
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
data.shape, data.size() # torch.Size([2, 3])
data.reshape(1, 6) # torch.Size([1, 6])
mydata1 = torch.tensor([1, 2, 3, 4, 5])
mydata1.unsqueeze(dim=0) # torch.Size([1, 5])
mydata1.unsqueeze(dim=1) # torch.Size([5, 1])
mydata1.unsqueeze(dim=-1) # torch.Size([5, 1])
mydata1.unsqueeze(dim=0).squeeze() # torch.Size([5])
data = torch.tensor(np.random.randint(0, 10, [3, 4, 5]))
torch.transpose(data, 1, 2) # torch.Size([3, 5, 4])
torch.permute(data, [1, 2, 0]) # torch.Size([4, 5, 3])
data.permute([1, 2, 0]) # torch.Size([4, 5, 3])
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
data.is_contiguous() # True
data.view(3, 2) # 可用
mydata3 = torch.transpose(data, 0, 1)
mydata3.is_contiguous() # False
mydata3.contiguous().view(2, 3) # 先用 contiguous 再用 view
8. 张量拼接操作
8.1 torch.cat()
按指定维度拼接,不增加维度。
python
data1 = torch.randint(0, 10, [1, 2, 3])
data2 = torch.randint(0, 10, [1, 2, 3])
torch.cat([data1, data2], dim=0) # torch.Size([2, 2, 3])
torch.cat([data1, data2], dim=1) # torch.Size([1, 4, 3])
torch.cat([data1, data2], dim=2) # torch.Size([1, 2, 6])
8.2 torch.stack()
在新维度上拼接,所有输入张量形状必须完全相同。
python
data1 = torch.randint(0, 10, [2, 3])
data2 = torch.randint(0, 10, [2, 3])
torch.stack([data1, data2], dim=0) # torch.Size([2, 2, 3])
torch.stack([data1, data2], dim=1) # torch.Size([2, 2, 3])
torch.stack([data1, data2], dim=2) # torch.Size([2, 3, 2])
9. 自动微分模块
9.1 基本概念
- PyTorch 不支持向量张量对向量张量求导,只支持 标量对向量 求导。
requires_grad=True:自动计算梯度并保存到grad。y.backward():反向传播,y必须是标量。x.grad:获取梯度,会累加历史梯度。x.grad.zero_():清空梯度。
python
x = torch.tensor(10, requires_grad=True, dtype=torch.float32)
y = 2 * x ** 2
y.sum().backward()
print(x.grad) # tensor(40.)
向量张量:
python
x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float32)
y = 2 * x ** 2
y.sum().backward()
print(x.grad) # tensor([40., 80.])
9.2 梯度下降法求最优解
公式:w = w - r * grad(r 是学习率)
python
x = torch.tensor(10, requires_grad=True, dtype=torch.float32)
y = x ** 2 + 20
for i in range(1, 1001):
y = x ** 2 + 20
if x.grad is not None:
x.grad.zero_()
y.backward()
x.data = x.data - 0.01 * x.grad
注意:不能写成 x = x - 0.01 * x.grad,应使用 x.data = x.data - 0.01 * x.grad。
9.3 梯度计算注意点
- 不能将自动微分的张量直接转成 NumPy 数组,会报错。
- 使用
detach()产生一个新张量,共享数据但不自动微分。
python
x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
# x1.numpy() # 报错
x2 = x1.detach()
print(x1.requires_grad) # True
print(x2.requires_grad) # False
print(x1.data, x2.data) # 共享内存
9.4 自动微分模块应用
python
x = torch.ones(2, 5)
y = torch.zeros(2, 3)
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w) + b
loss = torch.nn.MSELoss()
loss = loss(z, y)
loss.backward()
print(w.grad)
print(b.grad)
10. 线性回归案例
10.1 模型构建流程
- 准备训练集数据
- 构建模型
- 设置损失函数和优化器
- 模型训练
10.2 使用 API
| 组件 | 替代 |
|---|---|
nn.MSELoss() |
平方损失函数 |
data.DataLoader |
数据加载器 |
optim.SGD |
优化器 |
nn.Linear |
假设函数 |
10.3 代码实现
python
import torch
from torch.utils.data import TensorDataset, DataLoader
from torch import nn, optim
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def create_dataset():
x, y, coef = make_regression(
n_samples=100, n_features=1, noise=10,
coef=True, bias=14.5, random_state=0
)
x = torch.tensor(x)
y = torch.tensor(y)
return x, y, coef
if __name__ == "__main__":
x, y, coef = create_dataset()
plt.scatter(x, y)
x_line = torch.linspace(x.min(), x.max(), 1000)
y_line = torch.tensor([v * coef + 14.5 for v in x_line])
plt.plot(x_line, y_line, label='real')
plt.grid()
plt.legend()
plt.show()
dataset = TensorDataset(x, y)
dataloader = DataLoader(dataset=dataset, batch_size=16, shuffle=True)
model = nn.Linear(in_features=1, out_features=1)
criterion = nn.MSELoss()
optimizer = optim.SGD(params=model.parameters(), lr=1e-2)
epochs = 100
epoch_loss = []
total_loss = 0.0
train_sample = 0.0
for _ in range(epochs):
for train_x, train_y in dataloader:
y_pred = model(train_x.type(torch.float32))
loss = criterion(
y_pred,
train_y.reshape(-1, 1).type(torch.float32)
)
total_loss += loss.item()
train_sample += 1
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch_loss.append(total_loss / train_sample)
plt.plot(range(epochs), epoch_loss)
plt.title('损失变化曲线')
plt.grid()
plt.show()
plt.scatter(x, y)
x_line = torch.linspace(x.min(), x.max(), 1000)
y1 = torch.tensor([v * model.weight + model.bias for v in x_line])
y2 = torch.tensor([v * coef + 14.5 for v in x_line])
plt.plot(x_line, y1, label='训练')
plt.plot(x_line, y2, label='真实')
plt.grid()
plt.legend()
plt.show()
11. 总结
- 张量创建 :
torch.tensor、torch.Tensor、IntTensor/FloatTensor/DoubleTensor、线性/随机张量、0/1/指定值张量。 - 类型转换 :
type()、half/double/float/short/int/long()、numpy()、from_numpy()、item()。 - 数值计算 :
add/sub/mul/div/neg、点乘、矩阵乘法@/matmul。 - 运算函数 :
sum/mean/sqrt/pow/exp/log等。 - 索引:行列索引、列表索引、范围索引、布尔索引、多维索引。
- 形状操作 :
reshape/squeeze/unsqueeze/transpose/permute/view/contiguous。 - 拼接 :
cat(不增加维度)、stack(新维度拼接)。 - 自动微分 :
requires_grad、backward()、grad、zero_()、detach()。 - 线性回归流程:数据准备 → 模型构建 → 损失函数与优化器 → 训练循环。