news 2026/6/8 23:09:34

记录softmax

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记录softmax

向量backward需要指定维度:

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True) y = x * 2 # y = [2.0, 4.0, 6.0] # ✅ 向量需要指定梯度参数 y.backward(torch.tensor([1.0, 1.0, 1.0])) print(f"x的梯度: {x.grad}") # 输出: tensor([2., 2., 2.])

读取数据集:

# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式, # 并除以255使得所有像素的数值均在0~1之间 # 创建数据转换管道,将PIL图像转换为PyTorch张量 # 这个转换会自动将像素值从[0, 255]范围缩放到[0.0, 1.0]范围 # 同时将图像维度从(H, W, C)调整为(C, H, W)格式,符合PyTorch的输入要求 trans = transforms.ToTensor() # 下载并加载Fashion-MNIST训练数据集 # root="../data": 指定数据集存储的根目录为上级目录中的"data"文件夹 # train=True: 表示加载训练集(共60,000张图片) # transform=trans: 对每张图片应用上面定义的转换 # download=True: 如果数据集不存在,则自动从互联网下载 mnist_train = torchvision.datasets.FashionMNIST( root="../data", train=True, transform=trans, download=True) # 下载并加载Fashion-MNIST测试数据集 # train=False: 表示加载测试集(共10,000张图片) # 其他参数含义与训练集相同 mnist_test = torchvision.datasets.FashionMNIST( root="../data", train=False, transform=trans, download=True)

例子:

创建迭代器dataloader

# 创建DataLoader,设置批次大小为18 loader = data.DataLoader(mnist_train, batch_size=18) # iter(loader) 创建迭代器 # next() 获取第一个批次的数据 X, y = next(iter(loader))

dataloader迭代机制:重要

# 查看DataLoader的内部实现 train_loader = DataLoader(mnist_train, batch_size=4, shuffle=True) print("DataLoader的迭代机制:") print("="*50) # 方法1: 使用for循环(最常用) print("方法1: 使用for循环(内部会自动调用iter)") count = 0 for batch_idx, (images, labels) in enumerate(train_loader): print(f" 批次 {batch_idx}: images.shape={images.shape}") count += 1 if count >= 2: # 只显示前2个批次 break print() # 方法2: 手动使用iter()和next() print("方法2: 手动使用iter()和next()") train_iter = iter(train_loader) # 创建迭代器 batch1 = next(train_iter) # 获取第一个批次 batch2 = next(train_iter) # 获取第二个批次 print(f" 批次1: images.shape={batch1[0].shape}") print(f" 批次2: images.shape={batch2[0].shape}") print() # 方法3: 使用iter()和next()的组合 print("方法3: 使用iter()和next()的组合(一次性)") # 这是你代码中的写法 single_batch = next(iter(train_loader)) print(f" 单个批次: images.shape={single_batch[0].shape}")

Python 迭代器和可迭代对象的区别

# 简单示例 numbers = [1, 2, 3, 4, 5] print("列表是可迭代对象:") print(f" hasattr(numbers, '__iter__'): {hasattr(numbers, '__iter__')}") print(f" hasattr(numbers, '__next__'): {hasattr(numbers, '__next__')}") print() # 但列表不是迭代器 try: next(numbers) except TypeError as e: print(f"直接对列表使用next()会报错: {e}") print() # 需要先用iter()创建迭代器 numbers_iter = iter(numbers) print("迭代器:") print(f" numbers_iter类型: {type(numbers_iter)}") print(f" hasattr(numbers_iter, '__next__'): {hasattr(numbers_iter, '__next__')}") print() # 现在可以使用next() print("使用迭代器:") print(f" next(numbers_iter): {next(numbers_iter)}") print(f" next(numbers_iter): {next(numbers_iter)}") print(f" next(numbers_iter): {next(numbers_iter)}")

总结

  1. 必须使用iter()DataLoader是可迭代对象,但不是迭代器。必须先用iter()将其转换为迭代器,然后才能用next()获取数据。

  2. next(iter(loader))的工作原理

    • iter(loader):创建一个新的迭代器

    • next(...):从该迭代器获取第一个批次

    • 这个组合每次都会创建新的迭代器,获取第一批数据

  3. 遍历数据集的正确方式

    • 使用for batch in loader:循环

    • 或创建一个迭代器:iterator = iter(loader),然后用next(iterator)手动控制

  4. 你的代码中的写法是合理的:当你只想快速查看一个批次的数据时,next(iter(loader))是最简洁的写法。

所以记住:一定要先用iter()创建迭代器,然后才能用next()获取数据!

enumerate

# 2.1 普通for循环 print("普通for循环:") for item in ['a', 'b', 'c']: print(f" item={item}") # 这里item也不需要预先定义 # 2.2 enumerate自动创建计数器 print("\nenumerate的工作原理:") my_list = ['x', 'y', 'z'] # enumerate返回一个迭代器,每次迭代返回(索引, 值) enumerator = enumerate(my_list) print(f" enumerate(my_list)类型: {type(enumerator)}") # 查看enumerate返回的内容 for pair in enumerator: print(f" enumerate返回: {pair} (类型: {type(pair)})")

高级用法:

# 6.1 自定义起始索引 print("enumerate自定义起始索引:") for batch_idx, (images, labels) in enumerate(loader, start=1): print(f" 批次{batch_idx}: 标签={labels.tolist()}") if batch_idx >= 2: break print() # 6.2 同时获取多个元素 print("同时解包多个元素:") data_list = [('a', 1), ('b', 2), ('c', 3)] for idx, (letter, number) in enumerate(data_list): print(f" idx={idx}, letter={letter}, number={number}") print() # 6.3 在DataLoader中的嵌套循环 print("DataLoader嵌套循环示例:") for epoch in range(2): # 2个epoch print(f"Epoch {epoch}:") for batch_idx, (images, labels) in enumerate(loader): if batch_idx < 2: # 每个epoch只显示前2个批次 print(f" 批次{batch_idx}: 标签={labels.tolist()}") print()

