一小时搞定PyTorch 📅 发布时间:2026/8/30 7:16:09 👁 浏览次数: https://www.bilibili.com/video/BV1Y9PnzrEBP/张量Tensor创建张量1.把已有列表转换成张量使用torch.tensor()2.根据期望的形状创建张量3.参照一个张量的形状、数据类型创建新张量总的来说创建张量1.把已有列表转换成张量使用torch.tensor()2.根据期望的模型创建张量3.参照一个张量的形状、数据类型创建新张量torch.tensor(data)torch.randn(shape)torch.rand_like(data_tensor, dtypetorch.float)张量的属性每个张量有三个关键属性1.形状2.类型默认是float32代表类型和计数的参数必须是整数模型参数如权重、偏置必须是浮点数类型float32是标准类型3.存储位置GPU/CPUpytorch的强大在于autograd是内置的梯度计算工具默认情况下张量只是一个数据为了告诉pytorch这是一个可学习的参数需要把requires_grad true这会告诉autograd引擎从现在开始追踪这个参数经历的每个操作一旦requires_gradTruepytorch开始建立一个计算图即操作过程的实时记录每个通过操作创建的张量有一个特殊属性.grad_fn指向创建它的函数当使用loss.backward()时pytorch会沿着路径计算梯度目前为止有了tensor作为被操作的基础元素以及自动求导系统这是神经系统接下来需要操作深度学习的大部分内容只是几个简单的操作这些操作会重复很多次操作** 操作两个张量时张量必须有相同的形状把两个张量对应位置上的数字进行乘法运算 or torch.matmul(A, B) 用于进行矩阵乘法运算or torch.matmul(A, B)矩阵乘法用一个矩阵表示一种线性变换再把这种变换作用到数据上。神经网络中的矩阵乘法可以理解成根据学到的权重对输入特征进行批量重组和映射。对于经典的线性公式y xw b用的总是 运算符即矩阵乘法运算降维reduction操作降维reduction操作和dim参数降维操作是指任何将张量压缩为更少元素的操作dim 0 按列计算平均值dim 1 按行计算平均值基础索引argmax 会找到最大值的索引动态选择torch.gather() torch.gather()函数用于根据指定的索引从输入张量中收集元素。它的主要用途是在多维张量中按特定的索引选择数据。 语法 torch.gather(input, dim, index, *, sparse_gradFalse, outNone) → Tensor data torch.tensor([[10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33]]) indices_to_select torch.tensor([[2], [0], [3]]) # 指定要收集的索引 selected_values torch.gather(data, dim1, indexindices_to_select) # 在dim1列上收集数据 print(selected_values) # 输出: tensor([[12], [20], [33]])tensor([[12], [20], [33]])即第一行第三个第二行第一个第三行第四个创建模型前向传播 forward pass实现模型的第一次猜测X 是输入数据W是权重b是偏置y_hat是模型的预测值总目标是找到W、b使得预测值接近真实值N 10 # 样本数量 D_in 1 # 样本特征数量 D_out 1 # 样本输出数量 X torch.randn(N, D_in) # 生成输入数据 X形状是(10, 1) # 定义“真实”的线性关系 true_M torch.tensor([[2.0]]) # 假设真实的线性关系是y 2x true_b torch.tensor([[1.0]]) # 假设真实的偏置是1 y_true X true_M true_b torch.randn(N, D_out) * 0.1 # 生成真实的输出数据,并加入一点噪声这里X形状是N * D_in代表N个样本每个样本有D_in个特征W是D_in * D_out其中D_out是要输出的特征的个数可以想象成把X中每个样本的D_in个特征经过W变换后得到D_out个特征关于这里b为什么是1*1的解释# 初始化权重和偏置 W torch.randn(D_in, D_out, requires_gradTrue) # 初始化权重 b torch.randn(D_out, requires_gradTrue) # 初始化偏置 print(fInitial weights W:\n{W}) print(fInitial bias b:\n{b})XW之后得到的一定是N*D_out的矩阵所以这里b的生成填一个D_out即可上面说到的广播机制会把他自动拓展成N*D_out# 正向传递 y_hat X W b # 用权重和偏置预测输出 print(fPredicted outputs y_hat:\n{y_hat})反向传播根据loss反向调整error y_hat - y_true # 计算预测值与真实值之间的误差 loss (error ** 2).mean() # 计算均方误差损失 print(fLoss:\n{loss})loss.backward() # 计算梯度 # loss值回头去算每个对每个参数的偏导数 # 现在梯度值存储在 .grad属性中 print(fGradient of W:\n{W.grad}) print(fGradient of b:\n{b.grad}) 对于这里的线性回归问题梯度的符号告诉我们如何调整参数以最小化损失函数。具体来说 - 如果梯度为正数意味着增加该参数的值会导致损失函数增加因此我们应该减小该参数的值。 - 如果梯度为负数意味着增加该参数的值会导致损失函数减小因此我们应该增加该参数的值。 这里其实是用了梯度下降的思想梯度下降法的核心是沿着梯度的反方向更新参数以最小化损失函数。 通过不断迭代这个过程我们可以逐步找到使损失函数最小化的参数值。 如果有多个loss对一个参数反向传播该参数的grad值梯度下降公式之前写过最优化理论里面关于梯度下降的博客【最优化方法】最速下降法_快速下降再平缓 用什么方程拟合-CSDN博客梯度下降就是一个重复步骤逼近loss值最小谷底的过程整个深度学习的重点就是The training loop这个循环的过程。上面的公式在这个例子中的解释就是一个epoch训练周期是一个完整循环下面是完整训练流程learning_rate 0.01 # 学习率 epochs 100 # 迭代次数 # 重新初始化权重和偏置 W,b torch.randn(1, 1, requires_gradTrue), torch.randn(1, requires_gradTrue) for epoch in range(epochs): y_hat X W b # 正向传递 loss (y_hat - y_true).pow(2).mean() # 计算损失 loss.backward() # 反向传播计算梯度 with torch.no_grad(): # 在不计算梯度的上下文中更新参数 W - learning_rate * W.grad # 更新权重 b - learning_rate * b.grad # 更新偏置 W.grad.zero_() # 清零梯度 b.grad.zero_() # 清零梯度 if epoch % 10 0: # 每10个epoch打印一次损失 print(fEpoch {epoch}: Loss {loss.item()})为什么要写torch.no_grad()代码照常执行但不记录这些运算用于求导因此只要是手动修改一个requires_gradTrue的参数本身就通常要放在with torch.no_grad():里面。TORCH.NN.LINEAR对于一个层数很多的模型参数数量可能是数以万计的这个时候对每个参数手写grad.zero_()清零是不现实的。这时我们可以使用TORCH.NN.LINEAR它相当于把这些参数封装起来便于管理。下面是一个例子import torch # 1. 人工制造一组训练数据 # 输入数据10 个样本每个样本 1 个特征 X torch.arange(1, 11, dtypetorch.float32).reshape(10, 1) # 真实规律y 2x 1 true_W torch.tensor([[2.0]]) true_b torch.tensor([1.0]) # 根据真实规律生成标签 y_true y_true X true_W true_b # 2. 创建线性模型 D_in 1 D_out 1 linear_layer torch.nn.Linear( in_featuresD_in, out_featuresD_out ) # 这里的 weight 和 bias 是模型随机初始化出来的它们不是 true_W 和 true_b print(\n模型初始 weight:) print(linear_layer.weight) print(\n模型初始 bias:) print(linear_layer.bias) # 3. 定义损失函数 loss_fn torch.nn.MSELoss() # 4. 定义优化器 learning_rate 0.01 optimizer torch.optim.SGD( linear_layer.parameters(), lrlearning_rate ) # 5. 开始训练 epochs 1000 for epoch in range(epochs): # ---------- 正向传播 ---------- # 内部实际做的是 # y_hat X weight.T bias y_hat linear_layer(X) # ---------- 计算损失 ---------- # 比较预测值 y_hat 和真实标签 y_true loss loss_fn(y_hat, y_true) # ---------- 梯度清零 ---------- optimizer.zero_grad() # ---------- 反向传播 ---------- # 计算 # weight.grad # bias.grad loss.backward() # ---------- 更新参数 ---------- optimizer.step() if epoch % 100 0: print(fEpoch {epoch}, loss {loss.item():.6f}) # # 6. 查看训练后的参数 # print(\n真实 true_W:) print(true_W) print(\n模型学习到的 weight:) print(linear_layer.weight) print(\n真实 true_b:) print(true_b) print(\n模型学习到的 bias:) print(linear_layer.bias)线性模型有个硬伤就是哪怕嵌套好几层线性模型也只能拟合线形关系所以我们需要引入激活函数。NN.RELUNN.GELUNN.SOFTMAX常见的一套训练写法:import torch import torch.nn as nn import torch.optim as optim # 1. 人工制造训练数据 # 10 个样本每个样本 1 个特征 X torch.arange(1, 11, dtypetorch.float32).reshape(10, 1) # 真实规律y 2x 3 true_W torch.tensor([[2.0]]) true_b torch.tensor([3.0]) # 生成真实标签 y_true X true_W true_b # 2. 定义模型 class LinearModel(nn.Module): def __init__(self): super().__init__() self.linear nn.Linear( in_features1, out_features1 ) def forward(self, X): y_hat self.linear(X) return y_hat # 创建模型 model LinearModel() # 3. 定义损失函数 loss_fn nn.MSELoss() # 4. 定义优化器 learning_rate 0.01 optimizer optim.SGD( model.parameters(), lrlearning_rate ) # 5. 开始训练 epochs 1000 for epoch in range(epochs): # ① 正向传播 y_hat model(X) # ② 计算损失 loss loss_fn(y_hat, y_true) # ③ 清空上一轮梯度 optimizer.zero_grad() # ④ 反向传播计算梯度 loss.backward() # ⑤ 根据梯度更新参数 optimizer.step() if epoch % 100 0: print(fEpoch {epoch}: loss {loss.item():.6f}) # 6. 查看训练结果 print(\n真实 W:) print(true_W) print(\n模型学习到的 W:) print(model.linear.weight) print(\n真实 b:) print(true_b) print(\n模型学习到的 b:) print(model.linear.bias)和原始代码的对比