第三十四天打卡

news2025/5/25 5:49:31

DAY 34 GPU训练及类的call方法
知识点回归:

CPU性能的查看:看架构代际、核心数、线程数
GPU性能的查看:看显存、看级别、看架构代际
GPU训练的方法:数据和模型移动到GPU device上
类的call方法:为什么定义前向传播时可以直接写作self.fc1(x)
作业

复习今天的内容,在巩固下代码。思考下为什么会出现这个问题。

# ------------------- 数据准备部分 -------------------
# 导入需要的库:sklearn用于数据处理,torch用于深度学习,matplotlib用于可视化
from sklearn.datasets import load_iris         # 加载经典鸢尾花数据集
from sklearn.model_selection import train_test_split  # 划分训练集和测试集
from sklearn.preprocessing import MinMaxScaler        # 数据归一化工具
import torch                                         # PyTorch深度学习框架
import torch.nn as nn                                # 神经网络模块
import torch.optim as optim                          # 优化器模块
import matplotlib.pyplot as plt                      # 可视化库
import time                                          # 用于计算训练时长
 
# 加载鸢尾花数据集(4特征,3分类)
iris = load_iris()
X = iris.data  # 特征数据(形状:[150, 4],150个样本,4个特征)
y = iris.target  # 标签数据(形状:[150],0-2代表3种鸢尾花)
 
# 划分训练集和测试集(80%训练,20%测试,random_state固定随机种子保证结果可复现)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 
# 数据归一化(将特征值缩放到[0,1]区间,避免神经网络因输入尺度差异训练不稳定)
scaler = MinMaxScaler()          # 创建归一化工具
X_train = scaler.fit_transform(X_train)  # 用训练集拟合归一化参数并转换
X_test = scaler.transform(X_test)        # 用训练集的参数转换测试集(保证数据分布一致)
 
# 将数据转换为PyTorch张量(PyTorch模型只能处理张量数据)
# 特征数据用FloatTensor(32位浮点数),标签用LongTensor(64位整数,用于分类任务)
X_train = torch.FloatTensor(X_train)
y_train = torch.LongTensor(y_train)
X_test = torch.FloatTensor(X_test)
y_test = torch.LongTensor(y_test)
 
# ------------------- GPU设备配置 -------------------
# 检查是否有可用的GPU:若有则使用GPU加速,否则使用CPU(PyTorch会自动处理设备间数据迁移)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"当前使用的设备:{device}")  # 打印当前设备,确认是否启用GPU
 
# ------------------- 模型定义(全连接神经网络) -------------------
# 定义一个多层感知机(MLP)模型,继承自nn.Module(PyTorch所有模型的基类)
class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()  # 调用父类构造函数(必须)
        # 定义网络层:输入层→隐藏层→输出层
        self.fc1 = nn.Linear(4, 10)   # 输入层(4特征)→隐藏层(10神经元):线性变换
        self.relu = nn.ReLU()         # 激活函数(引入非线性,增强模型表达能力)
        self.fc2 = nn.Linear(10, 3)   # 隐藏层(10神经元)→输出层(3类别):线性变换
 
    def forward(self, x):
        # 前向传播逻辑(模型如何从输入计算输出)
        x = self.fc1(x)   # 输入层到隐藏层:4维特征→10维隐藏状态
        x = self.relu(x)  # 激活函数:过滤负激活值,保留有用特征
        x = self.fc2(x)   # 隐藏层到输出层:10维隐藏状态→3维输出(未归一化的分类分数)
        return x
 
# ------------------- 模型与数据移动到GPU -------------------
# 将模型和数据迁移到GPU(若可用),GPU的并行计算能大幅加速训练
model = MLP().to(device)   # 模型迁移到GPU/CPU(自动判断)
X_train = X_train.to(device)  # 训练特征数据迁移到GPU
y_train = y_train.to(device)  # 训练标签迁移到GPU
X_test = X_test.to(device)    # 测试特征数据迁移到GPU
y_test = y_test.to(device)    # 测试标签迁移到GPU
 
# ------------------- 训练配置 -------------------
criterion = nn.CrossEntropyLoss()  # 损失函数:交叉熵(适合多分类任务)
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 优化器:随机梯度下降(学习率0.01)
num_epochs = 20000  # 训练轮数(完整遍历训练集的次数)
losses = []         # 记录每轮训练的损失值(用于后续可视化)
 
