首页 > 其他分享 >【预训练-微调】迁移学习项目实战自定义数据集宝可梦精灵-学习笔记

【预训练-微调】迁移学习项目实战自定义数据集宝可梦精灵-学习笔记

时间:2024-11-17 20:44:03浏览次数:3  
标签:__ 定义数据 可梦 self labels 集宝 images import model

本学习笔记来源于B站:深度学习—迁移学习项目实战自定义数据集宝可梦精灵

在本预训练-微调代码中,重点要学习的内容包括:加载官方提供的经典网络架构resnet18和已经训练好的模型,对最后一层全连接层进行修改,改为适合自己任务的网络架构。在此基础上,训练最后一层全连接层,并保存最优模型。

与上一篇 预训练-微调的学习笔记 不同,本视频教程中提供了另一种分割经典网络架构与预训练模型的方法,在代码中主要改动了两个位置。

改动位置一:

from torchvision.models import resnet18      # 加载官网上训练好的 resnet18

改动位置二:

    trained_model = resnet18(pretrained=True)
    # 通过 pretrained=True 指定该模型使用在大规模数据集上(如 ImageNet)预训练的权重。
    model = nn.Sequential(*list(trained_model.children())[:-1],           # [b, 512, 1, 1]
                          # trained_model.children() 返回一个包含该模型所有子模块的迭代器。使用 list(...) 将其转换为列表。
                          # [:-1] 表示切片操作,将列表中的最后一个子模块(通常是分类层)去掉,因此取出除了最后一层以外的所有层(即 1-17层)。
                          nn.Flatten(),         # 添加了一个 Flatten 层     # [b, 512, 1, 1] => [b, 512]
                          nn.Linear(512, 5)     # 添加了一个全连接层(线性层)
                          ).to(device)

主程序完整代码如下:

import torch
from torch import optim, nn
import visdom
from torch.utils.data import DataLoader
from pokemon import Pokemon

############################################ 改动位置一
from torchvision.models import resnet18      # 加载官网上训练好的 resnet18
############################################


batchsz = 32
lr = 1e-3
epochs = 10

device = torch.device('cuda')
torch.manual_seed(1234)

train_db = Pokemon('pokemon', 224, mode='train')
val_db = Pokemon('pokemon', 224, mode='val')
test_db = Pokemon('pokemon', 224, mode='test')
train_loader = DataLoader(train_db, batch_size=batchsz, shuffle=True,
                          num_workers=2)
val_loader = DataLoader(val_db, batch_size=batchsz, num_workers=2)
test_loader = DataLoader(test_db, batch_size=batchsz, num_workers=2)

viz = visdom.Visdom()


def evalute(model, loader):
    model.eval()
    
    correct = 0
    total = len(loader.dataset)

    for x,y in loader:
        x,y = x.to(device), y.to(device)
        with torch.no_grad():
            logits = model(x)
            pred = logits.argmax(dim=1)
        correct += torch.eq(pred, y).sum().float().item()

    return correct / total


def main():

    ############################################ 改动位置二
    trained_model = resnet18(pretrained=True)
    # 通过 pretrained=True 指定该模型使用在大规模数据集上(如 ImageNet)预训练的权重。
    model = nn.Sequential(*list(trained_model.children())[:-1],           # [b, 512, 1, 1]
                          # trained_model.children() 返回一个包含该模型所有子模块的迭代器。使用 list(...) 将其转换为列表。
                          # [:-1] 表示切片操作,将列表中的最后一个子模块(通常是分类层)去掉,因此取出除了最后一层以外的所有层(即 1-17层)。
                          nn.Flatten(),         # 添加了一个 Flatten 层     # [b, 512, 1, 1] => [b, 512]
                          nn.Linear(512, 5)     # 添加了一个全连接层(线性层)
                          ).to(device)
    ############################################

    print(model)

    optimizer = optim.Adam(model.parameters(), lr=lr)
    criteon = nn.CrossEntropyLoss()

    best_acc, best_epoch = 0, 0
    global_step = 0
    viz.line([0], [-1], win='loss', opts=dict(title='loss'))
    viz.line([0], [-1], win='val_acc', opts=dict(title='val_acc'))
    for epoch in range(epochs):

        for step, (x,y) in enumerate(train_loader):

            x, y = x.to(device), y.to(device)

            model.train()
            logits = model(x)
            loss = criteon(logits, y)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            viz.line([loss.item()], [global_step], win='loss', update='append')
            global_step += 1

        if epoch % 1 == 0:

            val_acc = evalute(model, val_loader)
            if val_acc> best_acc:
                best_epoch = epoch
                best_acc = val_acc

                torch.save(model.state_dict(), 'best.mdl')

                viz.line([val_acc], [global_step], win='val_acc', update='append')

    print('best acc:', best_acc, 'best epoch:', best_epoch)

    model.load_state_dict(torch.load('best.mdl'))
    print('loaded from ckpt!')

    test_acc = evalute(model, test_loader)
    print('test acc:', test_acc)