softmax实现

# PyTorch不会隐式地调整输入的形状。因此, # 我们在线性层前定义了展平层(flatten),来调整网络输入的形状 # 定义一个简单的神经网络模型 # nn.Sequential 是一个顺序容器,模块将按照它们在构造函数中传入的顺序被添加到计算图中 net = nn.Sequential( nn.Flatten(), # 展平层:将多维输入张量展平为一维 nn.Linear(784, 10) # 全连接层:输入784个特征,输出10个类别 ) # 定义权重初始化函数 def init_weights(m): """初始化网络权重 参数: m: 网络中的一个模块 功能: 如果是线性层(nn.Linear),则使用正态分布初始化其权重, 均值为0,标准差为0.01 """ if type(m) == nn.Linear: # 检查模块类型是否为线性层 # 使用正态分布初始化权重 # nn.init.normal_ 是PyTorch的原地初始化函数 # 参数: # tensor: 要初始化的张量(这里是线性层的权重) # mean: 均值,默认为0 # std: 标准差,这里设置为0.01 nn.init.normal_(m.weight, std=0.01) # 注意:这里没有初始化偏置(bias),因为PyTorch默认偏置初始化为0 # 如果需要初始化偏置,可以添加:nn.init.constant_(m.bias, 0) # 应用权重初始化函数到网络的每一层 # net.apply() 会递归地对网络中的每个模块应用指定的函数 net.apply(init_weights)

训练

# 定义损失函数 # nn.CrossEntropyLoss 是交叉熵损失函数,常用于多分类问题 # reduction='none' 表示不进行降维操作,返回每个样本的损失值 # 如果不设置'reduction',默认是'mean',即返回批次损失的平均值 loss = nn.CrossEntropyLoss(reduction='none') # 定义优化器 # torch.optim.SGD 是随机梯度下降优化器 # 参数: # net.parameters(): 获取网络中所有可训练参数 # lr=0.1: 学习率设置为0.1 trainer = torch.optim.SGD(net.parameters(), lr=0.1) # 设置训练轮数 num_epochs = 10 # 调用训练函数 # d2l.train_ch3 是d2l库中封装好的训练函数 # 参数: # net: 神经网络模型 # train_iter: 训练数据迭代器 # test_iter: 测试数据迭代器 # loss: 损失函数 # num_epochs: 训练轮数 # trainer: 优化器 d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater): #@save """训练模型(定义见第3章) 参数: net: 神经网络模型 train_iter: 训练数据迭代器 test_iter: 测试数据迭代器 loss: 损失函数 num_epochs: 训练轮数 updater: 优化器 """ # 创建动画器,用于可视化训练过程 # xlabel: x轴标签为'epoch' # xlim: x轴范围从1到num_epochs # ylim: y轴范围从0.3到0.9(预期准确率范围) # legend: 图例显示三条曲线:训练损失、训练准确率、测试准确率 animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9], legend=['train loss', 'train acc', 'test acc']) # 开始训练循环 for epoch in range(num_epochs): # 训练一个epoch,返回训练损失和训练准确率 train_metrics = train_epoch_ch3(net, train_iter, loss, updater) # 在测试集上评估准确率 test_acc = evaluate_accuracy(net, test_iter) # 将当前epoch的指标添加到动画器中 # 注意:train_metrics是一个元组,通常包含(train_loss, train_acc) # 所以 train_metrics + (test_acc,) 创建包含三个值的元组 animator.add(epoch + 1, train_metrics + (test_acc,)) # 获取最后一个epoch的训练指标 train_loss, train_acc = train_metrics # 断言:确保训练结果在合理范围内 # 1. 训练损失应该小于0.5 assert train_loss < 0.5, train_loss # 2. 训练准确率应该在0.7到1.0之间 assert train_acc <= 1 and train_acc > 0.7, train_acc # 3. 测试准确率应该在0.7到1.0之间 assert test_acc <= 1 and test_acc > 0.7, test_acc

train封装的函数太多了,需要自己看原文件(softmax-regression-scratch)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 23:08:24

3分钟快速上手:Windows 11/10经典游戏联机终极解决方案

3分钟快速上手&#xff1a;Windows 11/10经典游戏联机终极解决方案 【免费下载链接】ipxwrapper 项目地址: https://gitcode.com/gh_mirrors/ip/ipxwrapper 还在为《红色警戒2》、《星际争霸》、《暗黑破坏神》等经典游戏无法在现代Windows系统上联机而烦恼吗&#xff…

作者头像 李华
网站建设 2026/6/8 23:03:47

Linux 磁盘分区、格式化与挂载

大家好&#xff0c;今天我们来做一次完整的 Linux 磁盘管理实战&#xff0c;亲手完成三块不同类型硬盘的分区、格式化、挂载和文件写入。我们直接进入实战&#xff0c;通过三个题目来练习。首先让我们先添加三块硬盘&#xff0c;以便后面练习&#xff0c;硬盘编号接口类型大小分…

作者头像 李华
网站建设 2026/6/8 22:57:34

BetterNCM安装工具实战指南:告别手动配置的5个高效技巧

BetterNCM安装工具实战指南&#xff1a;告别手动配置的5个高效技巧 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 你是否曾为网易云音乐PC客户端的插件安装而烦恼&#xff1f;手动下载…

作者头像 李华