AI研习社“看图猜作者”优秀代码技术总结

首先,对用户000wangbo的代码进行学习。他的思路是:主干网络resnest200,输入448尺寸,在不同loss下取得5组最好效果,最后进行投票,得到最后分数。
1、进行相关的初始化

    np.random.seed(359)
    torch.manual_seed(359)
    torch.cuda.manual_seed_all(359)
    random.seed(359)

    os.environ["CUDA_VISIBLE_DEVICES"] = '0,1,2,3,4,5,6,7'
    batch_size = 48
    workers = 16

    # stage_epochs = [8, 8, 8, 6, 5, 4, 3, 2]
    # stage_epochs = [12, 6, 5, 3, 4]
    lr = 5e-4
    lr_decay = 10
    weight_decay = 1e-4

    stage = 0
    start_epoch = 0
    # total_epochs = sum(stage_epochs)
    total_epochs = 200
    patience = 4
    no_improved_times = 0
    total_stages = 3
    best_score = 0
    samples_num = 54

    print_freq = 20
    train_ratio = 0.9  # others for validation
    momentum = 0.9
    pre_model = 'senet'
    pre_trained = True
    evaluate = False
    use_pre_model = False
    # file_name = os.path.basename(__file__).split('.')[0]

    file_name = "resnest200_448_all_{}".format(index)
    img_size = 448

    resumeflg = False
    resume = ''

2、创建保存模型和结果的文件夹

    if not os.path.exists('./model/%s' % file_name):
        os.makedirs('./model/%s' % file_name)
    if not os.path.exists('./result/%s' % file_name):
        os.makedirs('./result/%s' % file_name)

    if not os.path.exists('./result/%s.txt' % file_name):
        txt_mode = 'w'
    else:
        txt_mode = 'a'
    with open('./result/%s.txt' % file_name, txt_mode) as acc_file:
        acc_file.write('\n%s %s\n' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), file_name))

3 建立模型

    # build a model
    model =resnest200(pretrained=True)
    model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1)#自适应平均池化函数
    model.fc = torch.nn.Linear(model.fc.in_features,49)
    model = torch.nn.DataParallel(model).cuda()#PyTorch中使用了张量类型,而不用numpy的array,就是为了可以在GPU上运行代码
    #使用多个GPU训练模型nn.DataParallel(model).cuda()
    #默认使用单个GPU训练模型model.gpu()

4、模态字典的保存

    def load_pre_cloth_model_dict(self, state_dict):
        own_state = self.state_dict()
        for name, param in state_dict.items():
            if name not in own_state:
                continue
            if 'fc' in name:
                continue
            if isinstance(param, nn.Parameter):
                # backwards compatibility for serialized parameters
                param = param.data
            own_state[name].copy_(param)
    if use_pre_model:
        print('using pre model')
        pre_model_path = ''
        load_pre_cloth_model_dict(model, torch.load(pre_model_path)['state_dict'])
    # optionally resume from a checkpoint
    if resume:
        if os.path.isfile(resume):
            print("=> loading checkpoint '{}'".format(resume))
            checkpoint = torch.load(resume)
            start_epoch = checkpoint['epoch']
            best_score = checkpoint['best_score']
            stage = checkpoint['stage']
            lr = checkpoint['lr']
            model.load_state_dict(checkpoint['state_dict'])
            no_improved_times = checkpoint['no_improved_times']
            if no_improved_times == 0:
                model.load_state_dict(torch.load('./model/%s/model_best.pth.tar' % file_name)['state_dict'])
            print("=> loaded checkpoint (epoch {})".format(checkpoint['epoch']))
        else:
            print("=> no checkpoint found at '{}'".format(resume))

    def default_loader(root_dir,path):
        final_path = os.path.join(root_dir,str(path))
        return Image.open(final_path+".jpg").convert('RGB')
        # return Image.open(path)

5、训练数据集

    class TrainDataset(Dataset):
        def __init__(self, label_list, transform=None, target_transform=None, loader=default_loader):
            imgs = []
            for index, row in label_list.iterrows():
                imgs.append((row['filename'], row['label']))
            self.imgs = imgs
            self.transform = transform
            self.target_transform = target_transform
            self.loader = loader

        def __getitem__(self, index):
            filename, label= self.imgs[index]
            label = label
            img = self.loader('../train/',filename)


            if self.transform is not None:
                    img = self.transform(img)

            return img, label

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

6、有效数据集

    class ValDataset(Dataset):
        def __init__(self, label_list, transform=None, target_transform=None, loader=default_loader):
            imgs = []
            for index, row in label_list.iterrows():
                imgs.append((row['filename'], row['label']))
            self.imgs = imgs
            self.transform = transform
            self.target_transform = target_transform
            self.loader = loader

        def __getitem__(self, index):
            filename, label= self.imgs[index]
            label = label
            img = self.loader('../train/',filename)
            if self.transform is not None:
                img = self.transform(img)
            return img, label, filename

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

