Module 8_pytorch_rfbnet.lib.train_detector
Expand source code
import sys
import os
import torch
import torch.nn as nn
import torch.optim as optim
import torch.backends.cudnn as cudnn
import torchvision.transforms as transforms
import torch.nn.init as init
import argparse
import numpy as np
from torch.autograd import Variable
import torch.utils.data as data
'''
from data import VOCroot, COCOroot, VOC_300, VOC_512, COCO_300, COCO_512, COCO_mobile_300, AnnotationTransform, COCODetection, VOCDetection, detection_collate, BaseTransform, preproc
from layers.modules import MultiBoxLoss
from layers.functions import PriorBox
import time
'''
class Detector():
'''
Class to train a detector
Args:
verbose (int): Set verbosity levels
0 - Print Nothing
1 - Print desired details
'''
def __init__(self, verbose=1):
self.system_dict = {};
self.system_dict["verbose"] = verbose;
self.system_dict["local"] = {};
self.system_dict["dataset"] = {};
self.system_dict["dataset"]["train"] = {};
self.system_dict["dataset"]["val"] = {};
self.system_dict["dataset"]["val"]["status"] = False;
self.system_dict["params"] = {};
self.system_dict["params"]["version"] = "RFB_vgg"; #RFB_E_vgg or RFB_mobile version
self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth";
self.system_dict["params"]["cuda"] = True;
self.system_dict["params"]["ngpu"] = 1;
self.system_dict["params"]["dataset"] = "COCO";
self.system_dict["params"]["num_workers"] = 3;
self.system_dict["params"]["size"] = 512; #300;
self.system_dict["params"]["batch_size"] = 4;
self.system_dict["params"]["jaccard_threshold"] = 0.5;
self.system_dict["params"]["lr"] = 0.0001;
self.system_dict["params"]["momentum"] = 0.9;
self.system_dict["params"]["weight_decay"] = 0.0005;
self.system_dict["params"]["gamma"] = 0.1;
self.system_dict["params"]["resume_epoch"] = 0
self.system_dict["params"]["resume_net"] = None;
self.system_dict["params"]["max_epoch"] = 200;
self.system_dict["params"]["log_iters"] = True;
self.system_dict["params"]["save_folder"] = "weights/";
def Train_Dataset(self, root_dir, coco_dir, set_dir, batch_size=4, image_size=512, num_workers=3):
'''
User function: Set training dataset parameters
Dataset Directory Structure
root_dir
|
|------coco_dir
| |
| |----<set_dir>
| |
| |---------img1.jpg
| |---------img2.jpg
| |---------..........(and so on)
|
|
| |---annotations
| |----|
| |--------------------instances_<set_dir>.json
| |--------------------classes.txt
- instances_<set_dir>.json -> In proper COCO format
- classes.txt -> A list of classes in alphabetical order
For TrainSet
- root_dir = "../sample_dataset";
- coco_dir = "kangaroo";
- set_dir = "Images";
Note: Annotation file name too coincides against the set_dir
Args:
root_dir (str): Path to root directory containing coco_dir
coco_dir (str): Name of coco_dir containing image folder and annotation folder
set_dir (str): Name of folder containing all training images
batch_size (int): Mini batch sampling size for training epochs
image_size (int): Either of [512, 300]
num_workers (int): Number of parallel processors for data loader
Returns:
None
'''
self.system_dict["dataset"]["train"]["root_dir"] = root_dir;
self.system_dict["dataset"]["train"]["coco_dir"] = coco_dir;
self.system_dict["dataset"]["train"]["set_dir"] = set_dir;
self.system_dict["params"]["batch_size"] = batch_size;
self.system_dict["params"]["size"] = image_size;
self.system_dict["params"]["num_workers"] = num_workers;
def Val_Dataset(self, root_dir, coco_dir, set_dir):
'''
User function: Set training dataset parameters
Dataset Directory Structure
root_dir
|
|------coco_dir
| |
| |----<set_dir>
| |
| |---------img1.jpg
| |---------img2.jpg
| |---------..........(and so on)
|
|
| |---annotations
| |----|
| |--------------------instances_<set_dir>.json
| |--------------------classes.txt
- instances_<set_dir>.json -> In proper COCO format
- classes.txt -> A list of classes in alphabetical order
For TrainSet
- root_dir = "../sample_dataset";
- coco_dir = "kangaroo";
- set_dir = "Images";
Note: Annotation file name too coincides against the set_dir
Args:
root_dir (str): Path to root directory containing coco_dir
coco_dir (str): Name of coco_dir containing image folder and annotation folder
set_dir (str): Name of folder containing all training images
Returns:
None
'''
self.system_dict["dataset"]["val"]["status"] = True;
self.system_dict["dataset"]["val"]["root_dir"] = root_dir;
self.system_dict["dataset"]["val"]["coco_dir"] = coco_dir;
self.system_dict["dataset"]["val"]["set_dir"] = set_dir;
def Model(self, model_name="vgg", use_gpu=True, ngpu=1):
'''
User function: Set Model parameters
Available Models
vgg
e_vgg
mobilenet
Args:
model_name (str): Select model from available models
use_gpu (bool): If True, model is loaded on GPU else cpu
ngpu (int): Number of GPUs to use in parallel
Returns:
None
'''
if(not os.path.isdir("weights/")):
cmd1 = "cp " + os.path.dirname(os.path.realpath(__file__)) + "/download.sh " + os.getcwd() + "/.";
os.system(cmd1);
os.system("chmod +x download.sh");
os.system("./download.sh");
if(model_name == "vgg"):
self.system_dict["params"]["version"] = "RFB_vgg";
self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth";
elif(model_name == "e_vgg"):
self.system_dict["params"]["version"] = "RFB_E_vgg";
self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth";
elif(model_name == "mobilenet"):
self.system_dict["params"]["basenet"] = "weights/mobilenet_feature.pth";
self.system_dict["params"]["version"] = "RFB_mobile";
self.system_dict["params"]["cuda"] = use_gpu;
self.system_dict["params"]["ngpu"] = ngpu;
def Set_HyperParams(self, lr=0.0001, momentum=0.9, weight_decay=0.0005, gamma=0.1, jaccard_threshold=0.5):
'''
User function: Set hyper parameters
Args:
lr (float): Initial learning rate for training
momentum (float): Momentum value for optimizer
weight_decay (float): Decay term for weights durng training for better regularization
gamma (float): Multiplicative factor for learning rate
jaccard_threshold (float): Limit nms thresholding
print_interval (int): Post every specified iteration the training losses and accuracies will be printed
Returns:
None
'''
self.system_dict["params"]["jaccard_threshold"] = jaccard_threshold;
self.system_dict["params"]["lr"] = lr;
self.system_dict["params"]["momentum"] = momentum;
self.system_dict["params"]["weight_decay"] = weight_decay;
self.system_dict["params"]["gamma"] = gamma;
def Train(self, epochs=200, log_iters=True, output_weights_dir="weights", saved_epoch_interval=10):
'''
User function: Start training
Args:
epochs (int): Number of epochs to train for
log_iters (bool): If True, logs will be saved
output_weights_dir (str): Folder path to save trained weights
saved_epoch_interval (int): Save intermediate weights aver every "saved_epoch_interval" number of epochs
Returns:
None
'''
self.system_dict["params"]["max_epoch"] = epochs;
self.system_dict["params"]["log_iters"] = log_iters;
self.system_dict["params"]["save_folder"] = output_weights_dir;
if not os.path.exists(self.system_dict["params"]["save_folder"]):
os.mkdir(self.system_dict["params"]["save_folder"])
if(self.system_dict["params"]["size"] == 300):
cfg = COCO_300;
else:
cfg = COCO_512;
if self.system_dict["params"]["version"] == 'RFB_vgg':
from models.RFB_Net_vgg import build_net
elif self.system_dict["params"]["version"] == 'RFB_E_vgg':
from models.RFB_Net_E_vgg import build_net
elif self.system_dict["params"]["version"] == 'RFB_mobile':
from models.RFB_Net_mobile import build_net
cfg = COCO_mobile_300
else:
print('Unkown version!')
img_dim = (300,512)[self.system_dict["params"]["size"]==512]
rgb_means = ((104, 117, 123),(103.94,116.78,123.68))[self.system_dict["params"]["version"] == 'RFB_mobile']
p = (0.6,0.2)[self.system_dict["params"]["version"] == 'RFB_mobile']
f = open(self.system_dict["dataset"]["train"]["root_dir"] + "/" +
self.system_dict["dataset"]["train"]["coco_dir"] + "/annotations/classes.txt", 'r');
lines = f.readlines();
if(lines[-1] == ""):
num_classes = len(lines) - 1;
else:
num_classes = len(lines) + 1;
batch_size = self.system_dict["params"]["batch_size"]
weight_decay = self.system_dict["params"]["weight_decay"]
gamma = self.system_dict["params"]["gamma"]
momentum = self.system_dict["params"]["momentum"]
self.system_dict["local"]["net"] = build_net('train', img_dim, num_classes)
if self.system_dict["params"]["resume_net"] == None:
base_weights = torch.load(self.system_dict["params"]["basenet"])
print('Loading base network...')
self.system_dict["local"]["net"].base.load_state_dict(base_weights)
def xavier(param):
init.xavier_uniform(param)
def weights_init(m):
for key in m.state_dict():
if key.split('.')[-1] == 'weight':
if 'conv' in key:
init.kaiming_normal_(m.state_dict()[key], mode='fan_out')
if 'bn' in key:
m.state_dict()[key][...] = 1
elif key.split('.')[-1] == 'bias':
m.state_dict()[key][...] = 0
print('Initializing weights...')
# initialize newly added layers' weights with kaiming_normal method
self.system_dict["local"]["net"].extras.apply(weights_init)
self.system_dict["local"]["net"].loc.apply(weights_init)
self.system_dict["local"]["net"].conf.apply(weights_init)
self.system_dict["local"]["net"].Norm.apply(weights_init)
if self.system_dict["params"]["version"] == 'RFB_E_vgg':
self.system_dict["local"]["net"].reduce.apply(weights_init)
self.system_dict["local"]["net"].up_reduce.apply(weights_init)
else:
# load resume network
print('Loading resume network...')
state_dict = torch.load(self.system_dict["params"]["resume_net"])
# create new OrderedDict that does not contain `module.`
from collections import OrderedDict
new_state_dict = OrderedDict()
for k, v in state_dict.items():
head = k[:7]
if head == 'module.':
name = k[7:] # remove `module.`
else:
name = k
new_state_dict[name] = v
self.system_dict["local"]["net"].load_state_dict(new_state_dict)
if self.system_dict["params"]["ngpu"] > 1:
self.system_dict["local"]["net"] = torch.nn.DataParallel(self.system_dict["local"]["net"], device_ids=list(range(self.system_dict["params"]["ngpu"])))
if self.system_dict["params"]["cuda"]:
self.system_dict["local"]["net"].cuda()
cudnn.benchmark = True
optimizer = optim.SGD(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"],
momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"])
#optimizer = optim.RMSprop(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"], alpha = 0.9, eps=1e-08,
# momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"])
criterion = MultiBoxLoss(num_classes, 0.5, True, 0, True, 3, 0.5, False)
priorbox = PriorBox(cfg)
with torch.no_grad():
priors = priorbox.forward()
if self.system_dict["params"]["cuda"]:
priors = priors.cuda()
self.system_dict["local"]["net"].train()
# loss counters
loc_loss = 0 # epoch
conf_loss = 0
epoch = 0 + self.system_dict["params"]["resume_epoch"]
print('Loading Dataset...')
if(os.path.isdir("coco_cache")):
os.system("rm -r coco_cache")
dataset = COCODetection(self.system_dict["dataset"]["train"]["root_dir"],
self.system_dict["dataset"]["train"]["coco_dir"],
self.system_dict["dataset"]["train"]["set_dir"],
preproc(img_dim, rgb_means, p))
epoch_size = len(dataset) // self.system_dict["params"]["batch_size"]
max_iter = self.system_dict["params"]["max_epoch"] * epoch_size
stepvalues = (90 * epoch_size, 120 * epoch_size, 140 * epoch_size)
print('Training', self.system_dict["params"]["version"], 'on', dataset.name)
step_index = 0
if self.system_dict["params"]["resume_epoch"] > 0:
start_iter = self.system_dict["params"]["resume_epoch"] * epoch_size
else:
start_iter = 0
lr = self.system_dict["params"]["lr"]
for iteration in range(start_iter, max_iter):
if iteration % epoch_size == 0:
# create batch iterator
batch_iterator = iter(data.DataLoader(dataset, batch_size,
shuffle=True, num_workers=self.system_dict["params"]["num_workers"],
collate_fn=detection_collate))
loc_loss = 0
conf_loss = 0
torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" + self.system_dict["params"]["version"]+'_'+
self.system_dict["params"]["dataset"] + '_epoches_'+
'intermediate' + '.pth')
epoch += 1
load_t0 = time.time()
if iteration in stepvalues:
step_index += 1
lr = self.adjust_learning_rate(optimizer, self.system_dict["params"]["gamma"], epoch, step_index, iteration, epoch_size)
# load train data
images, targets = next(batch_iterator)
#print(np.sum([torch.sum(anno[:,-1] == 2) for anno in targets]))
if self.system_dict["params"]["cuda"]:
images = Variable(images.cuda())
targets = [Variable(anno.cuda()) for anno in targets]
else:
images = Variable(images)
targets = [Variable(anno) for anno in targets]
# forward
t0 = time.time()
out = self.system_dict["local"]["net"](images)
# backprop
optimizer.zero_grad()
loss_l, loss_c = criterion(out, priors, targets)
loss = loss_l + loss_c
loss.backward()
optimizer.step()
t1 = time.time()
loc_loss += loss_l.item()
conf_loss += loss_c.item()
load_t1 = time.time()
if iteration % saved_epoch_interval == 0:
print('Epoch:' + repr(epoch) + ' || epochiter: ' + repr(iteration % epoch_size) + '/' + repr(epoch_size)
+ '|| Current iter ' +
repr(iteration) + '|| Total iter ' + repr(max_iter) +
' || L: %.4f C: %.4f||' % (
loss_l.item(),loss_c.item()) +
'Batch time: %.4f sec. ||' % (load_t1 - load_t0) + 'LR: %.8f' % (lr))
torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" +
'Final_' + self.system_dict["params"]["version"] +'_' + self.system_dict["params"]["dataset"] + '.pth')
def adjust_learning_rate(self, optimizer, gamma, epoch, step_index, iteration, epoch_size):
'''
Internal function: Adjust learning rates during training
Args:
optimizer (pytorch optimizer): Optimizer being used
gamma (float): Multiplicative factor for learning rate
epoch (int): Current epoch
step_index(int): Step index for scheduling learning rate
iteration (int): Current iteration
epoch_size (int): Total number of epochs
Returns:
None
'''
if epoch < 6:
lr = 1e-6 + (self.system_dict["params"]["lr"]-1e-6) * iteration / (epoch_size * 5)
else:
lr = self.system_dict["params"]["lr"] * (gamma ** (step_index))
for param_group in optimizer.param_groups:
param_group['lr'] = lr
return lr
Classes
class Detector (verbose=1)
-
Class to train a detector
Args
verbose
:int
- Set verbosity levels 0 - Print Nothing 1 - Print desired details
Expand source code
class Detector(): ''' Class to train a detector Args: verbose (int): Set verbosity levels 0 - Print Nothing 1 - Print desired details ''' def __init__(self, verbose=1): self.system_dict = {}; self.system_dict["verbose"] = verbose; self.system_dict["local"] = {}; self.system_dict["dataset"] = {}; self.system_dict["dataset"]["train"] = {}; self.system_dict["dataset"]["val"] = {}; self.system_dict["dataset"]["val"]["status"] = False; self.system_dict["params"] = {}; self.system_dict["params"]["version"] = "RFB_vgg"; #RFB_E_vgg or RFB_mobile version self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth"; self.system_dict["params"]["cuda"] = True; self.system_dict["params"]["ngpu"] = 1; self.system_dict["params"]["dataset"] = "COCO"; self.system_dict["params"]["num_workers"] = 3; self.system_dict["params"]["size"] = 512; #300; self.system_dict["params"]["batch_size"] = 4; self.system_dict["params"]["jaccard_threshold"] = 0.5; self.system_dict["params"]["lr"] = 0.0001; self.system_dict["params"]["momentum"] = 0.9; self.system_dict["params"]["weight_decay"] = 0.0005; self.system_dict["params"]["gamma"] = 0.1; self.system_dict["params"]["resume_epoch"] = 0 self.system_dict["params"]["resume_net"] = None; self.system_dict["params"]["max_epoch"] = 200; self.system_dict["params"]["log_iters"] = True; self.system_dict["params"]["save_folder"] = "weights/"; def Train_Dataset(self, root_dir, coco_dir, set_dir, batch_size=4, image_size=512, num_workers=3): ''' User function: Set training dataset parameters Dataset Directory Structure root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir Args: root_dir (str): Path to root directory containing coco_dir coco_dir (str): Name of coco_dir containing image folder and annotation folder set_dir (str): Name of folder containing all training images batch_size (int): Mini batch sampling size for training epochs image_size (int): Either of [512, 300] num_workers (int): Number of parallel processors for data loader Returns: None ''' self.system_dict["dataset"]["train"]["root_dir"] = root_dir; self.system_dict["dataset"]["train"]["coco_dir"] = coco_dir; self.system_dict["dataset"]["train"]["set_dir"] = set_dir; self.system_dict["params"]["batch_size"] = batch_size; self.system_dict["params"]["size"] = image_size; self.system_dict["params"]["num_workers"] = num_workers; def Val_Dataset(self, root_dir, coco_dir, set_dir): ''' User function: Set training dataset parameters Dataset Directory Structure root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir Args: root_dir (str): Path to root directory containing coco_dir coco_dir (str): Name of coco_dir containing image folder and annotation folder set_dir (str): Name of folder containing all training images Returns: None ''' self.system_dict["dataset"]["val"]["status"] = True; self.system_dict["dataset"]["val"]["root_dir"] = root_dir; self.system_dict["dataset"]["val"]["coco_dir"] = coco_dir; self.system_dict["dataset"]["val"]["set_dir"] = set_dir; def Model(self, model_name="vgg", use_gpu=True, ngpu=1): ''' User function: Set Model parameters Available Models vgg e_vgg mobilenet Args: model_name (str): Select model from available models use_gpu (bool): If True, model is loaded on GPU else cpu ngpu (int): Number of GPUs to use in parallel Returns: None ''' if(not os.path.isdir("weights/")): cmd1 = "cp " + os.path.dirname(os.path.realpath(__file__)) + "/download.sh " + os.getcwd() + "/."; os.system(cmd1); os.system("chmod +x download.sh"); os.system("./download.sh"); if(model_name == "vgg"): self.system_dict["params"]["version"] = "RFB_vgg"; self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth"; elif(model_name == "e_vgg"): self.system_dict["params"]["version"] = "RFB_E_vgg"; self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth"; elif(model_name == "mobilenet"): self.system_dict["params"]["basenet"] = "weights/mobilenet_feature.pth"; self.system_dict["params"]["version"] = "RFB_mobile"; self.system_dict["params"]["cuda"] = use_gpu; self.system_dict["params"]["ngpu"] = ngpu; def Set_HyperParams(self, lr=0.0001, momentum=0.9, weight_decay=0.0005, gamma=0.1, jaccard_threshold=0.5): ''' User function: Set hyper parameters Args: lr (float): Initial learning rate for training momentum (float): Momentum value for optimizer weight_decay (float): Decay term for weights durng training for better regularization gamma (float): Multiplicative factor for learning rate jaccard_threshold (float): Limit nms thresholding print_interval (int): Post every specified iteration the training losses and accuracies will be printed Returns: None ''' self.system_dict["params"]["jaccard_threshold"] = jaccard_threshold; self.system_dict["params"]["lr"] = lr; self.system_dict["params"]["momentum"] = momentum; self.system_dict["params"]["weight_decay"] = weight_decay; self.system_dict["params"]["gamma"] = gamma; def Train(self, epochs=200, log_iters=True, output_weights_dir="weights", saved_epoch_interval=10): ''' User function: Start training Args: epochs (int): Number of epochs to train for log_iters (bool): If True, logs will be saved output_weights_dir (str): Folder path to save trained weights saved_epoch_interval (int): Save intermediate weights aver every "saved_epoch_interval" number of epochs Returns: None ''' self.system_dict["params"]["max_epoch"] = epochs; self.system_dict["params"]["log_iters"] = log_iters; self.system_dict["params"]["save_folder"] = output_weights_dir; if not os.path.exists(self.system_dict["params"]["save_folder"]): os.mkdir(self.system_dict["params"]["save_folder"]) if(self.system_dict["params"]["size"] == 300): cfg = COCO_300; else: cfg = COCO_512; if self.system_dict["params"]["version"] == 'RFB_vgg': from models.RFB_Net_vgg import build_net elif self.system_dict["params"]["version"] == 'RFB_E_vgg': from models.RFB_Net_E_vgg import build_net elif self.system_dict["params"]["version"] == 'RFB_mobile': from models.RFB_Net_mobile import build_net cfg = COCO_mobile_300 else: print('Unkown version!') img_dim = (300,512)[self.system_dict["params"]["size"]==512] rgb_means = ((104, 117, 123),(103.94,116.78,123.68))[self.system_dict["params"]["version"] == 'RFB_mobile'] p = (0.6,0.2)[self.system_dict["params"]["version"] == 'RFB_mobile'] f = open(self.system_dict["dataset"]["train"]["root_dir"] + "/" + self.system_dict["dataset"]["train"]["coco_dir"] + "/annotations/classes.txt", 'r'); lines = f.readlines(); if(lines[-1] == ""): num_classes = len(lines) - 1; else: num_classes = len(lines) + 1; batch_size = self.system_dict["params"]["batch_size"] weight_decay = self.system_dict["params"]["weight_decay"] gamma = self.system_dict["params"]["gamma"] momentum = self.system_dict["params"]["momentum"] self.system_dict["local"]["net"] = build_net('train', img_dim, num_classes) if self.system_dict["params"]["resume_net"] == None: base_weights = torch.load(self.system_dict["params"]["basenet"]) print('Loading base network...') self.system_dict["local"]["net"].base.load_state_dict(base_weights) def xavier(param): init.xavier_uniform(param) def weights_init(m): for key in m.state_dict(): if key.split('.')[-1] == 'weight': if 'conv' in key: init.kaiming_normal_(m.state_dict()[key], mode='fan_out') if 'bn' in key: m.state_dict()[key][...] = 1 elif key.split('.')[-1] == 'bias': m.state_dict()[key][...] = 0 print('Initializing weights...') # initialize newly added layers' weights with kaiming_normal method self.system_dict["local"]["net"].extras.apply(weights_init) self.system_dict["local"]["net"].loc.apply(weights_init) self.system_dict["local"]["net"].conf.apply(weights_init) self.system_dict["local"]["net"].Norm.apply(weights_init) if self.system_dict["params"]["version"] == 'RFB_E_vgg': self.system_dict["local"]["net"].reduce.apply(weights_init) self.system_dict["local"]["net"].up_reduce.apply(weights_init) else: # load resume network print('Loading resume network...') state_dict = torch.load(self.system_dict["params"]["resume_net"]) # create new OrderedDict that does not contain `module.` from collections import OrderedDict new_state_dict = OrderedDict() for k, v in state_dict.items(): head = k[:7] if head == 'module.': name = k[7:] # remove `module.` else: name = k new_state_dict[name] = v self.system_dict["local"]["net"].load_state_dict(new_state_dict) if self.system_dict["params"]["ngpu"] > 1: self.system_dict["local"]["net"] = torch.nn.DataParallel(self.system_dict["local"]["net"], device_ids=list(range(self.system_dict["params"]["ngpu"]))) if self.system_dict["params"]["cuda"]: self.system_dict["local"]["net"].cuda() cudnn.benchmark = True optimizer = optim.SGD(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"], momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"]) #optimizer = optim.RMSprop(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"], alpha = 0.9, eps=1e-08, # momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"]) criterion = MultiBoxLoss(num_classes, 0.5, True, 0, True, 3, 0.5, False) priorbox = PriorBox(cfg) with torch.no_grad(): priors = priorbox.forward() if self.system_dict["params"]["cuda"]: priors = priors.cuda() self.system_dict["local"]["net"].train() # loss counters loc_loss = 0 # epoch conf_loss = 0 epoch = 0 + self.system_dict["params"]["resume_epoch"] print('Loading Dataset...') if(os.path.isdir("coco_cache")): os.system("rm -r coco_cache") dataset = COCODetection(self.system_dict["dataset"]["train"]["root_dir"], self.system_dict["dataset"]["train"]["coco_dir"], self.system_dict["dataset"]["train"]["set_dir"], preproc(img_dim, rgb_means, p)) epoch_size = len(dataset) // self.system_dict["params"]["batch_size"] max_iter = self.system_dict["params"]["max_epoch"] * epoch_size stepvalues = (90 * epoch_size, 120 * epoch_size, 140 * epoch_size) print('Training', self.system_dict["params"]["version"], 'on', dataset.name) step_index = 0 if self.system_dict["params"]["resume_epoch"] > 0: start_iter = self.system_dict["params"]["resume_epoch"] * epoch_size else: start_iter = 0 lr = self.system_dict["params"]["lr"] for iteration in range(start_iter, max_iter): if iteration % epoch_size == 0: # create batch iterator batch_iterator = iter(data.DataLoader(dataset, batch_size, shuffle=True, num_workers=self.system_dict["params"]["num_workers"], collate_fn=detection_collate)) loc_loss = 0 conf_loss = 0 torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" + self.system_dict["params"]["version"]+'_'+ self.system_dict["params"]["dataset"] + '_epoches_'+ 'intermediate' + '.pth') epoch += 1 load_t0 = time.time() if iteration in stepvalues: step_index += 1 lr = self.adjust_learning_rate(optimizer, self.system_dict["params"]["gamma"], epoch, step_index, iteration, epoch_size) # load train data images, targets = next(batch_iterator) #print(np.sum([torch.sum(anno[:,-1] == 2) for anno in targets])) if self.system_dict["params"]["cuda"]: images = Variable(images.cuda()) targets = [Variable(anno.cuda()) for anno in targets] else: images = Variable(images) targets = [Variable(anno) for anno in targets] # forward t0 = time.time() out = self.system_dict["local"]["net"](images) # backprop optimizer.zero_grad() loss_l, loss_c = criterion(out, priors, targets) loss = loss_l + loss_c loss.backward() optimizer.step() t1 = time.time() loc_loss += loss_l.item() conf_loss += loss_c.item() load_t1 = time.time() if iteration % saved_epoch_interval == 0: print('Epoch:' + repr(epoch) + ' || epochiter: ' + repr(iteration % epoch_size) + '/' + repr(epoch_size) + '|| Current iter ' + repr(iteration) + '|| Total iter ' + repr(max_iter) + ' || L: %.4f C: %.4f||' % ( loss_l.item(),loss_c.item()) + 'Batch time: %.4f sec. ||' % (load_t1 - load_t0) + 'LR: %.8f' % (lr)) torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" + 'Final_' + self.system_dict["params"]["version"] +'_' + self.system_dict["params"]["dataset"] + '.pth') def adjust_learning_rate(self, optimizer, gamma, epoch, step_index, iteration, epoch_size): ''' Internal function: Adjust learning rates during training Args: optimizer (pytorch optimizer): Optimizer being used gamma (float): Multiplicative factor for learning rate epoch (int): Current epoch step_index(int): Step index for scheduling learning rate iteration (int): Current iteration epoch_size (int): Total number of epochs Returns: None ''' if epoch < 6: lr = 1e-6 + (self.system_dict["params"]["lr"]-1e-6) * iteration / (epoch_size * 5) else: lr = self.system_dict["params"]["lr"] * (gamma ** (step_index)) for param_group in optimizer.param_groups: param_group['lr'] = lr return lr
Methods
def Model(self, model_name='vgg', use_gpu=True, ngpu=1)
-
User function: Set Model parameters
Available Models vgg e_vgg mobilenet
Args
model_name
:str
- Select model from available models
use_gpu
:bool
- If True, model is loaded on GPU else cpu
ngpu
:int
- Number of GPUs to use in parallel
Returns
None
Expand source code
def Model(self, model_name="vgg", use_gpu=True, ngpu=1): ''' User function: Set Model parameters Available Models vgg e_vgg mobilenet Args: model_name (str): Select model from available models use_gpu (bool): If True, model is loaded on GPU else cpu ngpu (int): Number of GPUs to use in parallel Returns: None ''' if(not os.path.isdir("weights/")): cmd1 = "cp " + os.path.dirname(os.path.realpath(__file__)) + "/download.sh " + os.getcwd() + "/."; os.system(cmd1); os.system("chmod +x download.sh"); os.system("./download.sh"); if(model_name == "vgg"): self.system_dict["params"]["version"] = "RFB_vgg"; self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth"; elif(model_name == "e_vgg"): self.system_dict["params"]["version"] = "RFB_E_vgg"; self.system_dict["params"]["basenet"] = "weights/vgg16_reducedfc.pth"; elif(model_name == "mobilenet"): self.system_dict["params"]["basenet"] = "weights/mobilenet_feature.pth"; self.system_dict["params"]["version"] = "RFB_mobile"; self.system_dict["params"]["cuda"] = use_gpu; self.system_dict["params"]["ngpu"] = ngpu;
def Set_HyperParams(self, lr=0.0001, momentum=0.9, weight_decay=0.0005, gamma=0.1, jaccard_threshold=0.5)
-
User function: Set hyper parameters
Args
lr
:float
- Initial learning rate for training
momentum
:float
- Momentum value for optimizer
weight_decay
:float
- Decay term for weights durng training for better regularization
gamma
:float
- Multiplicative factor for learning rate
jaccard_threshold
:float
- Limit nms thresholding
print_interval
:int
- Post every specified iteration the training losses and accuracies will be printed
Returns
None
Expand source code
def Set_HyperParams(self, lr=0.0001, momentum=0.9, weight_decay=0.0005, gamma=0.1, jaccard_threshold=0.5): ''' User function: Set hyper parameters Args: lr (float): Initial learning rate for training momentum (float): Momentum value for optimizer weight_decay (float): Decay term for weights durng training for better regularization gamma (float): Multiplicative factor for learning rate jaccard_threshold (float): Limit nms thresholding print_interval (int): Post every specified iteration the training losses and accuracies will be printed Returns: None ''' self.system_dict["params"]["jaccard_threshold"] = jaccard_threshold; self.system_dict["params"]["lr"] = lr; self.system_dict["params"]["momentum"] = momentum; self.system_dict["params"]["weight_decay"] = weight_decay; self.system_dict["params"]["gamma"] = gamma;
def Train(self, epochs=200, log_iters=True, output_weights_dir='weights', saved_epoch_interval=10)
-
User function: Start training
Args
epochs
:int
- Number of epochs to train for
log_iters
:bool
- If True, logs will be saved
output_weights_dir
:str
- Folder path to save trained weights
saved_epoch_interval
:int
- Save intermediate weights aver every "saved_epoch_interval" number of epochs
Returns
None
Expand source code
def Train(self, epochs=200, log_iters=True, output_weights_dir="weights", saved_epoch_interval=10): ''' User function: Start training Args: epochs (int): Number of epochs to train for log_iters (bool): If True, logs will be saved output_weights_dir (str): Folder path to save trained weights saved_epoch_interval (int): Save intermediate weights aver every "saved_epoch_interval" number of epochs Returns: None ''' self.system_dict["params"]["max_epoch"] = epochs; self.system_dict["params"]["log_iters"] = log_iters; self.system_dict["params"]["save_folder"] = output_weights_dir; if not os.path.exists(self.system_dict["params"]["save_folder"]): os.mkdir(self.system_dict["params"]["save_folder"]) if(self.system_dict["params"]["size"] == 300): cfg = COCO_300; else: cfg = COCO_512; if self.system_dict["params"]["version"] == 'RFB_vgg': from models.RFB_Net_vgg import build_net elif self.system_dict["params"]["version"] == 'RFB_E_vgg': from models.RFB_Net_E_vgg import build_net elif self.system_dict["params"]["version"] == 'RFB_mobile': from models.RFB_Net_mobile import build_net cfg = COCO_mobile_300 else: print('Unkown version!') img_dim = (300,512)[self.system_dict["params"]["size"]==512] rgb_means = ((104, 117, 123),(103.94,116.78,123.68))[self.system_dict["params"]["version"] == 'RFB_mobile'] p = (0.6,0.2)[self.system_dict["params"]["version"] == 'RFB_mobile'] f = open(self.system_dict["dataset"]["train"]["root_dir"] + "/" + self.system_dict["dataset"]["train"]["coco_dir"] + "/annotations/classes.txt", 'r'); lines = f.readlines(); if(lines[-1] == ""): num_classes = len(lines) - 1; else: num_classes = len(lines) + 1; batch_size = self.system_dict["params"]["batch_size"] weight_decay = self.system_dict["params"]["weight_decay"] gamma = self.system_dict["params"]["gamma"] momentum = self.system_dict["params"]["momentum"] self.system_dict["local"]["net"] = build_net('train', img_dim, num_classes) if self.system_dict["params"]["resume_net"] == None: base_weights = torch.load(self.system_dict["params"]["basenet"]) print('Loading base network...') self.system_dict["local"]["net"].base.load_state_dict(base_weights) def xavier(param): init.xavier_uniform(param) def weights_init(m): for key in m.state_dict(): if key.split('.')[-1] == 'weight': if 'conv' in key: init.kaiming_normal_(m.state_dict()[key], mode='fan_out') if 'bn' in key: m.state_dict()[key][...] = 1 elif key.split('.')[-1] == 'bias': m.state_dict()[key][...] = 0 print('Initializing weights...') # initialize newly added layers' weights with kaiming_normal method self.system_dict["local"]["net"].extras.apply(weights_init) self.system_dict["local"]["net"].loc.apply(weights_init) self.system_dict["local"]["net"].conf.apply(weights_init) self.system_dict["local"]["net"].Norm.apply(weights_init) if self.system_dict["params"]["version"] == 'RFB_E_vgg': self.system_dict["local"]["net"].reduce.apply(weights_init) self.system_dict["local"]["net"].up_reduce.apply(weights_init) else: # load resume network print('Loading resume network...') state_dict = torch.load(self.system_dict["params"]["resume_net"]) # create new OrderedDict that does not contain `module.` from collections import OrderedDict new_state_dict = OrderedDict() for k, v in state_dict.items(): head = k[:7] if head == 'module.': name = k[7:] # remove `module.` else: name = k new_state_dict[name] = v self.system_dict["local"]["net"].load_state_dict(new_state_dict) if self.system_dict["params"]["ngpu"] > 1: self.system_dict["local"]["net"] = torch.nn.DataParallel(self.system_dict["local"]["net"], device_ids=list(range(self.system_dict["params"]["ngpu"]))) if self.system_dict["params"]["cuda"]: self.system_dict["local"]["net"].cuda() cudnn.benchmark = True optimizer = optim.SGD(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"], momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"]) #optimizer = optim.RMSprop(self.system_dict["local"]["net"].parameters(), lr=self.system_dict["params"]["lr"], alpha = 0.9, eps=1e-08, # momentum=self.system_dict["params"]["momentum"], weight_decay=self.system_dict["params"]["weight_decay"]) criterion = MultiBoxLoss(num_classes, 0.5, True, 0, True, 3, 0.5, False) priorbox = PriorBox(cfg) with torch.no_grad(): priors = priorbox.forward() if self.system_dict["params"]["cuda"]: priors = priors.cuda() self.system_dict["local"]["net"].train() # loss counters loc_loss = 0 # epoch conf_loss = 0 epoch = 0 + self.system_dict["params"]["resume_epoch"] print('Loading Dataset...') if(os.path.isdir("coco_cache")): os.system("rm -r coco_cache") dataset = COCODetection(self.system_dict["dataset"]["train"]["root_dir"], self.system_dict["dataset"]["train"]["coco_dir"], self.system_dict["dataset"]["train"]["set_dir"], preproc(img_dim, rgb_means, p)) epoch_size = len(dataset) // self.system_dict["params"]["batch_size"] max_iter = self.system_dict["params"]["max_epoch"] * epoch_size stepvalues = (90 * epoch_size, 120 * epoch_size, 140 * epoch_size) print('Training', self.system_dict["params"]["version"], 'on', dataset.name) step_index = 0 if self.system_dict["params"]["resume_epoch"] > 0: start_iter = self.system_dict["params"]["resume_epoch"] * epoch_size else: start_iter = 0 lr = self.system_dict["params"]["lr"] for iteration in range(start_iter, max_iter): if iteration % epoch_size == 0: # create batch iterator batch_iterator = iter(data.DataLoader(dataset, batch_size, shuffle=True, num_workers=self.system_dict["params"]["num_workers"], collate_fn=detection_collate)) loc_loss = 0 conf_loss = 0 torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" + self.system_dict["params"]["version"]+'_'+ self.system_dict["params"]["dataset"] + '_epoches_'+ 'intermediate' + '.pth') epoch += 1 load_t0 = time.time() if iteration in stepvalues: step_index += 1 lr = self.adjust_learning_rate(optimizer, self.system_dict["params"]["gamma"], epoch, step_index, iteration, epoch_size) # load train data images, targets = next(batch_iterator) #print(np.sum([torch.sum(anno[:,-1] == 2) for anno in targets])) if self.system_dict["params"]["cuda"]: images = Variable(images.cuda()) targets = [Variable(anno.cuda()) for anno in targets] else: images = Variable(images) targets = [Variable(anno) for anno in targets] # forward t0 = time.time() out = self.system_dict["local"]["net"](images) # backprop optimizer.zero_grad() loss_l, loss_c = criterion(out, priors, targets) loss = loss_l + loss_c loss.backward() optimizer.step() t1 = time.time() loc_loss += loss_l.item() conf_loss += loss_c.item() load_t1 = time.time() if iteration % saved_epoch_interval == 0: print('Epoch:' + repr(epoch) + ' || epochiter: ' + repr(iteration % epoch_size) + '/' + repr(epoch_size) + '|| Current iter ' + repr(iteration) + '|| Total iter ' + repr(max_iter) + ' || L: %.4f C: %.4f||' % ( loss_l.item(),loss_c.item()) + 'Batch time: %.4f sec. ||' % (load_t1 - load_t0) + 'LR: %.8f' % (lr)) torch.save(self.system_dict["local"]["net"].state_dict(), self.system_dict["params"]["save_folder"] + "/" + 'Final_' + self.system_dict["params"]["version"] +'_' + self.system_dict["params"]["dataset"] + '.pth')
def Train_Dataset(self, root_dir, coco_dir, set_dir, batch_size=4, image_size=512, num_workers=3)
-
User function: Set training dataset parameters
Dataset Directory Structure
root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir
Args
root_dir
:str
- Path to root directory containing coco_dir
coco_dir
:str
- Name of coco_dir containing image folder and annotation folder
set_dir
:str
- Name of folder containing all training images
batch_size
:int
- Mini batch sampling size for training epochs
image_size
:int
- Either of [512, 300]
num_workers
:int
- Number of parallel processors for data loader
Returns
None
Expand source code
def Train_Dataset(self, root_dir, coco_dir, set_dir, batch_size=4, image_size=512, num_workers=3): ''' User function: Set training dataset parameters Dataset Directory Structure root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir Args: root_dir (str): Path to root directory containing coco_dir coco_dir (str): Name of coco_dir containing image folder and annotation folder set_dir (str): Name of folder containing all training images batch_size (int): Mini batch sampling size for training epochs image_size (int): Either of [512, 300] num_workers (int): Number of parallel processors for data loader Returns: None ''' self.system_dict["dataset"]["train"]["root_dir"] = root_dir; self.system_dict["dataset"]["train"]["coco_dir"] = coco_dir; self.system_dict["dataset"]["train"]["set_dir"] = set_dir; self.system_dict["params"]["batch_size"] = batch_size; self.system_dict["params"]["size"] = image_size; self.system_dict["params"]["num_workers"] = num_workers;
def Val_Dataset(self, root_dir, coco_dir, set_dir)
-
User function: Set training dataset parameters
Dataset Directory Structure
root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir
Args
root_dir
:str
- Path to root directory containing coco_dir
coco_dir
:str
- Name of coco_dir containing image folder and annotation folder
set_dir
:str
- Name of folder containing all training images
Returns
None
Expand source code
def Val_Dataset(self, root_dir, coco_dir, set_dir): ''' User function: Set training dataset parameters Dataset Directory Structure root_dir | |------coco_dir | | | |----<set_dir> | | | |---------img1.jpg | |---------img2.jpg | |---------..........(and so on) | | | |---annotations | |----| | |--------------------instances_<set_dir>.json | |--------------------classes.txt - instances_<set_dir>.json -> In proper COCO format - classes.txt -> A list of classes in alphabetical order For TrainSet - root_dir = "../sample_dataset"; - coco_dir = "kangaroo"; - set_dir = "Images"; Note: Annotation file name too coincides against the set_dir Args: root_dir (str): Path to root directory containing coco_dir coco_dir (str): Name of coco_dir containing image folder and annotation folder set_dir (str): Name of folder containing all training images Returns: None ''' self.system_dict["dataset"]["val"]["status"] = True; self.system_dict["dataset"]["val"]["root_dir"] = root_dir; self.system_dict["dataset"]["val"]["coco_dir"] = coco_dir; self.system_dict["dataset"]["val"]["set_dir"] = set_dir;
def adjust_learning_rate(self, optimizer, gamma, epoch, step_index, iteration, epoch_size)
-
Internal function: Adjust learning rates during training
Args
optimizer
:pytorch optimizer
- Optimizer being used
gamma
:float
- Multiplicative factor for learning rate
epoch
:int
- Current epoch
- step_index(int): Step index for scheduling learning rate
iteration
:int
- Current iteration
epoch_size
:int
- Total number of epochs
Returns
None
Expand source code
def adjust_learning_rate(self, optimizer, gamma, epoch, step_index, iteration, epoch_size): ''' Internal function: Adjust learning rates during training Args: optimizer (pytorch optimizer): Optimizer being used gamma (float): Multiplicative factor for learning rate epoch (int): Current epoch step_index(int): Step index for scheduling learning rate iteration (int): Current iteration epoch_size (int): Total number of epochs Returns: None ''' if epoch < 6: lr = 1e-6 + (self.system_dict["params"]["lr"]-1e-6) * iteration / (epoch_size * 5) else: lr = self.system_dict["params"]["lr"] * (gamma ** (step_index)) for param_group in optimizer.param_groups: param_group['lr'] = lr return lr