day22_深度学习与PyTorch入门


一、深度学习概述

1. 概念

深度学习具体是什么呢?一句话概括:深度学习模仿人类大脑的运行方式,依赖算法自动提取特征,而不需要人工设计特征

传统机器学习需要人工设计特征并手动提取,而深度学习把"提取特征"这事儿也交给了算法自己。这也是为什么深度学习经常被称为"黑盒子"——模型学到的特征是人眼难以直接理解的。

深度学习擅长处理高维数据,比如图像(每个像素都是特征)、文本(每个词都是特征)。

2. 深度学习的优缺点

优点:

  • 精度高 — 性能优于其他机器学习算法,某些领域甚至超越了人类水平
  • 可以近似任意非线性函数 — 随着硬件发展,深层网络的表达能力越来越强
  • 生态丰富 — 有大量的框架和开源库可供调用

缺点:

  • 黑箱问题 — 很难解释模型到底是怎么做出判断的
  • 训练时间长 — 需要大量的计算资源(GPU、TPU等)
  • 超参数多 — 网络结构复杂,需要调整的参数多
  • 容易过拟合 — 在部分数据集上表现不佳,需要正则化手段

3. 深度学习发展史

深度学习并非一夜爆红,它经历了三个主要时期:

时期 时间 关键事件
符号主义 1950s-1970s 1943年McCulloch-Pitts提出神经元模型;1956年达特茅斯会议提出"AI"概念;1957年Rosenblatt提出感知器;1962年跳棋程序战胜人类
统计主义 1980s-2000 1986年BP算法成熟,多层神经网络可训练;1997年深蓝战胜卡斯帕罗夫;1993年SVM提出
神经网络与深度学习 2006-至今 2006年Hinton提出DBN,开启深度学习复兴;2012年AlexNet大幅赢得ImageNet比赛;2016年AlphaGo战胜李世石;2017年Transformer框架出现;2018年BERT/GPT诞生;2022年ChatGPT引爆AIGC浪潮;2025年开启智能体时代

🔑 关键转折点:2012年AlexNet在ImageNet图像识别竞赛中以巨大优势夺冠,这是深度学习爆发的标志性事件;2017年Transformer的出现则彻底改变了NLP领域。

4. 主流算法模型

深度学习不是单一的算法,而是一族方法,下面是最主流的几种:

模型 适用场景 核心特点
卷积神经网络(CNN) 图像识别、视频分析、医学影像 擅长处理带有空间关系的数据,通过卷积核提取局部特征
循环神经网络(RNN)/LSTM/GRU 语音识别、音乐生成、NLP 处理序列数据中的时间动态性,有记忆能力
Transformer 复杂语言理解与生成 BERT、GPT系列的基础,用自注意力机制替代循环结构
自编码器(Autoencoder) 数据降维、去噪、异常检测 通过编码-解码结构学习数据的压缩表示
生成对抗网络(GAN) 图像生成、艺术创作、数据增强 生成器与判别器互相博弈,生成逼真数据

二、主流深度学习框架

1. 四大框架对比

目前最主流的深度学习框架有以下四个:

框架 出生地 特点 适合谁
TensorFlow Google 计算图架构、分布式训练强、底层C构建速度快、生态强大,但学术圈已式微 做工程/部署的小伙伴
PyTorch Meta(原Facebook) 动态图、代码量少、入门爽、学术界霸主,几乎所有顶会论文代码都用它写 想做学术的绝对首选
PaddlePaddle(飞桨) 百度 动态图/静态图都支持、部署方便、有专门平台和工具包 算力有限或想用国产框架的
ONNX 多家大厂联合 并不是训练框架,而是一种中间格式,用于模型格式转换(Pytorch→ONNX→其他) 不用刻意学,用到再看

📝 一句话总结:做学术搞研究选 PyTorch,做工程部署选 TensorFlow,搞国产生态选 PaddlePaddle,模型转换靠 ONNX

2. PyTorch简介

PyTorch 是基于 Python 的深度学习框架,核心概念是张量(Tensor)。它提供了灵活高效的工具,用于构建、训练和部署深度学习模型。

安装极其简单:

pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple

三、PyTorch张量操作详解

1. 什么是张量

张量(Tensor)是 PyTorch 的核心数据抽象,简单理解就是多维数组。它与 NumPy 的 ndarray 非常相似,但多了一个杀手锏——支持GPU加速(CUDA)

维度 名称
0维 标量(scalar)
1维 向量(vector)
2维 矩阵(matrix)
3维及以上 张量(tensor)

🔑 关键区别:PyTorch张量与NumPy数组类似,但通过CUDA可以在GPU上高效运行,大幅加速深度学习模型的训练。

2. 张量的创建方法

import torch

# 1. 根据指定数据创建
data = torch.tensor([[1, 2], [3, 4]])
print(data)  # tensor([[1, 2], [3, 4]])

# 2. 根据形状创建(未初始化)
data = torch.Tensor(2, 3)  # 2行3列

# 3. 指定类型创建
data_int = torch.IntTensor([1, 2, 3])
data_float = torch.FloatTensor([1.1, 2.2, 3.3])