# ------------------- 训练循环 -------------------
# 记录训练开始时间(用于计算总时长)
start_time = time.time()
 
for epoch in range(num_epochs):
    # 前向传播:模型根据输入数据计算预测值
    outputs = model(X_train)  # 隐式调用__call__方法,等价于model.forward(X_train)
    
    # 计算损失:预测值与真实标签的差异(越小说明模型越好)
    loss = criterion(outputs, y_train)
    
    # 反向传播与参数更新
    optimizer.zero_grad()  # 清空历史梯度(避免梯度累加)
    loss.backward()        # 反向传播计算梯度(自动求导)
    optimizer.step()       # 根据梯度更新模型参数(优化器核心操作)
    
    # 记录损失值(转换为Python标量,避免内存占用)
    losses.append(loss.item())
    
    # 每1000轮打印一次训练进度(方便观察训练是否收敛)
    if (epoch + 1) % 1000 == 0:
        print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}")
 
# 计算训练总时长
end_time = time.time()
train_duration = end_time - start_time
print(f"\n训练完成!总训练时长:{train_duration:.2f} 秒")
 
# ------------------- 可视化训练损失 -------------------
plt.figure(figsize=(10, 6))  # 设置画布大小
plt.plot(range(num_epochs), losses)  # 绘制损失曲线(x轴:轮数,y轴:损失值)
plt.xlabel("Epoch")           # x轴标签:训练轮数
plt.ylabel("Loss")            # y轴标签:损失值
plt.title(f"Training Loss on {device}")  # 图表标题:显示训练设备
plt.grid(True)                # 显示网格线(方便观察趋势)
plt.show()  # 显示图表
 
# 在PyTorch中,所有自定义的模型(如 MLP 类)都继承自 nn.Module 。
# nn.Module 类内部实现了 __call__ 方法,其核心逻辑如下:
class Module:
    def __call__(self, *args, **kwargs):
        # 执行前向传播前的钩子(Hook)
        result = self.forward(*args, **kwargs)  # 调用用户定义的forward方法
        # 执行前向传播后的钩子(Hook)
        return result
# 因此,当我们调用 model(X_train) 时,实际上触发了 __call__ 方法,
# 而 __call__ 方法内部会调用用户定义的 forward 方法。直接使用 model(x) 比显式调用 model.forward(x) 更推荐,
# 因为它会自动处理钩子(如梯度监控、中间变量记录等)。
# 总结
# - GPU训练的核心是将模型和数据移动到 device (通过 .to(device) 方法)。
# - nn.Module 的 __call__ 方法隐式调用 forward ,是PyTorch设计的关键机制,简化了代码编写。
# - 实际训练中,GPU能显著加速计算(尤其是大模型或大数据集),但需确保显卡显存足够(避免OOM错误)。
 
