• 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('
    %s %s
    ' % (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}]	'
                          'Time {batch_time.val:.3f} ({batch_time.avg:.3f})	'
                          'Data {data_time.val:.3f} ({data_time.avg:.3f})	'
                          'Loss {loss.val:.4f} ({loss.avg:.4f})	'
                          '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}]	'
                          'Time {batch_time.val:.3f} ({batch_time.avg:.3f})	'.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
    ' % (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---------------------
    ')
    

    23、

        with open('./result/%s.txt' % file_name, 'a') as acc_file:
            acc_file.write('* best acc: %.8f  %s
    ' % (best_score, os.path.basename(__file__)))
        with open('./result/best_acc.txt', 'a') as acc_file:
            acc_file.write('%s  * best acc: %.8f  %s
    ' % (
            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,{}
    '.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,{}
    '.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}
    '.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('{}:{}
    '.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)
    

  • 相关阅读:
    Spring Boot 学习随记
    Prometheus 普罗米修斯监控
    安装VC++6.0步骤及心得
    NFS 系统搭建
    Centos 搭建邮箱系统
    搭建 RTMP 服务器
    阿里云 DTS 实践
    ELK 搭建
    Prometheus 和 Grafana 安装部署
    Centos7 Nagios 搭建
  • 原文地址:https://www.cnblogs.com/Justing778/p/13913279.html
Copyright © 2020-2023  润新知