IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 【沐神课程 - 动手学深度学习】实战二详解之 Kaggle比赛:分类树叶 -> 正文阅读

[人工智能]【沐神课程 - 动手学深度学习】实战二详解之 Kaggle比赛:分类树叶

参考与前言

  1. 课程链接:跟李沐学AI的个人空间_哔哩哔哩_bilibili
  2. 课程主页:https://zh-v2.d2l.ai/chapter_introduction/index.html
  3. 相关代码参考:https://github.com/SHENZHENYI/Classify-Leaves-Kaggle-MuLi-d2l-course
  4. pytorch官方相关教程参考:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

本部分主要用于记录自己做第二次作业的一些感受,主要是也第一次Dataloader 也算是一次学习了

首先遇到的问题:

  1. Dataloader没有注意到一个是Dataset,然后还要建一个batch_size的Loader
  2. 输出的output无法和label进行比较,最后直接算max来的
  3. 现在算是知道了沐神讲的,数据预处理的重要性,特别是关于图片的分类中的处理看起来更为重要 -> 看原始数据不同 -> 水平垂直25%随机翻转
  4. loss抖动过大,原因loss的计算结果不应该作为看图的东西,而应该是准确率 -> label smoothing
  5. optimization选取 从SGD -> Adam-> AdamW

1. 模型

Resnet18

其实看kaggle讨论和代码区 挺多人上了resnet50及更为复杂的模型,基本没有自己手写的cnn,所以我就用了小巧点的 毕竟想快点看到结果(基本就训练个半小时),也不冲前五了

import torch
import pandas as pd
from tqdm.notebook import tqdm
import numpy as np
import os

import torchvision
from torchvision import datasets, models, transforms
import torch.nn as nn
from torch.nn import functional as F
from torch.utils import data
import torch.optim as optim

from torchvision.io import read_image
from PIL import Image
from torch.utils.data import Dataset,DataLoader
from torchvision.transforms import ToTensor, Lambda
import albumentations
from albumentations import pytorch as AT

import cv2
import matplotlib.pyplot as plt
import wandb

num_epochs, lr, bs, weight_decay = 50, 0.001, 64, 2e-4
NUM_SAVE = num_epochs//5

class MODEL(nn.Module):
    def __init__(self, out_label):
        super().__init__()
        self.resnet = models.resnet18(pretrained=True)
        self.resnet.fc = nn.Linear(self.resnet.fc.in_features,out_label)
        
    def forward(self, X):
        return self.resnet(X)

Loss选取

没啥讲究,就选了CrossEntropyLoss 但是看到讨论区有人对这个做了顺滑功能,不然loss看着抖动特别大 emmm

criterion = nn.CrossEntropyLoss()

但其实在后面计算精度的时候,是直接取最大的那个然后对比label是否一致,类似于这样:

acc = (outputs.argmax(dim=-1) == labels).float().mean()

优化器

倒是这个优化器,一开始选了SGD,Adam 都不太熟内在 然后weight decay还是临时补了看了一下 然后一开始这个weight decay直接拉到了0.95 没有意识到事情的严重性(就是之前从上一个那里拉的;相关阅读:L2正则=Weight Decay?并不是这样 - 知乎 (zhihu.com)

后面看搜了搜就发现有AdamW,然后看其他人做的时候(参考链接处的那位同学) 还有对不同的layer有不同的学习率

net = MODEL(out_label = len(classes)).to(device)
params_1x = [param for name, param in net.resnet.named_parameters()
             if name not in ["fc.weight", "fc.bias"]]
optimizer = optim.AdamW([{'params': params_1x},
                       {'params': net.resnet.fc.parameters(),
                        'lr': lr * 10}],
                        lr=lr, weight_decay=weight_decay)

2. 数据处理

这一块其实看训练和测试数据集 应该是要把光亮也多少加进去,就是随机加,但是我看了一下ColorJitter 并没有random的概率 emmm 所以就懒了,其实随便写一个random应该也可以

导入数据

和前一个其实差不多,主要是对着pytorch的教程写了一个dataloader然后看其他人 哦吼 原来图片操作这么多

首先是直接read_csv,然后大概按0.9和0.1随机分割训练和验证集,其实也可以用K-fold 我第一次没想好怎么个分割法,直接从train_dataloader那里不太好,从这里吧 每次又需要建新的loader也不太好,干脆 就不弄了,直接这样吧,这次有val主要是 意识到了 还是要看看的严重性 emmm

test_data = pd.read_csv('test.csv')
all_data = pd.read_csv('train.csv')
train_data = all_data.sample(n=int(len(all_data)*0.9),ignore_index=True)
val_data = all_data.sample(n=int(len(all_data)*0.1),ignore_index=True)
classes = all_data['label'].unique().tolist()
print("train_data:",all_data.shape,"test_data shape:",test_data.shape,"\nlabel size:", len(classes))

注意这里的sample函数是来源于pandas的,需要pandas New in version 1.3.0. 不然会报错没有ignore_index,如果不ignore index的话 emmm loader会报错,因为索引有问题,光这个bug 找了大概半小时,后知后觉 算是学习了

预处理

主要写在了dataset这一环,果然和杰哥说的一样 炼丹就是写dataloader hhhhh

class MyDataset(Dataset):
    def __init__(self, annotations, img_dir, mode=None, target_transform=None):
        super().__init__()
        self.img_labels = annotations
        self.img_dir = img_dir
        if mode=='train':
            preprocess = transforms.Compose([
                        transforms.Resize(256),
                        transforms.CenterCrop(224),
                        transforms.RandomHorizontalFlip(p=.25),
                        transforms.RandomVerticalFlip(p=.5),
                        transforms.ToTensor(),
                        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),])
        elif mode=='test':
            preprocess = transforms.Compose([
                        transforms.Resize(256),
                        transforms.CenterCrop(224),
                        transforms.ToTensor(),
                        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),])
        elif mode=='val':
            preprocess = transforms.Compose([
                        transforms.Resize(256),
                        transforms.CenterCrop(224),
                        transforms.ToTensor(),
                        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),])
        self.transform = preprocess
        self.target_transform = target_transform

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

    def __getitem__(self, idx):
        img_path = os.path.join(self.img_dir[idx])
        with Image.open(img_path) as im:
            image = im
            label = self.img_labels.iloc[idx]
            if self.transform:
                image = self.transform(image)
            if self.target_transform:
                label = self.target_transform(label)
            return image, label

