002-tensors basic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# PyTorch 张量基础

## 张量简介
张量是一种特殊的数据结构,与数组和矩阵非常相似。在PyTorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码。

## 基本操作

### 创建张量
```python
import torch
import numpy as np

# 从随机数据和全1数据创建张量
shape = (2, 3)
rand_tensor = torch.rand(shape) # 随机张量
ones_tensor = torch.ones(shape) # 全1张量

张量属性

1
2
3
print(f"Shape of tensor: {rand_tensor.shape}")  # 形状
print(f"Datatype of tensor: {rand_tensor.dtype}") # 数据类型
print(f"Device tensor is stored on: {rand_tensor.device}") # 存储设备

索引和切片

1
2
tensor = torch.ones(4, 4)
tensor[:, 1] = 0 # 将第1列所有元素设为0

张量连接

1
t1 = torch.cat([tensor, tensor, tensor], dim=1)  # 沿维度1连接

张量运算

元素级乘法

1
2
3
# 两种等价写法
print(tensor.mul(tensor)) # 方法形式
print(tensor * tensor) # 运算符形式

矩阵乘法

1
2
3
# 两种等价写法
print(tensor.matmul(tensor.T)) # 方法形式
print(tensor @ tensor.T) # 运算符形式

原地操作(In-place)

1
tensor.add_(5)  # 带_后缀的操作会修改原张量

注意:原地操作可以节省内存,但在计算导数时可能会出现问题,因此不鼓励使用。

与NumPy互转

张量转NumPy数组

1
2
t = torch.ones(5)
n = t.numpy() # 转为NumPy数组

NumPy数组转张量

1
2
n = np.ones(5)
t = torch.from_numpy(n) # 转为PyTorch张量

003-torch.autograd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# PyTorch Autograd 详解

## 背景介绍
`torch.autograd`是PyTorch的自动微分引擎,为神经网络训练提供支持。

神经网络(NN)是在输入数据上执行的嵌套函数集合,这些函数由参数(权重和偏差)定义,在PyTorch中存储在张量中。

训练NN分为两个步骤:
1. **前向传播**:NN对输出做出最佳猜测
2. **反向传播**:NN根据误差调整参数,收集误差导数并使用梯度下降优化参数

## Autograd内部机理

![Autograd流程示意图](../../../images/torch001.png)

实现autograd依赖于两种数据类型:
- `Variable`:包装tensor数据,包含额外属性:
- `data`:存储的tensor数据
- `grad`:存储梯度
- `creator`:创建此Variable的Function

工作流程:
1. 输入Variable经过操作(operation)生成输出Variable
2. 每个操作自动生成对应的Function实例
3. 反向传播时,Function自动计算梯度并存储在grad属性中

**重要概念**
- 只有creator为null的变量(叶子节点)才能返回导数
- 中间变量的grad为0

## 使用案例

### 1. 基本梯度采集

```python
import torch
import torchvision
import numpy as np

# 创建需要跟踪梯度的张量
a = torch.tensor([2., 3.], requires_grad=True)
b = torch.tensor([6., 4.], requires_grad=True)

# 定义计算图
Q = 3*a**3 - b**2

# 反向传播(只能对标量输出)
Q.sum().backward() # 或使用 Q.backward(gradient=torch.tensor([1., 1.]))

# 验证梯度
print(9*a**2 == a.grad) # tensor([True, True])
print(-2*b == b.grad) # tensor([True, True])

2. 在神经网络中的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 加载预训练模型
model = torchvision.models.resnet18(pretrained=True)
data = torch.rand(1, 3, 64, 64) # 模拟输入图像
labels = torch.rand(1, 1000) # 模拟标签

# 前向传播
prediction = model(data)

# 计算损失并反向传播
loss = (prediction - labels).sum()
loss.backward() # 自动计算梯度

# 使用优化器更新参数
optim = torch.optim.SGD(
model.parameters(),
lr=1e-2, # 学习率0.01
momentum=0.9 # 动量
)
optim.step() # 执行梯度下降

重要注意事项

  1. backward()只能对标量输出调用
  2. 中间变量的grad为0,只有叶子节点能获得梯度
  3. 优化器通过.step()方法更新参数
  4. 每次反向传播前需要清空梯度(可通过optim.zero_grad()实现)

提示:使用前需确保已安装torchvision(pip install torchvision
```