PyTorch 张量与自动微分完全指南:从核心概念到实战训练

1. 张量:PyTorch 的核心数据结构

PyTorch 中的所有数据都是以张量(Tensor) 的形式存在的。你可以把张量简单理解成一个多维数组

  • 一个单独的数字是 0 维张量(标量)
  • 一列数字是 1 维张量(向量)
  • 一张表格是 2 维张量(矩阵)
  • 一张彩色图片有高度、宽度、颜色通道,所以是 3 维张量

理解张量的创建、操作和变换,是使用 PyTorch 的第一步。下面我们会从最基础的创建开始,逐步深入到自动微分,最后完成一个真实的线性回归训练。

本文所有代码都可以直接运行,建议打开 Jupyter Notebook 边看边敲。


2. 创建张量的常用方法

2.1 从列表或 NumPy 数组创建

最直接的方式是使用 torch.tensor():

复制代码
import torch
import numpy as np

# 从一个数字创建标量张量
tensor_scalar = torch.tensor(10)
print(tensor_scalar)          # tensor(10)

# 从 Python 列表创建一维张量
tensor_1d = torch.tensor([1, 2, 3])
print(tensor_1d)              # tensor([1, 2, 3])

# 从 NumPy 数组创建二维张量
numpy_arr = np.array([[1, 2, 3], [4, 5, 6]])
tensor_2d = torch.tensor(numpy_arr)
print(tensor_2d)
# 输出:
# tensor([[1, 2, 3],
#         [4, 5, 6]])

2.2 创建指定形状的张量

如果你只关心张量的形状,暂时不关心具体数值,可以用 torch.Tensor(注意大写 T)。它分配内存但不会初始化,里面的数值是随机的。

复制代码
# 创建一个形状为 (3, 2, 4) 的三维张量,默认数据类型是 float32
tensor_shape = torch.Tensor(3, 2, 4)
print(tensor_shape.shape)      # torch.Size([3, 2, 4])
print(tensor_shape.dtype)      # torch.float32

# 也可以直接填入数据,效果类似 torch.tensor,但建议统一用 torch.tensor
tensor_with_data = torch.Tensor([[1, 2], [3, 4]])
print(tensor_with_data)

2.3 指定数据类型创建张量

PyTorch 支持多种数据类型,常见的有 int32、int64、float32、float64。有两种方式指定类型:

复制代码
# 方式一:使用专用构造函数
tensor_int32 = torch.IntTensor(2, 3)        # int32 类型
tensor_int64 = torch.LongTensor([1, 2, 3])  # int64 类型
tensor_f32 = torch.FloatTensor([9, 8, 7])   # float32 类型
tensor_f64 = torch.DoubleTensor(2, 3, 1)    # float64 类型

# 方式二:使用 dtype 参数(推荐,更清晰)
tensor_a = torch.tensor([1, 2, 3], dtype=torch.int32)
tensor_b = torch.tensor([1, 2, 3], dtype=torch.float32)

# 注意:如果数据类型不匹配,小数会被直接截断
tensor_trunc = torch.IntTensor([[1.1, 2.2, 3.6]])
print(tensor_trunc)   # tensor([[1, 2, 3]], dtype=torch.int32)

2.4 生成等差数列或等比数列

在构造输入数据或设置参数时,经常需要生成连续的数值序列。

复制代码
# torch.arange(start, end, step) --- 按步长生成 [start, end) 区间内的数
tensor_arange = torch.arange(10, 30, 2)
print(tensor_arange)   # tensor([10, 12, 14, 16, 18, 20, 22, 24, 26, 28])

# 只给 end,默认从 0 开始,步长为 1
tensor_arange_simple = torch.arange(6)
print(tensor_arange_simple)   # tensor([0, 1, 2, 3, 4, 5])

# torch.linspace(start, end, steps) --- 在 [start, end] 区间内均匀生成指定数量的数
tensor_linspace = torch.linspace(10, 30, 5)
print(tensor_linspace)   # tensor([10., 15., 20., 25., 30.])