可以看到对于test和val都不做图像增广的操作,train也是按0.25 0.25的比例来做,其实加一个亮光应该更好一点,另外我发现这个增广是增广并没有增多数据,其实增多应该也没啥问题?可能担心过拟合?

target_transform = Lambda(lambda y: torch.tensor(classes.index(y)))

training_data = MyDataset(train_data['label'], train_data['image'], 'train', target_transform)
train_dataloader = DataLoader(training_data, batch_size=bs, shuffle=True)

val_data = MyDataset(val_data['label'], val_data['image'], 'val', target_transform)
val_dataloader = DataLoader(val_data, batch_size=bs, shuffle=False)

testing_data = MyDataset(test_data['image'], test_data['image'], 'test', None)
test_dataloader = DataLoader(testing_data, batch_size=bs, shuffle=False)
print("train_data length:",len(training_data),"test_data length:",len(test_data))

3. 训练步骤

这一次没啥了 而且function都懒了 直接写在主体里了,其中有wandb的都是我… 习惯看数据的平台 对比与tensorboard emmm 可以让我多设备 在线看效果 hhh 想起来一开始,吃饭路上看了一眼自己的精度曲线95%好耶,然后一提交88% emmm

wandb.watch(net)
step = 0
for epoch in tqdm(range(num_epochs)):  # loop over the dataset multiple times
    
    # 训练集
    train_accs = []
    for i, data in enumerate(train_dataloader,0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        # zero the parameter gradients
        optimizer.zero_grad()
        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        # record
        step+=1
        # 对比labels是否一致
        acc = (outputs.argmax(dim=-1) == labels).float().mean()
        train_accs.append(acc)
        wandb.log({'loss': loss,'step':step})
        del inputs, labels
    # 分类的精度百分比
    train_accuracy = sum(train_accs) / len(train_accs)
    wandb.log({'train accuracy': train_accuracy,'epoch': epoch})
    
    # 验证集
    val_accs = []
    for i, data in enumerate(val_dataloader,0):
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        outputs = net(inputs)
        acc = (outputs.argmax(dim=-1) == labels).float().mean()
        val_accs.append(acc)
        del inputs, labels
    val_accuracy = sum(val_accs) / len(val_accs)
    wandb.log({'accuracy': val_accuracy,'epoch': epoch})
    print("No. epoch:",epoch, "accuracy:"+"{:.2f}%".format(train_accuracy.item()*100))
    if epoch%NUM_SAVE==0 and epoch!=0:
        torch.save(net.state_dict(),'checkpoint_'+str(epoch))
        print("Model Saved")
    
wandb.finish()
print('Finished Training, the last loss is:', loss.item())

唯一需要注意的是关于精度最好还是打一下 不然看着loss 抖动总是心有余悸,比如这样 是不是右边的顺眼多了

4. 结果

看kaggle上 有人0.99真的是 太太太太 吓人了,一开始光溜溜的写完loader,用的SGD基本默认参数,就大概直接train 上传后有92%结果,然后后面开始骚操作了一个比一个低,主要是我都不知道我改了些啥,emmm 做好记录的重要原因体现了,最新的结果emm 还是91%,所以又回到了最初的起点 hhhh 就是这篇博文上的代码提交的,给训练了50 epoch,大概贴一下val train loss的图和大致模型梯度(但是有太多个layer梯度了 所以 只截取了一点点)

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:09:34  更:2021-12-26 22:11:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 23:36:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码