if __name__ == '__main__':
    main()

在主程序中,调用了pokemon,pokemon.py代码如下:

import visdom
import time
import torch
import os, glob
import random, csv
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image


class Pokemon(Dataset):
    def __init__(self, root, resize, mode):
        super(Pokemon, self).__init__()

        self.root = root
        self.resize = resize
        self.name2label = {}
        for name in sorted(os.listdir(os.path.join(root))):
            if not os.path.isdir(os.path.join(root, name)):
                continue

            self.name2label[name] = len(self.name2label.keys())

        self.images, self.labels = self.load_csv('images.csv')

        if mode=='train':      # 60%
            self.images = self.images[:int(0.6*len(self.images))]
            self.labels = self.labels[:int(0.6*len(self.labels))]
        elif mode=='val':     # 20% = 60%->80%
            self.images = self.images[int(0.6*len(self.images)):int(0.8*len(self.images))]
            self.labels = self.labels[int(0.6*len(self.labels)):int(0.8*len(self.labels))]
        else:                 # 20% = 80%->100%
            self.images = self.images[int(0.8*len(self.images)):]
            self.labels = self.labels[int(0.8*len(self.labels)):]

    def load_csv(self, filename):
        if not os.path.exists(os.path.join(self.root, filename)):
            images = []
            for name in self.name2label.keys():
                images += glob.glob(os.path.join(self.root, name, '*.png'))
                images += glob.glob(os.path.join(self.root, name, '*.jpg'))
                images += glob.glob(os.path.join(self.root, name, '*.jpeg'))
            print(len(images), images)

            random.shuffle(images)
            with open(os.path.join(self.root, filename), mode='w', newline='') as f:
                writer = csv.writer(f)
                for img in images:
                    name = img.split(os.sep)[-2]
                    label = self.name2label[name]
                    writer.writerow([img, label])
                print('writen into csv file:', filename)

        # read from csv file
        images, labels = [], []
        with open(os.path.join(self.root, filename)) as f:
            reader = csv.reader(f)
            for row in reader:
                img, label = row
                label = int(label)

                images.append(img)
                labels.append(label)

        assert len(images) == len(labels)

        return images, labels

    def __len__(self):
        return len(self.images)

    def denormalize(self, x_hat):

        mean = [0.485, 0.456, 0.406]
        std = [0.229, 0.224, 0.225]

        mean = torch.tensor(mean).unsqueeze(1).unsqueeze(1)
        std = torch.tensor(std).unsqueeze(1).unsqueeze(1)
        x = x_hat * std + mean

        return x

    def __getitem__(self, idx):

        img, label = self.images[idx], self.labels[idx]

        tf = transforms.Compose([
            lambda x:Image.open(x).convert('RGB'),
            transforms.Resize((int(self.resize*1.25), int(self.resize*1.25))),
            transforms.RandomRotation(15),
            transforms.CenterCrop(self.resize),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])
        ])

        img = tf(img)
        label = torch.tensor(label)
        return img, label


def main():

    viz = visdom.Visdom()

    db = Pokemon('pokemon', 64, 'train')

    x,y = next(iter(db))
    print('sample:', x.shape, y.shape, y)

    viz.image(db.denormalize(x), win='sample_x', opts=dict(title='sample_x'))

    loader = DataLoader(db, batch_size=32, shuffle=True, num_workers=2)

    for x,y in loader:
        viz.images(db.denormalize(x), nrow=8, win='batch', opts=dict(title='batch'))
        viz.text(str(y.numpy()), win='label', opts=dict(title='batch-y'))
        time.sleep(10)

if __name__ == '__main__':
    main()

运行结果如下:

标签:__,定义数据,可梦,self,labels,集宝,images,import,model
From: https://blog.csdn.net/zly19980718/article/details/143759033

