首页app软件pytorch训练自己的数据集 pytorch训练分类模型

pytorch训练自己的数据集 pytorch训练分类模型

圆圆2025-07-07 23:00:30次浏览条评论

解决PyTorch多标签分类中批次大小不一致问题:模型架构与张量形变管理论文深入探讨了PyTorch多标签图像分类任务中常见的批次大小不一致问题。通过分析自定义模型中的形式层尺寸输出与全连接层输入尺寸不匹配的根本原因,详细阐述了如何精确计算张量形变后的维度,并提供修改后面的PyTorch模型代码。教程强调了张量尺寸追踪的重要性,以及如何正确使用视图操作和nn.Linear层,以确保模型输入输出一致性的一致性,从而解决训练过程中ValueError报错。1. 引言:多标签分类与模型架构挑战

在图像识别任务中,多标签分类(多标签)分类)是一种常见的场景,即一张图片可能同时包含多个独立的类别标签(例如,一张艺术品图片可能同时被标记为“印象派”、“风景画”和“莫奈”)。为了实现此类任务,通常会采用多头(multi-head)模型架构,即在共享的特征提取器之后,为每个分类任务设置独立的分类头。

在PyTorch中构建自定义模型时,尤其是在张量层和全连接层之间进行张量形变(扁平化)时,很容易出现张量尺寸计算错误,导致模型输入批量与输出间歇不一致的问题。这会直接导致训练循环中计算损失时出现ValueError:预期输入batch_size (...) 与目标batch_size (...) 的错误。2. 问题描述与初步尝试

本教程将以一个案例来阐述这个问题。用户尝试为一个Wikiart数据集具体构建一个多标签分类模型,需要同时预测艺术家(艺术家)、风格(风格)和流派(流派三个)标签。

最初,用户尝试基于拥抱面对的ResNetForImageClassification修改其分类头,适应多标签任务。然而,以直接修改model.classifier属性并不能允许修改模型在forward方法中自动包含新增的多个分类头,torchinfo的摘要也证实了这一点,模型结构仍然是单分类输出。#初始尝试:修改训练预模型的头分类(不适用多头输出)# model2.classifier_artist = torch.nn.Sequential(...)# model2.classifier_style = torch.nn.Sequential(...)# model2.classifier_genre = torch.nn.Sequential(...)登录后复制

由于预模型训练修改的复杂性,用户转向构建了一个自定义的PyTorch模型WikiartModel。该模型包含共享的指导层用于导出,然后分叉出三个独立的线性分类头。

import torchimport torch.nn as nnimport torch.nn.function as Fclass WikiartModel(nn.Module): def __init__(self, num_artists, num_genres, num_styles): super(WikiartModel, self).__init__() # 共享心血管层 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding =1) self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) # 最大池化层 # 艺术家分支分类 self.fc_artist1 = nn.Linear(256 * 16 * 16,第512章)# 错误:输入特征维度计算有误 self.fc_artist2 = nn.Linear(512, num_artists) # 流派分类分支 self.fc_genre1 = nn.Linear(256 * 16 * 16, 512) # 错误:输入特征维度计算有误 self.fc_genre2 = nn.Linear(512, num_genres) # 风格分类分支self.fc_style1 = nn.Linear(256 * 16 * 16, 512) # 错误:输入特征维度计算有误 self.fc_style2 = nn.Linear(512, num_styles) defforward(self, x): # 共享心血管层处理 x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = self.pool(F.relu(self.conv3(x))) # 张量形变:将多维特征图展平为一维支持 x = x.view(-1, 256 * 16 * 16) # 错误:展平后的维度计算有误差,且-1可能导致意外行为 # 艺术家分类 arts_out = F.relu(self.fc_artist1(x)) artsiest_out = self.fc_artist2(artists_out) # 流派分类分支 Genre_out = F.relu(self.fc_genre1(x)) Genre_out = self.fc_genre2(genre_out) # 风格分类分支 style_