'''
记录次数与剩余时长无明显线性关系的主要原因可从以下几个角度分析:
### 1. 核心计算耗时占比主导
训练总时长的核心瓶颈是GPU上的 前向传播、反向传播、参数更新 等计算操作(由 model(X_train) 、 loss.backward() 、
optimizer.step() 主导)。这些操作依赖GPU并行计算,速度远快于CPU的辅助操作(如 losses.append() 或 print )。
即使记录次数增加(如从10次到200次),CPU辅助操作的总耗时在整体训练时长中的占比极低(可能不足1%),
因此对剩余时长(总时长-3秒)的影响不显著。
### 2. GPU与CPU的异步性
PyTorch中,GPU计算(如模型推理、梯度计算)与CPU操作(如 loss.item() 将GPU张量转为CPU标量、 append 到列表)是 
异步执行 的。当GPU完成一个epoch的计算后,CPU会快速处理记录操作(几微秒到几毫秒),
而GPU可能已开始下一个epoch的计算。这种异步机制使得CPU辅助操作不会阻塞GPU的核心计算,
因此记录次数的增加不会线性延长总时长。
### 3. Python列表操作的高效性
losses.append(loss.item()) 是Python列表的 O(1)时间复杂度操作 (均摊时间),
即使记录200次,总耗时也仅为几十毫秒(远小于单个epoch的GPU计算时间)。
而 print 语句的IO操作虽然可能有波动(如终端输出延迟),但在20000轮训练中,
这种波动会被平均化,导致剩余时长的变化不规律。
### 4. 简单模型的计算量过小
鸢尾花数据集(150样本、4特征)和MLP模型(仅2层全连接)的计算量极小,单个epoch的GPU计算时间可能仅需 几微秒到几十微秒 。
此时,记录操作的耗时(如 print 的IO延迟)可能与核心计算时间处于同一数量级,
导致剩余时长的波动(如10.43秒→9.74秒)更多由环境噪声(如系统进程调度、GPU温度)引起,而非记录次数本身。
### 结论
记录次数的增加带来的额外耗时(CPU辅助操作)在总训练时长中占比极低,
且受GPU异步计算和简单模型的影响,剩余时长与记录次数无显著线性关系。
这一现象符合“核心计算主导总时长”的规律,辅助操作的影响可忽略。
'''
当前使用的设备:cpu
Epoch [1000/20000], Loss: 0.6529
Epoch [2000/20000], Loss: 0.3957
Epoch [3000/20000], Loss: 0.2886
Epoch [4000/20000], Loss: 0.2177
Epoch [5000/20000], Loss: 0.1712
Epoch [6000/20000], Loss: 0.1408
Epoch [7000/20000], Loss: 0.1204
Epoch [8000/20000], Loss: 0.1063
Epoch [9000/20000], Loss: 0.0961
Epoch [10000/20000], Loss: 0.0885
Epoch [11000/20000], Loss: 0.0827
Epoch [12000/20000], Loss: 0.0782
Epoch [13000/20000], Loss: 0.0746
Epoch [14000/20000], Loss: 0.0717
Epoch [15000/20000], Loss: 0.0693
Epoch [16000/20000], Loss: 0.0672
Epoch [17000/20000], Loss: 0.0655
Epoch [18000/20000], Loss: 0.0640
Epoch [19000/20000], Loss: 0.0627
Epoch [20000/20000], Loss: 0.0615
 
训练完成!总训练时长:10.48 秒

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385122.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

配置tomcat时,无法部署工件该怎么办?

当我们第一次在IDEA中创建Java项目时,配置tomcat可能会出现无法部署工件的情况,如图: 而正常情况应该是: 那么该如何解决呢? 步骤一 点开右上角该图标,会弹出如图页面 步骤二 步骤三 步骤四

.NET外挂系列:8. harmony 的IL编织 Transpiler

一:背景 1. 讲故事 前面文章所介绍的一些注入技术都是以方法为原子单位,但在一些罕见的场合中,这种方法粒度又太大了,能不能以语句为单位,那这个就是我们这篇介绍的 Transpiler,它可以修改方法的 IL 代码…

基于netty实现视频流式传输和多线程传输

文章目录 业务描述业务难点流式传输客户端(以tcp为例)服务端测试类测试步骤多线程传输客户端服务端测试类测试步骤多线程流式传输总结业务描述 多台终端设备持续给数据服务器(外)发送视频数据,数据服务器(外)通过HTTP协议将数据经过某安全平台转到数据服务器(内),数据…

全面指南:使用Node.js和Python连接与操作MongoDB

在现代Web开发中,数据库是存储和管理数据的核心组件。MongoDB作为一款流行的NoSQL数据库,以其灵活的数据模型、高性能和易扩展性广受开发者欢迎。无论是使用Node.js还是Python,MongoDB都提供了强大的官方驱动和第三方库,使得数据库…

游戏引擎学习第308天:调试循环检测

回顾并为今天的内容做准备 我们正在进行游戏开发中的精灵(sprite)排序工作,虽然目前的实现已经有了一些改进,情况也在逐步好转,我们已经实现了一个图结构的排序算法,用来处理精灵渲染顺序的问题。然而&…

WPF性能优化之延迟加载(解决页面卡顿问题)

文章目录 前言一. 基础知识回顾二. 问题分析三. 解决方案1. 新建一个名为DeferredContentHost的控件。2. 在DeferredContentHost控件中定义一个名为Content的object类型的依赖属性,用于承载要加载的子控件。3. 在DeferredContentHost控件中定义一个名为Skeleton的ob…

移植 FART 到 Android 10 实现自动化脱壳

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ FART 源码 FART 是 ART 环境下基于主动调用的自动化脱壳方案。 关于 FART 详细介绍参考: FART 自动化脱壳框架简介与脱壳点的选择 FART 主动调用…