相关文章

  • 手把手教你搭建Windows+YOLO11+CUDA环境,以EMA注意演示如何改进YOLO11, 训练自定义数据
    YOLOv11目标检测创新改进与实战案例专栏文章目录:YOLOv11创新改进系列及项目实战目录包含卷积,主干注意力,检测头等创新机制以及各种目标检测分割项目实战案例专栏链接:YOLOv11目标检测创新改进与实战案例文章目录YOLOv11目标检测创新改进与实战案例专栏前言本......
  • 稀疏感知&稀疏预定义数据调度器
    稀疏感知的数据调度器和稀疏预定义的数据调度器虽然都针对稀疏数据的高效调度,但在处理方式和灵活性上有所不同。稀疏感知数据调度器(Sparse-AwareScheduler)稀疏感知数据调度器的核心在于其动态适应性和智能调度能力。它不仅知道数据是稀疏的,还能动态识别稀疏性模式并实时适应调......
  • OpenCV与AI深度学习 | 实战 | YOLO11自定义数据集训练实现缺陷检测 (标注+训练+预测
    本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。原文链接:实战|YOLO11自定义数据集训练实现缺陷检测(标注+训练+预测保姆级教程)导 读   本文将手把手教你用YOLO11训练自己的数据集并实现缺陷检测。安装环境YOLO11的介绍和使用这里不再赘......
  • [SAP ABAP] SE11定义数据类型(结构与表类型)
    1.定义结构使用事务码SE11创建数据类型(结构),输入自定义的数据类型名称,点击创建按钮勾选结构并点击确定按钮 填写简短描述,并在"组件"页签上添加相关字段信息,点击激活按钮即可生效该结构ZSPO_HEADER_4372.定义表类型在定义表类型之前,我们先使用事务码SE11定义结构勾......
  • 使用StyleGAN3合成自定义数据(pytorch代码)
    使用StyleGAN3合成自定义数据在现代计算机视觉和机器学习领域,生成对抗网络(GAN)已成为生成高质量图像的重要工具。其中,StyleGAN3是NVIDIA团队推出的第三代生成对抗网络,其显著改进了图像生成的质量和稳定性。本文旨在介绍如何在训练数据较少的情况下,使用StyleGAN3来合成......
  • 基于qwen2.5 手把手实战 自定义数据集 微调(llama-factory)
    基于qwen2.5手把手实战自定义数据集微调(llama-factory)准备工作1.数据集准备(例:民法典.txt)2.服务器准备(阿里云DSW白嫖)3.环境配置pip升级模型下载微调助手4.数据集处理脚本文件4.1文本分割(bert-base-chinese)4.2数据集生成4.3.1数据集转换(只有一个数据集)alpaca格式......
  • 自定义数据源实现读写分离
    说明:读写分离,指把数据库的操作分为读操作、写操作(更新、新增、删除),在多数据库实例(如主从结构)下,把读操作和写操作访问的数据库分开,以此缓解单数据库的压力。读写分离实现的前提,需要数据库之间能同步数据,数据不一致,读写分离没有意义。数据同步可参考下面文章:MySQL主从结构......
  • 基于腾讯云 AI 代码助手的Web端宝可梦图鉴实践记录
    在编程的世界里,效率和质量是永恒的追求,每一位开发者不断追求的是如何以更快的速度、更高的质量完成代码的编写与调试。另一方面,大型语言模型,凭借其强大的神经网络架构和庞大数据训练,已具有模拟人类的语言理解与创造的能力,而这种能力的突破性进展让AI编程也成为现实。本篇文章,将介绍......
  • go基础-10.自定义数据类型
    在Go语言中,自定义类型指的是使用type关键字定义的新类型,它可以是基本类型的别名,也可以是结构体、函数等组合而成的新类型。自定义类型可以帮助我们更好地抽象和封装数据,让代码更加易读、易懂、易维护自定义类型结构体就是自定义类型中的一种除此之外我们使用自定义类型,还可......
  • 杭州英国集宝Chubbsafes保险柜保险箱安防智能锁空间si设计店铺设计公司
    上海班德设计,专注于为各类企业提供专业的空间设计与品牌形象升级服务。此次,我们荣幸地为杭州英国集宝Chubbsafes保险柜保险箱安防智能锁专卖店提供全方位的SI设计(空间识别系统设计)服务。在设计之初,我们充分了解英国集宝Chubbsafes品牌的历史底蕴、产品特点及市场定位,以确保设......