目录:

问题1:layer层是什么? 问题2:Tensor张量是什么? 问题3:Pytorch能做什么呢?

问题4:requires_grad=True 是什么? 问题5:为什么需要梯度?

问题6:要更新参数,就要知道每个参数对 loss 的导数(梯度)。 这是为什么呢,为什么更新参数就需要对loss的导数呢?

问题7:这个更新的操作,是用户写的吗,还是pytorch框架已经写好了?

问题8:为什么必须写 optimizer.zero_grad()? 问题9:不同优化器(SGD/Adam/...)有啥区别?

问题10:Pytorch是如何存储和更新梯度的? 问题11:torch.tensor是什么?

问题12:Tensor的维度是什么? 问题13:Tensor如何在GPU上移动?

问题14:pd.read.csv('temps,csv')


问题1:layer层是什么?

答案:在神经网络中,layer(层)就是网络的组成单元

可以把整个神经网络想象成多层结构组合的嘛

Input ->层1->层2->层3->Output

常见的layer有:

  • torch.nn.Linear ->全连接层

  • torch.nn.Conv2d ->卷积层

  • torch.nn.ReLU ->激活层

  • torch.nn.BatchNorm2d ->归一化层

torch.nn.Linear(100, 10) 表示 输入维度:100,输出维度:10

每次输入100个特征,然后输出10个特征

这个层内部自动创建了两个参数:

权重矩阵:(10,100),偏置向量:(10,)

手动初始化权重矩阵

layer.weight.data = torch.randn(10, 100)

正态分布随机数 生成一个 10×100 的矩阵,把它赋值给 layer 的权重

问题2:Tensor张量是什么?

张量就是一个可以放数字的容器,类似:

  • 标量(数字):0D 张量

  • 向量(list):1D 张量

  • 矩阵(表格):2D 张量

  • 图像(3D 或 4D)

  • 视频(5D)

PyTorch 中所有数据(图片、文本、特征)都是用 Tensor 表示的。

Tensor 就是 PyTorch 的“基本生命单元”。

问题3:Pytorch能做什么呢?

一、科学计算(类Numpy)——算数字

二、自动求导——帮你算梯度

三、构建神经网络——搭积木一样搭模型

问题4:requires_grad=True 是什么?

告诉 PyTorch:这个张量需要计算梯度。

x = torch.tensor([1.0], requires_grad=True)

表示:

  • x 是一个参与训练的参数(比如权重)

  • PyTorch 会追踪 x 的运算

  • 可以对 x 求导

问题5:为什么需要梯度?

因为深度学习的训练步骤是:

前向传播 → 计算损失 loss → 反向传播求梯度 → 更新参数

要更新参数,就要知道每个参数对 loss 的导数(梯度)。

有梯度 → 能训练参数 无梯度 → 参数不会更新

问题6:要更新参数,就要知道每个参数对 loss 的导数(梯度)。 这是为什么呢,为什么更新参数就需要对loss的导数呢?

我们可以把梯度就叫成导数,理解起来合适一点。

https://vitalflux.com/wp-content/uploads/2020/09/Gradient-1024x718.png

我们把 loss 看成一个山坡:

  • 你现在站在山坡上的某个位置(当前参数值)

  • 你想往山底走(最小 loss)

  • 但你不知道各个方向的坡度

这时候你需要:

梯度(导数)告诉你: “如果你往某个方向移动,loss 会变大还是变小,变多少?”

导数 = 坡度 = 方向信息

梯度为正 → 往这个方向走 loss 会变大
梯度为负 → 往这个方向走 loss 会变小

导数告诉你“最快下降方向”

假设你有一个参数 w,loss 是:

loss = f(w)

你想让 loss 变小,就要改变 w,但改变多少方向呢?

我们观察导数:

  • 如果 f’(w) > 0 → loss 随 w 的增加变大 → 要减小 w(朝负方向走)

  • 如果 f’(w) < 0 → loss 随 w 增加反而变小 → 要增加 w(朝正方向走)

也就是说:

梯度指向“让 loss 增大的方向”, 所以我们沿着“负梯度”方向更新,loss 就下降。

用非常简单的例子让你秒懂

假设:

loss = (w - 3)²

这是一个凸函数,最小点在 w = 3。

假设当前 w = 6

计算导数:

loss = (6 - 3)² = 9
d(loss)/dw = 2*(w - 3) = 2*(6 - 3) = 6

梯度是 正的,说明:

loss会随着w的增大,而增大。所以我们要往反方向走,就是减小w【因为我们最终的目的是要loss减到0】【Because 深度学习训练的目标:让loss最小】

于是更新:

w := w - 学习率 * grad
w := 6 - 0.1*6 = 5.4

loss 从 9 降到 5.76 成功下降!

如果没有梯度会怎样?

假如你完全不知道导数,只能:

  • 乱试

  • 瞎调

  • 猜方向

根本无法收敛,模型不会学任何东西。

深度学习有 千万级参数(ResNet、Transformer),你根本不可能靠猜方向训练。

梯度 = 高维空间里的指南针 它告诉你:

“往哪个方向动,能让 loss 降得最快”

梯度下降(Gradient Descent)本质一句话

深度学习训练的本质,就是不断沿着负梯度方向下山,直到找到最小 loss。

问题7:这个更新的操作,是用户写的吗,还是pytorch框架已经写好了

这个更新公式(w = w - lr * grad)本质是数学原理,但实际代码更新 不是你自己写的,而是由 PyTorch 的优化器(optimizer)帮你写好的。

你只需要调用:

optimizer.step()

PyTorch 就会自动做:

w := w - lr * grad

也就是:

  • 你不用手动改 w

  • PyTorch 会帮你修改模型里所有 requires_grad=True 的参数

  • 修改的规则就是你说的那个公式(梯度下降)

再说得更清楚一点:训练过程谁负责什么?

(1)用户负责的代码

用户需要写:

optimizer.zero_grad()    # 梯度清空
loss.backward()          # 自动求梯度
optimizer.step()         # 更新参数(PyTorch 来写)

(2)PyTorch 负责的事情

当你写 optimizer.step() 时:

PyTorch 会自动做:

for param in model.parameters():
    param = param - lr * param.grad

你完全不用写上面这些。

换句话说:

优化器 step() 就是把你学过的“梯度下降公式”自动执行一遍。

问题8:为什么必须写 optimizer.zero_grad()?

PyTorch 的梯度默认是“累积”的!

比如你有:

loss.backward()

PyTorch 会把梯度加到原来的梯度上:

param.grad = param.grad + 新计算的梯度

如果你不清空,第二次 backward 会变成:

param.grad = 第一次梯度 + 第二次梯度

梯度会越积越多,参数更新就会变得乱七八糟。

所以每次训练循环必须清空:

optimizer.zero_grad()

相当于:

param.grad = 0
🔥为什么 PyTorch 设计成累积?

为了方便多次 backward 再一次更新(比如 RNN、梯度累积),是一种「灵活性的设计」。

问题9:不同优化器(SGD / Adam / …)有啥区别?

SGD(最基础)—— w := w - lr * grad

特点:

  • 方向 = 纯梯度方向

  • 简单、稳定,但有时收敛慢

就像找路下山:

SGD 是盲走,只看当前坡度。

Momentum(带动量的 SGD)

特点:

  • 会记录之前的方向

  • 前后方向一致时,会“加速”

比喻:

Momentum 就像下坡时你顺着惯性冲下去。

Adam(深度学习最常用)

Adam = Momentum + RMSProp(缩放梯度)

特点:

  • 会根据不同参数的梯度大小,自动调节学习率

  • 收敛速度快,效果普遍好

  • 对新手非常友好

比喻:

Adam 像人工智能导航,不仅看坡度,还会自动调整步长。

什么时候用哪一个?

任务 用哪个?
新手训练一般模型 Adam(最稳)
训练 CNN Adam 或 SGD
大规模模型(ResNet/Transformer) AdamW(Adam + L2)
理论研究 / 保守优化 SGD
问题10:PyTorch 是如何存储和更新梯度的?

每个参数都有一个 “param.grad” 属性

当你写:

loss.backward()

之后:

print(w.grad)

就能看到它的梯度。

optimizer.step() 根据 param.grad 更新参数