7、测试数据集

    class TestDataset(Dataset):
        def __init__(self, label_list, transform=None, target_transform=None, loader=default_loader):
            imgs = []
            for index, row in label_list.iterrows():
                imgs.append((row['filename'], row['label']))
            self.imgs = imgs
            self.transform = transform
            self.target_transform = target_transform
            self.loader = loader

        def __getitem__(self, index):
            filename,label = self.imgs[index]
            img = self.loader('../test/',filename)
            if self.transform is not None:
                img = self.transform(img)
            return img, filename

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

8、获取数据

    train_data_list = pd.read_csv("data/train_{}.csv".format(index), sep=",")
    val_data_list = pd.read_csv("data/test_{}.csv".format(index), sep=",")
    test_data_list = pd.read_csv("../test.csv",sep=",")

    train_data_list = train_data_list.fillna(0)#对于缺失值进行填充,填充0

9、数据集预处理

    random_crop = [transforms.RandomCrop(640), transforms.RandomCrop(768), transforms.RandomCrop(896)]



    smax = nn.Softmax()
    normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

    train_data = TrainDataset(train_data_list,
                              transform=transforms.Compose([
                                  transforms.Resize((img_size, img_size)),
                                  transforms.ColorJitter(0.3, 0.3, 0.3, 0.15),
                                  # transforms.RandomRotation(30),
                                  transforms.RandomHorizontalFlip(),
#                                   transforms.RandomVerticalFlip(),
#                                   transforms.RandomGrayscale(),
                                  FixedRotation([-16,-14,-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12,14,16]),
                                  transforms.ToTensor(),
                                  normalize,
                              ]))

    val_data = ValDataset(val_data_list,
                          transform=transforms.Compose([
                              transforms.Resize((img_size, img_size)),
                              # transforms.CenterCrop((500, 500)),
                              transforms.ToTensor(),
                              normalize,
                          ]))

    test_data = TestDataset(test_data_list,
                            transform=transforms.Compose([
                                transforms.Resize((img_size, img_size)),
                                # transforms.CenterCrop((500, 500)),
                                transforms.ToTensor(),
                                normalize,
                                # transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])),
                                # transforms.Lambda(lambda crops: torch.stack([normalize(crop) for crop in crops])),
                            ]))

10、数据加载

    train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, pin_memory=True, num_workers=workers,drop_last=True)
    val_loader = DataLoader(val_data, batch_size=batch_size * 2, shuffle=False, pin_memory=False, num_workers=workers,drop_last=True)
    test_loader = DataLoader(test_data, batch_size=batch_size * 2, shuffle=False, pin_memory=False, num_workers=workers)

    test_data_hflip = TestDataset(test_data_list,
                            transform=transforms.Compose([
                                transforms.Resize((img_size, img_size)),
                                transforms.RandomHorizontalFlip(p=2),
                                # transforms.CenterCrop((500, 500)),
                                transforms.ToTensor(),
                                normalize,
                            ]))


    test_loader_hflip = DataLoader(test_data_hflip, batch_size=batch_size * 2, shuffle=False, pin_memory=False, num_workers=workers)

    test_data_vflip = TestDataset(test_data_list,
                                  transform=transforms.Compose([
                                      transforms.Resize((336, 336)),
                                      transforms.RandomVerticalFlip(p=2),
                                      # transforms.CenterCrop((500, 500)),
                                      transforms.ToTensor(),
                                      normalize,
                                  ]))

    test_loader_vflip = DataLoader(test_data_vflip, batch_size=batch_size * 2, shuffle=False, pin_memory=False,
                                   num_workers=workers)

    test_data_vhflip = TestDataset(test_data_list,
                                  transform=transforms.Compose([
                                      transforms.Resize((336, 336)),
                                      transforms.RandomHorizontalFlip(p=2),
                                      transforms.RandomVerticalFlip(p=2),
                                      # transforms.CenterCrop((500, 500)),
                                      transforms.ToTensor(),
                                      normalize,
                                  ]))

    test_loader_vhflip = DataLoader(test_data_vhflip, batch_size=batch_size * 2, shuffle=False, pin_memory=False,
                                   num_workers=workers)

11、模型训练

    def train(train_loader, model, criterion, optimizer, epoch):
        batch_time = AverageMeter()
        data_time = AverageMeter()
        losses = AverageMeter()
        acc = AverageMeter()

        # switch to train mode
        model.train()

        end = time.time()
        for i, (images, target) in enumerate(train_loader):
            # measure data loading
            # if len(target) % workers == 1:
            #     images = images[:-1]
            #     target = target[:-1]

            data_time.update(time.time() - end)
            image_var = torch.tensor(images, requires_grad=False).cuda(non_blocking=True)
            # print(image_var)
            label = torch.tensor(target).cuda(non_blocking=True)
            # compute y_pred
            y_pred = model(image_var)
            loss = criterion(y_pred, label)

            # measure accuracy and record loss
            prec, PRED_COUNT = accuracy(y_pred.data, target, topk=(1, 1))
            losses.update(loss.item(), images.size(0))
            acc.update(prec, PRED_COUNT)

            # compute gradient and do SGD step
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

            if i % print_freq == 0:
                print('Epoch: [{0}][{1}/{2}]\t'
                      'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                      'Data {data_time.val:.3f} ({data_time.avg:.3f})\t'
                      'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                      'Accuray {acc.val:.3f} ({acc.avg:.3f})'.format(
                    epoch, i, len(train_loader), batch_time=batch_time, data_time=data_time, loss=losses, acc=acc))