# torch.logspace(start, end, steps, base) --- 生成等比数列
# 底数为 2,指数从 1 到 3,共 3 个数 → 2^1=2, 2^2=4, 2^3=8
tensor_logspace = torch.logspace(1, 3, 3, 2)
print(tensor_logspace)   # tensor([2., 4., 8.])

2.5 用固定值填充

模型训练前初始化权重时,全 0、全 1 或者固定值的张量非常常用。

复制代码
# 全 0 张量
zeros = torch.zeros(2, 3)
print(zeros)
# tensor([[0., 0., 0.],
#         [0., 0., 0.]])

# 全 1 张量,形状与已有张量相同
ones_like = torch.ones_like(zeros)
print(ones_like)

# 所有元素都填成同一个值
full = torch.full((2, 3), 6)
print(full)

# 未初始化的空张量(内容随机,但分配速度很快)
empty = torch.empty(2, 3)
print(empty)

# 单位矩阵(对角线为 1)
eye = torch.eye(3)
print(eye)
# tensor([[1., 0., 0.],
#         [0., 1., 0.],
#         [0., 0., 1.]])

2.6 随机张量的创建

随机初始化是神经网络训练的关键步骤。PyTorch 提供了多种随机分布。

复制代码
# 均匀分布 [0, 1) 上的随机数
rand_uniform = torch.rand(2, 3)
print(rand_uniform)

# 整数均匀分布 [low, high) 上的随机整数
rand_int = torch.randint(1, 10, (2, 3))
print(rand_int)

# 标准正态分布 N(0, 1) 上的随机数
rand_normal = torch.randn(4, 2)
print(rand_normal)

# 自定义正态分布 N(mean, std),形状可以指定
rand_custom = torch.normal(5, 1, (2, 3))
print(rand_custom)

# 随机排列(洗牌):生成 0 到 n-1 的随机顺序
rand_perm = torch.randperm(10)
print(rand_perm)   # 每次运行结果不同,例如 tensor([4, 8, 0, 2, 3, 7, 1, 5, 9, 6])

# 固定随机种子,让结果可以复现
print(torch.random.initial_seed())   # 查看当前种子
torch.manual_seed(42)                # 设置种子为 42
print(torch.random.initial_seed())

3. 张量的类型转换与数组互转

3.1 修改张量的数据类型

训练过程中有时需要切换精度(比如从 float64 转为 float32 以节省显存)。

复制代码
tensor = torch.tensor([1, 2, 3])
print(tensor, tensor.dtype)   # tensor([1, 2, 3]) torch.int64

# 方法一:使用 type() 方法
tensor = tensor.type(torch.float32)
print(tensor, tensor.dtype)   # tensor([1., 2., 3.]) torch.float32

# 方法二:使用专用转换方法(更简洁)
tensor = tensor.double()      # 转换为 float64
tensor = tensor.long()        # 转换为 int64

3.2 Tensor 与 NumPy 数组互转

PyTorch 和 NumPy 可以非常方便地互相转换,但要注意内存共享的问题。

复制代码
# Tensor → NumPy(共享内存)
tensor = torch.rand(3, 2)
numpy_arr = tensor.numpy()
print(type(tensor), type(numpy_arr))   # <class 'torch.Tensor'> <class 'numpy.ndarray'>

# 修改 Tensor,NumPy 数组也会跟着变
tensor[:, 0] = 4
print("修改后的 Tensor:\n", tensor)
print("同步变化的 NumPy 数组:\n", numpy_arr)

# 如果不希望共享内存,可以复制一份
numpy_arr_copy = tensor.numpy().copy()
tensor[:, 0] = -1
print("Tensor 再次修改后:\n", tensor)
print("NumPy 副本没有变化:\n", numpy_arr_copy)

# NumPy → Tensor(同样共享内存)
numpy_arr = np.random.randn(3)
tensor_from_np = torch.from_numpy(numpy_arr)
print("原始 NumPy:", numpy_arr)
print("转换得到的 Tensor:", tensor_from_np)