out = F.relu(self.fc_style1(x)) style_out = self.fc_style2(style_out) return arts_out,genre_out,style_out#设置类别数量num_artists = 129num_genres = 11num_styles = 27登录后复制

当输入数据中断大小为32(即输入张量形状为[32, 3, 224, 224])时,torchinfo显示的模型输出批次大小为98,而不是预期的32,这导致了训练循环中损失计算的ValueError。3. 根本原因分析:张量尺寸计算错误

问题的核心在于平台层输出的特征图尺寸与全连接层nn.Linear的in_features参数不匹配,以及forward方法中x.view操作的错误。

让我们渐进分析输入张量[32, 3, 224, 224]经过校正和池化层后的尺寸变化:输入: [Batch_Size, Channels, Height, Width] -gt; [32, 3, 224, 224]self.conv1: nn.Conv2d(3, 64, kernel_size=3, padding=1) 输出尺寸公式:H_out = (H_in 2*padding - kernel_size)/stride 1224 2*1 - 3 / 1 1 = 224 输出: [32, 64, 224, 224]self.pool: nn.MaxPool2d(2, 2) (kernel_size=2, stride=2) 输出尺寸:H_out = H_in / stride224 / 2 = 112 输出: [32, 64, 112, 112]self.conv2: nn.Conv2d(64, 128, kernel_size=3, padding=1) 输出: [32, 128, 112, 112]self.pool: nn.MaxPool2d(2, 2) 输出: [32, 128, 56, 56]self.conv3: nn.Conv2d(128, 256, kernel_size=3, padding=1) 输出: [32, 256, 56, 56]self.pool: nn.MaxPool2d(2, 2) 最终特征图输出:[32, 256, 28, 28]

因此,在进入全连接层之前,特征图的应该是[Batch_Size, 256, 28, 28]。当将其展平为一维施工时,除了后面尺寸外侧的维度都应相乘:256 * 28 * 28 = 200704。

然而,原始代码中nn.Linear的in_features参数被错误地设置为256 * 16 * 16,这显然与实际的256 * 28 * 28不符。同时,x.view(-1, 256 * 16 * 16)中的-1表示PyTorch会自动推断该维度,但由于其后续设计的维度256 * 16 * 16与实际的展平尺寸不匹配,导致PyTorch在尝试展平时,不得不调整批次大小对应总元素数量,从而产生了98这个错误的批次大小。

4.解决方案:精确计算与正确形变

要此问题,需要进行两处关键修改:修改nn.Linear的in_features参数:将更改为仿真层最终输出特征图的展平尺寸,即256 * 28 * 28。确保修改x.view操作:确保修改展平操作正确,并且批量大小能够正确提供。其推荐使用x.view(x.size(0), -1),其中x.size(0)明确指定了当前张量的批量大小,而-1则让PyTorch自动计算剩余维度的乘积。

以下是修改后的WikiartModel代码:import torchimport torch.nn as nnimport torch.nn.function as Fclass WikiartModel(nn.Module): def __init__(self, num_artists, num_genres, num_styles): super(WikiartModel, self).__init__() # 共享接口层 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding =1) self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) # 计算模型层最终输出的特征图尺寸(例如,对于224x224输入,经过三次卷积pool后为28x28) # 建议在模型初始化时或者通过一个小的dummy_input计算结果 #保证这里的尺寸与实际计算结果一致 self.feature_map_size = 28 #经过三次池化后,224 -gt; 112 -gt; 56 -gt; 28 self.flattened_features = 256 * self.feature_map_size * self.feature_map_size # 256 * 28 * 28 = 200704 # 艺术家分类路径 self.fc_artist1 = nn.Linear(self.flattened_features, 512) # 修改此处输入特征维度 self.fc_artist2 = nn.Linear(512, num_artists) # 流派分类路径 self.fc_genre1 = nn.Linear(self.flattened_features, 512) #修改此处输入特征维度 self.fc_genre2 = nn.Linear(512, num_genres) # 风格分类分支 self.fc_style1 = nn.Linear(self.flattened_features, 512) # 修改此处输入特征维度 self.fc_style2 = nn.Linear(512, num_styles) defforward(self, x): # 共享流程图层处理 x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = self.pool(F.relu(self.con)