12、评测模型

    def validate(val_loader, model, criterion):
        batch_time = AverageMeter()
        # losses = AverageMeter()
        # acc = AverageMeter()

        # switch to evaluate mode
        model.eval()

        # 保存概率,用于评测
        val_imgs, val_preds, val_labels, = [], [], []

        end = time.time()
        for i, (images, labels, img_path) in enumerate(val_loader):
            # if len(labels) % workers == 1:
            #     images = images[:-1]
            #     labels = labels[:-1]
            image_var = torch.tensor(images, requires_grad=False).cuda(non_blocking=True)  # for pytorch 0.4
            # label_var = torch.tensor(labels, requires_grad=False).cuda(async=True)  # for pytorch 0.4
            target = torch.tensor(labels).cuda(non_blocking=True)

            # compute y_pred
            with torch.no_grad():
                y_pred = model(image_var)
                loss = criterion(y_pred, target)

            # measure accuracy and record loss
            # prec, PRED_COUNT = accuracy(y_pred.data, labels, topk=(1, 1))
            # losses.update(loss.item(), images.size(0))
            # acc.update(prec, PRED_COUNT)

            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

            if i % (print_freq * 5) == 0:
                print('TrainVal: [{0}/{1}]\t'
                      'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'.format(i, len(val_loader),
                                                                                  batch_time=batch_time))

            # 保存概率,用于评测
            smax_out = smax(y_pred)
            val_imgs.extend(img_path)
            val_preds.extend([i.tolist() for i in smax_out])
            val_labels.extend([i.item() for i in labels])
        val_preds = [';'.join([str(j) for j in i]) for i in val_preds]
        val_score = pd.DataFrame({'img_path': val_imgs, 'preds': val_preds, 'label': val_labels,})
        val_score.to_csv('./result/%s/val_score.csv' % file_name, index=False)
        acc, f1  = score(val_score)
        print('acc: %.4f, f1: %.4f' % (acc, f1))
        print(' * Score {final_score:.4f}'.format(final_score=f1), '(Previous Best Score: %.4f)' % best_score)
        return acc, f1

13、测试模型

    def test(test_loader, model):
        csv_map = OrderedDict({'FileName': [], 'type': [], 'probability': []})
        # switch to evaluate mode
        model.eval()
        for i, (images, filepath) in enumerate(tqdm(test_loader)):
            # bs, ncrops, c, h, w = images.size()

            filepath = [str(i) for i in filepath]
            image_var = torch.tensor(images, requires_grad=False)  # for pytorch 0.4

            with torch.no_grad():
                y_pred = model(image_var)  # fuse batch size and ncrops
                # y_pred = y_pred.view(bs, ncrops, -1).mean(1) # avg over crops

                # get the index of the max log-probability
                smax = nn.Softmax()
                smax_out = smax(y_pred)
            csv_map['FileName'].extend(filepath)
            for output in smax_out:
                prob = ';'.join([str(i) for i in output.data.tolist()])
                csv_map['probability'].append(prob)
                csv_map['type'].append(np.argmax(output.data.tolist()))
            # print(len(csv_map['filename']), len(csv_map['probability']))

        result = pd.DataFrame(csv_map)
        result.to_csv('./result/%s/submission.csv' % file_name, index=False)
        result[['FileName','type']].to_csv('./result/%s/final_submission.csv' % file_name, index=False)
        return

14、

    def save_checkpoint(state, is_best, filename='./model/%s/checkpoint.pth.tar' % file_name):
        torch.save(state, filename)
        if is_best:
            shutil.copyfile(filename, './model/%s/model_best.pth.tar' % file_name)

15、

    class AverageMeter(object):
        """Computes and stores the average and current value"""

        def __init__(self):
            self.reset()

        def reset(self):
            self.val = 0
            self.avg = 0
            self.sum = 0
            self.count = 0

        def update(self, val, n=1):
            self.val = val
            self.sum += val * n
            self.count += n
            self.avg = self.sum / self.count

16、

    def adjust_learning_rate():
        nonlocal lr
        lr = lr / lr_decay
        return optim.Adam(model.parameters(), lr, weight_decay=weight_decay, amsgrad=True)