# 4. 创建线性张量
arange_data = torch.arange(0, 10, 2)     # [0, 2, 4, 6, 8]
linspace_data = torch.linspace(0, 1, 5)  # [0, 0.25, 0.5, 0.75, 1]

# 5. 创建随机张量
torch.random.manual_seed(42)             # 固定随机种子
rand_data = torch.rand(2, 3)             # [0,1)均匀分布
randn_data = torch.randn(2, 3)           # 标准正态分布
randint_data = torch.randint(0, 10, (2, 3))  # [0,10)随机整数

# 6. 创建全0/全1/全指定值张量
zeros_data = torch.zeros(2, 3)           # 全0
ones_data = torch.ones(2, 3)             # 全1
full_data = torch.full((2, 3), 7)        # 全为7
# 还有 ones_like / zeros_like / full_like 可模仿形状

3. 张量类型转换

data = torch.tensor([1, 2, 3])

# 方法一:直接转换
data_float = data.float()      # torch.float32
data_double = data.double()    # torch.float64
data_int = data.int()          # torch.int32
data_long = data.long()        # torch.int64
data_half = data.half()        # torch.float16

# 方法二:用 type() 方法
data_fp32 = data.type(torch.float)
data_i32 = data.type(torch.int)

4. 张量与NumPy互转

import numpy as np

# 张量 → numpy(共享内存,修改一个会影响另一个)
data_tensor = torch.tensor([1, 2, 3])
data_numpy = data_tensor.numpy()            # 共享内存
data_numpy_copy = data_tensor.numpy().copy()  # 不共享内存

# numpy → 张量(共享内存)
data_np = np.array([4, 5, 6])
data_tensor_shared = torch.from_numpy(data_np)  # 共享内存
data_tensor_new = torch.tensor(data_np)         # 不共享内存

# 标量张量 ↔ 数字
scalar = torch.tensor(3.14)
print(scalar.item())  # 3.14

⚠️ 注意tensor.numpy()torch.from_numpy()共享内存的,修改其中一个会影响另一个。如果不希望共享,用 .copy()torch.tensor()

5. 张量基本运算

# 1. 基本算术运算
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
print(a + b)    # tensor([5, 7, 9])
print(a - b)    # tensor([-3, -3, -3])
print(a * b)    # tensor([4, 10, 18])
print(a / b)    # tensor([0.25, 0.40, 0.50])

# 函数形式(带下划线的为原地操作,会修改原张量)
torch.add(a, b)     # add, sub, mul, div
a.add_(b)           # 原地加法:a = a + b(注意下划线)

# 2. 矩阵乘法
matrix_a = torch.tensor([[1, 2], [3, 4]])
matrix_b = torch.tensor([[5, 6], [7, 8]])
print(matrix_a @ matrix_b)          # 使用 @ 运算符
print(torch.matmul(matrix_a, matrix_b))  # 使用 matmul 函数

# 3. 常见运算函数
data = torch.tensor([1.0, 2.0, 3.0, 4.0])
print(torch.sum(data))    # 求和:10.0
print(torch.mean(data))   # 均值:2.5
print(torch.sqrt(data))   # 平方根
print(torch.pow(data, 2)) # 平方:tensor([1, 4, 9, 16])
print(torch.exp(data))    # 指数
print(torch.log(data))    # 对数

6. 张量索引操作

张量的索引和 NumPy 完全一致,非常直观:

data = torch.randint(0, 10, (3, 4))
print(data)
# 假设输出:
# tensor([[5, 1, 8, 3],
#         [9, 2, 6, 0],
#         [4, 7, 2, 5]])

# 格式:张量[行, 列]

# 1. 单索引
print(data[1, 2])     # 第2行第3列 → 6

# 2. 列表索引
print(data[[0, 2], :])  # 第1行和第3行的所有列

# 3. 切片索引
print(data[0:2, 1:3])   # 前两行的第2~4列

# 4. 布尔索引
mask = data > 5
print(data[mask])       # 所有大于5的元素

# 5. 多维索引
print(data[1])          # 第2行所有列

7. 张量形状操作

data = torch.arange(12)  # tensor([0, 1, 2, ..., 11])

# reshape — 重塑形状(最常用)
reshaped = data.reshape(3, 4)
print(reshaped.shape)  # torch.Size([3, 4])

# view — 类似reshape,但要求内存连续
viewed = data.view(3, 4)  # data本身连续,所以可以

# 对于不连续的张量,先 contiguous 再 view
transposed = data.reshape(3, 4).transpose(0, 1)
# transposed 是不连续的
viewed = transposed.contiguous().view(4, 3)

# squeeze — 删除长度为1的维度
data_with_dim1 = data.reshape(1, 3, 1, 4)  # shape: [1, 3, 1, 4]
squeezed = data_with_dim1.squeeze()         # shape: [3, 4]

# unsqueeze — 增加长度为1的维度
data_2d = torch.tensor([[1, 2, 3], [4, 5, 6]])  # shape: [2, 3]
unsqueezed = data_2d.unsqueeze(0)                # shape: [1, 2, 3]

