├── .gitignore ├── 2018_AL_defect_train.py ├── 2018_bd_tiangong_train.py ├── 2018_bd_xjtu_train.py ├── 2018_pdr_train.py ├── README.md ├── dataset ├── AL_defect_dataset.py ├── __init__.py ├── bd_tiangong_dataset.py ├── bd_xjtu_dataset.py ├── data_aug.py └── pdr_dataset.py ├── models ├── __init__.py ├── inception_resnet_v2.py ├── inception_v4.py ├── multiscale_resnet.py └── xception.py ├── predict ├── bd_tiangong_model_merge.py ├── bd_tiangong_pred.py ├── bd_tiangong_pred_unknow.py └── bd_xjtu_pred.py └── utils ├── __init__.py ├── losses.py └── train_util.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.txt 3 | *.pth 4 | predict/Baidu/ 5 | .idea -------------------------------------------------------------------------------- /2018_AL_defect_train.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import pandas as pd 4 | from sklearn.model_selection import train_test_split 5 | from dataset.AL_defect_dataset import collate_fn, dataset,get_image_pd 6 | import torch 7 | import torch.utils.data as torchdata 8 | from torchvision import datasets, models, transforms 9 | from torchvision.models import resnet50,resnet101 10 | from models.multiscale_resnet import multiscale_resnet 11 | import torch.optim as optim 12 | from torch.optim import lr_scheduler 13 | from utils.train_util import train, trainlog 14 | from torch.nn import CrossEntropyLoss 15 | import logging 16 | from dataset.data_aug import * 17 | import sys 18 | import argparse 19 | from dataset.AL_defect_dataset import defect_label 20 | 21 | reload(sys) 22 | sys.setdefaultencoding('utf8') 23 | ''' 24 | https://tianchi.aliyun.com/competition/information.htm?spm=5176.11165268.5678.2.7d4910c5YfrwzY&raceId=231682 25 | ''' 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument('--batch_size', type=int, default=8, help='size of each image batch') 28 | 29 | parser.add_argument('--learning_rate', type=float, default=0.001, help='learning rate') 30 | parser.add_argument('--checkpoint_dir', type=str, default='/media/hszc/model/detao/models/AL/resnet50', help='directory where model checkpoints are saved') 31 | parser.add_argument('--cuda_device', type=str, default="2,3", help='whether to use cuda if available') 32 | parser.add_argument('--net', dest='net',type=str, default='resnet50',help='resnet101,resnet50') 33 | parser.add_argument('--resume', type=str, default=None, help='path to resume weights file') 34 | parser.add_argument('--epochs', type=int, default=30, help='number of epochs') 35 | parser.add_argument('--start_epoch', type=int, default=0, help='number of start epoch') 36 | 37 | parser.add_argument('--save_checkpoint_val_interval', type=int, default=300, help='interval between saving model weights') 38 | parser.add_argument('--print_interval', type=int, default=100, help='interval between print log') 39 | parser.add_argument('--img_root_train', type=str, default= "/media/hszc/model/detao/data/guangdong/guangdong_round1_train2_2018091622/瑕疵样本", help='whether to img root') 40 | 41 | parser.add_argument('--n_cpu', type=int, default=4, help='number of cpu threads to use during batch generation') 42 | opt = parser.parse_args() 43 | os.environ["CUDA_VISIBLE_DEVICES"] = opt.cuda_device 44 | if __name__ == '__main__': 45 | 46 | # # saving dir 47 | save_dir = opt.checkpoint_dir 48 | if not os.path.exists(save_dir): 49 | os.makedirs(save_dir) 50 | 51 | logfile = '%s/trainlog.log' % save_dir 52 | trainlog(logfile) 53 | 54 | all_pd= get_image_pd(opt.img_root_train) 55 | train_pd,val_pd = train_test_split(all_pd, test_size=0.1, random_state=53,stratify=all_pd["label"]) 56 | 57 | print(val_pd.shape) 58 | 59 | '''数据扩增''' 60 | data_transforms = { 61 | 'train': Compose([ 62 | Resize(size=(640, 640)), 63 | FixRandomRotate(bound='Random'), 64 | RandomHflip(), 65 | RandomVflip(), 66 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 67 | ]), 68 | 'val': Compose([ 69 | Resize(size=(640, 640)), 70 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 71 | ]), 72 | } 73 | 74 | data_set = {} 75 | data_set['train'] = dataset( anno_pd=train_pd, transforms=data_transforms["train"]) 76 | data_set['val'] = dataset( anno_pd=val_pd, transforms=data_transforms["val"]) 77 | 78 | dataloader = {} 79 | dataloader['train']=torch.utils.data.DataLoader(data_set['train'], batch_size=opt.batch_size, 80 | shuffle=True, num_workers=2*opt.n_cpu,collate_fn=collate_fn) 81 | dataloader['val']=torch.utils.data.DataLoader(data_set['val'], batch_size=4, 82 | shuffle=True, num_workers=opt.n_cpu,collate_fn=collate_fn) 83 | '''model''' 84 | if opt.net == "resnet50": 85 | model =resnet50(pretrained=True) 86 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 87 | model.fc = torch.nn.Linear(model.fc.in_features,61) 88 | elif opt.net == "resnet101": 89 | model =resnet101(pretrained=True) 90 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 91 | model.fc = torch.nn.Linear(model.fc.in_features,61) 92 | 93 | if opt.resume: 94 | model.eval() 95 | logging.info('resuming finetune from %s' % opt.resume) 96 | try: 97 | model.load_state_dict(torch.load(opt.resume)) 98 | model = torch.nn.DataParallel(model) 99 | except KeyError: 100 | model = torch.nn.DataParallel(model) 101 | model.load_state_dict(torch.load(opt.resume)) 102 | else: 103 | model = torch.nn.DataParallel(model) 104 | model = model.cuda() 105 | 106 | optimizer = optim.SGD(model.parameters(), lr=opt.learning_rate, momentum=0.9, weight_decay=1e-5) 107 | criterion = CrossEntropyLoss() 108 | exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1) 109 | 110 | train(model, 111 | epoch_num=opt.epochs, 112 | start_epoch=opt.start_epoch, 113 | optimizer=optimizer, 114 | criterion=criterion, 115 | exp_lr_scheduler=exp_lr_scheduler, 116 | data_set=data_set, 117 | data_loader=dataloader, 118 | save_dir=save_dir, 119 | print_inter=opt.print_interval, 120 | val_inter=opt.save_checkpoint_val_interval) -------------------------------------------------------------------------------- /2018_bd_tiangong_train.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import pandas as pd 4 | from sklearn.model_selection import train_test_split 5 | from dataset.bd_tiangong_dataset import collate_fn, dataset 6 | import torch 7 | import torch.utils.data as torchdata 8 | from torchvision import datasets, models, transforms 9 | from torchvision.models import resnet50,resnet101 10 | from models.multiscale_resnet import multiscale_resnet 11 | import torch.optim as optim 12 | from torch.optim import lr_scheduler 13 | from utils.train_util import train, trainlog 14 | from torch.nn import CrossEntropyLoss 15 | import logging 16 | from dataset.data_aug import * 17 | import sys 18 | import argparse 19 | from dataset.bd_tiangong_dataset import class2label 20 | 21 | reload(sys) 22 | sys.setdefaultencoding('utf8') 23 | ''' 24 | http://dianshi.baidu.com/dianshi/pc/competition/22/rank''' 25 | parser = argparse.ArgumentParser() 26 | parser.add_argument('--batch_size', type=int, default=8, help='size of each image batch') 27 | 28 | parser.add_argument('--learning_rate', type=float, default=0.001, help='learning rate') 29 | parser.add_argument('--checkpoint_dir', type=str, default='/media/hszc/model/detao/models/bd_tiangong/resnet50', help='directory where model checkpoints are saved') 30 | parser.add_argument('--cuda_device', type=str, default="0", help='whether to use cuda if available') 31 | parser.add_argument('--net', dest='net',type=str, default='resnet50',help='resnet101,resnet50') 32 | parser.add_argument('--resume', type=str, default=None, help='path to resume weights file') 33 | parser.add_argument('--epochs', type=int, default=100, help='number of epochs') 34 | parser.add_argument('--start_epoch', type=int, default=0, help='number of start epoch') 35 | 36 | parser.add_argument('--save_checkpoint_val_interval', type=int, default=200, help='interval between saving model weights') 37 | parser.add_argument('--print_interval', type=int, default=100, help='interval between print log') 38 | # parser.add_argument('--img_root_train', type=str, default= "/media/hszc/model/detao/data/guangdong/guangdong_round1_train2_2018091622/瑕疵样本", help='whether to img root') 39 | 40 | parser.add_argument('--n_cpu', type=int, default=4, help='number of cpu threads to use during batch generation') 41 | opt = parser.parse_args() 42 | os.environ["CUDA_VISIBLE_DEVICES"] = opt.cuda_device 43 | if __name__ == '__main__': 44 | 45 | # # saving dir 46 | save_dir = opt.checkpoint_dir 47 | if not os.path.exists(save_dir): 48 | os.makedirs(save_dir) 49 | 50 | logfile = '%s/trainlog.log' % save_dir 51 | trainlog(logfile) 52 | 53 | label_csv ="/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/光学数据集-预赛训练集-2000-有标签.csv" 54 | imgroot="/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/预赛训练集-2000" 55 | label = pd.read_csv(label_csv,names=["ImageName","class"]) 56 | label["label"]=label["class"].apply(lambda x:class2label[x]) 57 | train_pd,val_pd = train_test_split(label, test_size=0.12, random_state=43,stratify=label["label"]) 58 | 59 | print(val_pd.shape) 60 | 61 | '''数据扩增''' 62 | data_transforms = { 63 | 'train': Compose([ 64 | Resize(size=(256, 256)), 65 | FixRandomRotate(bound='Random'), 66 | RandomHflip(), 67 | RandomVflip(), 68 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 69 | ]), 70 | 'val': Compose([ 71 | Resize(size=(256, 256)), 72 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 73 | ]), 74 | } 75 | 76 | data_set = {} 77 | data_set['train'] = dataset(imgroot, anno_pd=train_pd, transforms=data_transforms["train"]) 78 | data_set['val'] = dataset(imgroot, anno_pd=val_pd, transforms=data_transforms["val"]) 79 | 80 | dataloader = {} 81 | dataloader['train']=torch.utils.data.DataLoader(data_set['train'], batch_size=opt.batch_size, 82 | shuffle=True, num_workers=2*opt.n_cpu,collate_fn=collate_fn) 83 | dataloader['val']=torch.utils.data.DataLoader(data_set['val'], batch_size=4, 84 | shuffle=True, num_workers=opt.n_cpu,collate_fn=collate_fn) 85 | '''model''' 86 | if opt.net == "resnet50": 87 | model =resnet50(pretrained=True) 88 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 89 | model.fc = torch.nn.Linear(model.fc.in_features,6) 90 | elif opt.net == "resnet101": 91 | model =resnet101(pretrained=True) 92 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 93 | model.fc = torch.nn.Linear(model.fc.in_features,6) 94 | 95 | if opt.resume: 96 | model.eval() 97 | logging.info('resuming finetune from %s' % opt.resume) 98 | try: 99 | model.load_state_dict(torch.load(opt.resume)) 100 | except KeyError: 101 | model = torch.nn.DataParallel(model) 102 | model.load_state_dict(torch.load(opt.resume)) 103 | model = model.cuda() 104 | 105 | optimizer = optim.SGD(model.parameters(), lr=opt.learning_rate, momentum=0.9, weight_decay=1e-5) 106 | criterion = CrossEntropyLoss() 107 | exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.1) 108 | 109 | train(model, 110 | epoch_num=opt.epochs, 111 | start_epoch=opt.start_epoch, 112 | optimizer=optimizer, 113 | criterion=criterion, 114 | exp_lr_scheduler=exp_lr_scheduler, 115 | data_set=data_set, 116 | data_loader=dataloader, 117 | save_dir=save_dir, 118 | print_inter=opt.print_interval, 119 | val_inter=opt.save_checkpoint_val_interval) -------------------------------------------------------------------------------- /2018_bd_xjtu_train.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import pandas as pd 4 | from sklearn.model_selection import train_test_split 5 | from dataset.bd_xjtu_dataset import collate_fn, dataset 6 | import torch 7 | import torch.utils.data as torchdata 8 | from torchvision import datasets, models, transforms 9 | from torchvision.models import resnet50 10 | import torch.optim as optim 11 | from torch.optim import lr_scheduler 12 | from utils.train_util import train, trainlog 13 | from torch.nn import CrossEntropyLoss 14 | import logging 15 | from dataset.data_aug import * 16 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 17 | ''' 18 | http://dianshi.baidu.com/gemstone/competitions/detail?raceId=17 19 | ''' 20 | save_dir = '/media/hszc/model/detao/baidu_model/resnet50' 21 | if not os.path.exists(save_dir): 22 | os.makedirs(save_dir) 23 | logfile = '%s/trainlog.log'%save_dir 24 | trainlog(logfile) 25 | 26 | rawdata_root = '/media/hszc/data/detao/data/baidu/datasets/train' 27 | all_pd = pd.read_csv("/media/hszc/data/detao/data/baidu/datasets/train.txt",sep=" ", 28 | header=None, names=['ImageName', 'label']) 29 | train_pd, val_pd = train_test_split(all_pd, test_size=0.15, random_state=43, 30 | stratify=all_pd['label']) 31 | print(val_pd.shape) 32 | 33 | '''数据扩增''' 34 | data_transforms = { 35 | 'train': Compose([ 36 | RandomRotate(angles=(-15,15)), 37 | ExpandBorder(size=(368,368),resize=True), 38 | RandomResizedCrop(size=(336, 336)), 39 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 40 | ]), 41 | 'val': Compose([ 42 | ExpandBorder(size=(336,336),resize=True), 43 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 44 | ]), 45 | } 46 | 47 | data_set = {} 48 | data_set['train'] = dataset(imgroot=rawdata_root,anno_pd=train_pd, 49 | transforms=data_transforms["train"], 50 | ) 51 | data_set['val'] = dataset(imgroot=rawdata_root,anno_pd=val_pd, 52 | transforms=data_transforms["val"], 53 | ) 54 | dataloader = {} 55 | dataloader['train']=torch.utils.data.DataLoader(data_set['train'], batch_size=4, 56 | shuffle=True, num_workers=4,collate_fn=collate_fn) 57 | dataloader['val']=torch.utils.data.DataLoader(data_set['val'], batch_size=4, 58 | shuffle=True, num_workers=4,collate_fn=collate_fn) 59 | '''model''' 60 | model =resnet50(pretrained=True) 61 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 62 | model.fc = torch.nn.Linear(model.fc.in_features,100) 63 | 64 | base_lr =0.001 65 | resume =None 66 | if resume: 67 | logging.info('resuming finetune from %s'%resume) 68 | model.load_state_dict(torch.load(resume)) 69 | model = model.cuda() 70 | 71 | optimizer = optim.SGD(model.parameters(), lr=base_lr, momentum=0.9, weight_decay=1e-5) 72 | criterion = CrossEntropyLoss() 73 | exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=6, gamma=0.1) 74 | 75 | train(model, 76 | epoch_num=50, 77 | start_epoch=0, 78 | optimizer=optimizer, 79 | criterion=criterion, 80 | exp_lr_scheduler=exp_lr_scheduler, 81 | data_set=data_set, 82 | data_loader=dataloader, 83 | save_dir=save_dir, 84 | print_inter=50, 85 | val_inter=400) -------------------------------------------------------------------------------- /2018_pdr_train.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import pandas as pd 4 | from sklearn.model_selection import train_test_split 5 | from dataset.pdr_dataset import collate_fn, dataset 6 | import torch 7 | import torch.utils.data as torchdata 8 | from torchvision import datasets, models, transforms 9 | from torchvision.models import resnet50,resnet101 10 | from models.xception import pdr_xception 11 | from models.inception_v4 import inceptionv4 12 | from models.multiscale_resnet import multiscale_resnet 13 | import torch.optim as optim 14 | from torch.optim import lr_scheduler 15 | from utils.train_util import train, trainlog 16 | from torch.nn import CrossEntropyLoss 17 | from utils.losses import FocalLoss 18 | import logging 19 | from dataset.data_aug import * 20 | import sys 21 | import argparse 22 | reload(sys) 23 | sys.setdefaultencoding('utf8') 24 | ''' 25 | https://challenger.ai/competition/pdr2018 26 | ''' 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument('--batch_size', type=int, default=32, help='size of each image batch') 29 | 30 | parser.add_argument('--learning_rate', type=float, default=0.0001, help='learning rate') 31 | parser.add_argument('--checkpoint_dir', type=str, default='/media/hszc/model/detao/models/pdr/resnet101_32', help='directory where model checkpoints are saved') 32 | parser.add_argument('--cuda_device', type=str, default="0,3", help='whether to use cuda if available') 33 | parser.add_argument('--net', dest='net',type=str, default='resnet101',help='resnet101,resnet50,xception,inceptionv4') 34 | parser.add_argument('--loss', dest='loss',type=str, default='CrossEntropyLoss',help='focal_loss,CrossEntropyLoss') 35 | parser.add_argument('--optim', dest='optim',type=str, default='sgd',help='adam,sgd') 36 | parser.add_argument('--resume', type=str, default="/media/hszc/model/detao/models/pdr/resnet101/weights-6-1718-[0.8310].pth", help='path to resume weights file') 37 | # parser.add_argument('--resume', type=str, default="/media/hszc/model/detao/models/pdr/inceptionv4/weights-9-1577-[0.8312].pth", help='path to resume weights file') 38 | parser.add_argument('--epochs', type=int, default=30, help='number of epochs') 39 | parser.add_argument('--start_epoch', type=int, default=0, help='number of start epoch') 40 | 41 | parser.add_argument('--save_checkpoint_val_interval', type=int, default=500, help='interval between saving model weights') 42 | parser.add_argument('--print_interval', type=int, default=100, help='interval between print log') 43 | parser.add_argument('--img_root_train', type=str, default= "/media/hszc/model/detao/data/pdr2/ai_challenger_pdr2018_trainingset_20180905/AgriculturalDisease_trainingset", help='whether to img root') 44 | parser.add_argument('--img_root_val', type=str, default= "/media/hszc/model/detao/data/pdr2/ai_challenger_pdr2018_validationset_20180905/AgriculturalDisease_validationset", help='whether to img root') 45 | 46 | parser.add_argument('--n_cpu', type=int, default=4, help='number of cpu threads to use during batch generation') 47 | opt = parser.parse_args() 48 | os.environ["CUDA_VISIBLE_DEVICES"] = opt.cuda_device 49 | if __name__ == '__main__': 50 | 51 | # # saving dir 52 | save_dir = opt.checkpoint_dir 53 | if not os.path.exists(save_dir): 54 | os.makedirs(save_dir) 55 | 56 | logfile = '%s/trainlog.log' % save_dir 57 | trainlog(logfile) 58 | logging.info(opt) 59 | 60 | train_info = open(os.path.join(opt.img_root_train, "AgriculturalDisease_train_annotations.json")) 61 | val_info = open(os.path.join(opt.img_root_val, "AgriculturalDisease_validation_annotations.json")) 62 | 63 | train_pd = pd.read_json(train_info) 64 | val_pd = pd.read_json(val_info) 65 | train_pd["label"] = train_pd['disease_class'] 66 | val_pd["label"] = val_pd['disease_class'] 67 | 68 | train_pd["ImageName"]=train_pd["image_id"].apply(lambda x:os.path.join(opt.img_root_train,"images",x)) 69 | val_pd["ImageName"]=val_pd["image_id"].apply(lambda x:os.path.join(opt.img_root_val,"images",x)) 70 | 71 | print(val_pd.shape) 72 | 73 | '''数据扩增''' 74 | if opt.net == "resnet50" : 75 | 76 | data_transforms = { 77 | 'train': Compose([ 78 | RandomRotate(angles=(-15,15)), 79 | ExpandBorder(size=(368,368),resize=True), 80 | RandomResizedCrop(size=(336, 336)), 81 | RandomHflip(), 82 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 83 | ]), 84 | 'val': Compose([ 85 | ExpandBorder(size=(336,336),resize=True), 86 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 87 | ]), 88 | } 89 | elif opt.net == "resnet101": 90 | data_transforms = { 91 | 'train': Compose([ 92 | RandomRotate(angles=(-15,15)), 93 | ExpandBorder(size=(396,396),resize=True), 94 | RandomResizedCrop(size=(368, 368)), 95 | RandomHflip(), 96 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 97 | ]), 98 | 'val': Compose([ 99 | ExpandBorder(size=(368,368),resize=True), 100 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 101 | ]), 102 | } 103 | elif opt.net == "inceptionv4" or opt.net == "xception" : 104 | data_transforms = { 105 | 'train': Compose([ 106 | RandomRotate(angles=(-15,15)), 107 | ExpandBorder(size=(428,428),resize=True), 108 | RandomResizedCrop(size=(396, 396)), 109 | RandomHflip(), 110 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 111 | ]), 112 | 'val': Compose([ 113 | ExpandBorder(size=(396,396),resize=True), 114 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 115 | ]), 116 | } 117 | 118 | data_set = {} 119 | data_set['train'] = dataset(anno_pd=train_pd, 120 | transforms=data_transforms["train"], 121 | ) 122 | data_set['val'] = dataset(anno_pd=val_pd, 123 | transforms=data_transforms["val"], 124 | ) 125 | dataloader = {} 126 | dataloader['train']=torch.utils.data.DataLoader(data_set['train'], batch_size=opt.batch_size, 127 | shuffle=True, num_workers=2*opt.n_cpu,collate_fn=collate_fn) 128 | dataloader['val']=torch.utils.data.DataLoader(data_set['val'], batch_size=8, 129 | shuffle=True, num_workers=opt.n_cpu,collate_fn=collate_fn) 130 | '''model''' 131 | if opt.net == "resnet50": 132 | model =resnet50(pretrained=True) 133 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 134 | model.fc = torch.nn.Linear(model.fc.in_features,61) 135 | elif opt.net == "resnet101": 136 | model =resnet101(pretrained=True) 137 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 138 | model.fc = torch.nn.Linear(model.fc.in_features,61) 139 | elif opt.net == "xception": 140 | model =pdr_xception(61) 141 | elif opt.net == "inceptionv4": 142 | model =inceptionv4(61) 143 | if opt.resume: 144 | logging.info('resuming finetune from %s'%opt.resume) 145 | model.load_state_dict(torch.load(opt.resume)) 146 | model= torch.nn.DataParallel(model) 147 | model = model.cuda() 148 | if opt.optim =="sgd": 149 | optimizer = optim.SGD(model.parameters(), lr=opt.learning_rate, momentum=0.9, weight_decay=1e-5) 150 | elif opt.optim =="adam": 151 | optimizer = optim.Adam(model.parameters(), lr=opt.learning_rate, weight_decay=1e-5) 152 | 153 | if opt.loss =="CrossEntropyLoss": 154 | criterion = CrossEntropyLoss() 155 | else: 156 | criterion = FocalLoss(class_num=61) 157 | 158 | exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=6, gamma=0.1) 159 | 160 | train(model, 161 | epoch_num=opt.epochs, 162 | start_epoch=opt.start_epoch, 163 | optimizer=optimizer, 164 | criterion=criterion, 165 | exp_lr_scheduler=exp_lr_scheduler, 166 | data_set=data_set, 167 | data_loader=dataloader, 168 | save_dir=save_dir, 169 | print_inter=opt.print_interval, 170 | val_inter=opt.save_checkpoint_val_interval) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 基于pytorch框架的分类baseline 2 | ========================================= 3 | [百度-西交大·大数据竞赛2018——商家招牌的分类与检测](http://dianshi.baidu.com/gemstone/competitions/detail?raceId=17):单模型线上0.99+
4 | 5 | [天池 > 广东工业智造大数据创新大赛:铝型材表面瑕疵识别](https://tianchi.aliyun.com/competition/information.htm?spm=5176.11165268.5678.2.7d4910c5YfrwzY&raceId=231682):单模型线上0.91+
6 | 7 | [农作物病害检测](https://challenger.ai/competition/pdr2018):单模型线上0.845+
8 | 9 | [“探寻地球密码”天宫数据利用大赛](http://dianshi.baidu.com/dianshi/pc/competition/22/rank):单模型未调参线上0.99+
10 | 11 | -------------------------------------------------------- 12 | 运行环境:Ubuntu系统 Python2 pytorch0.3 13 | -------------------------------------------------------- 14 | -------------------------------------------------------------------------------- /dataset/AL_defect_dataset.py: -------------------------------------------------------------------------------- 1 | # coding=utf8 2 | from __future__ import division 3 | import os 4 | import torch 5 | import torch.utils.data as data 6 | import PIL.Image as Image 7 | from data_aug import * 8 | import cv2 9 | import numpy as np 10 | import random 11 | import glob 12 | import pandas as pd 13 | defect_label_order = ['norm', 'defect1', 'defect2', 'defect3', 'defect4', 'defect5', 'defect6', 'defect7', 14 | 'defect8', 'defect9', 'defect10', 'defect11'] 15 | defect_code = { 16 | '正常': 'norm', 17 | '不导电': 'defect1', 18 | '擦花': 'defect2', 19 | '横条压凹': 'defect3', 20 | '桔皮': 'defect4', 21 | '漏底': 'defect5', 22 | '碰伤': 'defect6', 23 | '起坑': 'defect7', 24 | '凸粉': 'defect8', 25 | '涂层开裂': 'defect9', 26 | '脏点': 'defect10', 27 | '其他': 'defect11' 28 | } 29 | defect_label = { 30 | '正常': '0', 31 | '不导电': '1', 32 | '擦花': '2', 33 | '横条压凹': '3', 34 | '桔皮': '4', 35 | '漏底': '5', 36 | '碰伤': '6', 37 | '起坑': '7', 38 | '凸粉': '8', 39 | '涂层开裂':'9', 40 | '脏点': '10', 41 | '其他': '11' 42 | } 43 | label2defect_map = dict(zip(defect_label.values(), defect_label.keys())) 44 | 45 | def get_image_pd(img_root): 46 | img_list = glob.glob(img_root + "/*/*.jpg") 47 | img_list2 = glob.glob(img_root+ "/*/*/*.jpg") 48 | 49 | image_pd1 = pd.DataFrame(img_list, columns=["ImageName"]) 50 | 51 | image_pd2 = pd.DataFrame(img_list2, columns=["ImageName"]) 52 | image_pd1["label_name"]=image_pd1["ImageName"].apply(lambda x:x.split("/")[-2]) 53 | image_pd2["label_name"]=image_pd2["ImageName"].apply(lambda x:x.split("/")[-3]) 54 | all_pd=image_pd1.append(image_pd2) 55 | all_pd["label"]=all_pd["label_name"].apply(lambda x:defect_label[x]) 56 | print(all_pd["label"].value_counts()) 57 | return all_pd 58 | 59 | class dataset(data.Dataset): 60 | def __init__(self, anno_pd, transforms=None,debug=False,test=False): 61 | self.paths = anno_pd['ImageName'].tolist() 62 | self.labels = anno_pd['label'].tolist() 63 | self.transforms = transforms 64 | self.debug=debug 65 | self.test=test 66 | 67 | def __len__(self): 68 | return len(self.paths) 69 | 70 | def __getitem__(self, item): 71 | img_path =self.paths[item] 72 | img_id =img_path.split("/")[-1] 73 | img =cv2.imread(img_path) #BGR 74 | 75 | img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # [h,w,3] RGB 76 | 77 | if self.transforms is not None: 78 | img = self.transforms(img) 79 | label = self.labels[item] 80 | if self.debug: 81 | print(label) 82 | plt.imshow(img) 83 | plt.show() 84 | if self.test: 85 | return torch.from_numpy(img).float(), int(label) 86 | else: 87 | return torch.from_numpy(img).float(), int(label) 88 | 89 | 90 | def collate_fn(batch): 91 | imgs = [] 92 | label = [] 93 | 94 | for sample in batch: 95 | imgs.append(sample[0]) 96 | label.append(sample[1]) 97 | 98 | return torch.stack(imgs, 0), \ 99 | label 100 | 101 | if __name__ == '__main__': 102 | import matplotlib.pyplot as plt 103 | import pandas as pd 104 | import sys 105 | from sklearn.model_selection import train_test_split 106 | reload(sys) 107 | sys.setdefaultencoding('utf8') 108 | rawdata_root = '/media/hszc/model/detao/data/guangdong/guangdong_round1_train2_2018091622/瑕疵样本' 109 | all_pd= get_image_pd(rawdata_root) 110 | train_pd,val_pd = train_test_split(all_pd, test_size=0.15, random_state=43,stratify=all_pd["label"]) 111 | 112 | print(val_pd["label"].value_counts()) 113 | 114 | class train_Aug(object): 115 | def __init__(self): 116 | self.augment = Compose([ 117 | Resize(size=(640, 640)), 118 | FixRandomRotate(bound='Random'), 119 | RandomHflip(), 120 | RandomVflip(), 121 | # Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 122 | ]) 123 | 124 | def __call__(self, *args): 125 | return self.augment(*args) 126 | data_set = {} 127 | data_set['val'] = dataset(anno_pd=train_pd,transforms=train_Aug(),debug=True) 128 | for data in data_set["val"]: 129 | image, label =data 130 | print(label) -------------------------------------------------------------------------------- /dataset/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdingdongO/pytorch_classification/0b66c6f6aabf66eda0591712525ec036ee9a94e5/dataset/__init__.py -------------------------------------------------------------------------------- /dataset/bd_tiangong_dataset.py: -------------------------------------------------------------------------------- 1 | # coding=utf8 2 | from __future__ import division 3 | import os 4 | import torch 5 | import torch.utils.data as data 6 | import PIL.Image as Image 7 | from data_aug import * 8 | import cv2 9 | class2label={"DESERT":0,"MOUNTAIN":1,"OCEAN":2,"FARMLAND":3,"LAKE":4,"CITY":5} 10 | label2class=["DESERT","MOUNTAIN","OCEAN","FARMLAND","LAKE","CITY"] 11 | 12 | class dataset(data.Dataset): 13 | def __init__(self, imgroot, anno_pd, transforms=None): 14 | self.root_path = imgroot 15 | self.paths = anno_pd['ImageName'].tolist() 16 | self.labels = anno_pd['label'].tolist() 17 | self.transforms = transforms 18 | 19 | def __len__(self): 20 | return len(self.paths) 21 | 22 | def __getitem__(self, item): 23 | img_path = os.path.join(self.root_path, self.paths[item]) 24 | 25 | img =cv2.imread(img_path) 26 | img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # [h,w,3] RGB 27 | 28 | if self.transforms is not None: 29 | img = self.transforms(img) 30 | label = self.labels[item] 31 | # plt.imshow(img) 32 | # plt.show() 33 | return torch.from_numpy(img).float(), label 34 | 35 | def pil_loader(self,imgpath): 36 | with open(imgpath, 'rb') as f: 37 | with Image.open(f) as img: 38 | return img.convert('RGB') 39 | def collate_fn(batch): 40 | imgs = [] 41 | label = [] 42 | 43 | for sample in batch: 44 | imgs.append(sample[0]) 45 | label.append(sample[1]) 46 | 47 | return torch.stack(imgs, 0), \ 48 | label 49 | 50 | if __name__ == '__main__': 51 | import matplotlib.pyplot as plt 52 | import pandas as pd 53 | import sys 54 | from sklearn.model_selection import train_test_split 55 | reload(sys) 56 | sys.setdefaultencoding('utf8') 57 | label_csv ="/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/光学数据集-预赛训练集-2000-有标签.csv" 58 | imgroot="/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/预赛训练集-2000" 59 | label = pd.read_csv(label_csv,names=["ImageName","class"]) 60 | label["label"]=label["class"].apply(lambda x:class2label[x]) 61 | print(label["label"].value_counts()) 62 | train_pd,val_pd = train_test_split(label, test_size=0.15, random_state=43,stratify=label["label"]) 63 | data_set = {} 64 | data_set['val'] = dataset(imgroot,anno_pd=train_pd,transforms=None) 65 | for data in data_set["val"]: 66 | image, label =data 67 | print(label) 68 | -------------------------------------------------------------------------------- /dataset/bd_xjtu_dataset.py: -------------------------------------------------------------------------------- 1 | # coding=utf8 2 | from __future__ import division 3 | import os 4 | import torch 5 | import torch.utils.data as data 6 | import PIL.Image as Image 7 | from data_aug import * 8 | import cv2 9 | class dataset(data.Dataset): 10 | def __init__(self, imgroot, anno_pd, transforms=None): 11 | self.root_path = imgroot 12 | self.paths = anno_pd['ImageName'].tolist() 13 | self.labels = anno_pd['label'].tolist() 14 | self.transforms = transforms 15 | 16 | def __len__(self): 17 | return len(self.paths) 18 | 19 | def __getitem__(self, item): 20 | img_path = os.path.join(self.root_path, self.paths[item]) 21 | 22 | img =cv2.imread(img_path) 23 | img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # [h,w,3] RGB 24 | 25 | if self.transforms is not None: 26 | img = self.transforms(img) 27 | label = self.labels[item]-1 28 | 29 | return torch.from_numpy(img).float(), label 30 | 31 | def pil_loader(self,imgpath): 32 | with open(imgpath, 'rb') as f: 33 | with Image.open(f) as img: 34 | return img.convert('RGB') 35 | def collate_fn(batch): 36 | imgs = [] 37 | label = [] 38 | 39 | for sample in batch: 40 | imgs.append(sample[0]) 41 | label.append(sample[1]) 42 | 43 | return torch.stack(imgs, 0), \ 44 | label -------------------------------------------------------------------------------- /dataset/data_aug.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import cv2 3 | import numpy as np 4 | from numpy import random 5 | import math 6 | from sklearn.utils import shuffle 7 | 8 | __all__ = ['Compose','RandomHflip', 'RandomUpperCrop', 'Resize', 'UpperCrop', 'RandomBottomCrop',"RandomErasing", 9 | 'BottomCrop', 'Normalize', 'RandomSwapChannels', 'RandomRotate', 'RandomHShift',"CenterCrop","RandomVflip", 10 | 'ExpandBorder', 'RandomResizedCrop','RandomDownCrop', 'DownCrop', 'ResizedCrop',"FixRandomRotate"] 11 | 12 | def rotate_nobound(image, angle, center=None, scale=1.): 13 | (h, w) = image.shape[:2] 14 | 15 | 16 | # if the center is None, initialize it as the center of 17 | # the image 18 | if center is None: 19 | center = (w // 2, h // 2) 20 | 21 | # perform the rotation 22 | M = cv2.getRotationMatrix2D(center, angle, scale) 23 | rotated = cv2.warpAffine(image, M, (w, h)) 24 | 25 | return rotated 26 | 27 | def scale_down(src_size, size): 28 | w, h = size 29 | sw, sh = src_size 30 | if sh < h: 31 | w, h = float(w * sh) / h, sh 32 | if sw < w: 33 | w, h = sw, float(h * sw) / w 34 | return int(w), int(h) 35 | 36 | 37 | def fixed_crop(src, x0, y0, w, h, size=None): 38 | out = src[y0:y0 + h, x0:x0 + w] 39 | if size is not None and (w, h) != size: 40 | out = cv2.resize(out, (size[0], size[1]), interpolation=cv2.INTER_CUBIC) 41 | return out 42 | class FixRandomRotate(object): 43 | def __init__(self, angles=[0,90,180,270], bound=False): 44 | self.angles = angles 45 | self.bound = bound 46 | 47 | def __call__(self,img): 48 | do_rotate = random.randint(0, 4) 49 | angle=self.angles[do_rotate] 50 | if self.bound: 51 | img = rotate_bound(img, angle) 52 | else: 53 | img = rotate_nobound(img, angle) 54 | return img 55 | 56 | def center_crop(src, size): 57 | h, w = src.shape[0:2] 58 | new_w, new_h = scale_down((w, h), size) 59 | 60 | x0 = int((w - new_w) / 2) 61 | y0 = int((h - new_h) / 2) 62 | 63 | out = fixed_crop(src, x0, y0, new_w, new_h, size) 64 | return out 65 | 66 | 67 | def bottom_crop(src, size): 68 | h, w = src.shape[0:2] 69 | new_w, new_h = scale_down((w, h), size) 70 | 71 | x0 = int((w - new_w) / 2) 72 | y0 = int((h - new_h) * 0.75) 73 | 74 | out = fixed_crop(src, x0, y0, new_w, new_h, size) 75 | return out 76 | 77 | def rotate_bound(image, angle): 78 | # grab the dimensions of the image and then determine the 79 | # center 80 | h, w = image.shape[:2] 81 | 82 | (cX, cY) = (w // 2, h // 2) 83 | 84 | M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0) 85 | cos = np.abs(M[0, 0]) 86 | sin = np.abs(M[0, 1]) 87 | 88 | # compute the new bounding dimensions of the image 89 | nW = int((h * sin) + (w * cos)) 90 | nH = int((h * cos) + (w * sin)) 91 | 92 | # adjust the rotation matrix to take into account translation 93 | M[0, 2] += (nW / 2) - cX 94 | M[1, 2] += (nH / 2) - cY 95 | 96 | rotated = cv2.warpAffine(image, M, (nW, nH)) 97 | 98 | return rotated 99 | 100 | 101 | class Compose(object): 102 | def __init__(self, transforms): 103 | self.transforms = transforms 104 | def __call__(self, img): 105 | for t in self.transforms: 106 | img = t(img) 107 | return img 108 | class RandomRotate(object): 109 | def __init__(self, angles, bound=False): 110 | self.angles = angles 111 | self.bound = bound 112 | 113 | def __call__(self,img): 114 | do_rotate = random.randint(0, 2) 115 | if do_rotate: 116 | angle = np.random.uniform(self.angles[0], self.angles[1]) 117 | if self.bound: 118 | img = rotate_bound(img, angle) 119 | else: 120 | img = rotate_nobound(img, angle) 121 | return img 122 | class RandomBrightness(object): 123 | def __init__(self, delta=10): 124 | assert delta >= 0 125 | assert delta <= 255 126 | self.delta = delta 127 | 128 | def __call__(self, image): 129 | if random.randint(2): 130 | delta = random.uniform(-self.delta, self.delta) 131 | image = (image + delta).clip(0.0, 255.0) 132 | # print('RandomBrightness,delta ',delta) 133 | return image 134 | 135 | 136 | class RandomContrast(object): 137 | def __init__(self, lower=0.9, upper=1.05): 138 | self.lower = lower 139 | self.upper = upper 140 | assert self.upper >= self.lower, "contrast upper must be >= lower." 141 | assert self.lower >= 0, "contrast lower must be non-negative." 142 | 143 | # expects float image 144 | def __call__(self, image): 145 | if random.randint(2): 146 | alpha = random.uniform(self.lower, self.upper) 147 | # print('contrast:', alpha) 148 | image = (image * alpha).clip(0.0,255.0) 149 | return image 150 | 151 | 152 | class RandomSaturation(object): 153 | def __init__(self, lower=0.8, upper=1.2): 154 | self.lower = lower 155 | self.upper = upper 156 | assert self.upper >= self.lower, "contrast upper must be >= lower." 157 | assert self.lower >= 0, "contrast lower must be non-negative." 158 | 159 | def __call__(self, image): 160 | if random.randint(2): 161 | alpha = random.uniform(self.lower, self.upper) 162 | image[:, :, 1] *= alpha 163 | # print('RandomSaturation,alpha',alpha) 164 | return image 165 | 166 | 167 | class RandomHue(object): 168 | def __init__(self, delta=18.0): 169 | assert delta >= 0.0 and delta <= 360.0 170 | self.delta = delta 171 | 172 | def __call__(self, image): 173 | if random.randint(2): 174 | alpha = random.uniform(-self.delta, self.delta) 175 | image[:, :, 0] += alpha 176 | image[:, :, 0][image[:, :, 0] > 360.0] -= 360.0 177 | image[:, :, 0][image[:, :, 0] < 0.0] += 360.0 178 | # print('RandomHue,alpha:', alpha) 179 | return image 180 | 181 | 182 | class ConvertColor(object): 183 | def __init__(self, current='BGR', transform='HSV'): 184 | self.transform = transform 185 | self.current = current 186 | 187 | def __call__(self, image): 188 | if self.current == 'BGR' and self.transform == 'HSV': 189 | image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) 190 | elif self.current == 'HSV' and self.transform == 'BGR': 191 | image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) 192 | else: 193 | raise NotImplementedError 194 | return image 195 | 196 | class RandomSwapChannels(object): 197 | def __call__(self, img): 198 | if np.random.randint(2): 199 | order = np.random.permutation(3) 200 | return img[:,:,order] 201 | return img 202 | 203 | class RandomCrop(object): 204 | def __init__(self, size): 205 | self.size = size 206 | def __call__(self, image): 207 | h, w, _ = image.shape 208 | new_w, new_h = scale_down((w, h), self.size) 209 | 210 | if w == new_w: 211 | x0 = 0 212 | else: 213 | x0 = random.randint(0, w - new_w) 214 | 215 | if h == new_h: 216 | y0 = 0 217 | else: 218 | y0 = random.randint(0, h - new_h) 219 | 220 | out = fixed_crop(image, x0, y0, new_w, new_h, self.size) 221 | return out 222 | 223 | 224 | 225 | class RandomResizedCrop(object): 226 | def __init__(self, size,scale=(0.49, 1.0), ratio=(1., 1.)): 227 | self.size = size 228 | self.scale = scale 229 | self.ratio = ratio 230 | 231 | def __call__(self,img): 232 | if random.random() < 0.2: 233 | return cv2.resize(img,self.size) 234 | h, w, _ = img.shape 235 | area = h * w 236 | d=1 237 | for attempt in range(10): 238 | target_area = random.uniform(self.scale[0], self.scale[1]) * area 239 | aspect_ratio = random.uniform(self.ratio[0], self.ratio[1]) 240 | 241 | 242 | new_w = int(round(math.sqrt(target_area * aspect_ratio))) 243 | new_h = int(round(math.sqrt(target_area / aspect_ratio))) 244 | 245 | if random.random() < 0.5: 246 | new_h, new_w = new_w, new_h 247 | 248 | if new_w < w and new_h < h: 249 | x0 = random.randint(0, w - new_w) 250 | y0 = (random.randint(0, h - new_h))//d 251 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 252 | 253 | return out 254 | 255 | # Fallback 256 | return center_crop(img, self.size) 257 | 258 | 259 | class DownCrop(): 260 | def __init__(self, size, select, scale=(0.36,0.81)): 261 | self.size = size 262 | self.scale = scale 263 | self.select = select 264 | 265 | def __call__(self,img, attr_idx): 266 | if attr_idx not in self.select: 267 | return img, attr_idx 268 | if attr_idx == 0: 269 | self.scale=(0.64,1.0) 270 | h, w, _ = img.shape 271 | area = h * w 272 | 273 | s = (self.scale[0]+self.scale[1])/2.0 274 | 275 | target_area = s * area 276 | 277 | new_w = int(round(math.sqrt(target_area))) 278 | new_h = int(round(math.sqrt(target_area))) 279 | 280 | if new_w < w and new_h < h: 281 | dw = w-new_w 282 | x0 = int(0.5*dw) 283 | y0 = h-new_h 284 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 285 | return out, attr_idx 286 | 287 | # Fallback 288 | return center_crop(img, self.size), attr_idx 289 | 290 | 291 | class ResizedCrop(object): 292 | def __init__(self, size, select,scale=(0.64, 1.0), ratio=(3. / 4., 4. / 3.)): 293 | self.size = size 294 | self.scale = scale 295 | self.ratio = ratio 296 | self.select = select 297 | 298 | def __call__(self,img, attr_idx): 299 | if attr_idx not in self.select: 300 | return img, attr_idx 301 | h, w, _ = img.shape 302 | area = h * w 303 | d=1 304 | if attr_idx == 2: 305 | self.scale=(0.36,0.81) 306 | d=2 307 | if attr_idx == 0: 308 | self.scale=(0.81,1.0) 309 | 310 | target_area = (self.scale[0]+self.scale[1])/2.0 * area 311 | # aspect_ratio = random.uniform(self.ratio[0], self.ratio[1]) 312 | 313 | 314 | new_w = int(round(math.sqrt(target_area))) 315 | new_h = int(round(math.sqrt(target_area))) 316 | 317 | # if random.random() < 0.5: 318 | # new_h, new_w = new_w, new_h 319 | 320 | if new_w < w and new_h < h: 321 | x0 = (w - new_w)//2 322 | y0 = (h - new_h)//d//2 323 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 324 | # cv2.imshow('{}_img'.format(idx2attr_map[attr_idx]), img) 325 | # cv2.imshow('{}_crop'.format(idx2attr_map[attr_idx]), out) 326 | # 327 | # cv2.waitKey(0) 328 | return out, attr_idx 329 | 330 | # Fallback 331 | return center_crop(img, self.size), attr_idx 332 | 333 | class RandomHflip(object): 334 | def __call__(self, image): 335 | if random.randint(2): 336 | return cv2.flip(image, 1) 337 | else: 338 | return image 339 | class RandomVflip(object): 340 | def __call__(self, image): 341 | if random.randint(2): 342 | return cv2.flip(image, 0) 343 | else: 344 | return image 345 | 346 | 347 | class Hflip(object): 348 | def __init__(self,doHflip): 349 | self.doHflip = doHflip 350 | 351 | def __call__(self, image): 352 | if self.doHflip: 353 | return cv2.flip(image, 1) 354 | else: 355 | return image 356 | 357 | 358 | class CenterCrop(object): 359 | def __init__(self, size): 360 | self.size = size 361 | 362 | def __call__(self, image): 363 | return center_crop(image, self.size) 364 | 365 | class UpperCrop(): 366 | def __init__(self, size, scale=(0.09, 0.64)): 367 | self.size = size 368 | self.scale = scale 369 | 370 | def __call__(self,img): 371 | h, w, _ = img.shape 372 | area = h * w 373 | 374 | s = (self.scale[0]+self.scale[1])/2.0 375 | 376 | target_area = s * area 377 | 378 | new_w = int(round(math.sqrt(target_area))) 379 | new_h = int(round(math.sqrt(target_area))) 380 | 381 | if new_w < w and new_h < h: 382 | dw = w-new_w 383 | x0 = int(0.5*dw) 384 | y0 = 0 385 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 386 | return out 387 | 388 | # Fallback 389 | return center_crop(img, self.size) 390 | 391 | 392 | 393 | class RandomUpperCrop(object): 394 | def __init__(self, size, select, scale=(0.09, 0.64), ratio=(3. / 4., 4. / 3.)): 395 | self.size = size 396 | self.scale = scale 397 | self.ratio = ratio 398 | self.select = select 399 | 400 | def __call__(self,img, attr_idx): 401 | if random.random() < 0.2: 402 | return img, attr_idx 403 | if attr_idx not in self.select: 404 | return img, attr_idx 405 | 406 | h, w, _ = img.shape 407 | area = h * w 408 | for attempt in range(10): 409 | s = random.uniform(self.scale[0], self.scale[1]) 410 | d = 0.1 + (0.3 - 0.1) / (self.scale[1] - self.scale[0]) * (s - self.scale[0]) 411 | target_area = s * area 412 | aspect_ratio = random.uniform(self.ratio[0], self.ratio[1]) 413 | new_w = int(round(math.sqrt(target_area * aspect_ratio))) 414 | new_h = int(round(math.sqrt(target_area / aspect_ratio))) 415 | 416 | 417 | # new_w = int(round(math.sqrt(target_area))) 418 | # new_h = int(round(math.sqrt(target_area))) 419 | 420 | if new_w < w and new_h < h: 421 | dw = w-new_w 422 | x0 = random.randint(int((0.5-d)*dw), int((0.5+d)*dw)+1) 423 | y0 = (random.randint(0, h - new_h))//10 424 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 425 | return out, attr_idx 426 | 427 | # Fallback 428 | return center_crop(img, self.size), attr_idx 429 | class RandomDownCrop(object): 430 | def __init__(self, size, select, scale=(0.36, 0.81), ratio=(3. / 4., 4. / 3.)): 431 | self.size = size 432 | self.scale = scale 433 | self.ratio = ratio 434 | self.select = select 435 | 436 | def __call__(self,img, attr_idx): 437 | if random.random() < 0.2: 438 | return img, attr_idx 439 | if attr_idx not in self.select: 440 | return img, attr_idx 441 | if attr_idx == 0: 442 | self.scale=(0.64,1.0) 443 | 444 | h, w, _ = img.shape 445 | area = h * w 446 | for attempt in range(10): 447 | s = random.uniform(self.scale[0], self.scale[1]) 448 | d = 0.1 + (0.3 - 0.1) / (self.scale[1] - self.scale[0]) * (s - self.scale[0]) 449 | target_area = s * area 450 | aspect_ratio = random.uniform(self.ratio[0], self.ratio[1]) 451 | new_w = int(round(math.sqrt(target_area * aspect_ratio))) 452 | new_h = int(round(math.sqrt(target_area / aspect_ratio))) 453 | # 454 | # new_w = int(round(math.sqrt(target_area))) 455 | # new_h = int(round(math.sqrt(target_area))) 456 | 457 | if new_w < w and new_h < h: 458 | dw = w-new_w 459 | x0 = random.randint(int((0.5-d)*dw), int((0.5+d)*dw)+1) 460 | y0 = (random.randint((h - new_h)*9//10, h - new_h)) 461 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 462 | 463 | # cv2.imshow('{}_img'.format(idx2attr_map[attr_idx]), img) 464 | # cv2.imshow('{}_crop'.format(idx2attr_map[attr_idx]), out) 465 | # 466 | # cv2.waitKey(0) 467 | 468 | return out, attr_idx 469 | 470 | # Fallback 471 | return center_crop(img, self.size), attr_idx 472 | 473 | class RandomHShift(object): 474 | def __init__(self, select, scale=(0.0, 0.2)): 475 | self.scale = scale 476 | self.select = select 477 | 478 | def __call__(self,img, attr_idx): 479 | if attr_idx not in self.select: 480 | return img, attr_idx 481 | do_shift_crop = random.randint(0, 2) 482 | if do_shift_crop: 483 | h, w, _ = img.shape 484 | min_shift = int(w*self.scale[0]) 485 | max_shift = int(w*self.scale[1]) 486 | shift_idx = random.randint(min_shift, max_shift) 487 | direction = random.randint(0,2) 488 | if direction: 489 | right_part = img[:, -shift_idx:, :] 490 | left_part = img[:, :-shift_idx, :] 491 | else: 492 | left_part = img[:, :shift_idx, :] 493 | right_part = img[:, shift_idx:, :] 494 | img = np.concatenate((right_part, left_part), axis=1) 495 | 496 | # Fallback 497 | return img, attr_idx 498 | 499 | 500 | class RandomBottomCrop(object): 501 | def __init__(self, size, select, scale=(0.4, 0.8)): 502 | self.size = size 503 | self.scale = scale 504 | self.select = select 505 | 506 | def __call__(self,img, attr_idx): 507 | if attr_idx not in self.select: 508 | return img, attr_idx 509 | 510 | h, w, _ = img.shape 511 | area = h * w 512 | for attempt in range(10): 513 | s = random.uniform(self.scale[0], self.scale[1]) 514 | d = 0.25 + (0.45 - 0.25) / (self.scale[1] - self.scale[0]) * (s - self.scale[0]) 515 | target_area = s * area 516 | 517 | new_w = int(round(math.sqrt(target_area))) 518 | new_h = int(round(math.sqrt(target_area))) 519 | 520 | if new_w < w and new_h < h: 521 | dw = w-new_w 522 | dh = h - new_h 523 | x0 = random.randint(int((0.5-d)*dw), min(int((0.5+d)*dw)+1,dw)) 524 | y0 = (random.randint(max(0,int(0.8*dh)-1), dh)) 525 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 526 | return out, attr_idx 527 | 528 | # Fallback 529 | return bottom_crop(img, self.size), attr_idx 530 | 531 | 532 | class BottomCrop(): 533 | def __init__(self, size, select, scale=(0.4, 0.8)): 534 | self.size = size 535 | self.scale = scale 536 | self.select = select 537 | 538 | def __call__(self,img, attr_idx): 539 | if attr_idx not in self.select: 540 | return img, attr_idx 541 | 542 | h, w, _ = img.shape 543 | area = h * w 544 | 545 | s = (self.scale[0]+self.scale[1])/3.*2. 546 | 547 | target_area = s * area 548 | 549 | new_w = int(round(math.sqrt(target_area))) 550 | new_h = int(round(math.sqrt(target_area))) 551 | 552 | if new_w < w and new_h < h: 553 | dw = w-new_w 554 | dh = h-new_h 555 | x0 = int(0.5*dw) 556 | y0 = int(0.9*dh) 557 | out = fixed_crop(img, x0, y0, new_w, new_h, self.size) 558 | return out, attr_idx 559 | 560 | # Fallback 561 | return bottom_crop(img, self.size), attr_idx 562 | 563 | 564 | 565 | class Resize(object): 566 | def __init__(self, size, inter=cv2.INTER_CUBIC): 567 | self.size = size 568 | self.inter = inter 569 | 570 | def __call__(self, image): 571 | return cv2.resize(image, (self.size[0], self.size[0]), interpolation=self.inter) 572 | 573 | class ExpandBorder(object): 574 | def __init__(self, mode='constant', value=255, size=(336,336), resize=False): 575 | self.mode = mode 576 | self.value = value 577 | self.resize = resize 578 | self.size = size 579 | 580 | def __call__(self, image): 581 | h, w, _ = image.shape 582 | if h > w: 583 | pad1 = (h-w)//2 584 | pad2 = h - w - pad1 585 | if self.mode == 'constant': 586 | image = np.pad(image, ((0, 0), (pad1, pad2), (0, 0)), 587 | self.mode, constant_values=self.value) 588 | else: 589 | image = np.pad(image,((0,0), (pad1, pad2),(0,0)), self.mode) 590 | elif h < w: 591 | pad1 = (w-h)//2 592 | pad2 = w-h - pad1 593 | if self.mode == 'constant': 594 | image = np.pad(image, ((pad1, pad2),(0, 0), (0, 0)), 595 | self.mode,constant_values=self.value) 596 | else: 597 | image = np.pad(image, ((pad1, pad2), (0, 0), (0, 0)),self.mode) 598 | if self.resize: 599 | image = cv2.resize(image, (self.size[0], self.size[0]),interpolation=cv2.INTER_LINEAR) 600 | return image 601 | class AstypeToInt(): 602 | def __call__(self, image, attr_idx): 603 | return image.clip(0,255.0).astype(np.uint8), attr_idx 604 | 605 | class AstypeToFloat(): 606 | def __call__(self, image, attr_idx): 607 | return image.astype(np.float32), attr_idx 608 | 609 | import matplotlib.pyplot as plt 610 | class Normalize(object): 611 | def __init__(self,mean, std): 612 | ''' 613 | :param mean: RGB order 614 | :param std: RGB order 615 | ''' 616 | self.mean = np.array(mean).reshape(3,1,1) 617 | self.std = np.array(std).reshape(3,1,1) 618 | def __call__(self, image): 619 | ''' 620 | :param image: (H,W,3) RGB 621 | :return: 622 | ''' 623 | # plt.figure(1) 624 | # plt.imshow(image) 625 | # plt.show() 626 | return (image.transpose((2, 0, 1)) / 255. - self.mean) / self.std 627 | 628 | class RandomErasing(object): 629 | def __init__(self, select,EPSILON=0.5,sl=0.02, sh=0.09, r1=0.3, mean=[0.485, 0.456, 0.406]): 630 | self.EPSILON = EPSILON 631 | self.mean = mean 632 | self.sl = sl 633 | self.sh = sh 634 | self.r1 = r1 635 | self.select = select 636 | 637 | def __call__(self, img,attr_idx): 638 | if attr_idx not in self.select: 639 | return img,attr_idx 640 | 641 | if random.uniform(0, 1) > self.EPSILON: 642 | return img,attr_idx 643 | 644 | for attempt in range(100): 645 | area = img.shape[1] * img.shape[2] 646 | 647 | target_area = random.uniform(self.sl, self.sh) * area 648 | aspect_ratio = random.uniform(self.r1, 1 / self.r1) 649 | 650 | h = int(round(math.sqrt(target_area * aspect_ratio))) 651 | w = int(round(math.sqrt(target_area / aspect_ratio))) 652 | 653 | if w <= img.shape[2] and h <= img.shape[1]: 654 | x1 = random.randint(0, img.shape[1] - h) 655 | y1 = random.randint(0, img.shape[2] - w) 656 | if img.shape[0] == 3: 657 | # img[0, x1:x1+h, y1:y1+w] = random.uniform(0, 1) 658 | # img[1, x1:x1+h, y1:y1+w] = random.uniform(0, 1) 659 | # img[2, x1:x1+h, y1:y1+w] = random.uniform(0, 1) 660 | img[0, x1:x1 + h, y1:y1 + w] = self.mean[0] 661 | img[1, x1:x1 + h, y1:y1 + w] = self.mean[1] 662 | img[2, x1:x1 + h, y1:y1 + w] = self.mean[2] 663 | # img[:, x1:x1+h, y1:y1+w] = torch.from_numpy(np.random.rand(3, h, w)) 664 | else: 665 | img[0, x1:x1 + h, y1:y1 + w] = self.mean[1] 666 | # img[0, x1:x1+h, y1:y1+w] = torch.from_numpy(np.random.rand(1, h, w)) 667 | return img,attr_idx 668 | 669 | return img,attr_idx 670 | 671 | if __name__ == '__main__': 672 | import matplotlib.pyplot as plt 673 | 674 | 675 | class FSAug(object): 676 | def __init__(self): 677 | self.augment = Compose([ 678 | AstypeToFloat(), 679 | # RandomHShift(scale=(0.,0.2),select=range(8)), 680 | # RandomRotate(angles=(-20., 20.), bound=True), 681 | ExpandBorder(select=range(8), mode='symmetric'),# symmetric 682 | # Resize(size=(336, 336), select=[ 2, 7]), 683 | AstypeToInt() 684 | ]) 685 | 686 | def __call__(self, spct,attr_idx): 687 | return self.augment(spct,attr_idx) 688 | 689 | 690 | trans = FSAug() 691 | 692 | img_path = '/media/gserver/data/FashionAI/round2/train/Images/coat_length_labels/0b6b4a2146fc8616a19fcf2026d61d50.jpg' 693 | img = cv2.cvtColor(cv2.imread(img_path),cv2.COLOR_BGR2RGB) 694 | img_trans,_ = trans(img,5) 695 | # img_trans2,_ = trans(img,6) 696 | print img_trans.max(), img_trans.min() 697 | print img_trans.dtype 698 | 699 | plt.figure() 700 | plt.subplot(221) 701 | plt.imshow(img) 702 | 703 | plt.subplot(222) 704 | plt.imshow(img_trans) 705 | 706 | # plt.subplot(223) 707 | # plt.imshow(img_trans2) 708 | # plt.imshow(img_trans2) 709 | plt.show() 710 | -------------------------------------------------------------------------------- /dataset/pdr_dataset.py: -------------------------------------------------------------------------------- 1 | # coding=utf8 2 | from __future__ import division 3 | import os 4 | import torch 5 | import torch.utils.data as data 6 | import PIL.Image as Image 7 | from data_aug import * 8 | import cv2 9 | class dataset(data.Dataset): 10 | def __init__(self, imgroot, anno_pd, transforms=None): 11 | self.root_path = imgroot 12 | self.paths = anno_pd['ImageName'].tolist() 13 | self.labels = anno_pd['label'].tolist() 14 | self.transforms = transforms 15 | 16 | def __len__(self): 17 | return len(self.paths) 18 | 19 | def __getitem__(self, item): 20 | img_path =self.paths[item] 21 | img =cv2.imread(img_path) 22 | img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # [h,w,3] RGB 23 | 24 | if self.transforms is not None: 25 | img = self.transforms(img) 26 | label = self.labels[item] 27 | 28 | return torch.from_numpy(img).float(), label 29 | 30 | def pil_loader(self,imgpath): 31 | with open(imgpath, 'rb') as f: 32 | with Image.open(f) as img: 33 | return img.convert('RGB') 34 | 35 | def collate_fn(batch): 36 | imgs = [] 37 | label = [] 38 | 39 | for sample in batch: 40 | imgs.append(sample[0]) 41 | label.append(sample[1]) 42 | 43 | return torch.stack(imgs, 0), \ 44 | label -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdingdongO/pytorch_classification/0b66c6f6aabf66eda0591712525ec036ee9a94e5/models/__init__.py -------------------------------------------------------------------------------- /models/inception_resnet_v2.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.utils.model_zoo as model_zoo 4 | import os 5 | import sys 6 | ''' 7 | https://github.com/Cadene/pretrained-models.pytorch 8 | ''' 9 | __all__ = ['InceptionResNetV2', 'inceptionresnetv2'] 10 | 11 | pretrained_settings = { 12 | 'inceptionresnetv2': { 13 | 'imagenet': { 14 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionresnetv2-520b38e4.pth', 15 | 'input_space': 'RGB', 16 | 'input_size': [3, 299, 299], 17 | 'input_range': [0, 1], 18 | 'mean': [0.5, 0.5, 0.5], 19 | 'std': [0.5, 0.5, 0.5], 20 | 'num_classes': 1000 21 | }, 22 | 'imagenet+background': { 23 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionresnetv2-520b38e4.pth', 24 | 'input_space': 'RGB', 25 | 'input_size': [3, 299, 299], 26 | 'input_range': [0, 1], 27 | 'mean': [0.5, 0.5, 0.5], 28 | 'std': [0.5, 0.5, 0.5], 29 | 'num_classes': 1001 30 | } 31 | } 32 | } 33 | 34 | 35 | class BasicConv2d(nn.Module): 36 | 37 | def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): 38 | super(BasicConv2d, self).__init__() 39 | self.conv = nn.Conv2d(in_planes, out_planes, 40 | kernel_size=kernel_size, stride=stride, 41 | padding=padding, bias=False) # verify bias false 42 | self.bn = nn.BatchNorm2d(out_planes, 43 | eps=0.001, # value found in tensorflow 44 | momentum=0.1, # default pytorch value 45 | affine=True) 46 | self.relu = nn.ReLU(inplace=False) 47 | 48 | def forward(self, x): 49 | x = self.conv(x) 50 | x = self.bn(x) 51 | x = self.relu(x) 52 | return x 53 | 54 | 55 | class Mixed_5b(nn.Module): 56 | 57 | def __init__(self): 58 | super(Mixed_5b, self).__init__() 59 | 60 | self.branch0 = BasicConv2d(192, 96, kernel_size=1, stride=1) 61 | 62 | self.branch1 = nn.Sequential( 63 | BasicConv2d(192, 48, kernel_size=1, stride=1), 64 | BasicConv2d(48, 64, kernel_size=5, stride=1, padding=2) 65 | ) 66 | 67 | self.branch2 = nn.Sequential( 68 | BasicConv2d(192, 64, kernel_size=1, stride=1), 69 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), 70 | BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1) 71 | ) 72 | 73 | self.branch3 = nn.Sequential( 74 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 75 | BasicConv2d(192, 64, kernel_size=1, stride=1) 76 | ) 77 | 78 | def forward(self, x): 79 | x0 = self.branch0(x) 80 | x1 = self.branch1(x) 81 | x2 = self.branch2(x) 82 | x3 = self.branch3(x) 83 | out = torch.cat((x0, x1, x2, x3), 1) 84 | return out 85 | 86 | 87 | class Block35(nn.Module): 88 | 89 | def __init__(self, scale=1.0): 90 | super(Block35, self).__init__() 91 | 92 | self.scale = scale 93 | 94 | self.branch0 = BasicConv2d(320, 32, kernel_size=1, stride=1) 95 | 96 | self.branch1 = nn.Sequential( 97 | BasicConv2d(320, 32, kernel_size=1, stride=1), 98 | BasicConv2d(32, 32, kernel_size=3, stride=1, padding=1) 99 | ) 100 | 101 | self.branch2 = nn.Sequential( 102 | BasicConv2d(320, 32, kernel_size=1, stride=1), 103 | BasicConv2d(32, 48, kernel_size=3, stride=1, padding=1), 104 | BasicConv2d(48, 64, kernel_size=3, stride=1, padding=1) 105 | ) 106 | 107 | self.conv2d = nn.Conv2d(128, 320, kernel_size=1, stride=1) 108 | self.relu = nn.ReLU(inplace=False) 109 | 110 | def forward(self, x): 111 | x0 = self.branch0(x) 112 | x1 = self.branch1(x) 113 | x2 = self.branch2(x) 114 | out = torch.cat((x0, x1, x2), 1) 115 | out = self.conv2d(out) 116 | out = out * self.scale + x 117 | out = self.relu(out) 118 | return out 119 | 120 | 121 | class Mixed_6a(nn.Module): 122 | 123 | def __init__(self): 124 | super(Mixed_6a, self).__init__() 125 | 126 | self.branch0 = BasicConv2d(320, 384, kernel_size=3, stride=2) 127 | 128 | self.branch1 = nn.Sequential( 129 | BasicConv2d(320, 256, kernel_size=1, stride=1), 130 | BasicConv2d(256, 256, kernel_size=3, stride=1, padding=1), 131 | BasicConv2d(256, 384, kernel_size=3, stride=2) 132 | ) 133 | 134 | self.branch2 = nn.MaxPool2d(3, stride=2) 135 | 136 | def forward(self, x): 137 | x0 = self.branch0(x) 138 | x1 = self.branch1(x) 139 | x2 = self.branch2(x) 140 | out = torch.cat((x0, x1, x2), 1) 141 | return out 142 | 143 | 144 | class Block17(nn.Module): 145 | 146 | def __init__(self, scale=1.0): 147 | super(Block17, self).__init__() 148 | 149 | self.scale = scale 150 | 151 | self.branch0 = BasicConv2d(1088, 192, kernel_size=1, stride=1) 152 | 153 | self.branch1 = nn.Sequential( 154 | BasicConv2d(1088, 128, kernel_size=1, stride=1), 155 | BasicConv2d(128, 160, kernel_size=(1, 7), stride=1, padding=(0, 3)), 156 | BasicConv2d(160, 192, kernel_size=(7, 1), stride=1, padding=(3, 0)) 157 | ) 158 | 159 | self.conv2d = nn.Conv2d(384, 1088, kernel_size=1, stride=1) 160 | self.relu = nn.ReLU(inplace=False) 161 | 162 | def forward(self, x): 163 | x0 = self.branch0(x) 164 | x1 = self.branch1(x) 165 | out = torch.cat((x0, x1), 1) 166 | out = self.conv2d(out) 167 | out = out * self.scale + x 168 | out = self.relu(out) 169 | return out 170 | 171 | 172 | class Mixed_7a(nn.Module): 173 | 174 | def __init__(self): 175 | super(Mixed_7a, self).__init__() 176 | 177 | self.branch0 = nn.Sequential( 178 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 179 | BasicConv2d(256, 384, kernel_size=3, stride=2) 180 | ) 181 | 182 | self.branch1 = nn.Sequential( 183 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 184 | BasicConv2d(256, 288, kernel_size=3, stride=2) 185 | ) 186 | 187 | self.branch2 = nn.Sequential( 188 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 189 | BasicConv2d(256, 288, kernel_size=3, stride=1, padding=1), 190 | BasicConv2d(288, 320, kernel_size=3, stride=2) 191 | ) 192 | 193 | self.branch3 = nn.MaxPool2d(3, stride=2) 194 | 195 | def forward(self, x): 196 | x0 = self.branch0(x) 197 | x1 = self.branch1(x) 198 | x2 = self.branch2(x) 199 | x3 = self.branch3(x) 200 | out = torch.cat((x0, x1, x2, x3), 1) 201 | return out 202 | 203 | 204 | class Block8(nn.Module): 205 | 206 | def __init__(self, scale=1.0, noReLU=False): 207 | super(Block8, self).__init__() 208 | 209 | self.scale = scale 210 | self.noReLU = noReLU 211 | 212 | self.branch0 = BasicConv2d(2080, 192, kernel_size=1, stride=1) 213 | 214 | self.branch1 = nn.Sequential( 215 | BasicConv2d(2080, 192, kernel_size=1, stride=1), 216 | BasicConv2d(192, 224, kernel_size=(1, 3), stride=1, padding=(0, 1)), 217 | BasicConv2d(224, 256, kernel_size=(3, 1), stride=1, padding=(1, 0)) 218 | ) 219 | 220 | self.conv2d = nn.Conv2d(448, 2080, kernel_size=1, stride=1) 221 | if not self.noReLU: 222 | self.relu = nn.ReLU(inplace=False) 223 | 224 | def forward(self, x): 225 | x0 = self.branch0(x) 226 | x1 = self.branch1(x) 227 | out = torch.cat((x0, x1), 1) 228 | out = self.conv2d(out) 229 | out = out * self.scale + x 230 | if not self.noReLU: 231 | out = self.relu(out) 232 | return out 233 | 234 | 235 | class InceptionResNetV2(nn.Module): 236 | 237 | def __init__(self, num_classes=1001): 238 | super(InceptionResNetV2, self).__init__() 239 | # Special attributs 240 | self.input_space = None 241 | self.input_size = (299, 299, 3) 242 | self.mean = None 243 | self.std = None 244 | # Modules 245 | self.conv2d_1a = BasicConv2d(3, 32, kernel_size=3, stride=2) 246 | self.conv2d_2a = BasicConv2d(32, 32, kernel_size=3, stride=1) 247 | self.conv2d_2b = BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1) 248 | self.maxpool_3a = nn.MaxPool2d(3, stride=2) 249 | self.conv2d_3b = BasicConv2d(64, 80, kernel_size=1, stride=1) 250 | self.conv2d_4a = BasicConv2d(80, 192, kernel_size=3, stride=1) 251 | self.maxpool_5a = nn.MaxPool2d(3, stride=2) 252 | self.mixed_5b = Mixed_5b() 253 | self.repeat = nn.Sequential( 254 | Block35(scale=0.17), 255 | Block35(scale=0.17), 256 | Block35(scale=0.17), 257 | Block35(scale=0.17), 258 | Block35(scale=0.17), 259 | Block35(scale=0.17), 260 | Block35(scale=0.17), 261 | Block35(scale=0.17), 262 | Block35(scale=0.17), 263 | Block35(scale=0.17) 264 | ) 265 | self.mixed_6a = Mixed_6a() 266 | self.repeat_1 = nn.Sequential( 267 | Block17(scale=0.10), 268 | Block17(scale=0.10), 269 | Block17(scale=0.10), 270 | Block17(scale=0.10), 271 | Block17(scale=0.10), 272 | Block17(scale=0.10), 273 | Block17(scale=0.10), 274 | Block17(scale=0.10), 275 | Block17(scale=0.10), 276 | Block17(scale=0.10), 277 | Block17(scale=0.10), 278 | Block17(scale=0.10), 279 | Block17(scale=0.10), 280 | Block17(scale=0.10), 281 | Block17(scale=0.10), 282 | Block17(scale=0.10), 283 | Block17(scale=0.10), 284 | Block17(scale=0.10), 285 | Block17(scale=0.10), 286 | Block17(scale=0.10) 287 | ) 288 | self.mixed_7a = Mixed_7a() 289 | self.repeat_2 = nn.Sequential( 290 | Block8(scale=0.20), 291 | Block8(scale=0.20), 292 | Block8(scale=0.20), 293 | Block8(scale=0.20), 294 | Block8(scale=0.20), 295 | Block8(scale=0.20), 296 | Block8(scale=0.20), 297 | Block8(scale=0.20), 298 | Block8(scale=0.20) 299 | ) 300 | self.block8 = Block8(noReLU=True) 301 | self.conv2d_7b = BasicConv2d(2080, 1536, kernel_size=1, stride=1) 302 | self.avgpool_1a = nn.AdaptiveAvgPool2d(output_size=1) 303 | self.last_linear = nn.Linear(1536, num_classes) 304 | 305 | def features(self, input): 306 | x = self.conv2d_1a(input) 307 | x = self.conv2d_2a(x) 308 | x = self.conv2d_2b(x) 309 | x = self.maxpool_3a(x) 310 | x = self.conv2d_3b(x) 311 | x = self.conv2d_4a(x) 312 | x = self.maxpool_5a(x) 313 | x = self.mixed_5b(x) 314 | x = self.repeat(x) 315 | x = self.mixed_6a(x) 316 | x = self.repeat_1(x) 317 | x = self.mixed_7a(x) 318 | x = self.repeat_2(x) 319 | x = self.block8(x) 320 | x = self.conv2d_7b(x) 321 | return x 322 | 323 | def logits(self, features): 324 | x = self.avgpool_1a(features) 325 | x = x.view(x.size(0), -1) 326 | x = self.last_linear(x) 327 | return x 328 | 329 | def forward(self, input): 330 | x = self.features(input) 331 | x = self.logits(x) 332 | return x 333 | 334 | 335 | def inceptionresnetv2(num_classes=1000, pretrained='imagenet'): 336 | r"""InceptionResNetV2 model architecture from the 337 | `"InceptionV4, Inception-ResNet..." `_ paper. 338 | """ 339 | if pretrained: 340 | settings = pretrained_settings['inceptionresnetv2'][pretrained] 341 | assert num_classes == settings['num_classes'], \ 342 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 343 | 344 | # both 'imagenet'&'imagenet+background' are loaded from same parameters 345 | model = InceptionResNetV2(num_classes=1001) 346 | model.load_state_dict(model_zoo.load_url(settings['url'])) 347 | 348 | if pretrained == 'imagenet': 349 | new_last_linear = nn.Linear(1536, 1000) 350 | new_last_linear.weight.data = model.last_linear.weight.data[1:] 351 | new_last_linear.bias.data = model.last_linear.bias.data[1:] 352 | model.last_linear = new_last_linear 353 | 354 | model.input_space = settings['input_space'] 355 | model.input_size = settings['input_size'] 356 | model.input_range = settings['input_range'] 357 | 358 | model.mean = settings['mean'] 359 | model.std = settings['std'] 360 | else: 361 | model = InceptionResNetV2(num_classes=num_classes) 362 | return model 363 | def pdr_inceptionresnetv2(num_classes=1000): 364 | settings = pretrained_settings['inceptionresnetv2']['imagenet'] 365 | 366 | model = InceptionResNetV2(num_classes=1001) 367 | model.load_state_dict(model_zoo.load_url(settings['url'])) 368 | model.last_linear=nn.Linear(1536, num_classes) 369 | return model 370 | 371 | ''' 372 | TEST 373 | Run this code with: 374 | ``` 375 | cd $HOME/pretrained-models.pytorch 376 | python -m pretrainedmodels.inceptionresnetv2 377 | ``` 378 | ''' 379 | if __name__ == '__main__': 380 | assert inceptionresnetv2(num_classes=10, pretrained=None) 381 | print('success') 382 | assert inceptionresnetv2(num_classes=1000, pretrained='imagenet') 383 | print('success') 384 | assert inceptionresnetv2(num_classes=1001, pretrained='imagenet+background') 385 | print('success') 386 | 387 | # fail 388 | assert pdr_inceptionresnetv2(num_classes=10) -------------------------------------------------------------------------------- /models/inception_v4.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.utils.model_zoo as model_zoo 4 | import os 5 | import sys 6 | ''' 7 | https://github.com/Cadene/pretrained-models.pytorch 8 | ''' 9 | __all__ = ['InceptionV4', 'inceptionv4'] 10 | 11 | pretrained_settings = { 12 | 'inceptionv4': { 13 | 'imagenet': { 14 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth', 15 | 'input_space': 'RGB', 16 | 'input_size': [3, 299, 299], 17 | 'input_range': [0, 1], 18 | 'mean': [0.5, 0.5, 0.5], 19 | 'std': [0.5, 0.5, 0.5], 20 | 'num_classes': 1000 21 | }, 22 | 'imagenet+background': { 23 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth', 24 | 'input_space': 'RGB', 25 | 'input_size': [3, 299, 299], 26 | 'input_range': [0, 1], 27 | 'mean': [0.5, 0.5, 0.5], 28 | 'std': [0.5, 0.5, 0.5], 29 | 'num_classes': 1001 30 | } 31 | } 32 | } 33 | 34 | 35 | class BasicConv2d(nn.Module): 36 | 37 | def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): 38 | super(BasicConv2d, self).__init__() 39 | self.conv = nn.Conv2d(in_planes, out_planes, 40 | kernel_size=kernel_size, stride=stride, 41 | padding=padding, bias=False) # verify bias false 42 | self.bn = nn.BatchNorm2d(out_planes, 43 | eps=0.001, # value found in tensorflow 44 | momentum=0.1, # default pytorch value 45 | affine=True) 46 | self.relu = nn.ReLU(inplace=True) 47 | 48 | def forward(self, x): 49 | x = self.conv(x) 50 | x = self.bn(x) 51 | x = self.relu(x) 52 | return x 53 | 54 | 55 | class Mixed_3a(nn.Module): 56 | 57 | def __init__(self): 58 | super(Mixed_3a, self).__init__() 59 | self.maxpool = nn.MaxPool2d(3, stride=2) 60 | self.conv = BasicConv2d(64, 96, kernel_size=3, stride=2) 61 | 62 | def forward(self, x): 63 | x0 = self.maxpool(x) 64 | x1 = self.conv(x) 65 | out = torch.cat((x0, x1), 1) 66 | return out 67 | 68 | 69 | class Mixed_4a(nn.Module): 70 | 71 | def __init__(self): 72 | super(Mixed_4a, self).__init__() 73 | 74 | self.branch0 = nn.Sequential( 75 | BasicConv2d(160, 64, kernel_size=1, stride=1), 76 | BasicConv2d(64, 96, kernel_size=3, stride=1) 77 | ) 78 | 79 | self.branch1 = nn.Sequential( 80 | BasicConv2d(160, 64, kernel_size=1, stride=1), 81 | BasicConv2d(64, 64, kernel_size=(1, 7), stride=1, padding=(0, 3)), 82 | BasicConv2d(64, 64, kernel_size=(7, 1), stride=1, padding=(3, 0)), 83 | BasicConv2d(64, 96, kernel_size=(3, 3), stride=1) 84 | ) 85 | 86 | def forward(self, x): 87 | x0 = self.branch0(x) 88 | x1 = self.branch1(x) 89 | out = torch.cat((x0, x1), 1) 90 | return out 91 | 92 | 93 | class Mixed_5a(nn.Module): 94 | 95 | def __init__(self): 96 | super(Mixed_5a, self).__init__() 97 | self.conv = BasicConv2d(192, 192, kernel_size=3, stride=2) 98 | self.maxpool = nn.MaxPool2d(3, stride=2) 99 | 100 | def forward(self, x): 101 | x0 = self.conv(x) 102 | x1 = self.maxpool(x) 103 | out = torch.cat((x0, x1), 1) 104 | return out 105 | 106 | 107 | class Inception_A(nn.Module): 108 | 109 | def __init__(self): 110 | super(Inception_A, self).__init__() 111 | self.branch0 = BasicConv2d(384, 96, kernel_size=1, stride=1) 112 | 113 | self.branch1 = nn.Sequential( 114 | BasicConv2d(384, 64, kernel_size=1, stride=1), 115 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1) 116 | ) 117 | 118 | self.branch2 = nn.Sequential( 119 | BasicConv2d(384, 64, kernel_size=1, stride=1), 120 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), 121 | BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1) 122 | ) 123 | 124 | self.branch3 = nn.Sequential( 125 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 126 | BasicConv2d(384, 96, kernel_size=1, stride=1) 127 | ) 128 | 129 | def forward(self, x): 130 | x0 = self.branch0(x) 131 | x1 = self.branch1(x) 132 | x2 = self.branch2(x) 133 | x3 = self.branch3(x) 134 | out = torch.cat((x0, x1, x2, x3), 1) 135 | return out 136 | 137 | 138 | class Reduction_A(nn.Module): 139 | 140 | def __init__(self): 141 | super(Reduction_A, self).__init__() 142 | self.branch0 = BasicConv2d(384, 384, kernel_size=3, stride=2) 143 | 144 | self.branch1 = nn.Sequential( 145 | BasicConv2d(384, 192, kernel_size=1, stride=1), 146 | BasicConv2d(192, 224, kernel_size=3, stride=1, padding=1), 147 | BasicConv2d(224, 256, kernel_size=3, stride=2) 148 | ) 149 | 150 | self.branch2 = nn.MaxPool2d(3, stride=2) 151 | 152 | def forward(self, x): 153 | x0 = self.branch0(x) 154 | x1 = self.branch1(x) 155 | x2 = self.branch2(x) 156 | out = torch.cat((x0, x1, x2), 1) 157 | return out 158 | 159 | 160 | class Inception_B(nn.Module): 161 | 162 | def __init__(self): 163 | super(Inception_B, self).__init__() 164 | self.branch0 = BasicConv2d(1024, 384, kernel_size=1, stride=1) 165 | 166 | self.branch1 = nn.Sequential( 167 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 168 | BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)), 169 | BasicConv2d(224, 256, kernel_size=(7, 1), stride=1, padding=(3, 0)) 170 | ) 171 | 172 | self.branch2 = nn.Sequential( 173 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 174 | BasicConv2d(192, 192, kernel_size=(7, 1), stride=1, padding=(3, 0)), 175 | BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)), 176 | BasicConv2d(224, 224, kernel_size=(7, 1), stride=1, padding=(3, 0)), 177 | BasicConv2d(224, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)) 178 | ) 179 | 180 | self.branch3 = nn.Sequential( 181 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 182 | BasicConv2d(1024, 128, kernel_size=1, stride=1) 183 | ) 184 | 185 | def forward(self, x): 186 | x0 = self.branch0(x) 187 | x1 = self.branch1(x) 188 | x2 = self.branch2(x) 189 | x3 = self.branch3(x) 190 | out = torch.cat((x0, x1, x2, x3), 1) 191 | return out 192 | 193 | 194 | class Reduction_B(nn.Module): 195 | 196 | def __init__(self): 197 | super(Reduction_B, self).__init__() 198 | 199 | self.branch0 = nn.Sequential( 200 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 201 | BasicConv2d(192, 192, kernel_size=3, stride=2) 202 | ) 203 | 204 | self.branch1 = nn.Sequential( 205 | BasicConv2d(1024, 256, kernel_size=1, stride=1), 206 | BasicConv2d(256, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)), 207 | BasicConv2d(256, 320, kernel_size=(7, 1), stride=1, padding=(3, 0)), 208 | BasicConv2d(320, 320, kernel_size=3, stride=2) 209 | ) 210 | 211 | self.branch2 = nn.MaxPool2d(3, stride=2) 212 | 213 | def forward(self, x): 214 | x0 = self.branch0(x) 215 | x1 = self.branch1(x) 216 | x2 = self.branch2(x) 217 | out = torch.cat((x0, x1, x2), 1) 218 | return out 219 | 220 | 221 | class Inception_C(nn.Module): 222 | 223 | def __init__(self): 224 | super(Inception_C, self).__init__() 225 | 226 | self.branch0 = BasicConv2d(1536, 256, kernel_size=1, stride=1) 227 | 228 | self.branch1_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 229 | self.branch1_1a = BasicConv2d(384, 256, kernel_size=(1, 3), stride=1, padding=(0, 1)) 230 | self.branch1_1b = BasicConv2d(384, 256, kernel_size=(3, 1), stride=1, padding=(1, 0)) 231 | 232 | self.branch2_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 233 | self.branch2_1 = BasicConv2d(384, 448, kernel_size=(3, 1), stride=1, padding=(1, 0)) 234 | self.branch2_2 = BasicConv2d(448, 512, kernel_size=(1, 3), stride=1, padding=(0, 1)) 235 | self.branch2_3a = BasicConv2d(512, 256, kernel_size=(1, 3), stride=1, padding=(0, 1)) 236 | self.branch2_3b = BasicConv2d(512, 256, kernel_size=(3, 1), stride=1, padding=(1, 0)) 237 | 238 | self.branch3 = nn.Sequential( 239 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 240 | BasicConv2d(1536, 256, kernel_size=1, stride=1) 241 | ) 242 | 243 | def forward(self, x): 244 | x0 = self.branch0(x) 245 | 246 | x1_0 = self.branch1_0(x) 247 | x1_1a = self.branch1_1a(x1_0) 248 | x1_1b = self.branch1_1b(x1_0) 249 | x1 = torch.cat((x1_1a, x1_1b), 1) 250 | 251 | x2_0 = self.branch2_0(x) 252 | x2_1 = self.branch2_1(x2_0) 253 | x2_2 = self.branch2_2(x2_1) 254 | x2_3a = self.branch2_3a(x2_2) 255 | x2_3b = self.branch2_3b(x2_2) 256 | x2 = torch.cat((x2_3a, x2_3b), 1) 257 | 258 | x3 = self.branch3(x) 259 | 260 | out = torch.cat((x0, x1, x2, x3), 1) 261 | return out 262 | 263 | 264 | class InceptionV4(nn.Module): 265 | 266 | def __init__(self, num_classes=1001): 267 | super(InceptionV4, self).__init__() 268 | # Special attributs 269 | self.input_space = None 270 | self.input_size = (299, 299, 3) 271 | self.mean = None 272 | self.std = None 273 | # Modules 274 | self.features = nn.Sequential( 275 | BasicConv2d(3, 32, kernel_size=3, stride=2), 276 | BasicConv2d(32, 32, kernel_size=3, stride=1), 277 | BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1), 278 | Mixed_3a(), 279 | Mixed_4a(), 280 | Mixed_5a(), 281 | Inception_A(), 282 | Inception_A(), 283 | Inception_A(), 284 | Inception_A(), 285 | Reduction_A(), # Mixed_6a 286 | Inception_B(), 287 | Inception_B(), 288 | Inception_B(), 289 | Inception_B(), 290 | Inception_B(), 291 | Inception_B(), 292 | Inception_B(), 293 | Reduction_B(), # Mixed_7a 294 | Inception_C(), 295 | Inception_C(), 296 | Inception_C() 297 | ) 298 | self.avg_pool = nn.AdaptiveAvgPool2d(output_size=1) 299 | self.last_linear = nn.Linear(1536, num_classes) 300 | 301 | def logits(self, features): 302 | x = self.avg_pool(features) 303 | x = x.view(x.size(0), -1) 304 | x = self.last_linear(x) 305 | return x 306 | 307 | def forward(self, input): 308 | x = self.features(input) 309 | # print(x.size()) 310 | x = self.logits(x) 311 | return x 312 | 313 | 314 | def inceptionv4(num_classes=11,pretrained=True): 315 | """Constructs a ResNet-101 model. 316 | 317 | Args: 318 | pretrained (bool): If True, returns a model pre-trained on ImageNet 319 | """ 320 | model = InceptionV4(num_classes=1001) 321 | if pretrained: 322 | settings = pretrained_settings['inceptionv4']["imagenet"] 323 | model.load_state_dict(model_zoo.load_url(settings['url'])) 324 | model.last_linear = nn.Linear(model.last_linear.in_features, num_classes) 325 | return model 326 | 327 | ''' 328 | TEST 329 | Run this code with: 330 | ``` 331 | cd $HOME/pretrained-models.pytorch 332 | python -m pretrainedmodels.inceptionv4 333 | ``` 334 | ''' 335 | if __name__ == '__main__': 336 | import torch 337 | model = inceptionv4(num_classes=11) 338 | input = torch.autograd.Variable(torch.randn(2, 3, 299, 299)) 339 | y = model(input) 340 | print y.size() 341 | # # -------------------------------------------------------------------------------- /models/multiscale_resnet.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | import torch 3 | from torchvision import models,transforms,datasets 4 | import torch.nn.functional as F 5 | class multiscale_resnet(nn.Module): 6 | def __init__(self,num_class): 7 | super(multiscale_resnet,self).__init__() 8 | resnet50 =models.resnet50(pretrained=True) 9 | self.base_model =nn.Sequential(*list(resnet50.children())[:-2]) 10 | self.avgpool = nn.AdaptiveAvgPool2d(output_size=1) 11 | self.classifier = nn.Linear(resnet50.fc.in_features,num_class) 12 | 13 | def forward(self, x): 14 | input_size = x.size()[2] 15 | self.interp = nn.UpsamplingBilinear2d(size = (int(input_size*0.75)+1, int(input_size*0.75)+1)) 16 | 17 | x2 = self.interp(x) 18 | x = self.base_model(x) 19 | x = self.avgpool(x) 20 | x = x.view(x.size(0), -1) 21 | 22 | x2 = self.base_model(x2) 23 | x2 = self.avgpool(x2) 24 | x2 = x2.view(x2.size(0), -1) 25 | 26 | out =[] 27 | out.append(self.classifier(x)) 28 | out.append(self.classifier(x2)) 29 | return out 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /models/xception.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ported to pytorch thanks to [tstandley](https://github.com/tstandley/Xception-PyTorch) 3 | 4 | @author: tstandley 5 | Adapted by cadene 6 | 7 | Creates an Xception Model as defined in: 8 | 9 | Francois Chollet 10 | Xception: Deep Learning with Depthwise Separable Convolutions 11 | https://arxiv.org/pdf/1610.02357.pdf 12 | 13 | This weights ported from the Keras implementation. Achieves the following performance on the validation set: 14 | 15 | Loss:0.9173 Prec@1:78.892 Prec@5:94.292 16 | 17 | REMEMBER to set your image size to 3x299x299 for both test and validation 18 | 19 | normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], 20 | std=[0.5, 0.5, 0.5]) 21 | 22 | The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299 23 | """ 24 | import math 25 | import torch 26 | import torch.nn as nn 27 | import torch.nn.functional as F 28 | import torch.utils.model_zoo as model_zoo 29 | from torch.nn import init 30 | 31 | __all__ = ['xception'] 32 | ''' 33 | https://github.com/Cadene/pretrained-models.pytorch 34 | ''' 35 | pretrained_settings = { 36 | 'xception': { 37 | 'imagenet': { 38 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/xception-b5690688.pth', 39 | 'input_space': 'RGB', 40 | 'input_size': [3, 299, 299], 41 | 'input_range': [0, 1], 42 | 'mean': [0.5, 0.5, 0.5], 43 | 'std': [0.5, 0.5, 0.5], 44 | 'num_classes': 1000, 45 | 'scale': 0.8975 46 | # The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299 47 | } 48 | } 49 | } 50 | 51 | 52 | class SeparableConv2d(nn.Module): 53 | def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False): 54 | super(SeparableConv2d, self).__init__() 55 | 56 | self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation, groups=in_channels, 57 | bias=bias) 58 | self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias) 59 | 60 | def forward(self, x): 61 | x = self.conv1(x) 62 | x = self.pointwise(x) 63 | return x 64 | 65 | 66 | class Block(nn.Module): 67 | def __init__(self, in_filters, out_filters, reps, strides=1, start_with_relu=True, grow_first=True): 68 | super(Block, self).__init__() 69 | 70 | if out_filters != in_filters or strides != 1: 71 | self.skip = nn.Conv2d(in_filters, out_filters, 1, stride=strides, bias=False) 72 | self.skipbn = nn.BatchNorm2d(out_filters) 73 | else: 74 | self.skip = None 75 | 76 | self.relu = nn.ReLU(inplace=True) 77 | rep = [] 78 | 79 | filters = in_filters 80 | if grow_first: 81 | rep.append(self.relu) 82 | rep.append(SeparableConv2d(in_filters, out_filters, 3, stride=1, padding=1, bias=False)) 83 | rep.append(nn.BatchNorm2d(out_filters)) 84 | filters = out_filters 85 | 86 | for i in range(reps - 1): 87 | rep.append(self.relu) 88 | rep.append(SeparableConv2d(filters, filters, 3, stride=1, padding=1, bias=False)) 89 | rep.append(nn.BatchNorm2d(filters)) 90 | 91 | if not grow_first: 92 | rep.append(self.relu) 93 | rep.append(SeparableConv2d(in_filters, out_filters, 3, stride=1, padding=1, bias=False)) 94 | rep.append(nn.BatchNorm2d(out_filters)) 95 | 96 | if not start_with_relu: 97 | rep = rep[1:] 98 | else: 99 | rep[0] = nn.ReLU(inplace=False) 100 | 101 | if strides != 1: 102 | rep.append(nn.MaxPool2d(3, strides, 1)) 103 | self.rep = nn.Sequential(*rep) 104 | 105 | def forward(self, inp): 106 | x = self.rep(inp) 107 | 108 | if self.skip is not None: 109 | skip = self.skip(inp) 110 | skip = self.skipbn(skip) 111 | else: 112 | skip = inp 113 | 114 | x += skip 115 | return x 116 | 117 | 118 | class Xception(nn.Module): 119 | """ 120 | Xception optimized for the ImageNet dataset, as specified in 121 | https://arxiv.org/pdf/1610.02357.pdf 122 | """ 123 | 124 | def __init__(self, num_classes=1000): 125 | """ Constructor 126 | Args: 127 | num_classes: number of classes 128 | """ 129 | super(Xception, self).__init__() 130 | self.num_classes = num_classes 131 | 132 | self.conv1 = nn.Conv2d(3, 32, 3, 2, 0, bias=False) 133 | self.bn1 = nn.BatchNorm2d(32) 134 | self.relu = nn.ReLU(inplace=True) 135 | 136 | self.conv2 = nn.Conv2d(32, 64, 3, bias=False) 137 | self.bn2 = nn.BatchNorm2d(64) 138 | # do relu here 139 | 140 | self.block1 = Block(64, 128, 2, 2, start_with_relu=False, grow_first=True) 141 | self.block2 = Block(128, 256, 2, 2, start_with_relu=True, grow_first=True) 142 | self.block3 = Block(256, 728, 2, 2, start_with_relu=True, grow_first=True) 143 | 144 | self.block4 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 145 | self.block5 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 146 | self.block6 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 147 | self.block7 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 148 | 149 | self.block8 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 150 | self.block9 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 151 | self.block10 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 152 | self.block11 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True) 153 | 154 | self.block12 = Block(728, 1024, 2, 2, start_with_relu=True, grow_first=False) 155 | 156 | self.conv3 = SeparableConv2d(1024, 1536, 3, 1, 1) 157 | self.bn3 = nn.BatchNorm2d(1536) 158 | 159 | # do relu here 160 | self.conv4 = SeparableConv2d(1536, 2048, 3, 1, 1) 161 | self.bn4 = nn.BatchNorm2d(2048) 162 | 163 | self.fc = nn.Linear(2048, num_classes) 164 | 165 | # #------- init weights -------- 166 | # for m in self.modules(): 167 | # if isinstance(m, nn.Conv2d): 168 | # n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 169 | # m.weight.data.normal_(0, math.sqrt(2. / n)) 170 | # elif isinstance(m, nn.BatchNorm2d): 171 | # m.weight.data.fill_(1) 172 | # m.bias.data.zero_() 173 | # #----------------------------- 174 | 175 | def features(self, input): 176 | x = self.conv1(input) 177 | x = self.bn1(x) 178 | x = self.relu(x) 179 | 180 | x = self.conv2(x) 181 | x = self.bn2(x) 182 | x = self.relu(x) 183 | 184 | x = self.block1(x) 185 | x = self.block2(x) 186 | x = self.block3(x) 187 | x = self.block4(x) 188 | x = self.block5(x) 189 | x = self.block6(x) 190 | x = self.block7(x) 191 | x = self.block8(x) 192 | x = self.block9(x) 193 | x = self.block10(x) 194 | x = self.block11(x) 195 | x = self.block12(x) 196 | 197 | x = self.conv3(x) 198 | x = self.bn3(x) 199 | x = self.relu(x) 200 | 201 | x = self.conv4(x) 202 | x = self.bn4(x) 203 | return x 204 | 205 | def logits(self, features): 206 | x = self.relu(features) 207 | 208 | x = F.adaptive_avg_pool2d(x, (1, 1)) 209 | x = x.view(x.size(0), -1) 210 | x = self.fc(x) 211 | return x 212 | 213 | def forward(self, input): 214 | x = self.features(input) 215 | x = self.logits(x) 216 | return x 217 | 218 | 219 | def xception(num_classes=1000, pretrained='imagenet'): 220 | model = Xception(num_classes=num_classes) 221 | if pretrained: 222 | settings = pretrained_settings['xception'][pretrained] 223 | assert num_classes == settings['num_classes'], \ 224 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 225 | 226 | model = Xception(num_classes=num_classes) 227 | model.load_state_dict(model_zoo.load_url(settings['url'])) 228 | 229 | model.input_space = settings['input_space'] 230 | model.input_size = settings['input_size'] 231 | model.input_range = settings['input_range'] 232 | model.mean = settings['mean'] 233 | model.std = settings['std'] 234 | 235 | # TODO: ugly 236 | model.last_linear = model.fc 237 | del model.fc 238 | return model 239 | def pdr_xception(num_classes): 240 | model = Xception(num_classes=1000) 241 | settings = pretrained_settings['xception']['imagenet'] 242 | model.load_state_dict(model_zoo.load_url(settings['url'])) 243 | model.fc = nn.Linear(2048, num_classes) 244 | return model 245 | 246 | if __name__ == '__main__': 247 | import torch 248 | model = pdr_xception(num_classes=11) 249 | input = torch.autograd.Variable(torch.randn(2, 3, 299, 299)) 250 | y = model(input) 251 | print (y.size()) -------------------------------------------------------------------------------- /predict/bd_tiangong_model_merge.py: -------------------------------------------------------------------------------- 1 | import time 2 | import copy 3 | import pandas as pd 4 | from collections import defaultdict 5 | import numpy as np 6 | class2label={"DESERT":0,"MOUNTAIN":1,"OCEAN":2,"FARMLAND":3,"LAKE":4,"CITY":5,"UNKNOW":6} 7 | label2class=["DESERT","MOUNTAIN","OCEAN","FARMLAND","LAKE","CITY","UNKNOW"] 8 | 9 | result_ratios = defaultdict(lambda: 0) 10 | mode="val" 11 | result_ratios['resnet50'] = 0.5 12 | # result_ratios['resnet101'] = 0.5 13 | result_ratios['densent121'] = 0.5 14 | # result_ratios['densent169'] = 0.25 15 | 16 | assert sum(result_ratios.values()) == 1 17 | def str2np(str): 18 | return np.array([float(x) for x in str.split(";")]) 19 | def np2str(arr): 20 | return ";".join(["%.16f" % x for x in arr]) 21 | for index, model in enumerate(result_ratios.keys()): 22 | print('ratio: %.3f, model: %s' % (result_ratios[model], model)) 23 | result = pd.read_csv('tiangong/csv/{}_{}_prob.csv'.format(model,mode),names=["filename","label","probability"]) 24 | # result = result.sort_values(by='filename').reset_index(drop=True) 25 | result['probability'] = result['probability'].apply(lambda x: str2np(x)) 26 | print(result.head()) 27 | 28 | if index == 0: 29 | ensembled_result = copy.deepcopy(result) 30 | ensembled_result['probability'] =0 31 | 32 | ensembled_result['probability'] = ensembled_result['probability'] + result['probability']*result_ratios[model] 33 | print(ensembled_result.head()) 34 | def parase_prob(x): 35 | if np.max(x)<0.33: 36 | label=label2class[6] 37 | else: 38 | label = label2class[int(np.argmax(x))] 39 | return label 40 | def get_class_pro(x,class_name): 41 | # sum =np.sum(x) 42 | # prob=x[class2label[class_name]]*1.0/sum 43 | prob=x[class2label[class_name]] 44 | prob =np.round(prob,8) 45 | # return str("({},{})".format(class_name,str("%.8f" % prob))) 46 | return "("+class_name+","+str(prob)+")" 47 | 48 | ensembled_result['label'] = ensembled_result['probability'].apply(lambda x: parase_prob(x)) 49 | for class_name in label2class[:-1]: 50 | ensembled_result[class_name] = ensembled_result['probability'].map(lambda x: get_class_pro(x,class_name)) 51 | # ensembled_result['probability'] = ensembled_result['probability'].map(lambda x: np2str(x)) 52 | # ensembled_result[["filename","label","OCEAN","MOUNTAIN","LAKE","FARMLAND","DESERT","CITY"]].to_csv('%s_ensembled_result.csv' % time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime(time.time())), header=None,index=False) 53 | # ensembled_result[["filename","label","OCEAN","MOUNTAIN","LAKE","FARMLAND","DESERT","CITY"]].to_csv('ensembled_result2.csv', header=None,index=False) 54 | with open('ensembled_result.csv',"w") as f: 55 | for filename,label,OCEAN,MOUNTAIN,LAKE,FARMLAND,DESERT,CITY in zip(ensembled_result["filename"], 56 | ensembled_result["label"], 57 | ensembled_result["OCEAN"], 58 | ensembled_result["MOUNTAIN"], 59 | ensembled_result["LAKE"], 60 | ensembled_result["FARMLAND"], 61 | ensembled_result["DESERT"], 62 | ensembled_result["CITY"]): 63 | output_str=",".join([x for x in [filename,label,OCEAN,MOUNTAIN,LAKE,FARMLAND,DESERT,CITY]]) 64 | f.write(output_str) 65 | f.write("\n") 66 | -------------------------------------------------------------------------------- /predict/bd_tiangong_pred.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import numpy as np 4 | import pandas as pd 5 | from dataset.bd_tiangong_dataset import dataset, collate_fn,class2label,label2class 6 | import torch 7 | from torch.nn import CrossEntropyLoss 8 | import torch.utils.data as torchdata 9 | from torchvision import datasets, models, transforms 10 | from torchvision.models import resnet50 11 | from sklearn.model_selection import train_test_split 12 | from torch.autograd import Variable 13 | from math import ceil 14 | from torch.nn.functional import softmax 15 | from dataset.data_aug import * 16 | import glob 17 | test_transforms= Compose([ 18 | Resize(size=(256, 256)), 19 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 20 | ]) 21 | 22 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 23 | mode ="test" 24 | 25 | label_csv = "/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/光学数据集-预赛训练集-2000-有标签.csv" 26 | train_root = "/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛训练集2000/预赛训练集-2000" 27 | test_root = "/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛测试集A1000/预赛测试集A-1000" 28 | label = pd.read_csv(label_csv, names=["ImageName", "class"]) 29 | label["label"] = label["class"].apply(lambda x: class2label[x]) 30 | train_pd, val_pd = train_test_split(label, test_size=0.12, random_state=43, stratify=label["label"]) 31 | test_list = glob.glob(test_root+"/*.jpg") 32 | true_test_pb=pd.DataFrame(test_list,columns=["path"]) 33 | true_test_pb["ImageName"]=true_test_pb["path"].apply(lambda x:os.path.basename(x)) 34 | "addFakeLabel" 35 | true_test_pb['label'] =1 36 | 37 | test_pd =true_test_pb if mode=="test" else val_pd 38 | rawdata_root =test_root if mode=="test" else train_root 39 | 40 | print(test_pd.head()) 41 | 42 | data_set = {} 43 | data_set['test'] = dataset(imgroot=rawdata_root, anno_pd=test_pd, 44 | transforms=test_transforms, 45 | ) 46 | data_loader = {} 47 | data_loader['test'] = torchdata.DataLoader(data_set['test'], batch_size=4, num_workers=4, 48 | shuffle=False, pin_memory=True, collate_fn=collate_fn) 49 | 50 | model_name = 'resnet50-out' 51 | resume = '/media/hszc/model/detao/models/bd_tiangong/resnet50/weights-26-80-[0.9917].pth' 52 | 53 | model =resnet50(pretrained=True) 54 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 55 | model.fc = torch.nn.Linear(model.fc.in_features,6) 56 | model = torch.nn.DataParallel(model) 57 | 58 | print('resuming finetune from %s'%resume) 59 | model.load_state_dict(torch.load(resume)) 60 | 61 | model = model.cuda() 62 | model.eval() 63 | 64 | criterion = CrossEntropyLoss() 65 | 66 | if not os.path.exists('./Baidu/csv'): 67 | os.makedirs('./Baidu/csv') 68 | 69 | test_size = ceil(len(data_set['test']) / data_loader['test'].batch_size) 70 | test_preds = np.zeros((len(data_set['test'])), dtype=np.float32) 71 | true_label = np.zeros((len(data_set['test'])), dtype=np.int) 72 | idx = 0 73 | test_loss = 0 74 | test_corrects = 0 75 | for batch_cnt_test, data_test in enumerate(data_loader['test']): 76 | # print data 77 | print("{0}/{1}".format(batch_cnt_test, int(test_size))) 78 | inputs, labels = data_test 79 | inputs = Variable(inputs.cuda()) 80 | labels = Variable(torch.from_numpy(np.array(labels)).long().cuda()) 81 | # forward 82 | outputs = model(inputs) 83 | 84 | # statistics 85 | if isinstance(outputs, list): 86 | loss = criterion(outputs[0], labels) 87 | loss += criterion(outputs[1], labels) 88 | outputs = (outputs[0]+outputs[1])/2 89 | else: 90 | loss = criterion(outputs, labels) 91 | _, preds = torch.max(outputs, 1) 92 | 93 | test_loss += loss.data[0] 94 | batch_corrects = torch.sum((preds == labels)).data[0] 95 | test_corrects += batch_corrects 96 | test_preds[idx:(idx + labels.size(0))] = preds 97 | true_label[idx:(idx + labels.size(0))] = labels.data.cpu().numpy() 98 | # statistics 99 | idx += labels.size(0) 100 | test_loss = test_loss / test_size 101 | test_acc = 1.0 * test_corrects / len(data_set['test']) 102 | print('test-loss: %.4f ||test-acc@1: %.4f' 103 | % (test_loss, test_acc)) 104 | 105 | test_pred = test_pd[['ImageName']].copy() 106 | test_pred['label'] = list(test_preds) 107 | test_pred['label'] = test_pred['label'].apply(lambda x: label2class[int(x)]) 108 | test_pred[['ImageName',"label"]].to_csv('Baidu/csv/{0}_{1}.csv'.format(model_name,mode) ,sep=",", 109 | header=None, index=False) 110 | print (test_pred.info()) 111 | -------------------------------------------------------------------------------- /predict/bd_tiangong_pred_unknow.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import os 3 | import numpy as np 4 | import pandas as pd 5 | from dataset.bd_tiangong_dataset import dataset, collate_fn,class2label,label2class 6 | import torch 7 | from torch.nn import CrossEntropyLoss 8 | import torch.utils.data as torchdata 9 | from torchvision import datasets, models, transforms 10 | from torchvision.models import resnet50 11 | from sklearn.model_selection import train_test_split 12 | from torch.autograd import Variable 13 | from math import ceil 14 | from torch.nn.functional import softmax 15 | from dataset.data_aug import * 16 | import glob 17 | from models.resnet import resnet50,resnet101 18 | from models.inception_resnet_v2 import inceptionresnetv2 19 | from models.densenet import densenet169,densenet121 20 | import argparse 21 | from dataset.bd_tiangong_dataset import class2label 22 | from torch import nn 23 | ''' 24 | http://dianshi.baidu.com/dianshi/pc/competition/22/rank''' 25 | parser = argparse.ArgumentParser() 26 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 27 | parser.add_argument('--net', dest='net',type=str, default='resnet50',help='densent121,resnet101,resnet50,inceptionv4,densent169,inceptionresnetv2') 28 | parser.add_argument('--resume', type=str, default="/home/detao/Videos/detao/code/pytorch_classification/predict/" 29 | "model_weights/resnet50_unknow/best_weigths_[1.0000000000000002e-06].pth") 30 | # parser.add_argument('--resume', type=str, default="/home/detao/Videos/detao/code/pytorch_classification/predict/" 31 | # "model_weights/densent169_unknow/best_weigths_[1.0000000000000002e-06].pth") 32 | # parser.add_argument('--resume', type=str, default="/home/detao/Videos/detao/code/pytorch_classification/predict/" 33 | # "model_weights/densenet121_unknow/best_weigths_[0.0001].pth") 34 | # parser.add_argument('--resume', type=str, default="/home/detao/Videos/detao/code/pytorch_classification/predict/" 35 | # "model_weights/resnet101_unknow/best_weigths_[0.001].pth") 36 | parser.add_argument('--mode', type=str, default="val", help='val,test') 37 | parser.add_argument('--start_epoch', type=int, default=0, help='number of start epoch') 38 | 39 | parser.add_argument('--save_checkpoint_val_interval', type=int, default=200, help='interval between saving model weights') 40 | parser.add_argument('--n_cpu', type=int, default=4, help='number of cpu threads to use during batch generation') 41 | opt = parser.parse_args() 42 | test_transforms= Compose([ 43 | Resize(size=(256, 256)), 44 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 45 | ]) 46 | def np2str(arr): 47 | return ";".join(["%.16f" % x for x in arr]) 48 | def str2np(str): 49 | return np.array([x for x in str.split(";")]) 50 | if __name__ == '__main__': 51 | if opt.mode=="val": 52 | label_csv = "/home/detao/Videos/detao/data/all/label/9970_b.csv" 53 | train_root = "/home/detao/Videos/detao/data/all/data/testb" 54 | else: 55 | label_csv = "/home/detao/Videos/detao/data/all/label/9990_a.csv" 56 | train_root = "/home/detao/Videos/detao/data/all/data/testa/testa" 57 | test_root = "/media/hszc/model/detao/data/dianshi/宽波段数据集-预赛测试集A1000/预赛测试集A-1000" 58 | val_pd = pd.read_csv(label_csv, names=["ImageName", "class"]) 59 | val_pd["label"] = val_pd["class"].apply(lambda x: class2label[x]) 60 | val_pd["img_path"]=val_pd["ImageName"].apply(lambda x:os.path.join(train_root,x)) 61 | 62 | test_list = glob.glob(test_root+"/*.jpg") 63 | true_test_pb=pd.DataFrame(test_list,columns=["path"]) 64 | true_test_pb["ImageName"]=true_test_pb["path"].apply(lambda x:os.path.basename(x)) 65 | "addFakeLabel" 66 | true_test_pb['label'] =1 67 | 68 | test_pd =true_test_pb if opt.mode=="test" else val_pd 69 | rawdata_root =test_root if opt.mode=="test" else train_root 70 | 71 | print(test_pd.head()) 72 | '''data_set&data_loader''' 73 | data_set = {} 74 | data_set['test'] = dataset(imgroot=rawdata_root, anno_pd=test_pd, 75 | transforms=test_transforms, 76 | ) 77 | data_loader = {} 78 | data_loader['test'] = torchdata.DataLoader(data_set['test'], batch_size=4, num_workers=4, 79 | shuffle=False, pin_memory=True, collate_fn=collate_fn) 80 | 81 | '''model''' 82 | if opt.net == "resnet50": 83 | model =resnet50(pretrained=True) 84 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 85 | model.fc = torch.nn.Linear(model.fc.in_features,6) 86 | elif opt.net == "resnet101": 87 | model =resnet101(pretrained=True) 88 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 89 | model.fc = torch.nn.Linear(model.fc.in_features,6) 90 | elif opt.net == "inceptionresnetv2": 91 | model =inceptionresnetv2(num_classes=6) 92 | elif opt.net == "densent169": 93 | model =densenet169(pretrained=True) 94 | model.classifier = nn.Linear(model.classifier.in_features, 6) 95 | elif opt.net == "densent121": 96 | model =densenet121(pretrained=True) 97 | model.classifier = nn.Linear(model.classifier.in_features, 6) 98 | if opt.resume: 99 | model.eval() 100 | print('resuming finetune from %s' % opt.resume) 101 | try: 102 | model.load_state_dict(torch.load(opt.resume)) 103 | except KeyError: 104 | model = torch.nn.DataParallel(model) 105 | model.load_state_dict(torch.load(opt.resume)) 106 | model = model.cuda() 107 | model.eval() 108 | 109 | criterion = CrossEntropyLoss() 110 | 111 | if not os.path.exists('./tiangong/csv'): 112 | os.makedirs('./tiangong/csv') 113 | 114 | test_size = ceil(len(data_set['test']) / data_loader['test'].batch_size) 115 | test_preds = np.zeros((len(data_set['test'])), dtype=np.float32) 116 | true_label = np.zeros((len(data_set['test'])), dtype=np.int) 117 | test_scores = np.zeros((len(data_set['test']),6), dtype=np.float32) 118 | 119 | idx = 0 120 | test_loss = 0 121 | test_corrects = 0 122 | for batch_cnt_test, data_test in enumerate(data_loader['test']): 123 | # print data 124 | print("{0}/{1}".format(batch_cnt_test, int(test_size))) 125 | inputs, labels = data_test 126 | inputs = Variable(inputs.cuda()) 127 | labels = Variable(torch.from_numpy(np.array(labels)).long().cuda()) 128 | # forward 129 | outputs = model(inputs) 130 | # print(torch.sum(outputs.sigmoid()>0.5).cpu().float()) 131 | # num =torch.sum(outputs.sigmoid()>0.288).cpu().float() 132 | scores=outputs.sigmoid() 133 | print(scores) 134 | if isinstance(outputs, list): 135 | loss = criterion(outputs[0], labels) 136 | loss += criterion(outputs[1], labels) 137 | outputs = (outputs[0]+outputs[1])/2 138 | else: 139 | loss = criterion(outputs, labels) 140 | _, preds = torch.max(outputs, 1) 141 | 142 | test_loss += loss.data[0] 143 | batch_corrects = torch.sum((preds == labels)).data[0] 144 | test_corrects += batch_corrects 145 | test_preds[idx:(idx + labels.size(0))] = preds 146 | test_scores[idx:(idx + labels.size(0))] = scores.data.cpu().numpy() 147 | true_label[idx:(idx + labels.size(0))] = labels.data.cpu().numpy() 148 | # statistics 149 | idx += labels.size(0) 150 | test_loss = test_loss / test_size 151 | test_acc = 1.0 * test_corrects / len(data_set['test']) 152 | print('test-loss: %.4f ||test-acc@1: %.4f' 153 | % (test_loss, test_acc)) 154 | 155 | test_pred = test_pd[['ImageName']].copy() 156 | test_pred['label'] = list(test_preds) 157 | test_pred['label'] = test_pred['label'].apply(lambda x: label2class[int(x)]) 158 | test_pred['prob'] = list(test_scores) 159 | test_pred['prob'] = test_pred['prob'].apply(lambda x: np2str(x)) 160 | test_pred[['ImageName',"label","prob"]].to_csv('tiangong/csv/{0}_{1}_prob.csv'.format(opt.net,opt.mode) ,sep=",", 161 | header=None, index=False) 162 | test_pred[['ImageName',"label"]].to_csv('tiangong/csv/{0}_{1}_result.csv'.format(opt.net,opt.mode) ,sep=",", 163 | header=None, index=False) -------------------------------------------------------------------------------- /predict/bd_xjtu_pred.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import pandas as pd 4 | from dataset.bd_xjtu_dataset import dataset, collate_fn 5 | import torch 6 | from torch.nn import CrossEntropyLoss 7 | import torch.utils.data as torchdata 8 | from torchvision import datasets, models, transforms 9 | from torchvision.models import resnet50 10 | from sklearn.model_selection import train_test_split 11 | from torch.autograd import Variable 12 | from math import ceil 13 | from torch.nn.functional import softmax 14 | from dataset.data_aug import * 15 | test_transforms= Compose([ 16 | ExpandBorder(size=(336,336),resize=True), 17 | Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 18 | ]) 19 | 20 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 21 | mode ="train" 22 | 23 | rawdata_root = '/media/hszc/data/detao/data/baidu/datasets/' 24 | all_pd = pd.read_csv("/media/hszc/data/detao/data/baidu/datasets/train.txt",sep=" ", 25 | header=None, names=['ImageName', 'label']) 26 | train_pd, val_pd = train_test_split(all_pd, test_size=0.15, random_state=43, 27 | stratify=all_pd['label']) 28 | true_test_pb = pd.read_csv("/media/hszc/data/detao/data/baidu/datasets/test.txt",sep=" ", 29 | header=None, names=['ImageName']) 30 | "addFakeLabel" 31 | true_test_pb['label'] =1 32 | 33 | test_pd =true_test_pb if mode=="test" else val_pd 34 | print(test_pd.head()) 35 | 36 | data_set = {} 37 | data_set['test'] = dataset(imgroot=os.path.join(rawdata_root, mode), anno_pd=test_pd, 38 | transforms=test_transforms, 39 | ) 40 | data_loader = {} 41 | data_loader['test'] = torchdata.DataLoader(data_set['test'], batch_size=4, num_workers=4, 42 | shuffle=False, pin_memory=True, collate_fn=collate_fn) 43 | 44 | model_name = 'resnet50-out' 45 | resume = '/media/hszc/model/detao/baidu_model/resnet/weights-20-360-[0.9870].pth' 46 | 47 | model =resnet50(pretrained=True) 48 | model.avgpool = torch.nn.AdaptiveAvgPool2d(output_size=1) 49 | model.fc = torch.nn.Linear(model.fc.in_features,100) 50 | 51 | print('resuming finetune from %s'%resume) 52 | model.load_state_dict(torch.load(resume)) 53 | model = model.cuda() 54 | model.eval() 55 | 56 | criterion = CrossEntropyLoss() 57 | 58 | if not os.path.exists('./Baidu/csv'): 59 | os.makedirs('./Baidu/csv') 60 | 61 | test_size = ceil(len(data_set['test']) / data_loader['test'].batch_size) 62 | test_preds = np.zeros((len(data_set['test'])), dtype=np.float32) 63 | true_label = np.zeros((len(data_set['test'])), dtype=np.int) 64 | idx = 0 65 | test_loss = 0 66 | test_corrects = 0 67 | for batch_cnt_test, data_test in enumerate(data_loader['test']): 68 | # print data 69 | print("{0}/{1}".format(batch_cnt_test, int(test_size))) 70 | inputs, labels = data_test 71 | inputs = Variable(inputs.cuda()) 72 | labels = Variable(torch.from_numpy(np.array(labels)).long().cuda()) 73 | # forward 74 | outputs = model(inputs) 75 | 76 | # statistics 77 | if isinstance(outputs, list): 78 | loss = criterion(outputs[0], labels) 79 | loss += criterion(outputs[1], labels) 80 | outputs = (outputs[0]+outputs[1])/2 81 | else: 82 | loss = criterion(outputs, labels) 83 | _, preds = torch.max(outputs, 1) 84 | 85 | test_loss += loss.data[0] 86 | batch_corrects = torch.sum((preds == labels)).data[0] 87 | test_corrects += batch_corrects 88 | test_preds[idx:(idx + labels.size(0))] = preds 89 | true_label[idx:(idx + labels.size(0))] = labels.data.cpu().numpy() 90 | # statistics 91 | idx += labels.size(0) 92 | test_loss = test_loss / test_size 93 | test_acc = 1.0 * test_corrects / len(data_set['test']) 94 | print('test-loss: %.4f ||test-acc@1: %.4f' 95 | % (test_loss, test_acc)) 96 | 97 | test_pred = test_pd[['ImageName']].copy() 98 | test_pred['label'] = list(test_preds) 99 | test_pred['label'] = test_pred['label'].apply(lambda x: int(x)+1) 100 | test_pred[['ImageName',"label"]].to_csv('Baidu/csv/{0}_{1}.csv'.format(model_name,mode) ,sep=" ", 101 | header=None, index=False) 102 | print (test_pred.info()) 103 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdingdongO/pytorch_classification/0b66c6f6aabf66eda0591712525ec036ee9a94e5/utils/__init__.py -------------------------------------------------------------------------------- /utils/losses.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Variable 5 | 6 | class FocalLoss(nn.Module): 7 | """ 8 | 9 | This criterion is a implemenation of Focal Loss, which is proposed in 10 | Focal Loss for Dense Object Detection. 11 | 12 | Loss(x, class) = - \alpha (1-softmax(x)[class])^gamma \log(softmax(x)[class]) 13 | 14 | The losses are averaged across observations for each minibatch. 15 | 16 | Args: 17 | alpha(1D Tensor, Variable) : the scalar factor for this criterion 18 | gamma(float, double) : gamma > 0; reduces the relative loss for well-classi?ed examples (p > .5), 19 | putting more focus on hard, misclassi?ed examples 20 | size_average(bool): By default, the losses are averaged over observations for each minibatch. 21 | However, if the field size_average is set to False, the losses are 22 | instead summed for each minibatch. 23 | """ 24 | def __init__(self, class_num, alpha=None, gamma=2, size_average=True): 25 | super(FocalLoss, self).__init__() 26 | if alpha is None: 27 | self.alpha = Variable(torch.ones(class_num, 1)) 28 | else: 29 | if isinstance(alpha, Variable): 30 | self.alpha = alpha 31 | else: 32 | self.alpha = Variable(alpha) 33 | self.gamma = gamma 34 | self.class_num = class_num 35 | self.size_average = size_average 36 | 37 | def forward(self, inputs, targets): 38 | N = inputs.size(0) 39 | C = inputs.size(1) 40 | P = F.softmax(inputs) 41 | 42 | class_mask = inputs.data.new(N, C).fill_(0) 43 | class_mask = Variable(class_mask) 44 | 45 | ids = targets.view(-1, 1) 46 | class_mask.scatter_(1, Variable(ids.data), 1.0) 47 | 48 | if inputs.is_cuda and not self.alpha.is_cuda: 49 | self.alpha = self.alpha.cuda() 50 | alpha = self.alpha[ids.data.view(-1)] 51 | 52 | probs = (P*class_mask).sum(1).view(-1,1) 53 | 54 | log_p = probs.log() 55 | 56 | batch_loss = -alpha*(torch.pow((1-probs), self.gamma))*log_p 57 | 58 | if self.size_average: 59 | loss = batch_loss.mean() 60 | else: 61 | loss = batch_loss.sum() 62 | return loss 63 | 64 | class SoftmaxCrossEntropy(nn.Module): 65 | def __init__(self): 66 | super(SoftmaxCrossEntropy, self).__init__() 67 | 68 | 69 | def forward(self, y_preds, y_true,y_mask): 70 | ''' 71 | :param y_preds: (N, C), Variable of FloatTensor 72 | :param y_true: (N, C), Variable of FloatTensor 73 | :return: 74 | ''' 75 | # logp = F.log_softmax(y_preds) 76 | logp = y_preds.log() # (N, C) 77 | ylogp = y_true * logp 78 | ylogp =ylogp*y_mask 79 | return -ylogp.sum() / (y_true.sum()+0.000001) -------------------------------------------------------------------------------- /utils/train_util.py: -------------------------------------------------------------------------------- 1 | #coding=utf8 2 | from __future__ import division 3 | import torch 4 | import os,time,datetime 5 | from torch.autograd import Variable 6 | import logging 7 | import numpy as np 8 | from math import ceil 9 | 10 | def dt(): 11 | return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 12 | 13 | def trainlog(logfilepath, head='%(message)s'): 14 | logger = logging.getLogger('mylogger') 15 | logging.basicConfig(filename=logfilepath, level=logging.INFO, format=head) 16 | console = logging.StreamHandler() 17 | console.setLevel(logging.INFO) 18 | formatter = logging.Formatter(head) 19 | console.setFormatter(formatter) 20 | logging.getLogger('').addHandler(console) 21 | 22 | def train(model, 23 | epoch_num, 24 | start_epoch, 25 | optimizer, 26 | criterion, 27 | exp_lr_scheduler, 28 | data_set, 29 | data_loader, 30 | save_dir, 31 | print_inter=200, 32 | val_inter=3500 33 | ): 34 | 35 | step = -1 36 | for epoch in range(start_epoch,epoch_num): 37 | # train phase 38 | exp_lr_scheduler.step(epoch) 39 | model.train(True) # Set model to training mode 40 | 41 | for batch_cnt, data in enumerate(data_loader['train']): 42 | 43 | step+=1 44 | model.train(True) 45 | # print data 46 | inputs, labels = data 47 | 48 | inputs = Variable(inputs.cuda()) 49 | labels = Variable(torch.from_numpy(np.array(labels)).long().cuda()) 50 | 51 | # zero the parameter gradients 52 | optimizer.zero_grad() 53 | 54 | outputs = model(inputs) 55 | if isinstance(outputs, list): 56 | loss = criterion(outputs[0], labels) 57 | loss += criterion(outputs[1], labels) 58 | outputs=outputs[0] 59 | else: 60 | loss = criterion(outputs, labels) 61 | 62 | _, preds = torch.max(outputs, 1) 63 | loss.backward() 64 | optimizer.step() 65 | 66 | # batch loss 67 | if step % print_inter == 0: 68 | _, preds = torch.max(outputs, 1) 69 | 70 | batch_corrects = torch.sum((preds == labels)).data[0] 71 | batch_acc = batch_corrects / (labels.size(0)) 72 | 73 | logging.info('%s [%d-%d] | batch-loss: %.3f | acc@1: %.3f' 74 | % (dt(), epoch, batch_cnt, loss.data[0], batch_acc)) 75 | 76 | 77 | if step % val_inter == 0: 78 | logging.info('current lr:%s' % exp_lr_scheduler.get_lr()) 79 | # val phase 80 | model.train(False) # Set model to evaluate mode 81 | 82 | val_loss = 0 83 | val_corrects = 0 84 | val_size = ceil(len(data_set['val']) / data_loader['val'].batch_size) 85 | 86 | t0 = time.time() 87 | 88 | for batch_cnt_val, data_val in enumerate(data_loader['val']): 89 | # print data 90 | inputs, labels = data_val 91 | 92 | inputs = Variable(inputs.cuda()) 93 | labels = Variable(torch.from_numpy(np.array(labels)).long().cuda()) 94 | 95 | # forward 96 | outputs = model(inputs) 97 | if isinstance(outputs, list): 98 | loss = criterion(outputs[0], labels) 99 | loss += criterion(outputs[1], labels) 100 | outputs = outputs[0] 101 | 102 | else: 103 | loss = criterion(outputs, labels) 104 | _, preds = torch.max(outputs, 1) 105 | 106 | # statistics 107 | val_loss += loss.data[0] 108 | batch_corrects = torch.sum((preds == labels)).data[0] 109 | val_corrects += batch_corrects 110 | 111 | val_loss = val_loss / val_size 112 | val_acc = 1.0 * val_corrects / len(data_set['val']) 113 | 114 | t1 = time.time() 115 | since = t1-t0 116 | logging.info('--'*30) 117 | logging.info('current lr:%s' % exp_lr_scheduler.get_lr()) 118 | 119 | logging.info('%s epoch[%d]-val-loss: %.4f ||val-acc@1: %.4f ||time: %d' 120 | % (dt(), epoch, val_loss, val_acc, since)) 121 | 122 | # save model 123 | save_path = os.path.join(save_dir, 124 | 'weights-%d-%d-[%.4f].pth'%(epoch,batch_cnt,val_acc)) 125 | torch.save(model.state_dict(), save_path) 126 | logging.info('saved model to %s' % (save_path)) 127 | logging.info('--' * 30) 128 | 129 | 130 | --------------------------------------------------------------------------------