17、

    def accuracy(y_pred, y_actual, topk=(1,)):
        """Computes the precision@k for the specified values of k"""
        final_acc = 0
        maxk = max(topk)
        # for prob_threshold in np.arange(0, 1, 0.01):
        PRED_COUNT = y_actual.size(0)
        PRED_CORRECT_COUNT = 0

        prob, pred = y_pred.topk(maxk, 1, True, True)
        # prob = np.where(prob > prob_threshold, prob, 0)


        for j in range(pred.size(0)):
            if int(y_actual[j]) == int(pred[j]):
                PRED_CORRECT_COUNT += 1
        if PRED_COUNT == 0:
            final_acc = 0
        else:
            final_acc = PRED_CORRECT_COUNT / PRED_COUNT
        return final_acc * 100, PRED_COUNT

18、

    def softmax(x):
        return np.exp(x) / np.sum(np.exp(x), axis=0)

19、

    def doitf(tp, fp, fn):
        if (tp + fp == 0):
            return 0
        if (tp + fn == 0):
            return 0
        pre = float(1.0 * float(tp) / float(tp + fp))
        rec = float(1.0 * float(tp) / float(tp + fn))
        if (pre + rec == 0):
            return 0
        return (2 * pre * rec) / (pre + rec)

20、

    def score(val_score):
        val_score['preds'] = val_score['preds'].map(lambda x: [float(i) for i in x.split(';')])
        acc = 0
        tp = np.zeros(49)
        fp = np.zeros(49)
        fn = np.zeros(49)
        f1 = np.zeros(49)
        f1_tot = 0

        print(val_score.head(10))

        val_score['preds_label'] = val_score['preds'].apply(lambda x: np.argmax(x))
        for i in range(val_score.shape[0]):
            preds = val_score['preds_label'].iloc[i]
            label = val_score['label'].iloc[i]
            if (preds == label):
                acc = acc + 1
                tp[label] = tp[label] + 1
            else:
                fp[preds] = fp[preds] + 1
                fn[label] = fn[label] + 1
        
        for classes in range(49):
            f1[classes] = doitf(tp[classes], fp[classes], fn[classes])
            f1_tot = f1_tot + f1[classes]
        acc = acc / val_score.shape[0]
        f1_tot = f1_tot / 49

        return acc, f1_tot

21、定义损失函数和优化器

    # define loss function (criterion) and pptimizer
    criterion = nn.CrossEntropyLoss().cuda()

    # optimizer = optim.Adam(model.module.last_linear.parameters(), lr, weight_decay=weight_decay, amsgrad=True)
    optimizer = optim.Adam(model.parameters(), lr, weight_decay=weight_decay, amsgrad=True)

22、

    if evaluate:
        validate(val_loader, model, criterion)
    else:
        for epoch in range(start_epoch, total_epochs):
            if stage >= total_stages - 1:
                break
            # train for one epoch
            train(train_loader, model, criterion, optimizer, epoch)
            # evaluate on validation set
            if epoch >= 0:
                acc , f1 = validate(val_loader, model, criterion)

                with open('./result/%s.txt' % file_name, 'a') as acc_file:
                    acc_file.write('Epoch: %2d, acc: %.8f, f1: %.8f\n' % (epoch, acc, f1))

                # remember best Accuracy and save checkpoint
                is_best = acc > best_score
                best_score = max(acc, best_score)

                # if (epoch + 1) in np.cumsum(stage_epochs)[:-1]:
                #     stage += 1
                #     optimizer = adjust_learning_rate()

                if is_best:
                    no_improved_times = 0
                else:
                    no_improved_times += 1

                print('stage: %d, no_improved_times: %d' % (stage, no_improved_times))

                if no_improved_times >= patience:
                    stage += 1
                    optimizer = adjust_learning_rate()

                state = {
                    'epoch': epoch + 1,
                    'arch': pre_model,
                    'state_dict': model.state_dict(),
                    'best_score': best_score,
                    'no_improved_times': no_improved_times,
                    'stage': stage,
                    'lr': lr,
                }
                save_checkpoint(state, is_best)

                # if (epoch + 1) in np.cumsum(stage_epochs)[:-1]:
                if no_improved_times >= patience:
                    no_improved_times = 0
                    model.load_state_dict(torch.load('./model/%s/model_best.pth.tar' % file_name)['state_dict'])
                    print('Step into next stage')
                    with open('./result/%s.txt' % file_name, 'a') as acc_file:
                        acc_file.write('---------------------Step into next stage---------------------\n')

23、

    with open('./result/%s.txt' % file_name, 'a') as acc_file:
        acc_file.write('* best acc: %.8f  %s\n' % (best_score, os.path.basename(__file__)))
    with open('./result/best_acc.txt', 'a') as acc_file:
        acc_file.write('%s  * best acc: %.8f  %s\n' % (
        time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), best_score, os.path.basename(__file__)))

24、

    # test
    best_model = torch.load('model/{}/model_best.pth.tar'.format(file_name))
    model.load_state_dict(best_model['state_dict'])
    test(test_loader=test_loader, model=model)

    torch.cuda.empty_cache()
    # resume = False

