2020-04-26-Kaggle猫狗识别Pytorch详细搭建过程

本文详细介绍了使用Pytorch进行Kaggle猫狗识别比赛的全过程,包括数据集创建、数据划分、网络搭建、训练过程和模型评估。作者通过自定义数据集类,利用torch.utils.data.Dataset和DataLoader进行数据处理。网络模型采用了ResNet50,并利用预训练权重进行微调。同时,文章还涉及了损失函数、优化器的选择,以及使用tensorboard进行训练日志的可视化。在训练过程中,作者遇到了loss值停滞不前的问题,但预训练的ResNet50模型表现良好。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章源码链接,包括Notebook和对应的Pycharm项目。求个Star!!

需求

Kaggle比赛链接 ,给出猫狗图片,然后预测图片中是狗的概率。

训练集有25,000张图片,测试集12,500 张图片。

]

自己最开始构思大致框架的时候的一个思维导图:

包的导入

需要注意的是将tqdm 改为tqdm.notebook,从而在notebook环境下获得更好的体验。因为导入tqdm的话,会发生进度条打印多次的情况,体验很不好

import os 
import pandas as pd 
from PIL import Image
import torch
from torch.utils.data import Dataset
from torchvision import transforms,models,utils
from tqdm.notebook import tqdm
# from tqdm import tqdm_notebook as tqdm
from torch import nn
import matplotlib.pyplot as plt
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter 
# from torchvision import datasets, transforms,utils

相关文件路径配置,在pycharm项目中将相关路径的配置都统一放在config.py中来管理

train_path = 'D:/AIdata/dog vs cat/train'
test_path = 'D:/AIdata/dog vs cat/test1'
data_root = 'D:/AIdata/dog vs cat/'
csv_path = './submission_valnet.csv'
tensorboard_path='C:/Users/BraveY/Documents/BraveY/AI-with-code/dog-vs-cat/tensortboard'
model_save_path = 'C:/Users/BraveY/Documents/BraveY/AI-with-code/dog-vs-cat/modelDict/dogs-vs-cats-notebook.pth'

数据集的创建

因为Kaggle官方提供的是原始数据,不像之前的手写数字数据集可以从pytorch中直接下载已经处理过的数据集,可以直接将数据放入模型进行训练。因此需要我们自己实现数据集的生成。

数据集生成的总体思路是继承torch.utils.data.Dataset这个类,自己实现__getitem__和__len__这两个私有方法来完成对我们自己数据的读取操作。其中__getitem__这个函数的主要功能是根据样本的索引,返回索引对应的一张图片的图像数据X与对应的标签Y,也就是返回一个对应的训练样本。__len__这个函数的功能比较简单直接返回数据集中样本的个数即可。

具体而言,__getitem__的实现思路比较简单,将索引idx转换为图片的路径,然后用PIL的Image包来读取图片数据,然后将数据用torchvision的transforms转换成tensor并且进行Resize来统一大小(给出的图片尺寸不一致)与归一化,这样一来就可以得到图像数据了。因为训练集中图片的文件名上面带有猫狗的标签,所以标签可以通过对图片文件名split后得到然后转成0,1编码。

在获取标签的时候,因为官方提供的测试数据集中并没有猫狗的标签,所以测试集的标签逻辑稍有不同。我的做法是使用一个train标志来进行区分,对于测试的数据,直接将测试样本的标签变成图片自带的id,这样方便后面输出提交的csv文件。因为测试样本不用计算loss,所以将标签置为id是没问题的。

为了实现将idx索引转换成图片路径,需要在__init__()函数中将所有的图片路径放在一个list中,这可以用os.listdir()来实现,然后就可以根据索引去获得路径了。

需要注意的是,之所以__getitem__()需要根据索引来返回样本,是因为训练数据并不是一次性将所有样本数据加载到内存中,这样太耗内存。而是只用加载对应batch中的一部分数据,所以通过索引来加载送入模型中的一批数据。

class MyDataset(Dataset):
    def __init__(self, data_path:str, train=True, transform=None):
        self.data_path = data_path
        self.train_flag = train
        if transform is None:
            self.transform = transforms.Compose(
            [
                transforms.Resize(size = (224,224)),#尺寸规范
                transforms.ToTensor(),   #转化为tensor
                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
            ])
        else:
            self.transform = transform
        self.path_list = os.listdir(data_path)
    def __getitem__(self, idx: int):
        # img to tensor and label to tensor
        img_path = self.path_list[idx]
        if self.train_flag is True:
            if img_path.split('.')[0] == 'dog' : 
                label = 1
            else:
                label = 0
        else:
            label = int(img_path.split('.')[0]) # split 的是str类型要转换为int
        label = torch.as_tensor(label, dtype=torch.int64) # 必须使用long 类型数据,否则后面训练会报错 expect long
        img_path = os.path.join(self.data_path, img_path)
        img = Image.open(img_path)
        img = self.transform(img)
        return img, label
    def __len__(self) -> int:
        return len(self.path_list)

测试一下,确保Dataset可以正常迭代

train_ds = MyDataset(train_path)
test_ds = MyDataset(test_path,train=False)
for i, item in enumerate(tqdm(train_ds)):
#     pass
    print(item)
    break

输出:

(tensor([[[ 0.5922,  0.6078,  0.6392,  ...,  0.9216,  0.8902,  0.8745],
         [ 0.5922,  0.6078,  0.6392,  ...,  0.9216,  0.8980,  0.8824],
         [ 0.5922,  0.6078,  0.6392,  ...,  0.9216,  0.9059,  0.8902],
         ...,
         [ 0.2078,  0.2157,  0.2235,  ..., -0.9765, -0.9765, -0.9765],
         [ 0.2000,  0.2000,  0.2078,  ..., -0.9843, -0.9843, -0.9843],
         [ 0.1843,  0.1922,  0.2000,  ..., -0.9922, -0.9922, -0.9922]],

        [[ 0.2863,  0.3020,  0.3333,  ...,  0.6000,  0.5843,  0.5686],
     
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值