# 修改 NumPy,Tensor 也会变
numpy_arr[0] = 100
print("修改 NumPy 后:\n", numpy_arr)
print("Tensor 同步变化:\n", tensor_from_np)

# 如果想彻底独立,用 copy()
tensor_safe = torch.from_numpy(numpy_arr.copy())

# 使用 torch.tensor() 也会创建独立副本(深拷贝)
tensor_independent = torch.tensor(numpy_arr)

3.3 张量提取标量

如果张量只有一个元素,可以用 .item() 把它提取成 Python 的普通数字。

复制代码
scalar_tensor = torch.tensor(1)
print(scalar_tensor)        # tensor(1)
print(scalar_tensor.item()) # 1 (Python int)

4. 张量的数值计算

4.1 基本运算(加减乘除、幂、平方根、指数、对数)

PyTorch 的运算分为两种:

  • 不修改原数据:add(), sub(), mul(), div() 等

  • 就地修改原数据:带下划线的版本,如 add_(), sub_(), mul_(), div_()

    tensor = torch.randint(1, 9, (2, 3))
    print("原始张量:\n", tensor)

    加法(不修改原数据)

    result = tensor.add(10)
    print("加法结果:\n", result)
    print("原张量不变:\n", tensor)

    加法(就地修改)

    tensor.add_(10)
    print("就地加法后:\n", tensor)

    类似地,减法 sub()/sub_(),乘法 mul()/mul_(),除法 div()/div_()

    取负

    print("取负:\n", tensor.neg())

    幂运算

    pow_tensor = torch.tensor([1, 2, 3])
    pow_tensor.pow_(2) # 原地求平方
    print("平方后:", pow_tensor) # tensor([1, 4, 9])

    平方根

    sqrt_tensor = torch.tensor([1.0, 2.0, 3.0])
    sqrt_tensor.sqrt_()
    print("平方根后:", sqrt_tensor)

    指数运算 e^x

    exp_tensor = torch.tensor([1.0, 2.0, 3.0])
    print("e^tensor:", exp_tensor.exp())

    自然对数 ln(x)

    print("ln(tensor):", exp_tensor.log())

4.2 哈达玛积(元素级乘法) vs 矩阵乘法

这两个概念经常被初学者混淆,一定要分清。

  • 哈达玛积:两个形状相同的张量,对应位置元素相乘,结果形状不变。

  • 矩阵乘法:按照线性代数的规则相乘(行 × 列),形状会改变。

    哈达玛积(对应元素相乘)

    a = torch.tensor([[1, 2], [3, 4]])
    b = torch.tensor([[1, 2], [3, 4]])
    hadamard = a * b # 也可以用 a.mul(b)
    print("哈达玛积:\n", hadamard)

    输出:

    tensor([[1, 4],

    [9, 16]])

    矩阵乘法

    A = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
    B = torch.tensor([[1, 2], [3, 4], [5, 6]]) # 形状 (3, 2)
    matmul_result = A.mm(B) # 二维矩阵专用,也可以用 A @ B 或 A.matmul(B)
    print("矩阵乘法结果:\n", matmul_result)

    输出:

    tensor([[22, 28],

    [49, 64]])

4.3 节省内存的技巧

在训练循环中,如果直接写 X = X @ Y,Python 会先计算 X @ Y 得到一个新张量,然后把变量名 X 指向这个新张量。原来的内存会被丢弃,这会导致频繁的内存分配和释放,影响性能。

更好的做法是使用切片赋值,把结果直接写回到原内存中:

复制代码
X = torch.randint(1, 9, (3, 2, 4))
Y = torch.randint(1, 9, (3, 4, 1))

print("原始 id:", id(X))
X[:] = X @ Y      # 原地更新,id 不会变
print("原地更新后 id:", id(X))

5. 常用的张量运算函数

PyTorch 内置了许多统计和操作函数,可以大大简化代码。