对用户今天没吃饭的代码进行学习。他的思路是:基于Resnext50,eff-b3训练图像尺寸448,512,600的模型,取得分最高的4组结果进行投票。
1、输入处理模块
datacount

import os
import pandas as pd
from sklearn.model_selection import train_test_split
import numpy as np


df = pd.read_csv('train.csv').values
print(df[:5])

class_cnt = {}


for idx, label in df:
    print(idx, label)
    if label not in class_cnt:
        class_cnt[label] = []
    class_cnt[label].append(idx)


for k, v in class_cnt.items():
    print(k, len(v))


big_x = []
big_y = []
small_x = []
small_y = []
for k, v in class_cnt.items():
    if len(v) < 30:
        small_x.extend(v)
        small_y.extend(np.ones(len(v), dtype=np.int16) * k)
    else:
        big_x.extend(v)
        big_y.extend(np.ones(len(v), dtype=np.int16) * k)

print(big_x)
print(big_y)

train_x, test_x, train_y, test_y = train_test_split(big_x, big_y, random_state=999, test_size=0.2)
train_x.extend(small_x)
train_y.extend(small_y)

with open('train.txt', 'w')as f:
    for fn, label in zip(train_x, train_y):
        f.write('./data/Art/data/train/{}.jpg,{}\n'.format(fn, label))

with open('val.txt', 'w')as f:
    for fn, label in zip(test_x, test_y):
        f.write('./data/Art/data/train/{}.jpg,{}\n'.format(fn, label))

dataloader--数据加载和数据增强

from torch.utils.data import dataset
from PIL import Image
from torchvision import transforms, models
import random
import numpy as np
import torch

size = 512
#数据增强,分为两个模式train和val
trans = {
        'train':
            transforms.Compose([
                transforms.RandomHorizontalFlip(),
                # transforms.RandomVerticalFlip(),
                # transforms.ColorJitter(brightness=0.126, saturation=0.5),
                # transforms.RandomAffine(degrees=30, translate=(0.2, 0.2), fillcolor=0, scale=(0.8, 1.2), shear=None),
                transforms.Resize((int(size / 0.875), int(size / 0.875))),
                transforms.RandomCrop((size, size)),
                transforms.ToTensor(),
                transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
                transforms.RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3))
            ]),
        'val':
            transforms.Compose([
                transforms.Resize((int(size / 0.875), int(size / 0.875))),
                transforms.CenterCrop((size, size)),
                transforms.ToTensor(),
                transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
            ])
        }


class Dataset(dataset.Dataset):
    def __init__(self, mode):
        assert mode in ['train', 'val']
        txt = './data/Art/data/%s.txt' % mode

        fpath = []
        labels = []
        with open(txt, 'r')as f:
            for i in f.readlines():
                fp, label = i.strip().split(',')
                fpath.append(fp)
                labels.append(int(label))

        self.fpath = fpath
        self.labels = labels
        self.mode = mode
        self.trans = trans[mode]
        
    def __getitem__(self, index):
        fp = self.fpath[index]
        label = self.labels[index]
        img = Image.open(fp).convert('RGB')
        if self.trans is not None:
            img = self.trans(img)

        return img, label

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

2、模型构建模块

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import models
import math
import numpy as np
from efficientnet_pytorch import EfficientNet
import random


class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return y


class AdaptiveConcatPool2d(nn.Module):
    def __init__(self, sz=(1,1)):
        super().__init__()
        self.ap = nn.AdaptiveAvgPool2d(sz)
        self.mp = nn.AdaptiveMaxPool2d(sz)
        
    def forward(self, x):
        return torch.cat([self.mp(x), self.ap(x)], 1)


class GeneralizedMeanPooling(nn.Module):
    def __init__(self, norm=3, output_size=1, eps=1e-6):
        super().__init__()
        assert norm > 0
        self.p = float(norm)
        self.output_size = output_size
        self.eps = eps

    def forward(self, x):
        x = x.clamp(min=self.eps).pow(self.p)
        
        return torch.nn.functional.adaptive_avg_pool2d(x, self.output_size).pow(1. / self.p)

    def __repr__(self):
        return self.__class__.__name__ + '(' \
               + str(self.p) + ', ' \
               + 'output_size=' + str(self.output_size) + ')'



