Closed hellbell closed 4 years ago
Hi @hellbell we can release the model of Pascal VOC. however, a deal is needed :-)
I was too lazy to create a full open-source validation source for COCO, and i saw you made one. if you can share your end-to-end validation code of COCO, i will release the pascal-VOC model :-)
Tal
@mrT23 Great!
Actually, that repo is not mine :)
I slightly modified that repo's MS-COCO validation code considering your infer.py
.
I hope this works well.
# Original code: https://github.com/allenai/elastic/blob/master/multilabel_classify.py
import argparse
import time
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.distributed as dist
import torch.optim
import torch.utils.data as data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import models
import os
from PIL import Image
from sklearn.metrics import average_precision_score
from src.models import create_model
class AverageMeter(object):
def __init__(self):
self.val = None
self.sum = None
self.cnt = None
self.avg = None
self.ema = None
self.initialized = False
def update(self, val, n=1):
if not self.initialized:
self.initialize(val, n)
else:
self.add(val, n)
def initialize(self, val, n):
self.val = val
self.sum = val * n
self.cnt = n
self.avg = val
self.ema = val
self.initialized = True
def add(self, val, n):
self.val = val
self.sum += val * n
self.cnt += n
self.avg = self.sum / self.cnt
self.ema = self.ema * 0.99 + self.val * 0.01
class CocoDetection(datasets.coco.CocoDetection):
def __init__(self, root, annFile, transform=None, target_transform=None):
from pycocotools.coco import COCO
self.root = root
self.coco = COCO(annFile)
self.ids = list(self.coco.imgToAnns.keys())
self.transform = transform
self.target_transform = target_transform
self.cat2cat = dict()
for cat in self.coco.cats.keys():
self.cat2cat[cat] = len(self.cat2cat)
# print(self.cat2cat)
def __getitem__(self, index):
coco = self.coco
img_id = self.ids[index]
ann_ids = coco.getAnnIds(imgIds=img_id)
target = coco.loadAnns(ann_ids)
output = torch.zeros((3, 80), dtype=torch.long)
for obj in target:
if obj['area'] < 32 * 32:
output[0][self.cat2cat[obj['category_id']]] = 1
elif obj['area'] < 96 * 96:
output[1][self.cat2cat[obj['category_id']]] = 1
else:
output[2][self.cat2cat[obj['category_id']]] = 1
target = output
path = coco.loadImgs(img_id)[0]['file_name']
img = Image.open(os.path.join(self.root, path)).convert('RGB')
if self.transform is not None:
img = self.transform(img)
if self.target_transform is not None:
target = self.target_transform(target)
return img, target
parser = argparse.ArgumentParser(description='PyTorch ImageNet Training')
parser.add_argument('data', metavar='DIR', help='path to dataset')
parser.add_argument('--model-name', default='tresnet_xl')
parser.add_argument('--num-classes', default=80)
parser.add_argument('-j', '--workers', default=16, type=int, metavar='N',
help='number of data loading workers (default: 16)')
parser.add_argument('--image-size', default=640, type=int,
metavar='N', help='input image size (default: 224)')
parser.add_argument('--thre', default=1.0, type=float,
metavar='N', help='threshold value')
parser.add_argument('-b', '--batch-size', default=16, type=int,
metavar='N', help='mini-batch size (default: 16)')
parser.add_argument('--print-freq', '-p', default=117, type=int,
metavar='N', help='print frequency (default: 117)')
def main():
global args
args = parser.parse_args()
args.batch_size = args.batch_size
# create model
# print("=> creating model '{}'".format(args.model_name))
# model = models.__dict__[args.model_name](num_classes=80)
# setup model
print('creating and loading the model...')
state = torch.load(args.model_path, map_location='cpu')
args.num_classes = state['num_classes']
model = create_model(args).cuda()
model.load_state_dict(state['model'], strict=True)
model.eval()
classes_list = np.array(list(state['idx_to_class'].values()))
print('done\n')
# count flops
model.eval()
# normal code
criterion = nn.BCEWithLogitsLoss().cuda()
cudnn.benchmark = True
# Data loading code
if 'tresnet' in args.model_name:
normalize = transforms.Normalize(mean=[0, 0, 0],
std=[1, 1, 1])
else:
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
# model = torch.nn.DataParallel(model).cuda()
model = model.cuda()
val_dataset = CocoDetection(os.path.join(args.data, 'val2014'),
os.path.join(args.data,
'annotations/instances_val2014.json'),
transforms.Compose([
transforms.Resize(
(args.image_size, args.image_size)),
transforms.ToTensor(),
normalize,
]))
print(len(val_dataset))
val_loader = torch.utils.data.DataLoader(
val_dataset, batch_size=args.batch_size, shuffle=False,
num_workers=args.workers, pin_memory=True)
validate_multi(val_loader, model, criterion)
def validate_multi(val_loader, model, criterion):
global args
batch_time = AverageMeter()
losses = AverageMeter()
prec = AverageMeter()
rec = AverageMeter()
# switch to evaluate mode
model.eval()
m = torch.nn.Sigmoid()
end = time.time()
tp, fp, fn, tn, count = 0, 0, 0, 0, 0
for i, (input, target) in enumerate(val_loader):
target = target.cuda(non_blocking=True)
target = target.max(dim=1)[0]
# compute output
with torch.no_grad():
output = model(input.cuda())
loss = criterion(output, target.float())
# measure accuracy and record loss
pred = output.data.gt(args.thre).long()
tp += (pred + target).eq(2).sum(dim=0)
fp += (pred - target).eq(1).sum(dim=0)
fn += (pred - target).eq(-1).sum(dim=0)
tn += (pred + target).eq(0).sum(dim=0)
count += input.size(0)
this_tp = (pred + target).eq(2).sum()
this_fp = (pred - target).eq(1).sum()
this_fn = (pred - target).eq(-1).sum()
this_tn = (pred + target).eq(0).sum()
this_prec = this_tp.float() / (
this_tp + this_fp).float() * 100.0 if this_tp + this_fp != 0 else 0.0
this_rec = this_tp.float() / (
this_tp + this_fn).float() * 100.0 if this_tp + this_fn != 0 else 0.0
losses.update(float(loss), input.size(0))
prec.update(float(this_prec), input.size(0))
rec.update(float(this_rec), input.size(0))
# measure elapsed time
batch_time.update(time.time() - end)
end = time.time()
p_c = [float(tp[i].float() / (tp[i] + fp[i]).float()) * 100.0 if tp[
i] > 0 else 0.0
for i in range(len(tp))]
r_c = [float(tp[i].float() / (tp[i] + fn[i]).float()) * 100.0 if tp[
i] > 0 else 0.0
for i in range(len(tp))]
f_c = [2 * p_c[i] * r_c[i] / (p_c[i] + r_c[i]) if tp[i] > 0 else 0.0 for
i in range(len(tp))]
mean_p_c = sum(p_c) / len(p_c)
mean_r_c = sum(r_c) / len(r_c)
mean_f_c = sum(f_c) / len(f_c)
p_o = tp.sum().float() / (tp + fp).sum().float() * 100.0
r_o = tp.sum().float() / (tp + fn).sum().float() * 100.0
f_o = 2 * p_o * r_o / (p_o + r_o)
np_target, np_output = target.detach().cpu().numpy(), \
m(output).detach().cpu().numpy()
if i % args.print_freq == 0:
print('Test: [{0}/{1}]\t'
'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
'Precision {prec.val:.2f} ({prec.avg:.2f})\t'
'Recall {rec.val:.2f} ({rec.avg:.2f})'.format(
i, len(val_loader), batch_time=batch_time, loss=losses,
prec=prec, rec=rec))
print(
'P_C {:.2f} R_C {:.2f} F_C {:.2f} P_O {:.2f} R_O {:.2f} F_O {:.2f}'
.format(mean_p_c, mean_r_c, mean_f_c, p_o, r_o, f_o))
print(
'--------------------------------------------------------------------')
print(' * P_C {:.2f} R_C {:.2f} F_C {:.2f} P_O {:.2f} R_O {:.2f} F_O {:.2f}'
.format(mean_p_c, mean_r_c, mean_f_c, p_o, r_o, f_o))
return
if __name__ == '__main__':
main()
Thanks @hellbell one bug that the code had is that the model's output did not undergo sigmoid squishing, before calculating the metrics.
anyway, i uploaded to here the updated validation code, and added mAP metrics. now you can see directly that the article results are reproduced (mAP score: 86.58929373407179)
i off-course also updated the model-zoo with pascal-VOC model
thanks for sharing the code
@mrT23 Great!
Hi, Could you upload the model pre-trained on Pascal VOC 2007? Thanks!