复制代码
# 创建一个 3×2×4 的随机整数张量,并转为 float 类型以便求均值
tensor = torch.randint(1, 9, (3, 2, 4)).float()
print("原始形状:", tensor.shape)

# 求和
print("所有元素之和:", tensor.sum())
print("按第 0 维求和后的形状:", tensor.sum(dim=0).shape)   # (2, 4)

# 求均值
print("所有元素的均值:", tensor.mean())
print("按第 1 维求均值后的形状:", tensor.mean(dim=1).shape) # (3, 4)

# 最大值及其索引
max_val = tensor.max()
print("全局最大值:", max_val)

# 按维度求最大值,返回 (最大值, 索引)
max_vals, max_idxs = tensor.max(dim=2)
print("沿第 2 维的最大值:", max_vals)
print("对应的索引:", max_idxs)

# 最小值索引(展平后的位置)
print("最小值索引(一维位置):", tensor.argmin())

# 标准差
print("标准差:", tensor.std())

# 去重
print("去重后的元素:", tensor.unique())

# 排序(返回排序后的值和原始索引)
sorted_vals, sorted_idxs = tensor.sort()
print("排序后的值:", sorted_vals)

dim 参数的含义:dim 表示你要沿着哪个维度进行压缩。例如,形状为 (3, 2, 4) 的张量,sum(dim=0) 会沿着第 0 维(大小为 3)求和,结果形状变成 (2, 4)。


6. 索引与切片

6.1 基本索引和范围索引

PyTorch 的索引语法和 NumPy 几乎一样,非常直观。

复制代码
tensor = torch.randint(1, 9, (3, 5, 4))
print("原始形状:", tensor.shape)   # (3, 5, 4)

# 取第 0 维的第 0 个元素(得到 5×4 的矩阵)
print(tensor[0])

# 取所有第 0 维,第 1 维的第 1 个元素(得到 3×4 的矩阵)
print(tensor[:, 1])

# 精确取一个标量:第 2 维的第 1 个,第 1 维的第 3 个,第 2 维的第 4 个(索引从 0 开始)
print(tensor[2, 1, 3])

# 范围切片
print(tensor[-1, 1:4, 0:3])   # 最后一批,第 1~3 行,前 3 列

6.2 列表索引和布尔索引

列表索引可以同时取多个不连续的位置。布尔索引则非常强大,可以按条件筛选元素。

复制代码
# 列表索引:取 (0,1) 和 (1,2) 位置的值
print(tensor[[0, 1], [1, 2]])

# 布尔索引:找出满足条件的元素
# 条件:第 2 维的第 0 个通道的值大于 5
mask = tensor[:, :, 0] > 5
print("布尔掩码形状:", mask.shape)   # (3, 5)
print("满足条件的元素:", tensor[mask])

# 更精细的筛选:特定位置大于 5
mask2 = tensor[:, 1, 2] > 5
print("满足条件的整批数据:", tensor[mask2])

7. 改变张量的形状

7.1 交换维度

transpose 交换两个维度,permute 可以按任意顺序重排所有维度。

复制代码
tensor = torch.randint(1, 9, (2, 3, 6))
print("原始形状:", tensor.shape)          # (2, 3, 6)

# 交换第 1 维和第 2 维
transposed = tensor.transpose(1, 2)
print("transpose(1,2) 后形状:", transposed.shape)   # (2, 6, 3)

# 重排所有维度:原始 (2,3,6) → (6,2,3)
permuted = tensor.permute(2, 0, 1)
print("permute(2,0,1) 后形状:", permuted.shape)      # (6, 2, 3)