class BaseModel(nn.Module):
    def __init__(self, model_name, num_classes=2, pretrained=True, pool_type='max', down=True, metric='linear'):
        super().__init__()
        self.model_name = model_name
        
        if model_name == 'eff-b3':
            backbone = EfficientNet.from_pretrained('efficientnet-b3')
            plane = 1536
        elif model_name == 'resnext50':
            backbone = nn.Sequential(*list(models.resnext50_32x4d(pretrained=pretrained).children())[:-2])
            plane = 2048
        else:
            backbone = None
            plane = None

        self.backbone = backbone
        
        if pool_type == 'avg':
            self.pool = nn.AdaptiveAvgPool2d((1, 1))
        elif pool_type == 'cat':
            self.pool = AdaptiveConcatPool2d()
            down = 1
        elif pool_type == 'max':
            self.pool = nn.AdaptiveMaxPool2d((1, 1))
        elif pool_type == 'gem':
            self.pool = GeneralizedMeanPooling()
        else:
            self.pool = None
        
        if down:
            if pool_type == 'cat':
                self.down = nn.Sequential(
                    nn.Linear(plane * 2, plane),
                    nn.BatchNorm1d(plane),
                    nn.Dropout(0.2),
                    nn.ReLU(True)
                    )
            else:
                self.down = nn.Sequential(
                    nn.Linear(plane, plane),
                    nn.BatchNorm1d(plane),
                    nn.Dropout(0.2),
                    nn.ReLU(True)
                )
        else:
            self.down = nn.Identity()
        
        self.se = SELayer(plane)
        self.hidden = nn.Linear(plane, plane)
        self.relu = nn.ReLU(True)
        
        if metric == 'linear':
            self.metric = nn.Linear(plane, num_classes)
        elif metric == 'am':
            self.metric = AddMarginProduct(plane, num_classes)
        else:
            self.metric = None

    def forward(self, x):
        if self.model_name == 'eff-b3':
            feat = self.backbone.extract_features(x)
        else:
            feat = self.backbone(x)
        
        feat = self.pool(feat)
        se = self.se(feat).view(feat.size(0), -1)
        feat_flat = feat.view(feat.size(0), -1)
        feat_flat = self.relu(self.hidden(feat_flat) * se)

        out = self.metric(feat_flat)
        return out


if __name__ == '__main__':
    model = BaseModel(model_name='eff-b3').eval()
    x = torch.randn((1, 3, 224, 224))
    out = model(x)
    print(out.size())
    print(model)

3、构建训练过程

from torch.utils.data import DataLoader
from ArtModel import BaseModel
import time
import numpy as np
import random
from torch.optim import lr_scheduler
from torch.backends import cudnn
import argparse
import os
import torch
import torch.nn as nn
from dataload import Dataset

#设置模型参数
parser = argparse.ArgumentParser()
parser.add_argument('--model_name', default='resnext50', type=str)#模型名字
parser.add_argument('--savepath', default='./Art/', type=str)
parser.add_argument('--loss', default='ce', type=str)#损失函数
parser.add_argument('--num_classes', default=49, type=int)#类的数目
parser.add_argument('--pool_type', default='avg', type=str)#池化类型
parser.add_argument('--metric', default='linear', type=str)
parser.add_argument('--down', default=0, type=int)
parser.add_argument('--lr', default=0.01, type=float)#学习率
parser.add_argument('--weight_decay', default=5e-4, type=float)#权重衰减
parser.add_argument('--momentum', default=0.9, type=float)
parser.add_argument('--scheduler', default='cos', type=str)
parser.add_argument('--resume', default=None, type=str)
parser.add_argument('--lr_step', default=25, type=int)
parser.add_argument('--lr_gamma', default=0.1, type=float)
parser.add_argument('--total_epoch', default=60, type=int)
parser.add_argument('--batch_size', default=32, type=int)
parser.add_argument('--num_workers', default=8, type=int)
parser.add_argument('--multi-gpus', default=0, type=int)
parser.add_argument('--gpu', default=0, type=int)
parser.add_argument('--seed', default=2020, type=int)
parser.add_argument('--pretrained', default=1, type=int)
parser.add_argument('--gray', default=0, type=int)

args = parser.parse_args()


def train():
    model.train()

    epoch_loss = 0
    correct = 0.
    total = 0.
    t1 = time.time()
    for idx, (data, labels) in enumerate(trainloader):
        data, labels = data.to(device), labels.long().to(device)
        
        out, se, feat_flat = model(data)
       
        loss = criterion(out, labels)
        optimizer.zero_grad()
        
        loss.backward()
        optimizer.step()

        epoch_loss += loss.item() * data.size(0)
        total += data.size(0)
        _, pred = torch.max(out, 1)
        correct += pred.eq(labels).sum().item()

    acc = correct / total
    loss = epoch_loss / total

    print(f'loss:{loss:.4f} acc@1:{acc:.4f} time:{time.time() - t1:.2f}s', end=' --> ')
    
    with open(os.path.join(savepath, 'log.txt'), 'a+')as f:
        f.write('loss:{:.4f}, acc:{:.4f} ->'.format(loss, acc))
    
    return {'loss': loss, 'acc': acc}


