what.models.detection.ssd.mobilenet_v1_ssd
1import os 2import itertools 3 4import torch 5from torch.optim.lr_scheduler import CosineAnnealingLR 6 7import what.utils.logger as log 8 9from .ssd.mobilenet_v1_ssd_create import create_mobilenet_v1_ssd, create_mobilenet_v1_ssd_predictor 10from .ssd.multibox_loss import MultiboxLoss 11from .ssd import mobilenet_ssd_config 12 13from .utils.misc import freeze_net_layers 14 15logger = log.get_logger(__name__) 16 17class MobileNetV1SSD: 18 def __init__(self, model_path, class_names, is_test=False, device=None): 19 20 self.class_names = class_names 21 22 self.net = create_mobilenet_v1_ssd(len(self.class_names), is_test=is_test) 23 24 self.predictor = None; 25 self.device = device; 26 27 self.net.load(model_path) 28 29 def predict(self, image, top_k=-1, prob_threshold=None): 30 if self.predictor is None: 31 self.predictor = create_mobilenet_v1_ssd_predictor(self.net, device=self.device, candidate_size=200) 32 33 return self.predictor.predict(image, top_k, prob_threshold) 34 35 def step(self, loader, criterion, optimizer, device, debug_steps=100, epoch=-1): 36 self.net.train(True) 37 running_loss = 0.0 38 running_regression_loss = 0.0 39 running_classification_loss = 0.0 40 for i, data in enumerate(loader): 41 images, boxes, labels = data 42 images = images.to(device) 43 boxes = boxes.to(device) 44 labels = labels.to(device) 45 46 optimizer.zero_grad() 47 confidence, locations = self.net(images) 48 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) # TODO CHANGE BOXES 49 loss = regression_loss + classification_loss 50 loss.backward() 51 optimizer.step() 52 53 running_loss += loss.item() 54 running_regression_loss += regression_loss.item() 55 running_classification_loss += classification_loss.item() 56 if i and i % debug_steps == 0: 57 avg_loss = running_loss / debug_steps 58 avg_reg_loss = running_regression_loss / debug_steps 59 avg_clf_loss = running_classification_loss / debug_steps 60 logger.info( 61 f"Epoch: {epoch}, Step: {i}, " + 62 f"Average Loss: {avg_loss:.4f}, " + 63 f"Average Regression Loss {avg_reg_loss:.4f}, " + 64 f"Average Classification Loss: {avg_clf_loss:.4f}" 65 ) 66 running_loss = 0.0 67 running_regression_loss = 0.0 68 running_classification_loss = 0.0 69 70 def train(self, train_loader, val_loader, device = "cpu", 71 scheduler = None, criterion = None, optimizer = None, 72 lr = 1e-3, base_net_lr = 1e-3, extra_layers_lr = 1e-3, num_epochs = 100, momentum = 0.9, weight_decay = 5e-4, 73 debug_steps = 100, validation_epochs = 5, 74 freeze_base_net = False, freeze_net = False, 75 resume = None, base_net = None, pretrained_ssd = None, 76 checkpoint_folder = "models/"): 77 78 if freeze_base_net: 79 logger.info("Freeze base net.") 80 81 freeze_net_layers(self.net.base_net) 82 params = itertools.chain(self.net.source_layer_add_ons.parameters(), self.net.extras.parameters(), 83 self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 84 params = [ 85 {'params': itertools.chain( 86 self.net.source_layer_add_ons.parameters(), 87 self.net.extras.parameters() 88 ), 'lr': extra_layers_lr}, 89 {'params': itertools.chain( 90 self.net.regression_headers.parameters(), 91 self.net.classification_headers.parameters() 92 )} 93 ] 94 elif freeze_net: 95 freeze_net_layers(self.net.base_net) 96 freeze_net_layers(self.net.source_layer_add_ons) 97 freeze_net_layers(self.net.extras) 98 params = itertools.chain(self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 99 logger.info("Freeze all the layers except prediction heads.") 100 else: 101 params = [ 102 {'params': self.net.base_net.parameters(), 'lr': base_net_lr}, 103 {'params': itertools.chain( 104 self.net.source_layer_add_ons.parameters(), 105 self.net.extras.parameters() 106 ), 'lr': extra_layers_lr}, 107 {'params': itertools.chain( 108 self.net.regression_headers.parameters(), 109 self.net.classification_headers.parameters() 110 )} 111 ] 112 113 if resume: 114 logger.info(f"Resume from the model {resume}") 115 self.net.load(resume) 116 elif base_net: 117 logger.info(f"Init from base net {base_net}") 118 self.net.init_from_base_net(base_net) 119 elif pretrained_ssd: 120 logger.info(f"Init from pretrained ssd {pretrained_ssd}") 121 self.net.init_from_pretrained_ssd(pretrained_ssd) 122 123 self.net.to(device) 124 125 if criterion is None: 126 criterion = MultiboxLoss(mobilenet_ssd_config.priors, iou_threshold=0.5, neg_pos_ratio=3, 127 center_variance=0.1, size_variance=0.2, device=device) 128 if optimizer is None: 129 optimizer = torch.optim.SGD(params, lr=lr, momentum=momentum, 130 weight_decay=weight_decay) 131 if scheduler is None: 132 scheduler = CosineAnnealingLR(optimizer, 120) 133 134 logger.info("Start training using CosineAnnealingLR scheduler.") 135 136 for epoch in range(0, num_epochs): 137 self.step(train_loader, criterion, optimizer, epoch=epoch, 138 device=device, debug_steps=debug_steps) 139 140 scheduler.step() 141 142 if (epoch % validation_epochs == 0) or (epoch == num_epochs - 1): 143 val_loss, val_regression_loss, val_classification_loss = self.eval(val_loader, criterion, device) 144 logger.info( 145 f"Epoch: {epoch}, " + 146 f"Validation Loss: {val_loss:.4f}, " + 147 f"Validation Regression Loss {val_regression_loss:.4f}, " + 148 f"Validation Classification Loss: {val_classification_loss:.4f}" 149 ) 150 model_path = os.path.join(checkpoint_folder, f"mobilenet-v1-ssd-Epoch-{epoch}-Loss-{val_loss}.pth") 151 self.net.save(model_path) 152 153 logger.info(f"Saved model {model_path}") 154 155 def eval(self, loader, criterion, device): 156 self.net.eval() 157 running_loss = 0.0 158 running_regression_loss = 0.0 159 running_classification_loss = 0.0 160 num = 0 161 for _, data in enumerate(loader): 162 images, boxes, labels = data 163 images = images.to(device) 164 boxes = boxes.to(device) 165 labels = labels.to(device) 166 num += 1 167 168 with torch.no_grad(): 169 confidence, locations = self.net(images) 170 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) 171 loss = regression_loss + classification_loss 172 173 running_loss += loss.item() 174 running_regression_loss += regression_loss.item() 175 running_classification_loss += classification_loss.item() 176 return running_loss / num, running_regression_loss / num, running_classification_loss / num
class
MobileNetV1SSD:
18class MobileNetV1SSD: 19 def __init__(self, model_path, class_names, is_test=False, device=None): 20 21 self.class_names = class_names 22 23 self.net = create_mobilenet_v1_ssd(len(self.class_names), is_test=is_test) 24 25 self.predictor = None; 26 self.device = device; 27 28 self.net.load(model_path) 29 30 def predict(self, image, top_k=-1, prob_threshold=None): 31 if self.predictor is None: 32 self.predictor = create_mobilenet_v1_ssd_predictor(self.net, device=self.device, candidate_size=200) 33 34 return self.predictor.predict(image, top_k, prob_threshold) 35 36 def step(self, loader, criterion, optimizer, device, debug_steps=100, epoch=-1): 37 self.net.train(True) 38 running_loss = 0.0 39 running_regression_loss = 0.0 40 running_classification_loss = 0.0 41 for i, data in enumerate(loader): 42 images, boxes, labels = data 43 images = images.to(device) 44 boxes = boxes.to(device) 45 labels = labels.to(device) 46 47 optimizer.zero_grad() 48 confidence, locations = self.net(images) 49 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) # TODO CHANGE BOXES 50 loss = regression_loss + classification_loss 51 loss.backward() 52 optimizer.step() 53 54 running_loss += loss.item() 55 running_regression_loss += regression_loss.item() 56 running_classification_loss += classification_loss.item() 57 if i and i % debug_steps == 0: 58 avg_loss = running_loss / debug_steps 59 avg_reg_loss = running_regression_loss / debug_steps 60 avg_clf_loss = running_classification_loss / debug_steps 61 logger.info( 62 f"Epoch: {epoch}, Step: {i}, " + 63 f"Average Loss: {avg_loss:.4f}, " + 64 f"Average Regression Loss {avg_reg_loss:.4f}, " + 65 f"Average Classification Loss: {avg_clf_loss:.4f}" 66 ) 67 running_loss = 0.0 68 running_regression_loss = 0.0 69 running_classification_loss = 0.0 70 71 def train(self, train_loader, val_loader, device = "cpu", 72 scheduler = None, criterion = None, optimizer = None, 73 lr = 1e-3, base_net_lr = 1e-3, extra_layers_lr = 1e-3, num_epochs = 100, momentum = 0.9, weight_decay = 5e-4, 74 debug_steps = 100, validation_epochs = 5, 75 freeze_base_net = False, freeze_net = False, 76 resume = None, base_net = None, pretrained_ssd = None, 77 checkpoint_folder = "models/"): 78 79 if freeze_base_net: 80 logger.info("Freeze base net.") 81 82 freeze_net_layers(self.net.base_net) 83 params = itertools.chain(self.net.source_layer_add_ons.parameters(), self.net.extras.parameters(), 84 self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 85 params = [ 86 {'params': itertools.chain( 87 self.net.source_layer_add_ons.parameters(), 88 self.net.extras.parameters() 89 ), 'lr': extra_layers_lr}, 90 {'params': itertools.chain( 91 self.net.regression_headers.parameters(), 92 self.net.classification_headers.parameters() 93 )} 94 ] 95 elif freeze_net: 96 freeze_net_layers(self.net.base_net) 97 freeze_net_layers(self.net.source_layer_add_ons) 98 freeze_net_layers(self.net.extras) 99 params = itertools.chain(self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 100 logger.info("Freeze all the layers except prediction heads.") 101 else: 102 params = [ 103 {'params': self.net.base_net.parameters(), 'lr': base_net_lr}, 104 {'params': itertools.chain( 105 self.net.source_layer_add_ons.parameters(), 106 self.net.extras.parameters() 107 ), 'lr': extra_layers_lr}, 108 {'params': itertools.chain( 109 self.net.regression_headers.parameters(), 110 self.net.classification_headers.parameters() 111 )} 112 ] 113 114 if resume: 115 logger.info(f"Resume from the model {resume}") 116 self.net.load(resume) 117 elif base_net: 118 logger.info(f"Init from base net {base_net}") 119 self.net.init_from_base_net(base_net) 120 elif pretrained_ssd: 121 logger.info(f"Init from pretrained ssd {pretrained_ssd}") 122 self.net.init_from_pretrained_ssd(pretrained_ssd) 123 124 self.net.to(device) 125 126 if criterion is None: 127 criterion = MultiboxLoss(mobilenet_ssd_config.priors, iou_threshold=0.5, neg_pos_ratio=3, 128 center_variance=0.1, size_variance=0.2, device=device) 129 if optimizer is None: 130 optimizer = torch.optim.SGD(params, lr=lr, momentum=momentum, 131 weight_decay=weight_decay) 132 if scheduler is None: 133 scheduler = CosineAnnealingLR(optimizer, 120) 134 135 logger.info("Start training using CosineAnnealingLR scheduler.") 136 137 for epoch in range(0, num_epochs): 138 self.step(train_loader, criterion, optimizer, epoch=epoch, 139 device=device, debug_steps=debug_steps) 140 141 scheduler.step() 142 143 if (epoch % validation_epochs == 0) or (epoch == num_epochs - 1): 144 val_loss, val_regression_loss, val_classification_loss = self.eval(val_loader, criterion, device) 145 logger.info( 146 f"Epoch: {epoch}, " + 147 f"Validation Loss: {val_loss:.4f}, " + 148 f"Validation Regression Loss {val_regression_loss:.4f}, " + 149 f"Validation Classification Loss: {val_classification_loss:.4f}" 150 ) 151 model_path = os.path.join(checkpoint_folder, f"mobilenet-v1-ssd-Epoch-{epoch}-Loss-{val_loss}.pth") 152 self.net.save(model_path) 153 154 logger.info(f"Saved model {model_path}") 155 156 def eval(self, loader, criterion, device): 157 self.net.eval() 158 running_loss = 0.0 159 running_regression_loss = 0.0 160 running_classification_loss = 0.0 161 num = 0 162 for _, data in enumerate(loader): 163 images, boxes, labels = data 164 images = images.to(device) 165 boxes = boxes.to(device) 166 labels = labels.to(device) 167 num += 1 168 169 with torch.no_grad(): 170 confidence, locations = self.net(images) 171 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) 172 loss = regression_loss + classification_loss 173 174 running_loss += loss.item() 175 running_regression_loss += regression_loss.item() 176 running_classification_loss += classification_loss.item() 177 return running_loss / num, running_regression_loss / num, running_classification_loss / num
def
step( self, loader, criterion, optimizer, device, debug_steps=100, epoch=-1):
36 def step(self, loader, criterion, optimizer, device, debug_steps=100, epoch=-1): 37 self.net.train(True) 38 running_loss = 0.0 39 running_regression_loss = 0.0 40 running_classification_loss = 0.0 41 for i, data in enumerate(loader): 42 images, boxes, labels = data 43 images = images.to(device) 44 boxes = boxes.to(device) 45 labels = labels.to(device) 46 47 optimizer.zero_grad() 48 confidence, locations = self.net(images) 49 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) # TODO CHANGE BOXES 50 loss = regression_loss + classification_loss 51 loss.backward() 52 optimizer.step() 53 54 running_loss += loss.item() 55 running_regression_loss += regression_loss.item() 56 running_classification_loss += classification_loss.item() 57 if i and i % debug_steps == 0: 58 avg_loss = running_loss / debug_steps 59 avg_reg_loss = running_regression_loss / debug_steps 60 avg_clf_loss = running_classification_loss / debug_steps 61 logger.info( 62 f"Epoch: {epoch}, Step: {i}, " + 63 f"Average Loss: {avg_loss:.4f}, " + 64 f"Average Regression Loss {avg_reg_loss:.4f}, " + 65 f"Average Classification Loss: {avg_clf_loss:.4f}" 66 ) 67 running_loss = 0.0 68 running_regression_loss = 0.0 69 running_classification_loss = 0.0
def
train( self, train_loader, val_loader, device='cpu', scheduler=None, criterion=None, optimizer=None, lr=0.001, base_net_lr=0.001, extra_layers_lr=0.001, num_epochs=100, momentum=0.9, weight_decay=0.0005, debug_steps=100, validation_epochs=5, freeze_base_net=False, freeze_net=False, resume=None, base_net=None, pretrained_ssd=None, checkpoint_folder='models/'):
71 def train(self, train_loader, val_loader, device = "cpu", 72 scheduler = None, criterion = None, optimizer = None, 73 lr = 1e-3, base_net_lr = 1e-3, extra_layers_lr = 1e-3, num_epochs = 100, momentum = 0.9, weight_decay = 5e-4, 74 debug_steps = 100, validation_epochs = 5, 75 freeze_base_net = False, freeze_net = False, 76 resume = None, base_net = None, pretrained_ssd = None, 77 checkpoint_folder = "models/"): 78 79 if freeze_base_net: 80 logger.info("Freeze base net.") 81 82 freeze_net_layers(self.net.base_net) 83 params = itertools.chain(self.net.source_layer_add_ons.parameters(), self.net.extras.parameters(), 84 self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 85 params = [ 86 {'params': itertools.chain( 87 self.net.source_layer_add_ons.parameters(), 88 self.net.extras.parameters() 89 ), 'lr': extra_layers_lr}, 90 {'params': itertools.chain( 91 self.net.regression_headers.parameters(), 92 self.net.classification_headers.parameters() 93 )} 94 ] 95 elif freeze_net: 96 freeze_net_layers(self.net.base_net) 97 freeze_net_layers(self.net.source_layer_add_ons) 98 freeze_net_layers(self.net.extras) 99 params = itertools.chain(self.net.regression_headers.parameters(), self.net.classification_headers.parameters()) 100 logger.info("Freeze all the layers except prediction heads.") 101 else: 102 params = [ 103 {'params': self.net.base_net.parameters(), 'lr': base_net_lr}, 104 {'params': itertools.chain( 105 self.net.source_layer_add_ons.parameters(), 106 self.net.extras.parameters() 107 ), 'lr': extra_layers_lr}, 108 {'params': itertools.chain( 109 self.net.regression_headers.parameters(), 110 self.net.classification_headers.parameters() 111 )} 112 ] 113 114 if resume: 115 logger.info(f"Resume from the model {resume}") 116 self.net.load(resume) 117 elif base_net: 118 logger.info(f"Init from base net {base_net}") 119 self.net.init_from_base_net(base_net) 120 elif pretrained_ssd: 121 logger.info(f"Init from pretrained ssd {pretrained_ssd}") 122 self.net.init_from_pretrained_ssd(pretrained_ssd) 123 124 self.net.to(device) 125 126 if criterion is None: 127 criterion = MultiboxLoss(mobilenet_ssd_config.priors, iou_threshold=0.5, neg_pos_ratio=3, 128 center_variance=0.1, size_variance=0.2, device=device) 129 if optimizer is None: 130 optimizer = torch.optim.SGD(params, lr=lr, momentum=momentum, 131 weight_decay=weight_decay) 132 if scheduler is None: 133 scheduler = CosineAnnealingLR(optimizer, 120) 134 135 logger.info("Start training using CosineAnnealingLR scheduler.") 136 137 for epoch in range(0, num_epochs): 138 self.step(train_loader, criterion, optimizer, epoch=epoch, 139 device=device, debug_steps=debug_steps) 140 141 scheduler.step() 142 143 if (epoch % validation_epochs == 0) or (epoch == num_epochs - 1): 144 val_loss, val_regression_loss, val_classification_loss = self.eval(val_loader, criterion, device) 145 logger.info( 146 f"Epoch: {epoch}, " + 147 f"Validation Loss: {val_loss:.4f}, " + 148 f"Validation Regression Loss {val_regression_loss:.4f}, " + 149 f"Validation Classification Loss: {val_classification_loss:.4f}" 150 ) 151 model_path = os.path.join(checkpoint_folder, f"mobilenet-v1-ssd-Epoch-{epoch}-Loss-{val_loss}.pth") 152 self.net.save(model_path) 153 154 logger.info(f"Saved model {model_path}")
def
eval(self, loader, criterion, device):
156 def eval(self, loader, criterion, device): 157 self.net.eval() 158 running_loss = 0.0 159 running_regression_loss = 0.0 160 running_classification_loss = 0.0 161 num = 0 162 for _, data in enumerate(loader): 163 images, boxes, labels = data 164 images = images.to(device) 165 boxes = boxes.to(device) 166 labels = labels.to(device) 167 num += 1 168 169 with torch.no_grad(): 170 confidence, locations = self.net(images) 171 regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) 172 loss = regression_loss + classification_loss 173 174 running_loss += loss.item() 175 running_regression_loss += regression_loss.item() 176 running_classification_loss += classification_loss.item() 177 return running_loss / num, running_regression_loss / num, running_classification_loss / num