Pytorch模型训练-----------数据集加载之ImageFolder之全过程

本文详细介绍了如何使用PyTorch的ImageFolder数据加载器,包括参数解读、数据结构展示、如何处理原始图像和应用transform,以及如何构建训练数据集和使用Dataloader。重点展示了如何将PILImage转为张量并配合transform进行预训练数据准备。
部署运行你感兴趣的模型镜像

数据集加载之ImageFolder

ImageFolder一个通用的数据加载器,数据集中的数据以以下方式组织

函数如下

ImageFolder(root, transform``=``None``, target_transform``=``None``, loader``=``default_loader)

参数解释

  • root 指定路径加载图片

  • transform:对PIL Image进行的转换操作,transform的输入是使用loader读取图片的返回对象

  • target_transform:对label的转换

  • loader:给定路径后如何读取图片,默认读取为RGB格式的PIL Image对象

label是按照文件夹名顺序排序后存成字典,即{类名:类序号(从0开始)},一般来说最好直接将文件夹命名为从0开始的数字,这样会和ImageFolder实际的label一致,如果不是这种命名规范,建议看看self.class_to_idx属性以了解label和文件夹名的映射关系

img

可见分成了cat和dog两类

import torchvision.datasets as dset
dataset = dset.ImageFolder('./data/dogcat_2') #没有transform,先看看取得的原始图像数据
print(dataset.classes)  #根据分的文件夹的名字来确定的类别
print(dataset.class_to_idx) #按顺序为这些类别定义索引为0,1...
print(dataset.imgs) #返回从所有文件夹中得到的图片的路径以及其类别

返回

['cat', 'dog']
{'cat': 0, 'dog': 1}
[('./data/dogcat_2/cat/cat.12484.jpg', 0), ('./data/dogcat_2/cat/cat.12485.jpg', 0), ('./data/dogcat_2/cat/cat.12486.jpg', 0), ('./data/dogcat_2/cat/cat.12487.jpg', 0), ('./data/dogcat_2/dog/dog.12496.jpg', 1), ('./data/dogcat_2/dog/dog.12497.jpg', 1), ('./data/dogcat_2/dog/dog.12498.jpg', 1), ('./data/dogcat_2/dog/dog.12499.jpg', 1)]

查看得到的图片数据:

#从返回结果可见得到的数据仍是PIL Image对象
print(dataset[0])
print(dataset[0][0])
print(dataset[0][1]) #得到的是类别0,即cat

返回:

(<PIL.Image.Image image mode=RGB size=497x500 at 0x11D99A9B0>, 0)
<PIL.Image.Image image mode=RGB size=497x500 at 0x11DD24278>
0

再通过transform变成张量

 data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(224),
                                     transforms.RandomHorizontalFlip(),
                                     transforms.ToTensor()
                                     ]),
        "val": transforms.Compose([transforms.Resize((224, 224)),  # cannot 224, must (224, 224)
                                   transforms.ToTensor()
                                   ])}

    train_dataset = datasets.ImageFolder(root=os.path.join(data_root, "train"),
                                         transform=data_transform["train"])
    
    print(train_dataset[0])
	print(train_dataset[0][0])
	print(train_dataset[0][1]) #得到的是类别0,即cat

得到