def test(epoch):
    model.eval()

    epoch_loss = 0
    correct = 0.
    total = 0.
    with torch.no_grad():
        for idx, (data, labels) in enumerate(valloader):
            data, labels = data.to(device), labels.long().to(device)
            
            out = model(data)

            loss = criterion(out, labels)

            epoch_loss += loss.item() * data.size(0)
            total += data.size(0)
            _, pred = torch.max(out, 1)
            correct += pred.eq(labels).sum().item()

        acc = correct / total
        loss = epoch_loss / total

        print(f'test loss:{loss:.4f} acc@1:{acc:.4f}', end=' ')

    global best_acc, best_epoch

    state = {
        'net': model.state_dict(),
        'acc': acc,
        'epoch': epoch
    }
                                                    
    if acc > best_acc:
        best_acc = acc
        best_epoch = epoch

        torch.save(state, os.path.join(savepath, 'best.pth'))
        print('*')
    else:
        print()

    torch.save(state, os.path.join(savepath, 'last.pth'))


    with open(os.path.join(savepath, 'log.txt'), 'a+')as f:
        f.write('epoch:{}, loss:{:.4f}, acc:{:.4f}\n'.format(epoch, loss, acc))

    return {'loss': loss, 'acc': acc}


def plot(d, mode='train', best_acc_=None):
    import matplotlib.pyplot as plt
    plt.figure(figsize=(10, 4))
    plt.suptitle('%s_curve' % mode)
    plt.subplots_adjust(wspace=0.2, hspace=0.2)
    epochs = len(d['acc'])

    plt.subplot(1, 2, 1)
    plt.plot(np.arange(epochs), d['loss'], label='loss')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.legend(loc='upper left')

    plt.subplot(1, 2, 2)
    plt.plot(np.arange(epochs), d['acc'], label='acc')
    if best_acc_ is not None:
        plt.scatter(best_acc_[0], best_acc_[1], c='r')
    plt.xlabel('epoch')
    plt.ylabel('acc')
    plt.legend(loc='upper left')

    plt.savefig(os.path.join(savepath, '%s.jpg' % mode), bbox_inches='tight')
    plt.close()