# transpose — 交换两个维度
data_3d = torch.randn(2, 3, 4)
transposed = data_3d.transpose(1, 2)  # shape: [2, 4, 3]

# permute — 任意重排所有维度
permuted = data_3d.permute(2, 0, 1)   # shape: [4, 2, 3]

📝 reshape vs viewreshape 更智能,自动处理不连续的张量;view 更快但要求内存连续,不连续时需配合 contiguous() 使用。

8. 张量拼接操作

data1 = torch.randint(0, 10, (1, 2, 3))
data2 = torch.randint(0, 10, (1, 2, 3))
print("data1:", data1)
print("data2:", data2)

# 1. cat — 沿已有维度拼接(不增加维度)
# dim=0 拼接 → shape: [2, 2, 3]
cat_dim0 = torch.cat([data1, data2], dim=0)

# dim=1 拼接 → shape: [1, 4, 3]
cat_dim1 = torch.cat([data1, data2], dim=1)

# dim=2 拼接 → shape: [1, 2, 6]
cat_dim2 = torch.cat([data1, data2], dim=2)

# 2. stack — 在新维度上堆叠(会增加一个维度)
data3 = torch.randint(0, 10, (2, 3))
data4 = torch.randint(0, 10, (2, 3))

# dim=0 → shape: [2, 2, 3](在第一个维度前插入新维度)
stack_dim0 = torch.stack([data3, data4], dim=0)

# dim=1 → shape: [2, 2, 3](在第二个维度前插入新维度)
stack_dim1 = torch.stack([data3, data4], dim=1)

# dim=2 → shape: [2, 3, 2](在第三个维度前插入新维度)
stack_dim2 = torch.stack([data3, data4], dim=2)

🔑 cat vs stack 的区别cat 不改变张量的维度数,只在现有维度上拼接;stack增加一个新维度,要求所有输入张量的形状完全相同。


四、实操案例:完整张量操作流水线

下面是一个综合案例,将我们学过的张量操作串起来走一遍:

import torch
import numpy as np

# ============================
# 1. 创建数据 — 模拟一个3通道2x2的"图像"
# ============================
torch.random.manual_seed(42)
image = torch.randint(0, 256, (3, 2, 2))  # shape: [3, 2, 2]
print("原始图像张量形状:", image.shape)

# ============================
# 2. 类型转换 — 转为浮点型便于计算
# ============================
image_float = image.float()
print("转换后类型:", image_float.dtype)

# ============================
# 3. 归一化 — 将像素值缩放到[0,1]
# ============================
image_norm = image_float / 255.0
print("归一化后的均值:", torch.mean(image_norm).item())

# ============================
# 4. 增加批次维度 — 模型需要4D输入
# ============================
image_batch = image_norm.unsqueeze(0)  # shape: [1, 3, 2, 2]
print("增加批次维度后:", image_batch.shape)

# ============================
# 5. 展平 — 将图像变为一维向量
# ============================
image_flat = image_batch.reshape(1, -1)  # shape: [1, 12]
print("展平后形状:", image_flat.shape)

# ============================
# 6. 转 NumPy 数组
# ============================
image_numpy = image_flat.numpy()
print("转换为NumPy数组, 类型:", type(image_numpy))

# ============================
# 7. 数学运算 — 模拟简单的特征变换
# ============================
weights = torch.randn(12, 4)  # 随机权重
bias = torch.randn(4)         # 随机偏置
output = torch.matmul(image_flat, weights) + bias
print("线性变换后输出形状:", output.shape)

# ============================
# 8. 激活函数 — 模拟ReLU
# ============================
output_activated = torch.relu(output)
print("激活后输出:", output_activated)

# ============================
# 9. 拼接多张"图像"(模拟batch处理)
# ============================
image2 = torch.rand(1, 12)  # 第二张"图像"
batch = torch.cat([image_flat, image2], dim=0)  # shape: [2, 12]
print("拼接batch后形状:", batch.shape)

print("\n✅ 完整流水线执行完毕!")

五、总结

知识点 一句话总结
深度学习 用深层神经网络自动提取特征,无需人工设计
深度学习 vs ML DL是ML的子集,DL自动提取特征,ML需要人工特征工程
主流模型 CNN处理图像、RNN处理序列、Transformer处理语言、GAN生成数据
PyTorch 学术界主流框架,动态图、上手快、生态丰富
张量(Tensor) PyTorch的核心数据抽象,类似NumPy但支持GPU加速
张量创建 tensor()Tensor()ones/zeros/fullrand/randn/randintarange/linspace
张量运算 + - * /@/matmulsum/mean/sqrt/pow/exp/log
形状操作 reshape(通用)、view(连续内存)、squeeze/unsqueeze(增减维度)、transpose/permute(交换维度)
拼接操作 cat(沿现有维度拼接,不增维)、stack(新维度堆叠,增一维)
NumPy互转 tensor.numpy()torch.from_numpy() 共享内存,.copy()torch.tensor() 不共享

更多推荐