(tensor([[[0.3765, 0.3765, 0.3765,  ..., 0.3765, 0.3765, 0.3765],
         [0.3765, 0.3765, 0.3765,  ..., 0.3765, 0.3765, 0.3765],
         [0.3804, 0.3804, 0.3804,  ..., 0.3765, 0.3765, 0.3765],
         ...,
         [0.4941, 0.4941, 0.4902,  ..., 0.3804, 0.3765, 0.3765],
         [0.5098, 0.5098, 0.5059,  ..., 0.3804, 0.3765, 0.3765],
         [0.5098, 0.5098, 0.5059,  ..., 0.3804, 0.3765, 0.3765]],

        [[0.5686, 0.5686, 0.5686,  ..., 0.5843, 0.5804, 0.5804],
         [0.5686, 0.5686, 0.5686,  ..., 0.5843, 0.5804, 0.5804],
         [0.5725, 0.5725, 0.5725,  ..., 0.5843, 0.5804, 0.5804],
         ...,
         [0.5686, 0.5686, 0.5686,  ..., 0.5961, 0.5922, 0.5922],
         [0.5686, 0.5686, 0.5686,  ..., 0.5961, 0.5922, 0.5922],
         [0.5686, 0.5686, 0.5686,  ..., 0.5961, 0.5922, 0.5922]],

        [[0.4824, 0.4824, 0.4824,  ..., 0.4902, 0.4902, 0.4902],
         [0.4824, 0.4824, 0.4824,  ..., 0.4902, 0.4902, 0.4902],
         [0.4863, 0.4863, 0.4863,  ..., 0.4902, 0.4902, 0.4902],
         ...,
         [0.3647, 0.3686, 0.3804,  ..., 0.4824, 0.4784, 0.4784],
         [0.3451, 0.3490, 0.3608,  ..., 0.4824, 0.4784, 0.4784],
         [0.3451, 0.3490, 0.3608,  ..., 0.4824, 0.4784, 0.4784]]]), 0)
         
         省略
         图像Tensor [........]
         标签Tensor [0]

可以知道train_dataset[0]是一个tuple里面一个是张量一个是标量

    print(train_dataset[0][0].shape)
    print(train_dataset[0][1])

返回

torch.Size([3, 224, 224])
0

DataLoader产生批训练数据

for epoch in range(epoch_num):
        for image, label in train_loader:
			print("label: ", labels, labels.dtype)
            print("imges: ", images, images.dtype)

返回

label:  tensor([0]) torch.int64
    
imges:  tensor([[[[0.2275, 0.2275, 0.2235,  ..., 0.2196, 0.2196, 0.2196],
          [0.2275, 0.2275, 0.2235,  ..., 0.2196, 0.2196, 0.2196],
          [0.2235, 0.2235, 0.2235,  ..., 0.2157, 0.2157, 0.2157],
          ...,
          [0.2392, 0.2392, 0.2392,  ..., 0.2235, 0.2235, 0.2235],
          [0.2353, 0.2353, 0.2353,  ..., 0.2235, 0.2275, 0.2275],
          [0.2353, 0.2353, 0.2353,  ..., 0.2235, 0.2275, 0.2275]],

         [[0.2392, 0.2392, 0.2353,  ..., 0.2275, 0.2275, 0.2275],
          [0.2392, 0.2392, 0.2353,  ..., 0.2275, 0.2275, 0.2275],
          [0.2353, 0.2353, 0.2353,  ..., 0.2235, 0.2235, 0.2235],
          ...,
          [0.2275, 0.2275, 0.2314,  ..., 0.2196, 0.2196, 0.2196],
          [0.2235, 0.2235, 0.2275,  ..., 0.2196, 0.2196, 0.2196],
          [0.2235, 0.2235, 0.2275,  ..., 0.2196, 0.2196, 0.2196]],

         [[0.1961, 0.1961, 0.1961,  ..., 0.1765, 0.1765, 0.1765],
          [0.1961, 0.1961, 0.1961,  ..., 0.1765, 0.1765, 0.1765],
          [0.1922, 0.1922, 0.1922,  ..., 0.1725, 0.1725, 0.1725],
          ...,
          [0.1529, 0.1529, 0.1529,  ..., 0.1686, 0.1686, 0.1686],
          [0.1490, 0.1490, 0.1490,  ..., 0.1686, 0.1686, 0.1686],
          [0.1490, 0.1490, 0.1490,  ..., 0.1686, 0.1686, 0.1686]]]]) torch.float32

enumerate加载

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

可以用这个循环加载batchsize下面的每一元组,来得到相应的图片及标签