例如 Adam 的一步更新做了这些事:

  1. 收集所有 parameters

  2. 获取每个 param.grad

  3. 用 Adam 公式更新

  4. 写回 param.data(新的参数值)

问题11:torch.tensor 是什么?

1.简单来说:

torch.tensor() 用来创建一个 PyTorch 张量(Tensor)。

Tensor 是 PyTorch 世界里的“数据容器”。 就像 Python 的 list / NumPy 的 array,但更强,因为它支持:

  • GPU 加速(CUDA)

  • 自动求导(autograd)

  • 高维矩阵计算

  • 神经网络训练

例子:

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

输出:

tensor([1, 2, 3])
  1. 常见用法(最重要)

(1)从列表创建张量

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

注意:默认类型是 int64float32(取决于输入)。

(2)创建浮点数张量

神经网络训练一般需要浮点数!

x = torch.tensor([1, 2, 3], dtype=torch.float32)

(3)创建多维张量

x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

这是一个 2×3 矩阵

(4)创建需要梯度的张量

x = torch.tensor([1.0, 2.0], requires_grad=True)

这意味着:

  • PyTorch 会记录它的操作

  • 你可以反向传播计算梯度

(5)指定设备(CPU / GPU)

x = torch.tensor([1,2,3], device="cuda")  # 创建在 GPU
  1. tensor 的常用属性

创建一个 tensor:

x = torch.tensor([[1., 2.], [3., 4.]])
属性 含义
x.dtype 数据类型(float32、int64…)
x.device CPU 还是 GPU
x.shape 张量的维度
x.requires_grad 是否需要梯度
x.grad 梯度(backward 后会出现)
  1. 和其他创建 Tensor 的函数有什么区别?

difference 1:torch.tensor vs torch.Tensor

torch.tensor()   # 推荐!
torch.Tensor()   # 不推荐,新手容易出错

为什么不推荐 torch.Tensor()

因为:

  • 它默认创建 未初始化的浮点数(垃圾值)

  • 容易导致奇怪 bug

a = torch.Tensor(2,3)
print(a)

你会看到随机垃圾值。

difference 2:torch.tensor vs torch.randn / zeros / ones

torch.tensor(data)

根据你的数据值创建张量

torch.randn(size)

创建一个 服从正态分布的随机数张量

torch.zeros(size)

全部为 0 的张量

torch.ones(size)

全部为 1 的张量

总结表格

函数 创建方式
torch.tensor 用指定的数据创建
torch.randn 随机数(正态分布)
torch.rand 随机数(0-1)
torch.zeros 全 0
torch.ones 全 1
torch.Tensor 未初始化的随机垃圾值(尽量不要用)

5.常见坑(一定要注意)

坑 1:数字是 int,结果 tensor 是 int

x = torch.tensor([1, 2, 3])
print(x.dtype)

得到 torch.int64

但深度学习需要 float32,所以你要写:

x = torch.tensor([1, 2, 3], dtype=torch.float32)

坑 2:用 torch.Tensor() 误创建垃圾值

不要这样:

x = torch.Tensor(2,3)

这样创建的张量内容未初始化,里面是随机垃圾! 应该用:

x = torch.zeros(2,3)

x = torch.randn(2,3)

问题12:Tensor的维度是什么?

tensor—张量其实就是一个多维数组

它的维度决定了它的结构。

0维——标量——>说人话就是一个数字

tensor(5)

1维——向量

tensor([1,2,3])

2维——矩阵

tensor([[1, 2, 3],
        [4, 5, 6]])

shape = (2, 3) 表示 2 行 3 列。

3维——多矩阵堆叠

tensor([
  [[...]],
  [[...]],
  [[...]]
])

比如一个形状 (3, 2, 4) 的张量可以理解成:

  • 有 3 个矩阵

  • 每个矩阵 2 行 4 列

4维——图像数据常用

PyTorch 图像一般用:

(batch_size, channels, height, width)

例如:

(32, 3, 224, 224)

表示:

  • 32 张图片

  • 每张 3 通道 (RGB)

  • 尺寸 224×224

如何查看 Tensor 维度?

x.shape
x.size()

问题13:Tensor 如何在 GPU 上移动?