7.2 reshape 与 view 的区别

  • reshape:通用方法,总能成功。

  • view:要求张量在内存中是连续存储的,但共享内存,效率更高。如果内存不连续,会报错。

    tensor = torch.randint(1, 9, (3, 5, 4))

    reshape 可以自动推断维度(-1 表示自动计算)

    reshaped = tensor.reshape(6, 10)
    print("reshape(6,10) 形状:", reshaped.shape)

    reshaped_auto = tensor.reshape(3, -1)
    print("reshape(3, -1) 形状:", reshaped_auto.shape) # (3, 20)

    view 要求内存连续

    print("是否连续:", tensor.is_contiguous()) # True
    viewed = tensor.view(-1, 10)
    print("view(-1,10) 形状:", viewed.shape)

    经典坑:transpose 之后内存不再连续

    tensor_t = tensor.T
    print("转置后是否连续:", tensor_t.is_contiguous()) # False

    下面这行会报错:view 要求连续内存

    tensor_t.view(-1)

    解决方法:先调用 contiguous()

    contiguous_t = tensor_t.contiguous()
    print("contiguous 后可以 view:", contiguous_t.view(-1).shape)

为什么会有连续性问题?

PyTorch 的张量是"逻辑视图"与"物理存储"分离的设计。像 transpose 这样的操作只是改变了维度映射关系,并没有实际移动内存中的元素,因此张量变得"不连续"。view 需要元素在物理上是连续排列的,所以必须先调用 contiguous() 强制整理内存。

7.3 增加或删除维度

unsqueeze 在指定位置插入一个大小为 1 的新维度,squeeze 删除所有大小为 1 的维度。

复制代码
tensor = torch.tensor([1, 2, 3, 4, 5])
print("原始形状:", tensor.shape)   # (5,)

# 在位置 0 插入新维度
unsqueezed_0 = tensor.unsqueeze(dim=0)
print("unsqueeze(0) 形状:", unsqueezed_0.shape)   # (1, 5)

# 在位置 1 插入新维度
unsqueezed_1 = tensor.unsqueeze(dim=1)
print("unsqueeze(1) 形状:", unsqueezed_1.shape)   # (5, 1)

# 在最后插入(dim=-1)
unsqueezed_last = tensor.unsqueeze(dim=-1)
print("unsqueeze(-1) 形状:", unsqueezed_last.shape)  # (5, 1)

# 删除所有大小为 1 的维度
squeezed = unsqueezed_0.squeeze()
print("squeeze 后形状:", squeezed.shape)   # (5,)

8. 拼接与堆叠

  • cat:沿已有维度拼接,不增加总维度数。要求除拼接维度外,其他维度大小相同。

  • stack:沿新维度堆叠,会增加一个维度。要求所有张量形状完全相同。

    cat 示例

    a = torch.randint(1, 9, (2, 2, 5))
    b = torch.randint(1, 9, (2, 1, 5))
    catted = torch.cat([a, b], dim=1)
    print("cat 后形状:", catted.shape) # (2, 3, 5)

    stack 示例

    x = torch.randint(1, 9, (3, 1, 5))
    y = torch.randint(1, 9, (3, 1, 5))
    stacked = torch.stack([x, y], dim=2)
    print("stack 后形状:", stacked.shape) # (3, 1, 2, 5)


9. 自动微分(Autograd)

9.1 什么是自动微分

PyTorch 最强大的功能之一就是自动计算梯度。你只需要把张量的 requires_grad 属性设为 True,PyTorch 就会记录所有基于这个张量的操作,构建一个计算图。然后调用 backward(),梯度就会自动计算出来,并保存在对应张量的 .grad 属性中。

下面是一个最简单的例子,模拟一个神经元:z = w * x + b,然后计算损失关于 w 和 b 的梯度。

复制代码
import torch

# 输入 x 和目标值 y
x = torch.tensor(10.0)
y = torch.tensor(3.0)

# 初始化权重 w 和偏置 b,并告诉 PyTorch 需要追踪它们的梯度
w = torch.rand(1, 1, requires_grad=True)
b = torch.rand(1, 1, requires_grad=True)

# 前向传播:计算预测值
z = w * x + b

# 定义损失函数(均方误差)
loss_fn = torch.nn.MSELoss()
loss = loss_fn(z, y)