COMPUTEX 2025 | 广和通创新解决方案共筑AI交互新纪元

5月20日至23日,广和通携多领域创新解决方案亮相2025年台北国际电脑展(COMPUTEX 2025),台北南港展览馆#K0727a展位。此次展会,广和通围绕“Advancing Connectivity Intelligent Future”为主题,设置四大核心…

了解Android studio 初学者零基础推荐(3)

kotlin中的数据类及对象 使用泛型创建可重复使用的类 我们将常在线答题考试,有的考试题型包括判断,或者填空,以及数学题,此外试题内容还包括难易程度:"easy”,"medium","hard",…

Spring 定时器和异步线程池 实践指南

前言:Spring:异步线程池和定时器 原理篇 一、Spring Scheduler 1. 创建一个 SpringBoot项目,在启动类上添加 EnableScheduling 注解,表示开启定时任务。 2. 创建SchedulerService,在方法上面启用Scheduled 注解 在方…

零基础设计模式——创建型模式 - 生成器模式

第二部分:创建型模式 - 生成器模式 (Builder Pattern) 前面我们学习了单例、工厂方法和抽象工厂模式,它们都关注如何创建对象。生成器模式(也常被称为建造者模式)是另一种创建型模式,它专注于将一个复杂对象的构建过程…

MD编辑器推荐【Obsidian】含下载安装和实用教程

为什么推荐 Obsidian ? 免费 (Typora 开始收费了)Typora 实现的功能,它都有!代码块可一键复制 文件目录支持文件夹 大纲支持折叠、搜索 特色功能 – 白板 特色功能 – 关系图谱 下载 https://pan.baidu.com/s/1I1fSly…

I-CON: A UNIFYING FRAMEWORK FOR REPRESENTATION LEARNING

I-con:表示学习的统一框架 基本信息 ICLR 2025 博客贡献人 田心 作者 Shaden Alshammari, John Hershey, Axel Feldmann, William T. Freeman, Mark Hamilton 关键词 I-Con框架,表征学习,损失函数统一框架 摘要 随着表征学习领域的快速发展,各类…

Missashe线代题型总结

Missashe线性代数考研题型总结 说明:这篇笔记用于博主对"线代"常考题型进行总结,99%为真题,大概可能应该会逐步更新解题思路。有目录可直接检索。 第一章 行列式 1 具体行列式计算 1)么字型 2015 数一 2016 数一三…

蓝桥杯13届 卡牌

问题描述 这天, 小明在整理他的卡牌。 他一共有 n 种卡牌, 第 i 种卡牌上印有正整数数 i(i∈[1,n]), 且第 i 种卡牌 现有 ai​ 张。 而如果有 n 张卡牌, 其中每种卡牌各一张, 那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌, 拿出了 m 张空白牌, 他可以在上面…

安卓开发用到的设计模式(1)创建型模式

安卓开发用到的设计模式(1)创建型模式 文章目录 安卓开发用到的设计模式(1)创建型模式1. 单例模式(Singleton Pattern)2. 工厂模式(Factory Pattern)3. 抽象工厂模式(Abs…

线程的一些基本知识

前言 最近在学习线程,线程与进程是面试中可能常考的问题,我总结了线程的一些知识。分享给大家,希望可以帮组到大家。 线程知识总结(包含与进程的区别) 结语 希望可以帮助到有需要的人,bye~~

【Python打卡Day30】模块与包的导入@浙大疏锦行

#一、导入官方库 我们复盘下学习python的逻辑,所谓学习python就是学习python常见的基础语法学习你所处理任务需要用到的第三方库 所以你用到什么学什么库即可。学习python本身就是个伪命题,就像你说学习科目一样,你没说清晰你学习的具体科目…

26考研|高等代数:λ-矩阵

前言 本章知识点较为简单,是作为工具性的一章,在学习过程中,要注意区分行列式因子、不变因子以及初等因子,同时还要对若尔当标准型的计算应该足够熟悉,尤其是复矩阵的若尔当标准型计算是十分重要的。 课本重点回顾 …

我店模式系统开发打造本地生活生态商圈

在当今快节奏的商业环境中,商家们面临着越来越多的挑战,包括市场竞争加剧、消费者需求多样化以及运营效率的提高等。为了应对这些挑战,越来越多的商家开始寻求信息化解决方案,以提升运营效率和客户体验。我的店模式系统平台应运而…