学习自定义层&读写文件&使用gpu

类实例执行过程:

init函数只是针对构建类实例时候是否需要传参数
forward函数原理:

forward函数不是直接自动执行的。​ 它是一个被调用的函数,而不是自动执行的脚本。

关键点:

  • 你没有直接调用 forward方法

  • 你调用的是实例本身(layer())

  • PyTorch在父类nn.Module中定义了__call__方法

  • 这个__call__方法内部会调用你的forward方法

读写文件(重点):

加载和保存张量:
python 复制代码
import torch
from torch import nn
from torch.nn import functional as F

x = torch.arange(4)
torch.save(x, 'x-file')
x2 = torch.load('x-file')

存在当前目录:

结果

保存模型参数:(常用)
恢复模型(常用)

clone = MLP() # 第1步:创建空白模型

clone.load_state_dict(torch.load('mlp.params')) # 第2步:加载训练好的参数 现在clone拥有了和训练时完全一样的权重,但模式还是训练模式

clone.eval() # 第3步:切换到评估模式

评估模式和训练模式区别:

eval模式下结果不会变的

特性 train 模式 (.train()) eval 模式 (.eval())
用途​ 训练模型 测试/推理/验证模型
随机性​ 有(Dropout 随机丢弃) 无(确定性输出)
统计量​ 实时计算并更新 使用训练时累积的固定值
结果一致性​ 同一输入可能输出不同 同一输入总是输出相同
内存占用​ 较大(需存储梯度) 较小(可配合 torch.no_grad())

如果你的模型包含Dropout、BatchNorm等特殊层 ,不要eval()会导致推理结果不一致、不准确

BatchNorm是另一个需要eval()的重要原因:

python 复制代码
import torch
import torch.nn as nn
import numpy as np

# 创建一个只有BatchNorm的网络
class BNOnlyNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.bn = nn.BatchNorm2d(1)  # 只有BatchNorm,没有Dropout
    
    def forward(self, x):
        return self.bn(x)

# 创建两个相同的网络
net1 = BNOnlyNet()
net2 = BNOnlyNet()

# 让它们有相同的初始参数
net2.load_state_dict(net1.state_dict())

# 固定输入
x = torch.randn(2, 1, 3, 3)  # 批次大小=2,通道=1,3x3
print("输入数据形状:", x.shape)
print("输入数据:\n", x)
print()

# 1. 不调用eval() - 训练模式
print("=== 训练模式(不调用eval)===")
print("但BatchNorm没有随机性,所以每次结果相同")
net1.train()  # 训练模式

for i in range(3):
    with torch.no_grad():
        output = net1(x)
    print(f"第{i+1}次输出的前2个值: {output[0, 0, 0, 0]:.4f}, {output[0, 0, 0, 1]:.4f}")

print()

# 2. 调用eval() - 评估模式
print("=== 评估模式(调用eval)===")
net2.eval()  # 评估模式

for i in range(3):
    with torch.no_grad():
        output = net2(x)
    print(f"第{i+1}次输出的前2个值: {output[0, 0, 0, 0]:.4f}, {output[0, 0, 0, 1]:.4f}")

因为用了不同的统计量,所以归一化的结果不同,最终输出也就不同了!

  • BatchNorm在训练模式下结果也是稳定的​ - 相同输入得到相同输出

  • 但训练模式和评估模式的结果不同​ - 因为用了不同的统计量

    这就是统计量不同的地方:

  • 训练模式统计量 :每次前向传播时,计算当前批次的均值和方差

  • 评估模式统计量 :使用训练过程中累积的running_mean 和running_var

  • 训练时:(x - batch_mean) / √(batch_var + ε)

  • 评估时:(x - running_mean) / √(running_var + ε)

小结:

训练要随机,预测要稳定;

训练用 train,预测用 eval。

使用gpu:(重点)

查看cpu/可用的gpu数目:

查看张量所在设备:

需要注意的是,无论何时我们要对多个项进行操作, 它们都必须在同一个设备上。 例如,如果我们对两个张量求和, 我们需要确保两个张量都位于同一个设备上, 否则框架将不知道在哪里存储结果,甚至不知道在哪里执行计算

def try_gpu(i=0): #@save

"""如果存在,则返回gpu(i),否则返回cpu()"""

if torch.cuda.device_count() >= i + 1:

return torch.device(f'cuda:{i}')

return torch.device('cpu')

Y = torch.rand(2, 3, device=try_gpu(1))

存在第二个gpu上

演示不同设备的张量如何运算:需要复制一份

关于 Z.cuda(1) is Z这个表达式,它的结果是取决于 Z 的当前设备位置的。让我详细解释一下:

核心原理

PyTorch 的张量操作方法遵循"原地操作原则":

  • 如果张量已经 在目标设备上,.cuda()会返回原张量本身 (原地操作,is为 True)

  • 如果张量不在 目标设备上,.cuda()会创建新的张量副本 (返回新对象,is为 False)

.cuda(xx)就是复制/返回一份

拓展:如何知道一个东西有啥方法属性(重要)

1 print(type(xx))

2 暴力print该东西print(dir(xx))

对于 PyTorch 张量,最常用的属性包括:

属性 说明 示例
.device 张量所在的设备 device(type='cuda', index=0)
.dtype 数据类型 torch.float32
.shape或 .size() 形状/尺寸 torch.Size([64, 3, 3, 3])
.ndim 维度数量 4
.requires_grad 是否需要梯度 True/False
.grad 梯度值 通常为 None或张量
.is_cuda 是否在 GPU 上 True/False
.is_leaf 是否是计算图的叶节点 True/False
相关推荐
apple-mapping11 小时前
网络RTK定位学习总结
学习·网络rtk
楚山之石11 小时前
【Lancet Neurology 】多发性硬化认知障碍的 SDMT 筛查、灰质萎缩标志与认知康复循证路径
图像处理·人工智能·学习·mri
海海不掉头发13 小时前
CSDN博客_时序预测9模型复现对比
人工智能·学习·软件工程
蓝祁子yoky15 小时前
Qt学习日记 Day13:网络编程(一)-TCP基础与Socket实战
网络·qt·学习
架构师伯子明16 小时前
Ros 学习十三:IK Demo
学习
小羊没烦恼!16 小时前
关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
java·服务器·网络·学习·负载均衡
幼儿园蛋小黄16 小时前
从 STM32N647 的 AI 部署入门嵌入式:一条可落地的学习路线
人工智能·stm32·学习
Y.99918 小时前
电脑黑屏只有鼠标能动
学习
架构师伯子明18 小时前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
叼烟扛炮18 小时前
[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战
服务器·开发语言·网络·笔记·学习·langchain