# 反向传播:自动计算 w 和 b 的梯度
loss.backward()

# 输出梯度
print("w 的梯度:\n", w.grad)
print("b 的梯度:\n", b.grad)

# 叶子节点:由用户直接创建,不是计算得到的
print("x 是叶子节点:", x.is_leaf)   # True
print("w 是叶子节点:", w.is_leaf)   # True
print("z 是叶子节点:", z.is_leaf)   # False(由计算得到)
print("loss 是叶子节点:", loss.is_leaf)  # False

关键点

  • requires_grad=True 开启梯度追踪。
  • backward() 执行反向传播。
  • .grad 存储计算好的梯度。
  • 叶子节点(用户直接创建的张量)的梯度在反向传播后会保留;非叶子节点的梯度默认会被释放(可以设置 retain_grad=True 保留)。

9.2 动态图的优势

PyTorch 采用的是动态计算图:每次执行前向传播时,计算图都是实时构建的。这意味着你可以在循环、条件判断中动态改变计算图的结构,就像写普通 Python 代码一样灵活。这也是 PyTorch 在科研领域特别受欢迎的原因------调试方便,修改模型也极其简单。

9.3 隔离计算图:detach 的用法

有时候我们希望把某些计算从计算图中剥离出来(例如在对抗训练中固定生成器的参数),可以用 detach()。

复制代码
x = torch.ones(2, 2, requires_grad=True)
y = x * x

# 分离 y,新变量 u 不再记录计算历史
u = y.detach()
z = u * x

# 反向传播时,梯度不会经过 u 传播到 x
z.sum().backward()

# 验证:x.grad 应该等于 u(被当作常数),而不是 3*x^2
print(x.grad == u)   # 所有元素为 True

10. 实战:用 PyTorch 实现线性回归

现在我们把前面的知识串起来,完成一个完整的机器学习任务:训练一个线性回归模型,拟合 y = 2.5 * x + 5.2 + 噪声。

标准的训练流程包含四步:

  1. 准备数据

  2. 构建模型

  3. 定义损失函数和优化器

  4. 训练循环

    import torch
    import matplotlib.pyplot as plt
    from torch import nn, optim
    from torch.utils.data import TensorDataset, DataLoader

    ---------- 1. 准备数据 ----------

    生成 100 个样本,每个样本 1 个特征

    X = torch.randn(100, 1) # 输入
    w_true = torch.tensor([2.5]) # 真实权重
    b_true = torch.tensor([5.2]) # 真实偏置
    noise = torch.randn(100, 1) * 0.1 # 添加噪声,模拟真实数据
    y = w_true * X + b_true + noise # 目标值

    将数据包装成 Dataset 和 DataLoader

    dataset = TensorDataset(X, y)
    dataloader = DataLoader(
    dataset,
    batch_size=10, # 每次取 10 个样本训练
    shuffle=True # 每个 epoch 打乱顺序
    )

    ---------- 2. 构建模型 ----------

    nn.Linear 就是一个线性层:y = weight * x + bias

    model = nn.Linear(in_features=1, out_features=1)

    ---------- 3. 定义损失函数和优化器 ----------

    loss_fn = nn.MSELoss() # 均方误差损失,适合回归
    optimizer = optim.SGD(model.parameters(), lr=1e-3) # 随机梯度下降,学习率 0.001

    ---------- 4. 训练循环 ----------

    loss_list = [] # 记录每个 epoch 的平均损失,用于绘图

    num_epochs = 1000
    for epoch in range(num_epochs):
    total_loss = 0
    num_samples = 0

    复制代码
     for x_batch, y_batch in dataloader:
         # 前向传播:计算预测值
         y_pred = model(x_batch)
         
         # 计算损失
         loss = loss_fn(y_pred, y_batch)
         total_loss += loss.item()
         num_samples += len(y_batch)
         
         # 反向传播前必须清零梯度(否则梯度会累积)
         optimizer.zero_grad()
         # 反向传播:计算梯度
         loss.backward()
         # 更新参数
         optimizer.step()
     
     avg_loss = total_loss / num_samples
     loss_list.append(avg_loss)

    打印结果

    print(f"训练得到的权重: {model.weight.item():.4f} (真实值: 2.5)")
    print(f"训练得到的偏置: {model.bias.item():.4f} (真实值: 5.2)")

    绘制损失曲线

    plt.plot(loss_list)
    plt.xlabel("Epoch")
    plt.ylabel("Loss")
    plt.title("线性回归训练损失曲线")
    plt.show()