if __name__ == '__main__':
    best_epoch = 0
    best_acc = 0.
    use_gpu = False

    if args.seed is not None:
        print('use random seed:', args.seed)
        torch.manual_seed(args.seed)
        torch.cuda.manual_seed(args.seed)
        torch.cuda.manual_seed_all(args.seed)
        np.random.seed(args.seed)
        random.seed(args.seed)
        cudnn.deterministic = False

    if torch.cuda.is_available():
        use_gpu = True
        cudnn.benchmark = True

    # loss
    criterion = nn.CrossEntropyLoss()
    # dataloader
    trainset = Dataset(mode='train')
    valset = Dataset(mode='val')
    
    trainloader = DataLoader(dataset=trainset, batch_size=args.batch_size, shuffle=True, \
                             num_workers=args.num_workers, pin_memory=True, drop_last=True)
    
    valloader = DataLoader(dataset=valset, batch_size=128, shuffle=False, num_workers=args.num_workers, \
                           pin_memory=True)

    # model
    model = BaseModel(model_name=args.model_name, num_classes=args.num_classes, pretrained=args.pretrained, pool_type=args.pool_type, down=args.down, metric=args.metric)
    if args.resume:
        state = torch.load(args.resume)
        print('best_epoch:{}, best_acc:{}'.format(state['epoch'], state['acc']))
        model.load_state_dict(state['net'])

    if torch.cuda.device_count() > 1 and args.multi_gpus:
        print('use multi-gpus...')
        os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        torch.distributed.init_process_group(backend="nccl", init_method='tcp://localhost:23456', rank=0, world_size=1)
        model = model.to(device)
        model = nn.parallel.DistributedDataParallel(model)
    else:
        device = ('cuda:%d'%args.gpu if torch.cuda.is_available() else 'cpu')
        model = model.to(device)
    print('device:', device)

    # optim
    optimizer = torch.optim.SGD(
            [{'params': filter(lambda p: p.requires_grad, model.parameters()), 'lr': args.lr}],
            weight_decay=args.weight_decay, momentum=args.momentum)

    print('init_lr={}, weight_decay={}, momentum={}'.format(args.lr, args.weight_decay, args.momentum))

    if args.scheduler == 'step':
        scheduler = lr_scheduler.StepLR(optimizer, step_size=args.lr_step, gamma=args.lr_gamma, last_epoch=-1)
    elif args.scheduler == 'multi':
        scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[150, 225], gamma=args.lr_gamma, last_epoch=-1)
    elif args.scheduler == 'cos':
        warm_up_step = 10
        lambda_ = lambda epoch: (epoch + 1) / warm_up_step if epoch < warm_up_step else 0.5 * (
                    np.cos((epoch - warm_up_step) / (args.total_epoch - warm_up_step) * np.pi) + 1)
        scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lambda_)
    
    # savepath
    savepath = os.path.join(args.savepath, args.model_name+args.pool_type+args.metric+'_'+str(args.down))

    print('savepath:', savepath)

    if not os.path.exists(savepath):
        os.makedirs(savepath)

    with open(os.path.join(savepath, 'setting.txt'), 'w')as f:
        for k, v in vars(args).items():
            f.write('{}:{}\n'.format(k, v))

    f = open(os.path.join(savepath, 'log.txt'), 'w')
    f.close()

    total = args.total_epoch
    start = time.time()

    train_info = {'loss': [], 'acc': []}
    test_info = {'loss': [], 'acc': []}

    for epoch in range(total):
        print('epoch[{:>3}/{:>3}]'.format(epoch, total), end=' ')
        d_train = train()
        scheduler.step()
        d_test = test(epoch)

        for k in train_info.keys():
            train_info[k].append(d_train[k])
            test_info[k].append(d_test[k])

        plot(train_info, mode='train')
        plot(test_info, mode='test', best_acc_=[best_epoch, best_acc])

    end = time.time()
    print('total time:{}m{:.2f}s'.format((end - start) // 60, (end - start) % 60))
    print('best_epoch:', best_epoch)
    print('best_acc:', best_acc)
    with open(os.path.join(savepath, 'log.txt'), 'a+')as f:
        f.write('# best_acc:{:.4f}, best_epoch:{}'.format(best_acc, best_epoch))

4、使用测试集测试模型,得到预测结果

import torch
from ArtModel import BaseModel
import os
import pandas as pd
from PIL import Image
from torchvision import transforms
import numpy as np
import argparse #argparse 是python自带的命令行参数解析包,可以用来方便地读取命令行参数。


def get_setting(path):
    args = {}
    with open(os.path.join(path, 'setting.txt'), 'r')as f:
        for i in f.readlines():
            k, v = i.strip().split(':')
            args[k] = v
    return args

#加载模型和参数
def load_pretrained_model(path, model, mode='best'):
    print('load pretrained model...')
    state = torch.load(os.path.join(path, '%s.pth' % mode))#导入训练好的网络
    print('best_epoch:{}, best_acc:{}'.format(state['epoch'], state['acc']))
    model.load_state_dict(state['net'])#完成模型参数的加载


if __name__ == '__main__':
    mode = 'best'

    #argparse基本框架
    parser = argparse.ArgumentParser()#ArgumentParser类生成一个parser对象
    #add_argument函数来增加参数。
    parser.add_argument('--savepath', default='./Base224L2/eff-b3', type=str)
    parser.add_argument('--last', action='store_true')
    args = parser.parse_args()#parse_args获取解析的参数
    

    path = args.savepath
    if args.last:
        mode = 'last'
    
    args = get_setting(path)
    # print(args)

    # model
    model = BaseModel(model_name=args['model_name'], num_classes=int(args['num_classes']), \
        pretrained=int(args['pretrained']), pool_type=args['pool_type'], down=int(args['down']), metric=args['metric'])

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    # device = torch.device('cpu')
    model = model.to(device)
    load_pretrained_model(path, model, mode=mode)

    size = 512
    trans = transforms.Compose([
        transforms.Resize((int(size / 0.875), int(size / 0.875))),
        transforms.RandomHorizontalFlip(),
        transforms.RandomCrop((size, size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])

    submit = {'uuid': [], 'label': []}
    TTA_times = 7  #训练七次

    model.eval()
    with torch.no_grad():
        for i in range(0, 800):
            img_path = './data/Art/data/test/%d.jpg' % i
            raw_img = Image.open(img_path).convert('RGB')
            results = np.zeros(49)

            for j in range(TTA_times):
                img = trans(raw_img)
                img = img.unsqueeze(0).to(device)#在第一维增加一个维度
                out = model(img)
                out = torch.softmax(out, dim=1)
                _, pred = torch.max(out.cpu(), dim=1)

                results[pred] += 1
            pred = np.argmax(results)#选择最大的值作为最后的label
            print(i, ',', pred)
            submit['uuid'].append(i)
            submit['label'].append(pred)

    df = pd.DataFrame(submit)
    df.to_csv(os.path.join(path, 'result.csv'), encoding='utf-8', index=False, header=False)

5、投票取优

import pandas as pd
import numpy as np


files = ['1.csv', '2.csv', '3.csv', '4.csv']
weights = [1, 1, 1, 1]

results = np.zeros((800, 49))
for file, w in zip(files, weights):#[('1.csv',1),('2.csv',1),('3.csv',1),('4.csv',1)]
    print(w)
    df = pd.read_csv(file, header=None).values
    for x, y in df:
        # print(x, y)
        results[x, y] += w #????
        # break

print(results[0])

submit = {
    'name': np.arange(800).tolist(),
    'pred': np.argmax(results, axis=1).tolist()#每一行取最大值的列下标
    }

for k, v in submit.items():
    print(k, v)

df = pd.DataFrame(submit)
df.to_csv('vote.csv', header=False, index=False)

posted on 2020-11-05 15:13  Justing778  阅读(183)  评论(0编辑  收藏  举报