├── README.md ├── data ├── dataset_k1.json └── dataset_test.json ├── dataset.py ├── fastai_version └── to_be_continue.txt ├── main.py ├── tools ├── cate_distribute.png ├── data_analysis.py └── re_clean_data.py ├── trainer.py └── untils.py /README.md: -------------------------------------------------------------------------------- 1 | # DF分类 2 | 模型调用基于[pretrainedmodels](https://github.com/Cadene/pretrained-models.pytorch) 和 [effcientnet](https://github.com/lukemelas/EfficientNet-PyTorch),模型与其详细信息可在链接中看到; 3 | 4 | **单模表现(A榜):** 5 | **effcientnet-b4**:_0.547_ 6 | **senet154**: _0.551_(这个模型比较大,量力而行) 7 | **inceptionresnetv2**: _0.522_ 8 | 9 | (TTA为左右翻转输出取平均) 10 | 11 | se154+effb4 ensemble *0.571* 12 | 13 | ### Requirements 14 | 15 | ```angular2html 16 | opencv-python 17 | torchsummary 18 | scikit-learn==0.21.2 19 | albumentations==0.3.3 20 | pytorch>=1.0.0 21 | pretrainedmodels==0.7.4 22 | efficientnet-pytorch==0.4.0 23 | ``` 24 | ### 数据 25 | 单标签分类,数据集经过处理,对于多个类别的图片,**使用总体数量最多的作为其类别**。 26 | 27 | 数据集索引为Json格式,位于`./data/dataset_k1.json`。其中4/5用于训练,1/5用于验证。可以根据json自己划分一下。 28 | 29 | 测试数据集索引为`./data/dataset_test.json` 30 | 31 | ### 训练 32 | 训练参数在`main.py`中查看,都有相关解释; 33 | 34 | 部分重要的参数在`untils.py`中,可以检查一下,写得比较粗糙难免有一些错误:**创建优化器**`build_optimizer()`、**初始化模型**`build_cls_model()`*(支持修改relu激活函数为mish,但不建议使用,显存会炸)*、**损失函数**`build_loss_function()`(*单标签就用ce和smooth感觉就足够了*) 35 | 36 | ### 测试 37 | 测试部分`main.py`的`test(option_path,test_image_folder, save_path,model_path,test_info_path)` 38 | **option_path**:训练过程保存了训练参数的json文件,就在模型保存的目录下。 39 | **test_image_folder**:测试图片文件夹。 40 | **save_path**:保存predictions的位置,以dict形式保存,`{'IMAGE_NAME':[OUTPUT_LIST]}`,输出的list是最后fc的输出,长度为类别数,这样保存是为了方便融模型,至于怎么融可自由发挥。 41 | **model_path**:模型位置。多gpu保存的在`resum_load()`里面改参数。 42 | 43 | 44 | ### 可能有用的 45 | 46 | **初始学习率寻找**:参考fastai的[lr_finder](https://sgugger.github.io/how-do-you-find-a-good-learning-rate.html) 47 | ``` 48 | import matplotlib.pyplot as plt 49 | trainer = MultiClsTrainer(opt) 50 | logs = trainer.lr_finder() 51 | plt.plot(logs['lr'][10:-5],logs['loss'][10:-5]) 52 | ``` 53 | 54 | **预裁剪**:对于过长的图片,裁剪掉下方的一部分,再进行训练。 55 | 56 | **split_weights**:权重衰减不优化再bias上,原理实验等谷歌。 57 | 58 | **数据简单EDA**:位于tools文件夹 59 | -------------------------------------------------------------------------------- /dataset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : dataset.py 5 | @Desciption : None 6 | @Modify Time @Author @Version 7 | ------------ ------- -------- 8 | 2019/9/26 13:36 Daic 1.0 9 | ''' 10 | import os 11 | import cv2 12 | import json 13 | import torch 14 | import numpy as np 15 | import albumentations as albu 16 | from torch.utils.data import DataLoader 17 | from torch.utils.data import Dataset as BaseDB 18 | 19 | 20 | def SkyCrop(img): 21 | #img [h,w,3] 22 | if img.shape[1]*1.8dict[str(final_cate)]: 27 | final_cate = li 28 | 29 | return final_cate 30 | 31 | def one_hot_list(cate): 32 | onehot = [] 33 | for x in range(29): 34 | if x in cate: 35 | onehot.append(1) 36 | else: 37 | onehot.append(0) 38 | return onehot 39 | 40 | ### this is cheecking single label that is belong to the category with most count 41 | # r = csv.reader(open('/media/disk2/daic/Cloud/Train_label.csv')) 42 | # datas = [l for l in r] 43 | # predata = json.load(open('/media/disk2/daic/Cloud/dataset_k1.json')) 44 | # count = {} 45 | # for x in range(29): 46 | # count[str(x)] = 0 47 | # for tmp in predata: 48 | # count[str(tmp['cate'])]+=1 49 | # 50 | # for i in range(1,len(datas)): 51 | # da = datas[i] 52 | # if len(da[1])>2: 53 | # tmp_cates = get_cates(da[1]) 54 | # tmp_cate = get_main_cate(tmp_cates,count) 55 | # img = da[0] 56 | # for tmp in predata: 57 | # if tmp['img']==img and tmp['cate']!=tmp_cate: 58 | # print("!!!!!!!!!!!!!!!!!!") 59 | 60 | ### this is getting the mutilabel dataset; 61 | 62 | if __name__ == '__main__': 63 | r = csv.reader(open('./Train_label.csv')) 64 | datas = [l for l in r] 65 | predata = json.load(open('./dataset_k1.json')) 66 | 67 | idx = {} 68 | for x in range(1,len(datas)): 69 | idx[datas[x][0]] = datas[x][1] 70 | 71 | for x in range(len(predata)): 72 | k = predata[x]['img'] 73 | oneh = one_hot_list(get_cates(idx[k])) 74 | 75 | predata[x]['muticate'] = oneh 76 | 77 | json.dump(predata) 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /trainer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : models.py 5 | @Desciption : None 6 | @Modify Time @Author @Version 7 | ------------ ------- -------- 8 | 2019/9/26 13:38 Daic 1.0 9 | ''' 10 | import time 11 | import torch 12 | import torch.nn as nn 13 | import numpy as np 14 | from untils import * 15 | from dataset import * 16 | from torch.optim.lr_scheduler import ReduceLROnPlateau,MultiStepLR 17 | 18 | class MultiClsTrainer(object): 19 | def __init__(self, opt): 20 | self.opt = opt 21 | print(opt) 22 | self.save_path = os.path.join(self.opt.out_path,self.opt.train_name) 23 | if not os.path.isdir(self.save_path): 24 | os.mkdir(self.save_path) 25 | 26 | self.train_bch = opt.train_bch 27 | self.val_bch = opt.val_bch 28 | self.num_worker = opt.num_worker 29 | self.model = build_cls_model(self.opt.cnn,active = 'relu',class_num=self.opt.num_class,chanel_num=3)#relu 30 | #print(self.nmodel) 31 | self.model.cuda() 32 | #self.model = torch.nn.DataParallel(self.nmodel) 33 | 34 | self.val_dataset = ClsSteelDataset(self.opt, 'val') 35 | self.train_arguementation = get_training_augmentation() 36 | self.train_dataset = ClsSteelDataset(self.opt,'train',self.train_arguementation) 37 | print("Initial dataset success! The train length: %d The val length: %d"% 38 | (len(self.train_dataset),len(self.val_dataset))) 39 | 40 | self.train_loader = DataLoader(dataset=self.train_dataset,shuffle=True , 41 | batch_size=self.train_bch, num_workers=self.num_worker) 42 | self.val_loader = DataLoader(dataset=self.val_dataset,shuffle=False , 43 | batch_size=self.val_bch, num_workers=self.num_worker-4) 44 | 45 | self.loss = build_loss_function(self.opt) 46 | 47 | if self.opt.split_weights == 1: 48 | params = split_weights(self.model) 49 | else: 50 | params = self.model.parameters() 51 | 52 | self.optimizer = build_optimizer(params, self.opt) 53 | self.scheduler = MultiStepLR(self.optimizer, milestones=self.opt.decay_step, gamma=self.opt.decay_rate) 54 | 55 | 56 | self.max_epoch = self.opt.max_epoch 57 | self.max_score = 0. 58 | 59 | self.best_acc = 0.5 60 | 61 | def resum_load(self,path,mutigpu=False): 62 | net_data = torch.load(path) 63 | 64 | if mutigpu: 65 | for k, v in net_data.items(): 66 | name = k[7:] 67 | net_data[name] = net_data.pop(k) 68 | self.model.load_state_dict(torch.load(net_data)) 69 | print("Loading success from %s"%path) 70 | 71 | def lr_finder(self,epoch,save_path,slr=1e-8,elr=1): 72 | log_lrs = [] 73 | log_loss = [] 74 | all_iter = self.train_dataset.__len__() * epoch // self.train_bch 75 | global_iter = 0. 76 | _lr__ = slr 77 | mult = (elr / slr) ** (1 / all_iter) 78 | 79 | for epoch in range(epoch): 80 | for i, data in enumerate(self.train_loader): 81 | _lr__ *= mult 82 | set_lr(self.optimizer, _lr__) 83 | log_lrs.append(math.log10(_lr__)) 84 | img = data[0].cuda() 85 | label = data[1].cuda() 86 | outputs = self.model(img) 87 | loss = self.loss(outputs, label) 88 | log_loss.append(loss.item()) 89 | 90 | self.optimizer.zero_grad() 91 | loss.backward() 92 | self.optimizer.step() 93 | 94 | global_iter+=1 95 | print("%.1f / %.1f loss:%.6f lr%.8f"%(global_iter,all_iter,loss.item(),_lr__)) 96 | logs = {'lr':log_lrs,'loss':log_loss} 97 | json.dump(logs,open(os.path.join(save_path,'find_lr.json'),'w')) 98 | return logs 99 | 100 | 101 | 102 | def eval_model(self): 103 | self.model.eval() 104 | pre = [] 105 | gt = [] 106 | 107 | with torch.no_grad(): 108 | for i, data in enumerate(self.val_loader): 109 | img = data[0].cuda() 110 | label = data[1] 111 | label = label.numpy().astype(int).tolist() 112 | outputs = self.model(img).data.cpu()#.squeeze().numpy()#b 113 | #print(outputs) 114 | 115 | #predicted = (outputs>0.5).astype(int).tolist() 116 | _, predicted = torch.max(outputs, 1) 117 | predicted = predicted.squeeze().numpy().tolist() 118 | #print(predicted) 119 | #print(label) 120 | pre += predicted 121 | gt += label 122 | print(classification_report(gt,pre)) 123 | accs = classification_report(gt,pre,output_dict=True) 124 | return accs 125 | 126 | def train_model(self): 127 | global_iter = 0 128 | running_loss = 0. 129 | item_num = 0 130 | start = time.time() 131 | for epoch in range(self.max_epoch): 132 | print('\nEpoch: {}'.format(epoch)) 133 | for i, data in enumerate(self.train_loader): 134 | img = data[0].cuda() 135 | label = data[1].cuda() 136 | #print(label) 137 | item_num += label.size(0) 138 | outputs = self.model(img) 139 | loss = self.loss(outputs, label) 140 | self.optimizer.zero_grad() 141 | loss.backward() 142 | self.optimizer.step() 143 | running_loss += loss.item() 144 | if i% 10 == 0 and i>0: 145 | print('[%d, %d] loss: %.5f lr:%.5f time:%.2f' % 146 | (epoch, i, running_loss / item_num,self.optimizer.param_groups[0]['lr'], 147 | (time.time()-start)) 148 | ) 149 | running_loss = 0. 150 | item_num = 0 151 | start = time.time() 152 | 153 | global_iter+=1 154 | 155 | acc = self.eval_model() 156 | json.dump(acc, open(os.path.join(self.save_path, 'log_epoch' + str(epoch) + '.json'), 'w')) 157 | 158 | # print("epoch %d:"%(epoch)) 159 | # print('macro avg',acc['macro avg']) 160 | # print('weighted avg', acc['weighted avg']) 161 | if self.best_acc<= acc["accuracy"]: 162 | torch.save(self.model.state_dict(),os.path.join(self.save_path,'model.pth')) 163 | print("saving model....") 164 | self.best_acc = acc["accuracy"] 165 | if epoch == (self.max_epoch-1): 166 | torch.save(self.model.state_dict(), os.path.join(self.save_path,'model_latest.pth')) 167 | 168 | self.scheduler.step() 169 | 170 | def test_model(self,test_info_path,test_image_folder,save_path,model_path=None): 171 | if model_path != None: 172 | self.resum_load(model_path) 173 | 174 | opt_test = self.opt 175 | opt_test.image_path = test_image_folder 176 | opt_test.input_json = test_info_path 177 | 178 | prediction = {} 179 | test_dataset = ClsSteelDataset(opt_test, 'test') 180 | test_loader = DataLoader(test_dataset,shuffle=False, 181 | batch_size=1, num_workers=4) 182 | 183 | for i, data in enumerate(test_loader): 184 | img = data[0].cuda() 185 | name = data[2][0] 186 | outputs = self.model(img) 187 | outputs = outputs.data.cpu().numpy().tolist() 188 | prediction[name] = outputs 189 | if i%100 == 0: 190 | print('%d / %d'%(i,len(test_dataset))) 191 | 192 | json.dump(prediction,open(save_path,'w')) 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /untils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : untils.py 5 | @Desciption : None 6 | @Modify Time @Author @Version 7 | ------------ ------- -------- 8 | 2019/9/26 13:36 Daic 1.0 9 | ''' 10 | import math 11 | import torch 12 | import random 13 | import torch.nn as nn 14 | import torch.nn.functional as F 15 | from torch.autograd import Variable 16 | from torchsummary import summary 17 | import torch.optim as optim 18 | from torch.optim import Optimizer 19 | import pretrainedmodels 20 | from efficientnet_pytorch import EfficientNet 21 | from sklearn.metrics import classification_report 22 | 23 | class RAdam(Optimizer): 24 | 25 | def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0): 26 | defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay) 27 | self.buffer = [[None, None, None] for ind in range(10)] 28 | super(RAdam, self).__init__(params, defaults) 29 | 30 | def __setstate__(self, state): 31 | super(RAdam, self).__setstate__(state) 32 | 33 | def step(self, closure=None): 34 | 35 | loss = None 36 | if closure is not None: 37 | loss = closure() 38 | 39 | for group in self.param_groups: 40 | 41 | for p in group['params']: 42 | if p.grad is None: 43 | continue 44 | grad = p.grad.data.float() 45 | if grad.is_sparse: 46 | raise RuntimeError('RAdam does not support sparse gradients') 47 | 48 | p_data_fp32 = p.data.float() 49 | 50 | state = self.state[p] 51 | 52 | if len(state) == 0: 53 | state['step'] = 0 54 | state['exp_avg'] = torch.zeros_like(p_data_fp32) 55 | state['exp_avg_sq'] = torch.zeros_like(p_data_fp32) 56 | else: 57 | state['exp_avg'] = state['exp_avg'].type_as(p_data_fp32) 58 | state['exp_avg_sq'] = state['exp_avg_sq'].type_as(p_data_fp32) 59 | 60 | exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] 61 | beta1, beta2 = group['betas'] 62 | 63 | exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) 64 | exp_avg.mul_(beta1).add_(1 - beta1, grad) 65 | 66 | state['step'] += 1 67 | buffered = self.buffer[int(state['step'] % 10)] 68 | if state['step'] == buffered[0]: 69 | N_sma, step_size = buffered[1], buffered[2] 70 | else: 71 | buffered[0] = state['step'] 72 | beta2_t = beta2 ** state['step'] 73 | N_sma_max = 2 / (1 - beta2) - 1 74 | N_sma = N_sma_max - 2 * state['step'] * beta2_t / (1 - beta2_t) 75 | buffered[1] = N_sma 76 | 77 | # more conservative since it's an approximated value 78 | if N_sma >= 5: 79 | step_size = group['lr'] * math.sqrt((1 - beta2_t) * (N_sma - 4) / (N_sma_max - 4) * (N_sma - 2) / N_sma * N_sma_max / (N_sma_max - 2)) / (1 - beta1 ** state['step']) 80 | else: 81 | step_size = group['lr'] / (1 - beta1 ** state['step']) 82 | buffered[2] = step_size 83 | 84 | if group['weight_decay'] != 0: 85 | p_data_fp32.add_(-group['weight_decay'] * group['lr'], p_data_fp32) 86 | 87 | # more conservative since it's an approximated value 88 | if N_sma >= 5: 89 | denom = exp_avg_sq.sqrt().add_(group['eps']) 90 | p_data_fp32.addcdiv_(-step_size, exp_avg, denom) 91 | else: 92 | p_data_fp32.add_(-step_size, exp_avg) 93 | 94 | p.data.copy_(p_data_fp32) 95 | 96 | return loss 97 | 98 | class FocalLoss(nn.Module): 99 | def __init__(self, gamma=0, alpha=None, size_average=True): 100 | super(FocalLoss, self).__init__() 101 | self.gamma = gamma 102 | self.alpha = alpha 103 | if isinstance(alpha, (float, int)): self.alpha = torch.Tensor([alpha, 1 - alpha]) 104 | if isinstance(alpha, list): self.alpha = torch.Tensor(alpha) 105 | self.size_average = size_average 106 | def forward(self, input, target): 107 | if input.dim() > 2: 108 | input = input.view(input.size(0), input.size(1), -1) # N,C,H,W => N,C,H*W 109 | input = input.transpose(1, 2) # N,C,H*W => N,H*W,C 110 | input = input.contiguous().view(-1, input.size(2)) # N,H*W,C => N*H*W,C 111 | target = target.view(-1, 1) 112 | logpt = F.log_softmax(input) 113 | logpt = logpt.gather(1, target) 114 | logpt = logpt.view(-1) 115 | pt = Variable(logpt.data.exp()) 116 | if self.alpha is not None: 117 | if self.alpha.type() != input.data.type(): 118 | self.alpha = self.alpha.type_as(input.data) 119 | at = self.alpha.gather(0, target.data.view(-1)) 120 | logpt = logpt * Variable(at) 121 | loss = -1 * (1 - pt) ** self.gamma * logpt 122 | if self.size_average: 123 | return loss.mean() 124 | else: 125 | return loss.sum() 126 | 127 | def build_optimizer(params, opt): 128 | if opt.optimizer == 'rmsprop': 129 | return optim.RMSprop(params, opt.lr, opt.momentum, weight_decay=opt.weight_decay) 130 | elif opt.optimizer == 'radam': 131 | return RAdam(params, opt.lr, weight_decay=opt.weight_decay) 132 | elif opt.optimizer == 'adagrad': 133 | return optim.Adagrad(params, opt.lr, weight_decay=opt.weight_decay) 134 | elif opt.optimizer == 'sgd': 135 | return optim.SGD(params, opt.lr, weight_decay=opt.weight_decay) 136 | elif opt.optimizer == 'sgdm': 137 | return optim.SGD(params, opt.lr, opt.momentum, weight_decay=opt.weight_decay) 138 | elif opt.optimizer == 'sgdmom': 139 | return optim.SGD(params, opt.lr, opt.momentum, weight_decay=opt.weight_decay, nesterov=True) 140 | elif opt.optimizer == 'adam': 141 | return optim.Adam(params, opt.lr, weight_decay=opt.weight_decay) 142 | else: 143 | raise Exception("bad option opt.optim: {}".format(opt.optim)) 144 | 145 | def build_cls_model(name,active = 'relu',class_num=5,chanel_num=3): 146 | if name in ['efficientnet-b0', 'efficientnet-b1', 'efficientnet-b2', 'efficientnet-b3', 'efficientnet-b4', 147 | 'efficientnet-b5','efficientnet-b6']: 148 | if name == 'efficientnet-b3': 149 | model = EfficientNet.from_pretrained('efficientnet-b3') 150 | model._fc = nn.Linear(in_features=1536, out_features=class_num, bias=True) 151 | elif name == 'efficientnet-b4': 152 | model = EfficientNet.from_pretrained('efficientnet-b3') 153 | model._fc = nn.Linear(in_features=1792, out_features=class_num, bias=True) 154 | elif name == 'efficientnet-b6': 155 | model = EfficientNet.from_pretrained('efficientnet-b6') 156 | model._fc = nn.Linear(in_features=2304, out_features=class_num, bias=True) 157 | if name not in ['efficientnet-b0','efficientnet-b1','efficientnet-b2','efficientnet-b3','efficientnet-b4','efficientnet-b5','efficientnet-b6']: 158 | model = pretrainedmodels.__dict__[name](num_classes=1000, pretrained='imagenet') 159 | if name in ['resnet18','resnet32']: 160 | if chanel_num==1: 161 | model.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False) 162 | model.last_linear = nn.Linear(in_features=512, out_features=class_num, bias=True) 163 | elif name in ['resnet50','resnet101','resnet152']: 164 | if chanel_num == 1: 165 | model.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False) 166 | model.last_linear = nn.Linear(in_features=2048, out_features=class_num, bias=True) 167 | elif name in ['senet154', 'se_resnet50', 'se_resnet101', 'se_resnet152', 'se_resnext50_32x4d', 'se_resnext101_32x4d']: 168 | #if chanel_num == 1: 169 | #model.layer0.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False) 170 | model.avg_pool = nn.AdaptiveAvgPool2d(1) 171 | model.last_linear = nn.Linear(in_features=2048, out_features=class_num, bias=True) 172 | elif name in ['inceptionv4']: 173 | model.last_linear = nn.Linear(in_features=1536, out_features=class_num, bias=True) 174 | elif name in ['inceptionresnetv2']: 175 | model.last_linear = nn.Linear(in_features=1536, out_features=class_num, bias=True) 176 | else: 177 | raise Exception("unsupported model! {}".format(name)) 178 | 179 | if active == 'relu': 180 | return model 181 | elif active == 'mish': 182 | convert_relu_to_Mish(model) 183 | return model 184 | 185 | def set_lr(optimizer, lr): 186 | for group in optimizer.param_groups: 187 | group['lr'] = lr 188 | def get_lr(optimizer): 189 | return optimizer.param_groups[0]['lr'] 190 | 191 | 192 | class LSR(nn.Module): 193 | def __init__(self, e=0.1, reduction='mean'): 194 | super(LSR,self).__init__() 195 | self.log_softmax = nn.LogSoftmax(dim=1) 196 | self.e = e 197 | self.reduction = reduction 198 | 199 | def _one_hot(self, labels, classes, value=1): 200 | """ 201 | Convert labels to one hot vectors 202 | 203 | Args: 204 | labels: torch tensor in format [label1, label2, label3, ...] 205 | classes: int, number of classes 206 | value: label value in one hot vector, default to 1 207 | 208 | Returns: 209 | return one hot format labels in shape [batchsize, classes] 210 | """ 211 | 212 | one_hot = torch.zeros(labels.size(0), classes) 213 | 214 | # labels and value_added size must match 215 | labels = labels.view(labels.size(0), -1) 216 | value_added = torch.Tensor(labels.size(0), 1).fill_(value) 217 | 218 | value_added = value_added.to(labels.device) 219 | one_hot = one_hot.to(labels.device) 220 | 221 | one_hot.scatter_add_(1, labels, value_added) 222 | 223 | return one_hot 224 | 225 | def _smooth_label(self, target, length, smooth_factor): 226 | """convert targets to one-hot format, and smooth 227 | them. 228 | Args: 229 | target: target in form with [label1, label2, label_batchsize] 230 | length: length of one-hot format(number of classes) 231 | smooth_factor: smooth factor for label smooth 232 | 233 | Returns: 234 | smoothed labels in one hot format 235 | """ 236 | one_hot = self._one_hot(target, length, value=1 - smooth_factor) 237 | one_hot += smooth_factor / length 238 | 239 | return one_hot.to(target.device) 240 | 241 | def forward(self, x, target): 242 | 243 | if x.size(0) != target.size(0): 244 | raise ValueError('Expected input batchsize ({}) to match target batch_size({})' 245 | .format(x.size(0), target.size(0))) 246 | 247 | if x.dim() < 2: 248 | raise ValueError('Expected input tensor to have least 2 dimensions(got {})' 249 | .format(x.size(0))) 250 | 251 | if x.dim() != 2: 252 | raise ValueError('Only 2 dimension tensor are implemented, (got {})' 253 | .format(x.size())) 254 | 255 | smoothed_target = self._smooth_label(target, x.size(1), self.e) 256 | x = self.log_softmax(x) 257 | loss = torch.sum(- x * smoothed_target, dim=1) 258 | 259 | if self.reduction == 'none': 260 | return loss 261 | 262 | elif self.reduction == 'sum': 263 | return torch.sum(loss) 264 | 265 | elif self.reduction == 'mean': 266 | return torch.mean(loss) 267 | 268 | else: 269 | raise ValueError('unrecognized option, expect reduction to be one of none, mean, sum') 270 | 271 | def build_loss_function(opt): 272 | if opt.loss =='lsr': 273 | return LSR() 274 | elif opt.loss =='ce': 275 | return nn.CrossEntropyLoss() 276 | elif opt.loss == 'bce': 277 | return nn.BCELoss() 278 | elif opt.loss == 'focal': 279 | return FocalLoss() 280 | elif opt.loss == 'bcel': 281 | return nn.BCEWithLogitsLoss() 282 | else: 283 | raise Exception("bad option opt.loss: {}".format(opt.loss)) 284 | 285 | 286 | 287 | def split_weights(net): 288 | """split network weights into to categlories, 289 | one are weights in conv layer and linear layer, 290 | others are other learnable paramters(conv bias, 291 | bn weights, bn bias, linear bias) 292 | Args: 293 | net: network architecture 294 | 295 | Returns: 296 | a dictionary of params splite into to categlories 297 | """ 298 | 299 | decay = [] 300 | no_decay = [] 301 | 302 | for m in net.modules(): 303 | if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear): 304 | decay.append(m.weight) 305 | 306 | if m.bias is not None: 307 | no_decay.append(m.bias) 308 | 309 | else: 310 | if hasattr(m, 'weight'): 311 | no_decay.append(m.weight) 312 | if hasattr(m, 'bias'): 313 | no_decay.append(m.bias) 314 | 315 | assert len(list(net.parameters())) == len(decay) + len(no_decay) 316 | 317 | return [dict(params=decay), dict(params=no_decay, weight_decay=0)] 318 | 319 | ##################################### 320 | #Pairwise Confusion for Fine-Grained Visual Classification 321 | #https://github.com/abhimanyudubey/confusion 322 | def PairwiseConfusion(features): 323 | batch_size = features.size(0) 324 | if float(batch_size) % 2 != 0: 325 | raise Exception('Incorrect batch size provided') 326 | batch_left = features[:int(0.5*batch_size)] 327 | batch_right = features[int(0.5*batch_size):] 328 | loss = torch.norm((batch_left - batch_right).abs(),2, 1).sum() / float(batch_size) 329 | 330 | return loss 331 | 332 | def EntropicConfusion(features): 333 | batch_size = features.size(0) 334 | return torch.mul(features, torch.log(features)).sum() * (1.0 / batch_size) --------------------------------------------------------------------------------