运行这段代码,你会看到损失不断下降,最终学到的权重和偏置非常接近真实值(2.5 和 5.2)。

代码要点解释

  • DataLoader 负责批量读取数据,batch_size=10 意味着每次迭代只用 10 个样本更新一次参数,这比用全部样本更高效,也更容易跳出局部最优。
  • optimizer.zero_grad() 是必须的,因为 PyTorch 默认会累积梯度,不清零的话梯度会越来越大。
  • loss.backward() 计算梯度,optimizer.step() 用梯度更新参数。
  • 每个 epoch 结束后记录平均损失,可以观察训练是否收敛。

11. 总结

通过这篇文章,你应该已经掌握了 PyTorch 的核心概念:

  1. 张量是 PyTorch 的基本数据单元,创建方式多种多样:从数据创建、指定形状、随机生成、固定值填充等等。
  2. 张量运算包括基本算术、哈达玛积、矩阵乘法,以及各种统计函数。特别要注意 view 和 reshape 的区别,以及内存连续性的问题。
  3. 自动微分让梯度计算变得极其简单,只需要设置 requires_grad=True 并调用 backward()。
  4. 完整的训练流程包含了数据加载、模型定义、损失函数、优化器以及训练循环,线性回归的完整代码就是一个标准的模板。

你可以在此基础上,把 nn.Linear 换成更复杂的网络(比如卷积层、循环层),把数据换成真实的图片或文本,就能解决各种各样的深度学习问题了。

建议你动手运行一遍文中的所有代码,并且尝试修改一些参数(比如学习率、batch size、模型结构),观察结果的变化。实践是掌握 PyTorch 最好的方式。

相关推荐
ManageEngineITSM1 天前
IT服务台为什么越忙越低效?
人工智能·自动化·excel·itsm·工单系统
程砚成1 天前
小微美业的数字化突围:一款轻量工具,如何让小店告别经营焦虑?
人工智能
IT_陈寒1 天前
为什么我的Vite热更新老是重新加载整个页面?
前端·人工智能·后端
zhaoshuzhaoshu1 天前
人工智能(AI)发展史:详细里程碑
人工智能·职场和发展
Luke~1 天前
阿里云计算巢已上架!3分钟部署 Loki AI 事故分析引擎,SRE 复盘时间直接砍掉 80%
人工智能·阿里云·云计算·loki·devops·aiops·sre
weixin_156241575761 天前
基于YOLOv8深度学习花卉识别系统摄像头实时图片文件夹多图片等另有其他的识别系统可二开
大数据·人工智能·python·深度学习·yolo
AI_Claude_code1 天前
ZLibrary访问困境方案三:Web代理与轻量级转发服务的搭建与优化
爬虫·python·web安全·搜索引擎·网络安全·web3·httpx
QQ676580081 天前
AI赋能轨道交通智能巡检 轨道交通故障检测 轨道缺陷断裂检测 轨道裂纹识别 鱼尾板故障识别 轨道巡检缺陷数据集深度学习yolo第10303期
人工智能·深度学习·yolo·智能巡检·轨道交通故障检测·鱼尾板故障识别·轨道缺陷断裂检测
小陈工1 天前
2026年4月7日技术资讯洞察:下一代数据库融合、AI基础设施竞赛与异步编程实战
开发语言·前端·数据库·人工智能·python
tq10861 天前
组织的本质:从科层制到伴星系统的决断理论
人工智能