PyTorch 的 Tensor 可以放在:

  • CPU(默认)

  • GPU(CUDA)

  • 多块 GPU

为什么要放 GPU?

因为 GPU 并行能力强,训练快数十倍。

把 Tensor 放到 GPU 上

x = torch.tensor([1,2,3], device="cuda")

或者:

x = torch.tensor([1,2,3])
x = x.to("cuda")         # 常用

把 Tensor 移回 CPU

x = x.to("cpu")

检查设备在哪

x.device

模型也要放在 GPU

model = model.to("cuda")

否则:

  • 模型在 GPU

  • 数据在 CPU 会报错。

所以深度学习常见套路:

device = "cuda" if torch.cuda.is_available() else "cpu"
​
model = model.to(device)
x = x.to(device)
y = y.to(device)

注意:Tensor 只能在同一个设备上计算

CPU tensor + GPU tensor 会报错

必须:

都在 CPU  
或  
都在 GPU

插曲:【这个插曲有点长】

“jupyter notebook里面无法用 cuda吗?”

其实是可以的,我们应该要明白Pytorch有CPU版本喝GPU版本,默认安装是CPU版本。

然后如果当前的虚拟环境没有安装GPU版本的Pytorch是肯定没法使用的。

因为我这里使用的Jupyter Notebook,所以更应该要去看一下他这里启动的python虚拟环境是哪个?

import sys
print(sys.executable)

我已经知道了在这个环境中,我没有安装GPU版的!

其实,准确的说这里都应该是Conda环境,因为我是用Anaconda提供的Anaconda Powershell Prompt 终端去打开的jupyter~

你可以从路径中看出:

  • 当前 python.exe 属于哪个 conda 环境

  • 或者 pip 环境路径

例如:

  • 如果路径里有 envs/myenv → 你正在用 conda 的 myenv 环境

  • 如果是 anaconda3/python.exe → 用的是 base 环境

  • 如果是普通路径 → pip 环境

小问题:什么是pip环境?

pip 是 Python 的官方包管理工具,即 Python 的安装器

pip 环境 = 一个只用 pip 来管理包的 Python 环境。

Python 安装后,会有一个默认环境:

C:\Python310\

里面包含:

  • python.exe(解释器)

  • pip(包管理工具)

  • 已安装的库(torch、numpy 等)

所有你安装的包,pip 都会放在:

site-packages/

这个环境就是:

pip 的默认 Python 环境,也叫 pip 环境。

为什么它叫“pip 环境”?

因为:

  • 它不是 conda 创建的环境

  • 只能用 pip 安装包

  • 所有包共享在一个目录中

所以人们就习惯叫它“pip 环境”。

你平时在命令行输入:

pip install xxx

安装的包一般就进了这个环境。

pip 环境 vs conda 环境(你一定会遇到)

对比点 pip 环境 conda 环境
管理工具 pip conda
可以创建多个独立环境? ❌ 不行(默认只有一个) ✔ 可以
DLL / C 库管理 ❌ 不行 ✔ 处理更好
CUDA 兼容性 不可靠 ✔ 最安全
是否适合深度学习 可以,但容易冲突 ✔ 最推荐
环境隔离 很好

pip 环境的最大问题:所有包都混在一起

pip 默认只有一个环境,所有库都装进同一个地方:

torch、tensorboard、opencv ...   
都堆在一起

如果你装了错误版本的库,就会冲突。

比如:

pip install torch==2.2
pip install torch==1.9

会直接把旧的覆盖! 这就是 pip 环境不可靠的原因。

那 pip 环境适合什么时候用?

适合:

  • 学习 Python 基础

  • 写小脚本

  • 安装简单库(numpy、pandas、matplotlib)

conda环境的优势——conda 环境:可以创建多个独立环境,每个环境互相隔离,是深度学习的最佳选择。

很多人能装好环境,但 Jupyter Notebook 却一直用不了 CUDA,就是因为没有给该环境安装 kernel。

Kernel = Jupyter Notebook 使用的 Python 解释器。

Notebook 自己不带 Python。 它必须靠某一个“环境”里的 python.exe 才能运行你的代码。

所以每次打开 Notebook,你右上角看到的:

Python 3 (myenv)
Python 3 (base)
Python 3 (cpu)
Python 3 (gpu)

这些就是 kernels

每个 kernel 对应着:

  • 一个 Python 环境

  • 一套独立的包

  • 自己的 CUDA / PyTorch / NumPy / Scipy 等

如何查看自己有哪些环境?

conda env list

就因为这里默认选中的是base,所以直接打开jupyter的时候才会直接用base版的pyhton解释器

我们要进入需要的环境:

conda activate 环境名


为什么切换环境之后,就无法打开jupyter了呢?

原因:这个环境里根本没有安装 Jupyter。

为什么 base 环境能打开 Jupyter?

因为 Anaconda 默认只在 base 环境安装了 jupyter / jupyterlab, 当你切换到别的环境(比如 pytorch12.8)后:

  • 如果这个环境没有安装 jupyter

  • 那命令行输入 jupyter notebook 当然会提示 “无法识别 jupyter”

就像你在一个新的房间(环境)里, 你没有放“jupyter.exe”进去, 自然就打不开。

解决方法非常简单:在当前环境安装 Jupyter

你现在在环境 pytorch12.8 中(从提示符可以看出来):

(pytorch12.8) PS D:\PY\PythonNotebook>

所以你只需要运行:

在当前环境安装 Jupyter

(推荐):

conda install jupyter

安装完成后,再运行:

jupyter notebook

就能正常打开了。

但是,注意更正确的方式:

通常我们 不直接在每个环境里装 Jupyter 而是在 base 环境运行 Jupyter, 然后给其他环境安装 kernel。

为什么要在当前环境安装 kernel?

因为:安装 kernel = 把当前 Python 环境注册给 Jupyter,让它知道并可以选择这个环境运行代码。

例如:

你在 myenv 环境中运行:

pip install ipykernel
python -m ipykernel install --user --name myenv --display-name "Python (myenv)"

你就告诉 Jupyter:

“喂,我有一个叫 myenv 的 Python 环境,请你记住它。”

然后你就能在 Notebook 里点:

Kernel → Change kernel → Python (myenv)

一旦切换:

  • Notebook 就使用 myenv 的 python

  • 就可以使用 myenv 里的 PyTorch GPU 版本

  • 就可以访问 myenv 里的所有包

一句话总结(你一定要记住)

Jupyter 是“外壳”,kernel 是“发动机”。

安装 kernel = 告诉 Jupyter 我这个环境可以作为发动机来跑你的代码。

没有 kernel,Jupyter 就永远不知道你的环境存在。

流程如下👇

推荐的正确做法(最专业最稳)

Step 1:激活你的 GPU 环境

conda activate pytorch12.8

Step 2:安装 kernel(不是 Jupyter)

pip install ipykernel
python -m ipykernel install --user --name pytorch12.8 --display-name "Python (pytorch12.8)"

这一步告诉 Jupyter:

我这个环境也可以作为 kernel 来用。

Step 3:回到 base 环境启动 jupyter

conda activate base
jupyter notebook

Step 4:在 Jupyter 右上角选择:

Kernel → Change Kernel → Python (pytorch12.8)

这样 Jupyter 就能用 GPU 环境运行代码,但本体仍然用 base 启动。 这是最干净、最推荐的方式。

这样就能看到jupyter里已经多了 ”Pytorch12.8“这个新环境了,这个环境中我是安装了GPU版的Pytorch的。

但是上面图片是新建文件用的,我们想要打开之前写好的文件,使用新的环境就得看下面的图片

然后就切换过来了!

然后我就能看到cuda是可用的啦~~~

不过为什么cuda版的,会多打印一个index=0呢?

因为 CPU 只有 1 个,但 CUDA 可能有多个 GPU

你的电脑只有一个 CPU,所以 PyTorch 写成:

device(type='cpu')

就足够描述这个设备了。

但 GPU 不一样:

一台电脑可能有:

  • 一张 GPU:cuda:0

  • 两张 GPU:cuda:0、cuda:1

  • 八张 GPU:cuda:0 ~ cuda:7

  • 集群里甚至几十张

所以 PyTorch 必须明确告诉你:

device(type='cuda', index=0)

表示:

  • CUDA 设备

  • 第 0 号 GPU(也叫 GPU0)

什么是 index=0

就是 GPU 的编号(device id)。

如果你有多个 GPU,可以指定:

x = torch.tensor([1,2,3], device="cuda:1")

打印:

device(type='cuda', index=1)

说明它被放到了第二张显卡上。

GPU就是显卡吗? ——也不能这么绝对的说其实!——GPU(图形处理器)

在深度学习、PyTorch、CUDA 语境下,GPU 就是指“显卡”(准确说是显卡上的图形处理芯片)。

当我们说:

  • “用 GPU 训练”

  • “CUDA 运行在 GPU 上”

  • “把 tensor 放到 cuda:0”

这里的 GPU 就是显卡,尤其是:

NVIDIA 显卡(唯一支持 CUDA,加速 PyTorch 的显卡)

常见型号:

  • RTX 3060 / 3070 / 3080 / 3090

  • RTX 4060 / 4070 / 4080 / 4090

  • Tesla V100 / A100

  • RTX A6000 -等等

这些都算 GPU。

但更准确地说:GPU 是显卡的“大脑”

显卡其实是一个硬件卡片,由:

  • GPU 芯片(核心,大脑)

  • 显存(VRAM)

  • 供电部分

  • 散热部分

  • PCB 板

组成。

而 CUDA 训练真正使用的是:

显卡上的 GPU 芯片(计算单元) 和显卡上的显存(VRAM)


问题14:pd.read_csv('temps.csv')怎么看?

pd.read_csv('temps.csv')pandas 中最常见、最核心的一个函数。

  1. pd.read_csv('temps.csv') 是什么?

这是 pandas 用来 读取 CSV 文件 的函数。

什么是csv文件?——Comma-Separated Values(逗号分隔值)可以把它看成“轻量版 Excel”。

CSV 文件长什么样?

例如 temps.csv 可能长这样:

date,temp
2023-01-01,12
2023-01-02,15
2023-01-03,10

第一行通常是表头(列名):

date,temp

后面是每一行数据:

2023-01-01,12

CSV 文件其实就是普通文本文件

CSV 为什么在机器学习中最常用?

因为:

  • 体积小

  • 格式简单

  • 各种语言都能轻松读写

  • 和 pandas / numpy 完全兼容

  • 不会有复杂格式(样式、表格结构)干扰数据

简单、纯粹、直接。

pandas 会把它读成一个表格形式:

date temp
2023-01-01 12
2023-01-02 15
2023-01-03 10

并存成 DataFrame。

read_csv() 返回什么?——返回一个 DataFrame

DataFrame 是 pandas 中的“表格数据结构”,就像 Excel 表格一样。

4.read_csv() 功能非常强大(重要参数)

常用参数:

指定分隔符(默认逗号)

pd.read_csv('file.csv', sep=';')

指定编码

有些中文 CSV 需要:

pd.read_csv('file.csv', encoding='utf-8')
pd.read_csv('file.csv', encoding='gbk')

指定列名

文件没有表头:

12,3
15,2
17,8

你可以自己给列名:

pd.read_csv('file.csv', names=['temp','count'])

只读某些列

pd.read_csv('file.csv', usecols=['temp'])

解析日期

pd.read_csv('temps.csv', parse_dates=['date'])

features = pd.read_csv('temps.csv')
features.head()

这是 DataFrame 的函数。

.head() 作用:

显示前 5 行数据(默认)

DataFrame 的维度 = 样本数 × 特征数

在机器学习里:

  • 行数 = 数据量(samples)

  • 列数 = 特征维度(features)

这是非常关键的,因为训练模型时:

  • X 的 shape 是 (样本数, 特征数)

  • y 的 shape 是 (样本数,)

y.shape = (3,) 为什么不写成y.shape = (3)

(3,)(3) 是两种不同的东西

(3,) —— 一个只包含一个元素的元组(tuple)

它表示:

一个 1 维的结构,长度是 3——只有一条“数字的直线队列”,里面有 3 个数字。

这正是 y 的 shape(形状)。形状必须是 tuple

例子:

[10, 20, 30]
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