多元素赋值

当Python检测到等号左边是多个变量,右边是list或者是tuple之后,会自动执行list和tuple的解压,将它依次赋值给对应的元素

l = [1, 2]
a, b = l

所以可以

for step, data in enumerate(train_bar):
            images, labels = data

最后nn.CrossEntropyLoss()计算loss回归

nn.CrossEntropyLoss()nn.logSoftmax()nn.NLLLoss()的整合,可以直接使用它来替换网络中的这两个操作。下面我们来看一下计算过程。

img

其中x是网络的输出向量,class是真实标签

举个例子,一个三分类网络对某个输入样本的输出为[-0.7715, -0.6205,-0.2562],该样本的真实标签为0,则用nn.CrossEntropyLoss()计算的损失为

img

参考链接讲的很好

参考二

您可能感兴趣的与本文相关的镜像

PyTorch 2.9

PyTorch 2.9

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

### 如何使用 Tiny-Imagenet 数据集进行模型训练 #### 准备工作 为了能够顺利地使用Tiny-Imagenet数据集进行模型训练,首先要确保安装好必要的库和工具。通常情况下,这涉及到Python编程语言以及深度学习框架如PyTorch的安装。 #### 加载数据集 加载Tiny-Imagenet数据集可以通过自定义Dataloader来实现。由于此数据集结构特殊,因此需要编写特定代码以适应其目录布局[^1]: ```python from torchvision import transforms, datasets import torch.utils.data as data transform_train = transforms.Compose([ transforms.RandomResizedCrop(64), transforms.RandomHorizontalFlip(), transforms.ToTensor(), ]) train_dataset = datasets.ImageFolder(root='path_to_tiny_imagenet/train', transform=transform_train) train_loader = data.DataLoader(train_dataset, batch_size=64, shuffle=True) ``` 这段代码展示了如何设置变换操作(例如随机裁剪、水平翻转),并将这些转换应用于从指定路径读取到的训练图像文件夹中的每一张图片。 #### 构建模型架构 构建合适的神经网络对于解决图像分类问题是至关重要的。考虑到Tiny-Imagenet的特点——即较小规模但仍具有挑战性的多类识别任务,可以考虑采用已经过大规模数据预训练过的卷积神经网络作为起点,并在此基础上调整最后一层全连接层以便匹配目标数量的类别数[^3]: ```python import torchvision.models as models model = models.resnet18(pretrained=True) num_ftrs = model.fc.in_features model.fc = nn.Linear(num_ftrs, 200) # 将最后线性层改为输出200维向量对应于tiny imagenet 的200个类别 ``` 这里选择了ResNet18作为一个例子;当然也可以尝试其他类型的CNNs或者其他更复杂的体系结构取决于具体需求和个人偏好。 #### 定义损失函数与优化器 选择适当的损失函数和优化算法同样重要。交叉熵损失常被用来衡量预测分布与真实标签之间的差异,在多分类问题上表现良好。Adam是一种常用的梯度下降方法,因为它能够在大多数时候提供稳定而有效的参数更新过程: ```python criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) ``` #### 开始训练循环 一旦完成了上述准备工作之后就可以进入实际的训练阶段了。下面给出了一段简单的训练脚本片段,其中包含了前向传播计算loss值、反向传播更新权重等基本步骤: ```python device = 'cuda' if torch.cuda.is_available() else 'cpu' model.to(device) for epoch in range(num_epochs): running_loss = 0.0 for inputs, labels in train_loader: inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print(f'[Epoch {epoch+1}] Loss: {running_loss/len(train_loader)}') ``` 通过以上几个部分的操作指南,应该可以帮助完成基于Tiny-Imagenet数据集上的初步模型训练流程。需要注意的是,在实践中可能还需要进一步调参优化,比如调整batch size大小、改变learning rate衰减策略等等,这些都是提高最终效果不可或缺的一部分。
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值