用最通俗的语言,带你搞懂深度学习是什么,以及PyTorch这个工具怎么用。
一、深度学习:让机器自己学会"看"和"听"
如果你让一个三岁小孩认识猫,你不需要给他讲"猫有两只尖耳朵、一条长尾巴"这些规则,你只需要给他看很多张猫的图片,他看多了自然就认识了。
深度学习做的就是类似的事 ------它不是教机器"猫长什么样",而是给机器看海量数据,让它自己从数据中总结出"猫"的特征。这种自动提取特征的能力,是深度学习的灵魂。
1. 深度学习有什么特别?
-
多层结构:像剥洋葱一样,第一层看到边缘和颜色,第二层看到形状,更深层看到完整的物体。层数越多,能识别的模式越复杂。
-
自动学特征:传统机器学习需要人工设计特征(比如"红色"、"圆形"),而深度学习自己从数据里找规律。
-
吃数据、烧显卡:深度学习模型通常需要上万张标注图片、数亿个文本词条,还需要强大的GPU来加速计算。
-
黑箱问题:模型为什么做出某个决定?有时候连开发者自己都说不清,这在医疗、金融等场景下是个挑战。
2. 常见的深度学习模型
| 模型 | 擅长什么 | 举个实际例子 |
|---|---|---|
| CNN(卷积神经网络) | 图像处理 | 拍照识花、人脸解锁 |
| RNN(循环神经网络) | 序列数据 | 语音转文字、股价预测 |
| GAN(生成对抗网络) | 生成假数据 | 生成逼真的人脸图片 |
| Transformer | 自然语言 | 机器翻译、写诗写文章 |
3. 深度学习能做什么?
-
看:自动驾驶识别行人、美颜相机定位五官、医院用AI看CT片。
-
听:智能音箱听懂你的命令、会议软件自动生成字幕。
-
读:Google翻译把中文变英文、聊天机器人回答你的问题。
-
推荐:抖音推你爱看的视频、淘宝推你想买的东西。
一句话总结:深度学习就是用多层神经网络 ,让机器从数据中自动学习 ,从而完成看、听、读、推荐等智能任务。
二、PyTorch:最流行的深度学习"工具箱"
要做深度学习,总得有个趁手的工具。PyTorch就是当下最火的那个。
PyTorch是一个基于Python的科学计算库,它把数据封装成张量(Tensor),并提供了一整套搭建神经网络的模块。
1. 为什么大家都爱PyTorch?
-
像NumPy一样简单:如果你用过NumPy,那PyTorch的张量操作会让你感到亲切,而且它还能在GPU上飞驰。
-
动态计算图:你可以一边运行一边修改模型结构,调试起来就像写普通Python代码一样方便,特别适合做研究。
-
自动求导:你只需要定义好前向传播(输入→输出),PyTorch会自动帮你算出所有参数的梯度(反向传播),不用手推公式。
-
社区庞大:网上有海量的教程、预训练模型,遇到问题一搜就有答案。
2. 安装PyTorch
bash
pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple
三、张量:PyTorch里的"万能容器"
张量(Tensor)就是PyTorch里的基本数据单元。你可以把它理解成能跑在GPU上的多维数组。
-
0维张量 :一个数字,比如
5 -
1维张量 :一排数字,比如
[1, 2, 3] -
2维张量 :一个表格,比如
[[1,2],[3,4]] -
3维张量 :像一堆表格叠在一起,RGB彩色图片就可以用
(高, 宽, 3)来表示 -
4维及以上:视频、批量图片等更复杂的数据
1. 创建张量的几种方式(附带小例子)
python
import torch
import numpy as np
# 从列表创建
a = torch.tensor([1, 2, 3]) # 整数张量
b = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) # 浮点张量
# 创建全0/全1/固定值的张量
zeros = torch.zeros(2, 3) # 2行3列全0
ones = torch.ones(2, 3) # 全1
full = torch.full((2, 3), 7) # 全部是7
# 创建随机张量(常用作初始化权重)
rand = torch.randn(2, 3) # 标准正态分布随机数
randint = torch.randint(0, 10, (2, 3)) # 0~9的随机整数
# 等差数列
arange = torch.arange(0, 10, 2) # 0,2,4,6,8
linspace = torch.linspace(0, 9, 5) # 0, 2.25, 4.5, 6.75, 9.0
# 从NumPy数组转换
np_arr = np.array([1, 2, 3])
t_from_np = torch.from_numpy(np_arr) # 共享内存,修改会互相影响
t_from_np_copy = torch.tensor(np_arr) # 拷贝,不共享
💡 小提示 :PyTorch张量默认是
float32类型,你可以用.float()、.double()、.int()等方法转换类型。
四、张量运算:像搭积木一样处理数据
1. 基本算术:加减乘除
python
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])
add = x + y # 对应元素相加
sub = x - y
mul = x * y # 对应元素相乘(不是矩阵乘法)
div = x / y
# 带下划线的操作会修改原数据
x.add_(10) # x 变成了 [11, 12, 13]
2. 矩阵乘法
python
A = torch.tensor([[1, 2], [3, 4]]) # 2x2
B = torch.tensor([[5, 6], [7, 8]]) # 2x2
# 两种写法
C = torch.matmul(A, B) # 矩阵乘法
D = A @ B # 更简洁的写法
3. 常用统计函数
python
data = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
mean_all = data.mean() # 所有元素的均值
mean_col = data.mean(dim=0) # 按列求均值(每列一个值)
sum_row = data.sum(dim=1) # 按行求和(每行一个值)
max_val = data.max() # 最大值
pow2 = data.pow(2) # 每个元素平方
sqrt = data.sqrt() # 平方根
exp = data.exp() # e^x
log = data.log() # 自然对数
dim=0表示沿着第0维度(行方向)操作,dim=1沿着第1维度(列方向)操作,多维度同理。
五、张量形状操作:让数据"变形"
训练神经网络时,经常要调整张量的维度,比如把一批图片从 (batch, 通道, 高, 宽) 变成 (batch, 高*宽, 通道)。
1. 查看形状
python
data = torch.randn(2, 3, 4)
print(data.shape) # torch.Size([2, 3, 4])
print(data.size()) # 同上
print(data.size(0)) # 2
2. 重塑形状:reshape
data = torch.tensor([[1,2,3], [4,5,6]]) # 2x3
new = data.reshape(3, 2) # 变成3x2,元素顺序不变
3. 增加/删除维度:unsqueeze / squeeze
x = torch.tensor([1, 2, 3]) # 形状 (3,)
x_2d = x.unsqueeze(dim=0) # 变成 (1, 3) 在开头加一维
x_2d_alt = x.unsqueeze(dim=1) # 变成 (3, 1) 在末尾加一维
y = torch.tensor([[1, 2, 3]]) # 形状 (1, 3)
y_1d = y.squeeze(dim=0) # 去掉第0维,变成 (3,)
y_1d_all = y.squeeze() # 去掉所有大小为1的维度
4. 交换维度:transpose / permute
python
data = torch.randn(2, 3, 4) # 形状 (2,3,4)
# 交换第1和第2维度
t1 = torch.transpose(data, 1, 2) # 变成 (2,4,3)
# 一次性调整顺序(比如把维度从 (2,3,4) 变成 (4,2,3))
t2 = data.permute(2, 0, 1) # 新的顺序是原来的第2、0、1维
5. 连续性问题:view vs reshape
view 要求张量在内存中连续存储 ,如果张量做过 transpose 或 permute,可能会不连续。这时可以用 contiguous() 先转为连续,再 view。而 reshape 会自动处理连续性问题,更安全。
python
data = torch.randn(2, 3, 4)
data_t = data.permute(1, 0, 2) # 不连续
# data_t.view(2, -1) 可能报错
safe = data_t.contiguous().view(2, -1) # 先连续再view
# 或者直接用 reshape
safe2 = data_t.reshape(2, -1) # reshape更省心
六、张量拼接:合并数据
cat:沿着已有维度拼接
要求除了拼接维度外,其他维度大小相同。
python
a = torch.randn(2, 3)
b = torch.randn(2, 3)
c = torch.cat([a, b], dim=0) # 形状 (4, 3)
d = torch.cat([a, b], dim=1) # 形状 (2, 6)
stack:沿着新维度堆叠
要求所有张量形状完全相同,会新增一个维度。
python
a = torch.randn(2, 3)
b = torch.randn(2, 3)
c = torch.stack([a, b], dim=0) # 形状 (2, 2, 3)
d = torch.stack([a, b], dim=1) # 形状 (2, 2, 3),但维度排列不同
七、自动微分(Autograd):让模型自己学会"调参"
这是PyTorch最核心的功能之一。你只需要定义好损失函数 (衡量模型预测好坏),PyTorch就能自动算出每个参数的梯度(指导参数往哪个方向调)。
1. 简单梯度计算示例
python
# 定义参数 x,并告诉PyTorch需要计算它的梯度
x = torch.tensor(3.0, requires_grad=True)
# 定义一个函数 y = x^2 + 2x + 1
y = x**2 + 2*x + 1
# 反向传播计算梯度(即导数 dy/dx 在 x=3 处的值)
y.backward()
# 查看梯度值
print(x.grad) # 输出 8.0,因为 dy/dx = 2x+2,代入 x=3 得 8
2. 向量化输入的梯度
如果 x 是向量,y 是向量,则不能直接对 y 调用 backward(),需要先对 y 求和(或求某个标量函数)来得到标量。
python
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x**2 + 2*x + 1 # y 也是向量
# 对 y 求和得到标量,再求导
y.sum().backward()
print(x.grad) # 每个点的导数:2x+2 → [4.0, 6.0, 8.0]
3. 梯度下降更新参数(核心思想)
python
# 假设我们想找到使 loss 最小的 w
w = torch.tensor(2.0, requires_grad=True)
lr = 0.1 # 学习率
for step in range(10):
loss = (w - 5) ** 2 # 显然最优 w=5
loss.backward() # 计算梯度
with torch.no_grad(): # 更新参数时不需要跟踪梯度
w = w - lr * w.grad # 梯度下降更新公式
w.grad.zero_() # 清空梯度,否则会累积
print(f"Step {step+1}: w = {w.item():.4f}, loss = {loss.item():.4f}")
这个过程就是深度学习的训练本质:不断前向传播计算损失,反向传播计算梯度,然后用梯度更新参数,循环往复。
4. 实际网络中的自动微分(模拟一个线性层)
python
# 输入 3个样本,每个样本有 4个特征
X = torch.randn(3, 4)
# 真实标签(3个样本,每个输出2个数)
y_true = torch.randn(3, 2)
# 权重和偏置,需要梯度
W = torch.randn(4, 2, requires_grad=True)
b = torch.randn(2, requires_grad=True)
# 前向传播(线性变换)
y_pred = X @ W + b
# 均方误差损失
loss = ((y_pred - y_true) ** 2).mean()
# 反向传播,自动计算 W 和 b 的梯度
loss.backward()
# 查看梯度
print(W.grad) # 形状同 W
print(b.grad) # 形状同 b
# 之后就可以用优化器(如SGD)根据这些梯度更新 W 和 b
八、总结
| 概念 | 通俗解释 |
|---|---|
| 深度学习 | 用多层神经网络,让机器从数据中自动学特征 |
| 张量(Tensor) | 多维数组,PyTorch处理数据的基本单位 |
| 自动微分(autograd) | PyTorch自动帮你求导,省去手推公式 |
| 梯度 | 函数在某一点的变化率,指导参数调整方向 |
| 梯度下降 | 沿着梯度反方向更新参数,让损失变小 |