v3(x))) # 张量形变:展平张量,获取批次大小 # x.size(0) 获取当前批次大小,-1让PyTorch自动计算剩余维度 x = x.view(x.size(0),-1) # 艺术家分类分支 arts_out = F.relu(self.fc_artist1(x)) arts_out = self.fc_artist2(artists_out) # 流派分类分支 Genre_out = F.relu(self.fc_genre1(x))genre_out = self.fc_genre2(genre_out) # 风格分类分支 style_out = F.relu(self.fc_style1(x)) style_out = self.fc_style2(style_out) return arts_out,genre_out,style_out#类别数量num_artists = 129num_genres = 11num_styles = 27#实例化模型并进行测试 (示例)model = WikiartModel(num_artists, num_genres, num_styles)dummy_input = torch.randn(32, 3, 224, 224) # 批次大小为32的模拟输入artist_output,genre_output, style_output = model(dummy_input)print(fquot;Artist Output Shape: {artist_output.shape}quot;) # 预期: [32, 129]print(fquot;流派输出形状: {genre_output.shape}quot;) # 预期: [32, 11]print(fquot;风格输出形状: {style_output.shape}quot;) # 预期: [32, 27]#同时,torchinfo 的输出也将显示正确的批次大小# from torchinfo import summarise#summary(model, input_size=(32, 3, 224, 224))登录后复制5. 注意事项与最佳实践张量尺寸追踪的重要性:在构建自定义神经网络时,一定要在每一层之后打印(或使用调试工具如torchinfo)张量的形状(tensor.shape或tensor.size()),以确保数据流经网络时尺寸符合预期。这是解决此类问题的最有效方法。x.view(x.size(0),-1)的优势:使用x.size(0)明确指定批次大小,而不是依赖-1来推断所有维度,可以避免在其他展示维度计算错误时导致批次大小被错误推断。这使得代码更加健壮,不易出错。动态计算展示平尺寸:对于更复杂的模型或可变输入尺寸,可以在正向方法中动态计算展示平尺寸。

例如,在展平之前,可以使用num_features = x.numel() // x.size(0)来获取每个样本的特征数量,然后将其用于nn.Linear层的初始化(如果模型结构允许)。但通常,对于固定输入尺寸的模型,预先计算好nn.Linear的in_features是比较常见的做法。预训练模型的使用:如果希望利用预训练模型(如ResNet)的强大特征提取能力,并进行多标签分类,正确的做法是加载预训练模型,冻结其特征提取层,然后替换或在其之上添加自定义的多个分类头。这通常涉及到直接修改模型的分类器或fc属性,并确保转发方法能够正确中断特征传递给这些新的分类头。面对ResNetForImageClassification,可能需要更深入地了解其内部结构或继承并重写其forward方法以实现多头输出。6. 总结

在PyTorch中构建自定义神经网络时,管理张量尺寸是至关重要的一个环。突发大小不一致的问题通常源于图层层输出与全连接层输入之间的尺寸不匹配,以及视图操作的误用。通过精确计算图层输出的特征图尺寸,并采用x.view(x.size(0), -1)这种健壮的展平方式,可以有效解决此类问题,确保数据在网络中超过流动,并避免过程中的ValueError。养成良好的张量形尺寸追踪习惯,将很大程度上提高模型开发的效率和准确性。

以上就是解决PyTorch多标签分类中批次大小不一致问题:架构模型与张量形变管理的详细内容,更多请关注乐哥常识网其他相关文章!

解决PyTorch多
如何用html做网站 如何用html生成pdf
相关内容
发表评论

游客 回复需填写必要信息