pytorch代码实战——猫狗分类任务

1、导包

#导包
import torch as t
import torch.nn as nn
import numpy as np
from torch.utils.data import Dataset,DataLoader
from torchvision import transforms
from PIL import Image
import os
import matplotlib.pyplot as plt
import torchvision.models as models
from tqdm import tqdm 

2、设置路径

work_dir = os.getcwd()
train_path = work_dir+'/dogs-vs-cats/train/'
test_path = work_dir+'/dogs-vs-cats/test/'
img_name = os.listdir(train_path)
test_img = os.listdir(test_path)

3、获取数据类别

classes = set()
for img in img_name:
    cls = img.split('.')[0]
    classes.add(cls)
classes = sorted(classes)
n_classes = len(classes)
class_to_num = dict(zip(classes,range(2)))
print(class_to_num)
num_to_class = {v:k for k,v in class_to_num.items()}
print(num_to_class)

4、拼接数据路径并制作标签

labels = []
img_paths = []  
for img in img_name:
    imgp = train_path+img
    img_paths.append(imgp)
    cls = img.split('.')[0]
    labels.append(class_to_num[cls])
test_img_name =[]
for i in test_img:
    imgp = test_path+i
    test_img_name.append(imgp)

5、定义transform

def Data_Transform(mode='train'):
    if mode == 'train':
        transform = transforms.Compose([
            transforms.Resize((224, 224)),
            transforms.RandomHorizontalFlip(p=0.5),   #随机水平翻转 选择一个概率
            #transforms.RandomResizedCrop(size=224, scale=(0.8, 1.0)),
            #transforms.RandomRotation(degrees=15),
            #transforms.RandomHorizontalFlip(),
            #transforms.CenterCrop(size=224),
            transforms.ToTensor(),
            #transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
            ])
    else:
        # valid和test不做数据增强
        transform = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.CenterCrop(size=224),
        transforms.ToTensor(),
        #transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
        ])
    return transform

6、定义Dataset

import random 
random.seed(2023)
random.shuffle(img_paths)
random.seed(2023)
random.shuffle(labels)
cut = int(len(img_paths)*0.15)

class CatDogDataset(Dataset):
    def __init__(self,mode ='train' ):
        self.mode = mode

        train_img = img_paths[cut:]
        train_label = labels[cut:]
        valid_img = img_paths[:cut]
        valid_label = labels[:cut]
        
        if self.mode == 'train':
            self.img = train_img
            self.label = train_label
        elif self.mode == 'valid':
            self.img = valid_img
            self.label = valid_label
        elif self.mode == 'test':
            self.img = test_img_name

        self.data_len = len(self.img)
        print(f'finish reading the {mode} set of dataset ({self.data_len} samples found)')
    def __getitem__(self,index):
        img = Image.open(self.img[index])
        transforms = Data_Transform(self.mode)
        img = transforms(img)
        if self.mode == 'test':
            return img
        else:
            label = self.label[index]
            return img,label
    def __len__(self):
        return len(self.img)
train_dataset = CatDogDataset(mode='train')
val_dataset = CatDogDataset(mode='valid')
test_dataset = CatDogDataset(mode='test')

7、定义DataLoader

#定义data_loader
train_loader = DataLoader(
    dataset = train_dataset,
    batch_size = 32,
    shuffle = False,
    num_workers = 0
)
val_loader = DataLoader(
    dataset=val_dataset,
    batch_size=16, 
    shuffle=False,
    num_workers=0
)
test_loader = DataLoader(
    dataset=test_dataset,
    batch_size=16, 
    shuffle=False,
    num_workers=0
)

8、加载模型

model_ft = models.resnet50(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 2)
model_ft.to('cpu')

9、设置超参数、损失函数和优化器

lr = 1e-4
weight_decay = 1e-3
num_epochs = 2
device = 'cpu'
#分类任务,使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()
#设置优化器
optimizer = t.optim.Adam(model_ft.parameters(),lr = lr,weight_decay = weight_decay)

10、定义训练方法和验证方法,并开始训练

def train(model,device,train_loader,optimizer,epoch):
    model.train()
    train_loss = []
    train_acc = []
    for batch in tqdm(train_loader):
        imgs,labels = batch
        imgs = imgs.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        output = model(imgs)
        loss = criterion(output,labels)
        loss.backward()
        optimizer.step()

        '''需要GPU支持
        with torch.cuda.amp.autocast():  # 混合精度加速训练
            output = model(imgs)
            loss = criterion(output, labels)
        optimizer.zero_grad()  # 重置梯度,不加会爆显存
        scaler.scale(loss).backward()
        scaler.step(optimizer)
        scaler.update()
        '''
        avg_acc = (output.argmax(dim=1)==labels).float().mean()
        train_acc.append(avg_acc)
        train_loss.append(loss)
    train_loss = sum(train_loss)/ len(train_loss)
    train_accs = sum(train_acc) / len(train_acc)
    print(f"[ Train | {epoch + 1}/{num_epochs} ] loss = {train_loss}, acc = {train_accs}")
def valid(model,device,val_loader,epoch,best_acc):
    with t.no_grad():
        model.eval()
        valid_loss = []
        valid_accs = []
        for batch in tqdm(val_loader):
            imgs,labels = batch
            imgs = imgs.to(device)
            labels = labels.to(device)
            outputs = model(imgs)
            loss = criterion(outputs,labels)
            avg_acc = (outputs.argmax(dim=1)==labels).float().mean()

            valid_accs.append(avg_acc)
            valid_loss.append(loss)
        valid_loss = sum(valid_loss)/ len(valid_loss)
        valid_accs = sum(valid_accs) / len(valid_accs)
        print(f"[ Valid | {epoch + 1}/{num_epochs} ] loss = {valid_loss}, acc = {valid_accs}")
        
        if valid_accs > best_acc:
                t.save(model.state_dict(), '66model_' + str(epoch) + '_' + str(valid_accs) + '.pth')
                best_acc = valid_accs
                print('当前最好模型精度:{}%'.format(best_acc*100))

        

开始训练

best_acc = 0.0
for epoch in range(num_epochs):
    train(model_ft,device,train_loader,optimizer,epoch)
    valid(model_ft, device, val_loader,epoch,best_acc)

11、测试模型

## predict
model_ft = model_ft.to(device)
model_ft.load_state_dict(t.load('./66model_1_tensor(1.).pth'))
model_ft.eval()
predictions = []
for batch in tqdm(test_loader):
    imgs = batch
    with t.no_grad():
        output = model_ft(imgs.to(device))
    predictions.extend(output.argmax(dim=-1).cpu().numpy().tolist())
preds = []
for i in predictions:
    preds.append(num_to_class[i])
print(preds)

后记

参考链接
猫狗数据集
链接:https://pan.baidu.com/s/1O4y1k5y2g1ig0GwMprHTVg
提取码:6666

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲸可落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值