├── AffectNet ├── train.txt └── val.txt ├── checkpoint ├── 87.73517581419489_96_2.pth ├── 92.75009731413002_1.pth ├── 95.45543012845465_32_2.pth └── 97_160_2.pth ├── datagen.py ├── flops_counter_pytorch ├── LICENSE ├── README.md ├── ptflops │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── flops_counter.cpython-36.pyc │ └── flops_counter.py ├── sample.py └── setup.py ├── image ├── 1679052023.jpg ├── 996012808.jpg ├── crop │ └── test_face.jpg ├── test.jpg ├── test1.jpg └── test2.jpg ├── loss.py ├── model ├── 97_160_2.pth └── haarcascade_frontalface_default.xml ├── net.py ├── pScores.mat ├── readme.md ├── result.csv ├── scripts └── get_state_dict.py ├── shufflenetv2.py ├── summary ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── model_hook.cpython-36.pyc │ ├── model_summary.cpython-36.pyc │ ├── module_mac.cpython-36.pyc │ └── summary_tree.cpython-36.pyc ├── example.py ├── model_hook.py ├── model_summary.py ├── module_mac.py └── summary_tree.py ├── test.py ├── test ├── __pycache__ │ └── shufflenetv2.cpython-36.pyc ├── image │ ├── crop │ │ ├── 00921_960627_fa_illu_cafe-inside-2_extracted.jpg │ │ ├── 00921_960627_fa_illu_cafe-inside-3_extracted.jpg │ │ ├── 00921_960627_fa_illu_cafe-sunshade-2pm-1_extracted.jpg │ │ ├── 00921_960627_fa_illu_cafe-sunshade-2pm-2_extracted.jpg │ │ └── 00921_960627_fa_illu_cafe-sunshade-2pm-3_extracted.jpg │ ├── test.jpg │ ├── test1.jpg │ └── test2.jpg ├── model │ ├── 97_160_2.pth │ └── haarcascade_frontalface_default.xml ├── pScores.mat ├── shufflenetv2.py ├── test.py └── test_without_crop.py ├── test_convert_to_caffe ├── __pycache__ │ └── shufflenetv2.cpython-36.pyc ├── httpClient.py ├── image │ ├── crop │ │ └── test_face.jpg │ ├── test.jpg │ ├── test1.jpg │ └── test2.jpg ├── model │ ├── 97_160_2.pth │ ├── fiiqa_shufflenetv2_1.0x.caffemodel │ ├── fiiqa_shufflenetv2_1.0x.prototxt │ └── haarcascade_frontalface_default.xml ├── pScores.mat ├── shufflenetv2.py ├── shufflenetv2_to_caffe.py ├── test.py └── utils │ ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── get_topk.cpython-36.pyc │ ├── load.cpython-36.pyc │ └── load_test_image.cpython-36.pyc │ ├── get_topk.py │ ├── load.py │ └── load_test_image.py ├── test_model.py ├── train.py └── train_affectnet.py /checkpoint/87.73517581419489_96_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/checkpoint/87.73517581419489_96_2.pth -------------------------------------------------------------------------------- /checkpoint/92.75009731413002_1.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/checkpoint/92.75009731413002_1.pth -------------------------------------------------------------------------------- /checkpoint/95.45543012845465_32_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/checkpoint/95.45543012845465_32_2.pth -------------------------------------------------------------------------------- /checkpoint/97_160_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/checkpoint/97_160_2.pth -------------------------------------------------------------------------------- /datagen.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import io 3 | import os 4 | import sys 5 | import random 6 | import torch 7 | import torch.utils.data as data 8 | import torchvision.transforms as transforms 9 | from PIL import Image 10 | 11 | class ListDataset(data.Dataset): 12 | def __init__(self, root, list_file, transform): 13 | ''' 14 | Args: 15 | root: (str) ditectory to images. 16 | list_file: (str) path to index file. 17 | transform: ([transforms]) image transforms. 18 | ''' 19 | self.root = root 20 | self.transform = transform 21 | 22 | self.fname = [] 23 | self.fiiqa = [] 24 | 25 | with io.open(list_file, encoding='gbk') as f: 26 | lines = f.readlines() 27 | self.num_imgs = len(lines) 28 | 29 | for line in lines: 30 | sp = line.strip().split() 31 | self.fname.append(sp[0]) 32 | self.fiiqa.append(int(sp[1])) 33 | 34 | def __getitem__(self, idx): 35 | '''Load image. 36 | 37 | Args: 38 | idx: (int) image index. 39 | 40 | Returns: 41 | img: (tensor) image tensor. 42 | fiiqa: (float) fiiqa. 43 | ''' 44 | # Load image and bbox locations. 45 | fname = self.fname[idx] 46 | fiiqa = self.fiiqa[idx] 47 | 48 | img = Image.open(os.path.join(self.root, fname)).convert('RGB') 49 | img = self.transform(img) 50 | return img, fiiqa 51 | 52 | def __len__(self): 53 | return self.num_imgs 54 | 55 | 56 | def test(): 57 | import torchvision 58 | transform = transforms.Compose([ 59 | transforms.RandomSizedCrop(224), 60 | transforms.RandomHorizontalFlip(), 61 | transforms.ToTensor(), 62 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 63 | ]) 64 | dataset = ListDataset(root='./data/validationset/val-faces/', list_file='./data/validationset/val-faces/new_4people_val_standard.txt', transform=transform) 65 | dataloader = torch.utils.data.DataLoader(dataset, batch_size=10, shuffle=True, num_workers=1) 66 | for img, fiiqa in dataloader: 67 | print(img.size()) 68 | print(fiiqa.size()) 69 | 70 | -------------------------------------------------------------------------------- /flops_counter_pytorch/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vladislav Sovrasov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /flops_counter_pytorch/README.md: -------------------------------------------------------------------------------- 1 | # Flops counter for convolutional networks in pytorch framework 2 | [![Pypi version](https://img.shields.io/pypi/v/ptflops.svg)](https://pypi.org/project/ptflops/) 3 | 4 | This script is designed to compute the theoretical amount of multiply-add operations 5 | in convolutional neural networks. It also can compute the number of parameters and 6 | print per-layer computational cost of a given network. 7 | 8 | Supported layers: 9 | - Convolution2d (including grouping) 10 | - BatchNorm2d 11 | - Activations (ReLU, PReLU, ELU, ReLU6, LeakyReLU) 12 | - Linear 13 | - Upsample 14 | - Poolings (AvgPool2d, MaxPool2d and adaptive ones) 15 | 16 | Requirements: Pytorch 0.4.1 or 1.0, torchvision 0.2.1 17 | 18 | Thanks to @warmspringwinds for the initial version of script. 19 | 20 | ## Install the latest version 21 | ```bash 22 | pip install --upgrade git+https://github.com/sovrasov/flops-counter.pytorch.git 23 | ``` 24 | 25 | ## Example 26 | ```python 27 | import torchvision.models as models 28 | import torch 29 | from ptflops import get_model_complexity_info 30 | 31 | with torch.cuda.device(0): 32 | net = models.densenet161() 33 | flops, params = get_model_complexity_info(net, (224, 224), as_strings=True, print_per_layer_stat=True) 34 | print('Flops: ' + flops) 35 | print('Params: ' + params) 36 | ``` 37 | -------------------------------------------------------------------------------- /flops_counter_pytorch/ptflops/__init__.py: -------------------------------------------------------------------------------- 1 | from .flops_counter import get_model_complexity_info 2 | -------------------------------------------------------------------------------- /flops_counter_pytorch/ptflops/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/flops_counter_pytorch/ptflops/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /flops_counter_pytorch/ptflops/__pycache__/flops_counter.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/flops_counter_pytorch/ptflops/__pycache__/flops_counter.cpython-36.pyc -------------------------------------------------------------------------------- /flops_counter_pytorch/ptflops/flops_counter.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch 3 | import numpy as np 4 | 5 | def get_model_complexity_info(model, input_res, print_per_layer_stat=True, as_strings=True, 6 | input_constructor=None): 7 | assert type(input_res) is tuple 8 | assert len(input_res) == 2 9 | flops_model = add_flops_counting_methods(model) 10 | flops_model.eval().start_flops_count() 11 | if input_constructor: 12 | input = input_constructor(input_res) 13 | _ = flops_model(**input) 14 | else: 15 | batch = torch.FloatTensor(1, 3, *input_res) 16 | _ = flops_model(batch) 17 | 18 | if print_per_layer_stat: 19 | print_model_with_flops(flops_model) 20 | flops_count = flops_model.compute_average_flops_cost() 21 | params_count = get_model_parameters_number(flops_model) 22 | flops_model.stop_flops_count() 23 | 24 | if as_strings: 25 | return flops_to_string(flops_count), params_to_string(params_count) 26 | 27 | return flops_count, params_count 28 | 29 | def flops_to_string(flops, units='GMac', precision=12): 30 | if units is None: 31 | if flops // 10**9 > 0: 32 | return str(round(flops / 10.**9, precision)) + ' GMac' 33 | elif flops // 10**6 > 0: 34 | return str(round(flops / 10.**6, precision)) + ' MMac' 35 | elif flops // 10**3 > 0: 36 | return str(round(flops / 10.**3, precision)) + ' KMac' 37 | else: 38 | return str(flops) + ' Mac' 39 | else: 40 | if units == 'GMac': 41 | return str(round(flops / 10.**9, precision)) + ' ' + units 42 | elif units == 'MMac': 43 | return str(round(flops / 10.**6, precision)) + ' ' + units 44 | elif units == 'KMac': 45 | return str(round(flops / 10.**3, precision)) + ' ' + units 46 | else: 47 | return str(flops) + ' Mac' 48 | 49 | def params_to_string(params_num): 50 | if params_num // 10 ** 6 > 0: 51 | return str(round(params_num / 10 ** 6, 2)) + ' M' 52 | elif params_num // 10 ** 3: 53 | return str(round(params_num / 10 ** 3, 2)) + ' k' 54 | 55 | def print_model_with_flops(model, units='GMac', precision=3): 56 | total_flops = model.compute_average_flops_cost() 57 | 58 | def accumulate_flops(self): 59 | if is_supported_instance(self): 60 | return self.__flops__ / model.__batch_counter__ 61 | else: 62 | sum = 0 63 | for m in self.children(): 64 | sum += m.accumulate_flops() 65 | return sum 66 | 67 | def flops_repr(self): 68 | accumulated_flops_cost = self.accumulate_flops() 69 | return ', '.join([flops_to_string(accumulated_flops_cost, units=units, precision=precision), 70 | '{:.3%} MACs'.format(accumulated_flops_cost / total_flops), 71 | self.original_extra_repr()]) 72 | 73 | def add_extra_repr(m): 74 | m.accumulate_flops = accumulate_flops.__get__(m) 75 | flops_extra_repr = flops_repr.__get__(m) 76 | if m.extra_repr != flops_extra_repr: 77 | m.original_extra_repr = m.extra_repr 78 | m.extra_repr = flops_extra_repr 79 | assert m.extra_repr != m.original_extra_repr 80 | 81 | def del_extra_repr(m): 82 | if hasattr(m, 'original_extra_repr'): 83 | m.extra_repr = m.original_extra_repr 84 | del m.original_extra_repr 85 | if hasattr(m, 'accumulate_flops'): 86 | del m.accumulate_flops 87 | 88 | model.apply(add_extra_repr) 89 | print(model) 90 | model.apply(del_extra_repr) 91 | 92 | def get_model_parameters_number(model): 93 | params_num = sum(p.numel() for p in model.parameters() if p.requires_grad) 94 | return params_num 95 | 96 | def add_flops_counting_methods(net_main_module): 97 | # adding additional methods to the existing module object, 98 | # this is done this way so that each function has access to self object 99 | net_main_module.start_flops_count = start_flops_count.__get__(net_main_module) 100 | net_main_module.stop_flops_count = stop_flops_count.__get__(net_main_module) 101 | net_main_module.reset_flops_count = reset_flops_count.__get__(net_main_module) 102 | net_main_module.compute_average_flops_cost = compute_average_flops_cost.__get__(net_main_module) 103 | 104 | net_main_module.reset_flops_count() 105 | 106 | # Adding variables necessary for masked flops computation 107 | net_main_module.apply(add_flops_mask_variable_or_reset) 108 | 109 | return net_main_module 110 | 111 | 112 | def compute_average_flops_cost(self): 113 | """ 114 | A method that will be available after add_flops_counting_methods() is called 115 | on a desired net object. 116 | 117 | Returns current mean flops consumption per image. 118 | 119 | """ 120 | 121 | batches_count = self.__batch_counter__ 122 | flops_sum = 0 123 | for module in self.modules(): 124 | if is_supported_instance(module): 125 | flops_sum += module.__flops__ 126 | 127 | return flops_sum / batches_count 128 | 129 | 130 | def start_flops_count(self): 131 | """ 132 | A method that will be available after add_flops_counting_methods() is called 133 | on a desired net object. 134 | 135 | Activates the computation of mean flops consumption per image. 136 | Call it before you run the network. 137 | 138 | """ 139 | add_batch_counter_hook_function(self) 140 | self.apply(add_flops_counter_hook_function) 141 | 142 | 143 | def stop_flops_count(self): 144 | """ 145 | A method that will be available after add_flops_counting_methods() is called 146 | on a desired net object. 147 | 148 | Stops computing the mean flops consumption per image. 149 | Call whenever you want to pause the computation. 150 | 151 | """ 152 | remove_batch_counter_hook_function(self) 153 | self.apply(remove_flops_counter_hook_function) 154 | 155 | 156 | def reset_flops_count(self): 157 | """ 158 | A method that will be available after add_flops_counting_methods() is called 159 | on a desired net object. 160 | 161 | Resets statistics computed so far. 162 | 163 | """ 164 | add_batch_counter_variables_or_reset(self) 165 | self.apply(add_flops_counter_variable_or_reset) 166 | 167 | 168 | def add_flops_mask(module, mask): 169 | def add_flops_mask_func(module): 170 | if isinstance(module, torch.nn.Conv2d): 171 | module.__mask__ = mask 172 | module.apply(add_flops_mask_func) 173 | 174 | 175 | def remove_flops_mask(module): 176 | module.apply(add_flops_mask_variable_or_reset) 177 | 178 | 179 | # ---- Internal functions 180 | def is_supported_instance(module): 181 | if isinstance(module, (torch.nn.Conv2d, torch.nn.ReLU, torch.nn.PReLU, torch.nn.ELU, \ 182 | torch.nn.LeakyReLU, torch.nn.ReLU6, torch.nn.Linear, \ 183 | torch.nn.MaxPool2d, torch.nn.AvgPool2d, torch.nn.BatchNorm2d, \ 184 | torch.nn.Upsample, nn.AdaptiveMaxPool2d, nn.AdaptiveAvgPool2d)): 185 | return True 186 | 187 | return False 188 | 189 | 190 | def empty_flops_counter_hook(module, input, output): 191 | module.__flops__ += 0 192 | 193 | 194 | def upsample_flops_counter_hook(module, input, output): 195 | output_size = output[0] 196 | batch_size = output_size.shape[0] 197 | output_elements_count = batch_size 198 | for val in output_size.shape[1:]: 199 | output_elements_count *= val 200 | module.__flops__ += int(output_elements_count) 201 | 202 | 203 | def relu_flops_counter_hook(module, input, output): 204 | active_elements_count = output.numel() 205 | module.__flops__ += int(active_elements_count) 206 | 207 | 208 | def linear_flops_counter_hook(module, input, output): 209 | input = input[0] 210 | batch_size = input.shape[0] 211 | module.__flops__ += int(batch_size * input.shape[1] * output.shape[1]) 212 | 213 | 214 | def pool_flops_counter_hook(module, input, output): 215 | input = input[0] 216 | module.__flops__ += int(np.prod(input.shape)) 217 | 218 | def bn_flops_counter_hook(module, input, output): 219 | module.affine 220 | input = input[0] 221 | 222 | batch_flops = np.prod(input.shape) 223 | if module.affine: 224 | batch_flops *= 2 225 | module.__flops__ += int(batch_flops) 226 | 227 | def conv_flops_counter_hook(conv_module, input, output): 228 | # Can have multiple inputs, getting the first one 229 | input = input[0] 230 | 231 | batch_size = input.shape[0] 232 | output_height, output_width = output.shape[2:] 233 | 234 | kernel_height, kernel_width = conv_module.kernel_size 235 | in_channels = conv_module.in_channels 236 | out_channels = conv_module.out_channels 237 | groups = conv_module.groups 238 | 239 | filters_per_channel = out_channels // groups 240 | conv_per_position_flops = kernel_height * kernel_width * in_channels * filters_per_channel 241 | 242 | active_elements_count = batch_size * output_height * output_width 243 | 244 | if conv_module.__mask__ is not None: 245 | # (b, 1, h, w) 246 | flops_mask = conv_module.__mask__.expand(batch_size, 1, output_height, output_width) 247 | active_elements_count = flops_mask.sum() 248 | 249 | overall_conv_flops = conv_per_position_flops * active_elements_count 250 | 251 | bias_flops = 0 252 | 253 | if conv_module.bias is not None: 254 | 255 | bias_flops = out_channels * active_elements_count 256 | 257 | overall_flops = overall_conv_flops + bias_flops 258 | 259 | conv_module.__flops__ += int(overall_flops) 260 | 261 | 262 | def batch_counter_hook(module, input, output): 263 | batch_size = 1 264 | if len(input) > 0: 265 | # Can have multiple inputs, getting the first one 266 | input = input[0] 267 | batch_size = len(input) 268 | else: 269 | pass 270 | print('Warning! No positional inputs found for a module, assuming batch size is 1.') 271 | module.__batch_counter__ += batch_size 272 | 273 | 274 | def add_batch_counter_variables_or_reset(module): 275 | 276 | module.__batch_counter__ = 0 277 | 278 | 279 | def add_batch_counter_hook_function(module): 280 | if hasattr(module, '__batch_counter_handle__'): 281 | return 282 | 283 | handle = module.register_forward_hook(batch_counter_hook) 284 | module.__batch_counter_handle__ = handle 285 | 286 | 287 | def remove_batch_counter_hook_function(module): 288 | if hasattr(module, '__batch_counter_handle__'): 289 | module.__batch_counter_handle__.remove() 290 | del module.__batch_counter_handle__ 291 | 292 | 293 | def add_flops_counter_variable_or_reset(module): 294 | if is_supported_instance(module): 295 | module.__flops__ = 0 296 | 297 | 298 | def add_flops_counter_hook_function(module): 299 | if is_supported_instance(module): 300 | if hasattr(module, '__flops_handle__'): 301 | return 302 | 303 | if isinstance(module, torch.nn.Conv2d): 304 | handle = module.register_forward_hook(conv_flops_counter_hook) 305 | elif isinstance(module, (torch.nn.ReLU, torch.nn.PReLU, torch.nn.ELU, \ 306 | torch.nn.LeakyReLU, torch.nn.ReLU6)): 307 | handle = module.register_forward_hook(relu_flops_counter_hook) 308 | elif isinstance(module, torch.nn.Linear): 309 | handle = module.register_forward_hook(linear_flops_counter_hook) 310 | elif isinstance(module, (torch.nn.AvgPool2d, torch.nn.MaxPool2d, nn.AdaptiveMaxPool2d, \ 311 | nn.AdaptiveAvgPool2d)): 312 | handle = module.register_forward_hook(pool_flops_counter_hook) 313 | elif isinstance(module, torch.nn.BatchNorm2d): 314 | handle = module.register_forward_hook(bn_flops_counter_hook) 315 | elif isinstance(module, torch.nn.Upsample): 316 | handle = module.register_forward_hook(upsample_flops_counter_hook) 317 | else: 318 | handle = module.register_forward_hook(empty_flops_counter_hook) 319 | module.__flops_handle__ = handle 320 | 321 | 322 | def remove_flops_counter_hook_function(module): 323 | if is_supported_instance(module): 324 | if hasattr(module, '__flops_handle__'): 325 | module.__flops_handle__.remove() 326 | del module.__flops_handle__ 327 | # --- Masked flops counting 328 | 329 | 330 | # Also being run in the initialization 331 | def add_flops_mask_variable_or_reset(module): 332 | if is_supported_instance(module): 333 | module.__mask__ = None 334 | -------------------------------------------------------------------------------- /flops_counter_pytorch/sample.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import torchvision.models as models 3 | import torch 4 | from ptflops import get_model_complexity_info 5 | 6 | pt_models = { 'resnet18': models.resnet18, 'resnet50': models.resnet50, 7 | 'alexnet': models.alexnet, 8 | 'vgg16': models.vgg16, 'squeezenet': models.squeezenet1_0, 9 | 'densenet': models.densenet161} 10 | 11 | if __name__ == '__main__': 12 | parser = argparse.ArgumentParser(description='Evaluation script for Face Recognition in PyTorch') 13 | parser.add_argument('--device', type=int, default=-1, help='Device to store the model.') 14 | parser.add_argument('--model', choices=list(pt_models.keys()), type=str, default='resnet18') 15 | args = parser.parse_args() 16 | 17 | with torch.cuda.device(args.device): 18 | net = pt_models[args.model]() 19 | flops, params = get_model_complexity_info(net, (224, 224), as_strings=True, print_per_layer_stat=True) 20 | print('Flops: ' + flops) 21 | print('Params: ' + params) 22 | -------------------------------------------------------------------------------- /flops_counter_pytorch/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import sys 4 | from setuptools import setup, find_packages 5 | 6 | readme = open('README.md').read() 7 | 8 | VERSION = '0.5' 9 | 10 | requirements = [ 11 | 'torch', 12 | ] 13 | 14 | setup( 15 | # Metadata 16 | name='ptflops', 17 | version=VERSION, 18 | author='Vladislav Sovrasov', 19 | author_email='sovrasov.vlad@gmail.com', 20 | url='https://github.com/sovrasov/flops-counter.pytorch', 21 | description='Flops counter for convolutional networks in pytorch framework', 22 | long_description=readme, 23 | license='MIT', 24 | 25 | # Package info 26 | packages=find_packages(exclude=('*test*',)), 27 | 28 | # 29 | zip_safe=True, 30 | install_requires=requirements, 31 | 32 | # Classifiers 33 | classifiers=[ 34 | 'Programming Language :: Python :: 3', 35 | ], 36 | ) 37 | -------------------------------------------------------------------------------- /image/1679052023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/1679052023.jpg -------------------------------------------------------------------------------- /image/996012808.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/996012808.jpg -------------------------------------------------------------------------------- /image/crop/test_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/crop/test_face.jpg -------------------------------------------------------------------------------- /image/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/test.jpg -------------------------------------------------------------------------------- /image/test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/test1.jpg -------------------------------------------------------------------------------- /image/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/image/test2.jpg -------------------------------------------------------------------------------- /loss.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | 7 | from torch.autograd import Variable 8 | 9 | 10 | class FIIQALoss(nn.Module): 11 | def __init__(self): 12 | super(AGLoss, self).__init__() 13 | 14 | def forward(self, fiiqa_preds, fiiqa_targets): 15 | '''Compute loss (fiiqa_preds, fiiqa_targets) . 16 | 17 | Args: 18 | fiiqa_preds: (tensor) predicted fiiqa, sized [batch_size,100]. 19 | fiiqa_targets: (tensor) target fiiqa, sized [batch_size,]. 20 | 21 | loss: 22 | (tensor) loss = SmoothL1Loss(fiiqa_preds, fiiqa_targets) 23 | ''' 24 | #使用分类概率和估计值相乘再求和来求期望的方法,比直接分类和直接回归的效果更好。 25 | #先求得分类概率 26 | fiiqa_prob = F.softmax(fiiqa_preds,dim=1) 27 | #利用分类概率与对应预测值相乘后累加求和,求得期望值 28 | fiiqa_expect = torch.sum(Variable(torch.arange(0,200)).cuda().float()*fiiqa_prob, 1) 29 | #loss是期望值与ground trouth 之间的误差 30 | fiiqa_loss = F.smooth_l1_loss(fiiqa_expect, fiiqa_targets.float()) 31 | return fiiqa_loss 32 | -------------------------------------------------------------------------------- /model/97_160_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/model/97_160_2.pth -------------------------------------------------------------------------------- /net.py: -------------------------------------------------------------------------------- 1 | '''Predict age in one shot.''' 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | from torch.autograd import Variable 6 | 7 | 8 | class BasicBlock(nn.Module): 9 | expansion = 1 10 | 11 | def __init__(self, in_planes, planes, stride=1): 12 | super(BasicBlock, self).__init__() 13 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 14 | self.bn1 = nn.BatchNorm2d(planes) 15 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 16 | self.bn2 = nn.BatchNorm2d(planes) 17 | 18 | self.downsample = nn.Sequential() 19 | if stride != 1 or in_planes != self.expansion*planes: 20 | self.downsample = nn.Sequential( 21 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 22 | nn.BatchNorm2d(self.expansion*planes) 23 | ) 24 | 25 | def forward(self, x): 26 | out = F.relu(self.bn1(self.conv1(x))) 27 | out = self.bn2(self.conv2(out)) 28 | out += self.downsample(x) 29 | out = F.relu(out) 30 | return out 31 | 32 | def freeze_bn(self): 33 | '''Freeze BatchNorm layers.''' 34 | for layer in self.modules(): 35 | if isinstance(layer, nn.BatchNorm2d): 36 | layer.training = False 37 | 38 | class Bottleneck(nn.Module): 39 | expansion = 4 40 | 41 | def __init__(self, in_planes, planes, stride=1): 42 | super(Bottleneck, self).__init__() 43 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 44 | self.bn1 = nn.BatchNorm2d(planes) 45 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 46 | self.bn2 = nn.BatchNorm2d(planes) 47 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 48 | self.bn3 = nn.BatchNorm2d(self.expansion*planes) 49 | 50 | self.downsample = nn.Sequential() 51 | if stride != 1 or in_planes != self.expansion*planes: 52 | self.downsample = nn.Sequential( 53 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 54 | nn.BatchNorm2d(self.expansion*planes) 55 | ) 56 | 57 | def forward(self, x): 58 | out = F.relu(self.bn1(self.conv1(x))) 59 | out = F.relu(self.bn2(self.conv2(out))) 60 | out = self.bn3(self.conv3(out)) 61 | out += self.downsample(x) 62 | out = F.relu(out) 63 | return out 64 | 65 | 66 | class ResNet(nn.Module): 67 | def __init__(self, block, num_blocks): 68 | super(ResNet, self).__init__() 69 | self.in_planes = 64 70 | 71 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) 72 | self.bn1 = nn.BatchNorm2d(64) 73 | self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 74 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 75 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 76 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 77 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 78 | # self.avg_pool = nn.AvgPool2d(kernel_size=7) 79 | 80 | def _make_layer(self, block, planes, num_blocks, stride): 81 | strides = [stride] + [1]*(num_blocks-1) 82 | layers = [] 83 | for stride in strides: 84 | layers.append(block(self.in_planes, planes, stride)) 85 | self.in_planes = planes * block.expansion 86 | return nn.Sequential(*layers) 87 | 88 | def forward(self, x): 89 | out = F.relu(self.bn1(self.conv1(x))) 90 | out = self.max_pool(out) 91 | out = self.layer1(out) 92 | out = self.layer2(out) 93 | out = self.layer3(out) 94 | out = self.layer4(out) 95 | return out 96 | 97 | def ResNet18(): 98 | return ResNet(BasicBlock, [2,2,2,2]) 99 | 100 | def ResNet50(): 101 | return ResNet(Bottleneck, [3,4,6,3]) 102 | 103 | def ResNet101(): 104 | return ResNet(Bottleneck, [2,4,23,3]) 105 | 106 | 107 | class AGNet(nn.Module): 108 | def __init__(self): 109 | super(AGNet, self).__init__() 110 | self.backbone = ResNet18() 111 | self.age_head = self._make_head() 112 | self.linear1 = nn.Linear(256,200) 113 | 114 | def _make_head(self): 115 | return nn.Sequential( 116 | nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1), 117 | nn.ReLU(True), 118 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 119 | nn.ReLU(True), 120 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 121 | ) 122 | 123 | def forward(self, x): 124 | N = x.size(0) 125 | y = self.backbone(x) 126 | y = F.avg_pool2d(y,5) 127 | # Age head 128 | y_age = self.age_head(y) 129 | y_age = self.linear1(y_age.view(N,-1)) 130 | 131 | return y_age 132 | 133 | 134 | def test(): 135 | net = AGNet() 136 | age = net(Variable(torch.randn(2,3,150,150))) 137 | print(age.size()) 138 | 139 | 140 | # test() 141 | -------------------------------------------------------------------------------- /pScores.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/pScores.mat -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------- 2 | Face Image Illumination Quality Assessment implements by pytorch 3 | ----------------------------------------------------------------- 4 | This is not the official version of Illumination Quality Assessment for Face Images: A Benchmark and A Convolutional Neural Networks Based Model ,original website:https://github.com/zhanglijun95/FIIQA 5 | 6 | 7 | 8 | 9 | Overview: 10 | ![image](https://github.com/yangyuke001/FIIQA_pytorch/blob/master/image/1679052023.jpg) 11 | ![image](https://github.com/yangyuke001/FIIQA_pytorch/blob/master/image/996012808.jpg) 12 | 13 | 14 | Dependencies 15 | ------------------------------------------------------------------------------------ 16 | *python 3.6+ 17 | 18 | *pytorch 1.0.1+ 19 | 20 | 21 | Usage 22 | ------------------------------------------------------------------------------------ 23 | 1.cloning the respository 24 | git clone https://github.com/yangyuke001/FIIQA-PyTorch 25 | 26 | cd FIIQA-PyTorch 27 | 28 | 2.Downloading the dataset 29 | 30 | Face Image Illumination Quality Dataset 1.0 31 | 32 | We have established a large-scale benchmark dataset, in which face images under various illumination patterns with associated illumination quality scores were constructed by making use of illumination transfer. Thus, we firstly collected an image set containing face images with various real-world illumination patterns, namely source illumination patterns set, and evaluated their illumination quality scores by subjective judgements. And after construction, this dataset is divided into three subsets for DCNN, the training set, the validation set and the testing set. 33 | 2.1 Source illumination patterns set (http://pan.baidu.com/s/1hrYayXI) 34 | 35 | Unzip ZIP files, "illumination patterns.zip". In the "illumination patterns" folder, there are 200 images with various real-world illumination patterns, and for each image pattern, the associated illumination quality scores are given in the "patternsScores.mat", the sorted ranks, which are the class labels of those patterns, are given in the "patternsRank.mat". 36 | 2.2 Training Set (http://pan.baidu.com/s/1mhFBusg) 37 | 38 | Unzip 7Z files, "trainingset.7z". In "train-faces" folder, there are 159159 images with various illumination patterns, and for each image the rank label of the associated illumination quality are given in the "train_standard.txt". 39 | 2.3 Validation Set (http://pan.baidu.com/s/1miMDkt6) 40 | 41 | Unzip ZIP files, "validationset.zip". In "val-faces" folder, there are 30930 images with various illumination patterns, and for each image the rank label of the associated illumination quality are given in the "val_standard.txt". 42 | 2.4 Testing Set (http://pan.baidu.com/s/1nuXQjH3) 43 | 44 | Unzip 7Z files, "testingset.7z". In "test-faces" folder, there are 34644 images with various illumination patterns, and for each image the rank label of the associated illumination quality are given in the "test_standard.txt". 45 | 46 | 3. Training 47 | 48 | To train FIIQA , run the script below: 49 | 50 | 51 | python train.py 52 | 53 | 4. Testing 54 | 55 | To test on FIIQA,run the script below: 56 | 57 | python test.py 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /scripts/get_state_dict.py: -------------------------------------------------------------------------------- 1 | '''Init AGNet18 with pretrained ResNet18 model.''' 2 | import math 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.init as init 6 | 7 | from net import AGNet, ResNet18 8 | 9 | 10 | print('Loading pretrained ResNet18 model..') 11 | d = torch.load('./model/resnet18.pth') 12 | 13 | print('Loading into backbone..') 14 | backbone = ResNet18() 15 | dd = backbone.state_dict() 16 | for k in d.keys(): 17 | if not k.startswith('fc'): # skip fc layers 18 | dd[k] = d[k] 19 | 20 | print('Saving AGNet..') 21 | net = AGNet() 22 | net.backbone.load_state_dict(dd) 23 | torch.save(net.state_dict(), 'net.pth') 24 | print('Done!') 25 | -------------------------------------------------------------------------------- /shufflenetv2.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Variable 5 | from collections import OrderedDict 6 | from torch.nn import init 7 | import math 8 | 9 | 10 | def conv_bn(inp, oup, stride): 11 | return nn.Sequential( 12 | nn.Conv2d(inp, oup, 3, stride, 1, bias=False), 13 | nn.BatchNorm2d(oup), 14 | nn.ReLU(inplace=True) 15 | ) 16 | 17 | 18 | def conv_1x1_bn(inp, oup): 19 | return nn.Sequential( 20 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 21 | nn.BatchNorm2d(oup), 22 | nn.ReLU(inplace=True) 23 | ) 24 | 25 | 26 | def channel_shuffle(x, groups): 27 | batchsize, num_channels, height, width = x.data.size() 28 | 29 | channels_per_group = num_channels // groups 30 | 31 | # reshape 32 | x = x.view(batchsize, groups, channels_per_group, height, width) 33 | 34 | x = torch.transpose(x, 1, 2).contiguous() 35 | 36 | # flatten 37 | x = x.view(batchsize, -1, height, width) 38 | 39 | return x 40 | 41 | 42 | class InvertedResidual(nn.Module): 43 | def __init__(self, inp, oup, stride, benchmodel): 44 | super(InvertedResidual, self).__init__() 45 | self.benchmodel = benchmodel 46 | self.stride = stride 47 | assert stride in [1, 2] 48 | 49 | oup_inc = oup // 2 50 | 51 | if self.benchmodel == 1: 52 | # assert inp == oup_inc 53 | self.banch2 = nn.Sequential( 54 | # pw 55 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 56 | nn.BatchNorm2d(oup_inc), 57 | nn.ReLU(inplace=True), 58 | # dw 59 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 60 | 1, groups=oup_inc, bias=False), 61 | nn.BatchNorm2d(oup_inc), 62 | # pw-linear 63 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 64 | nn.BatchNorm2d(oup_inc), 65 | nn.ReLU(inplace=True), 66 | ) 67 | else: 68 | self.banch1 = nn.Sequential( 69 | # dw 70 | nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), 71 | nn.BatchNorm2d(inp), 72 | # pw-linear 73 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 74 | nn.BatchNorm2d(oup_inc), 75 | nn.ReLU(inplace=True), 76 | ) 77 | 78 | self.banch2 = nn.Sequential( 79 | # pw 80 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 81 | nn.BatchNorm2d(oup_inc), 82 | nn.ReLU(inplace=True), 83 | # dw 84 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 85 | 1, groups=oup_inc, bias=False), 86 | nn.BatchNorm2d(oup_inc), 87 | # pw-linear 88 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 89 | nn.BatchNorm2d(oup_inc), 90 | nn.ReLU(inplace=True), 91 | ) 92 | 93 | @staticmethod 94 | def _concat(x, out): 95 | # concatenate along channel axis 96 | return torch.cat((x, out), 1) 97 | 98 | def forward(self, x): 99 | if 1 == self.benchmodel: 100 | # x1 = x[:, :(x.shape[1] // 2), :, :] 101 | # x2 = x[:, (x.shape[1] // 2):, :, :] 102 | x1, x2 = torch.split(x, x.shape[1] // 2, dim=1) 103 | out = self._concat(x1, self.banch2(x2)) 104 | elif 2 == self.benchmodel: 105 | out = self._concat(self.banch1(x), self.banch2(x)) 106 | 107 | return channel_shuffle(out, 2) 108 | 109 | 110 | class ShuffleNetV2(nn.Module): 111 | def __init__(self, n_class=200, input_size=160, width_mult=1): #1,0 112 | super(ShuffleNetV2, self).__init__() 113 | 114 | assert input_size % 32 == 0 115 | 116 | self.stage_repeats = [4, 8, 4] 117 | # index 0 is invalid and should never be called. 118 | # only used for indexing convenience. 119 | if width_mult == 0.5: 120 | self.stage_out_channels = [-1, 24, 48, 96, 192, 192] #175 121 | elif width_mult == 1.0: 122 | self.stage_out_channels = [-1, 24, 116, 232, 464, 1024] # 1024 123 | elif width_mult == 1.5: 124 | self.stage_out_channels = [-1, 24, 176, 352, 704, 1024] 125 | elif width_mult == 2.0: 126 | self.stage_out_channels = [-1, 24, 224, 488, 976, 2048] 127 | else: 128 | raise ValueError( 129 | """width_mult = {} is not supported""".format(width_mult)) 130 | 131 | # building first layer 132 | input_channel = self.stage_out_channels[1] 133 | self.conv1 = conv_bn(3, input_channel, 2) 134 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 135 | 136 | self.features = [] 137 | # building inverted residual blocks 138 | for idxstage in range(len(self.stage_repeats)): 139 | numrepeat = self.stage_repeats[idxstage] 140 | output_channel = self.stage_out_channels[idxstage + 2] 141 | for i in range(numrepeat): 142 | if i == 0: 143 | # inp, oup, stride, benchmodel): 144 | self.features.append(InvertedResidual( 145 | input_channel, output_channel, 2, 2)) 146 | else: 147 | self.features.append(InvertedResidual( 148 | input_channel, output_channel, 1, 1)) 149 | input_channel = output_channel 150 | 151 | # make it nn.Sequential 152 | self.features = nn.Sequential(*self.features) 153 | 154 | # building last several layers 155 | self.conv_last = conv_1x1_bn( 156 | input_channel, self.stage_out_channels[-1]) 157 | self.globalpool = nn.Sequential(nn.AvgPool2d(int(input_size / 32))) 158 | 159 | # building classifier 160 | self.classifier = nn.Sequential( 161 | nn.Linear(self.stage_out_channels[-1], n_class)) 162 | 163 | def forward(self, x): 164 | x = self.conv1(x) 165 | x = self.maxpool(x) 166 | x = self.features(x) 167 | x = self.conv_last(x) 168 | x = self.globalpool(x) 169 | x = x.view(-1, self.stage_out_channels[-1]) 170 | x = self.classifier(x) 171 | return x 172 | 173 | 174 | def shufflenetv2(width_mult=1.): 175 | model = ShuffleNetV2(width_mult=width_mult) 176 | return model 177 | 178 | 179 | if __name__ == "__main__": 180 | """Testing 181 | """ 182 | model = ShuffleNetV2() 183 | print(model) 184 | -------------------------------------------------------------------------------- /summary/__init__.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | from summary.model_summary import model_summary 3 | -------------------------------------------------------------------------------- /summary/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/summary/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /summary/__pycache__/model_hook.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/summary/__pycache__/model_hook.cpython-36.pyc -------------------------------------------------------------------------------- /summary/__pycache__/model_summary.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/summary/__pycache__/model_summary.cpython-36.pyc -------------------------------------------------------------------------------- /summary/__pycache__/module_mac.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/summary/__pycache__/module_mac.cpython-36.pyc -------------------------------------------------------------------------------- /summary/__pycache__/summary_tree.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/summary/__pycache__/summary_tree.cpython-36.pyc -------------------------------------------------------------------------------- /summary/example.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from misc.summary import model_summary 3 | from model.MobileNetV2 import MobileNetV2 4 | 5 | 6 | if __name__ == '__main__': 7 | net = MobileNetV2() 8 | model_summary(net, input_size=(3, 224, 224)) -------------------------------------------------------------------------------- /summary/model_hook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import time 4 | from collections import OrderedDict 5 | import numpy as np 6 | import torch 7 | import torch.nn as nn 8 | 9 | from summary.module_mac import compute_module_mac 10 | 11 | 12 | class CModelHook(object): 13 | def __init__(self, model, input_size): 14 | assert isinstance(model, nn.Module) 15 | assert isinstance(input_size, (list, tuple)) 16 | 17 | self._model = model 18 | self._input_size = input_size 19 | self._origin_call = dict() # sub module call hook 20 | 21 | self._hook_model() 22 | self._model.eval() 23 | self._model(torch.rand(1, *self._input_size)) 24 | 25 | @staticmethod 26 | def _register_buffer(module): 27 | assert isinstance(module, nn.Module) 28 | 29 | if len(list(module.children())) > 0: 30 | return 31 | 32 | module.register_buffer('input_shape', torch.zeros(3).int()) 33 | module.register_buffer('output_shape', torch.zeros(3).int()) 34 | module.register_buffer('parameter_quantity', torch.zeros(1).int()) 35 | module.register_buffer('inference_memory', torch.zeros(1).long()) 36 | module.register_buffer('MAdd', torch.zeros(1).long()) 37 | module.register_buffer('duration', torch.zeros(1).float()) 38 | 39 | def _sub_module_call_hook(self): 40 | def wrap_call(module, *input, **kwargs): 41 | assert module.__class__ in self._origin_call 42 | 43 | start = time.time() 44 | output = self._origin_call[module.__class__](module, *input, **kwargs) 45 | end = time.time() 46 | module.duration = torch.from_numpy( 47 | np.array([end - start], dtype=np.float32)) 48 | 49 | module.input_shape = torch.from_numpy( 50 | np.array(input[0].size()[1:], dtype=np.int32)) 51 | module.output_shape = torch.from_numpy( 52 | np.array(output.size()[1:], dtype=np.int32)) 53 | 54 | parameter_quantity = 0 55 | # iterate through parameters and count num params 56 | for name, p in module._parameters.items(): 57 | parameter_quantity += (0 if p is None else torch.numel(p.data)) 58 | module.parameter_quantity = torch.from_numpy( 59 | np.array([parameter_quantity], dtype=np.long)) 60 | 61 | inference_memory = 1 62 | for s in output.size()[1:]: 63 | inference_memory *= s 64 | # memory += parameters_number # exclude parameter memory 65 | inference_memory = inference_memory * 4 / (1024 ** 2) # shown as MB unit 66 | module.inference_memory = torch.from_numpy( 67 | np.array([inference_memory], dtype=np.float32)) 68 | 69 | madd = compute_module_mac(module, input[0], output) 70 | module.MAdd = torch.from_numpy( 71 | np.array([madd], dtype=np.int64)) 72 | return output 73 | 74 | for module in self._model.modules(): 75 | if len(list(module.children())) == 0 and module.__class__ not in self._origin_call: 76 | self._origin_call[module.__class__] = module.__class__.__call__ 77 | module.__class__.__call__ = wrap_call 78 | 79 | def _hook_model(self): 80 | self._model.apply(self._register_buffer) 81 | self._sub_module_call_hook() 82 | 83 | @staticmethod 84 | def _retrieve_leaf_modules(model): 85 | leaf_modules = [] 86 | for name, m in model.named_modules(): 87 | if len(list(m.children())) == 0: 88 | leaf_modules.append((name, m)) 89 | return leaf_modules 90 | 91 | def retrieve_leaf_modules(self): 92 | return OrderedDict(self._retrieve_leaf_modules(self._model)) 93 | -------------------------------------------------------------------------------- /summary/model_summary.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import queue 4 | from collections import OrderedDict 5 | import pandas as pd 6 | import torch.nn as nn 7 | 8 | from summary.model_hook import CModelHook 9 | from summary.summary_tree import CSummaryTree, CSummaryNode 10 | 11 | pd.set_option('display.width', 1000) 12 | pd.set_option('display.max_rows', 10000) 13 | 14 | 15 | def get_parent_node(root_node, summary_node_name): 16 | assert isinstance(root_node, CSummaryNode) 17 | 18 | node = root_node 19 | names = summary_node_name.split('.') 20 | for i in range(len(names) - 1): 21 | node_name = '.'.join(names[0:i+1]) 22 | child_index = node.find_child_index(node_name) 23 | assert child_index != -1 24 | node = node.children[child_index] 25 | return node 26 | 27 | 28 | def convert_leaf_modules_to_summary_tree(leaf_modules): 29 | assert isinstance(leaf_modules, OrderedDict) 30 | 31 | create_index = 1 32 | root_node = CSummaryNode(name='root', parent=None) 33 | for leaf_module_name, leaf_module in leaf_modules.items(): 34 | names = leaf_module_name.split('.') 35 | for i in range(len(names)): 36 | create_index += 1 37 | summary_node_name = '.'.join(names[0:i+1]) 38 | parent_node = get_parent_node(root_node, summary_node_name) 39 | node = CSummaryNode(name=summary_node_name, parent=parent_node) 40 | parent_node.add_child(node) 41 | if i == len(names) - 1: # leaf module itself 42 | input_shape = leaf_module.input_shape.numpy().tolist() 43 | output_shape = leaf_module.output_shape.numpy().tolist() 44 | node.input_shape = input_shape 45 | node.output_shape = output_shape 46 | node.parameter_quantity = leaf_module.parameter_quantity.numpy()[0] 47 | node.inference_memory = leaf_module.inference_memory.numpy()[0] 48 | node.MAdd = leaf_module.MAdd.numpy()[0] 49 | node.duration = leaf_module.duration.numpy()[0] 50 | return CSummaryTree(root_node) 51 | 52 | 53 | def get_collected_summary_nodes(root_node, query_granularity): 54 | assert isinstance(root_node, CSummaryNode) 55 | 56 | collected_nodes = [] 57 | q = queue.Queue() 58 | q.put(root_node) 59 | while not q.empty(): 60 | node = q.get() 61 | for child in node.children: 62 | q.put(child) 63 | if node.depth == query_granularity: 64 | collected_nodes.append(node) 65 | if node.depth < query_granularity <= node.granularity: 66 | collected_nodes.append(node) 67 | collected_nodes = sorted(collected_nodes, key=lambda x: x.create_index) 68 | return collected_nodes 69 | 70 | 71 | def pretty_format(collected_nodes): 72 | data = list() 73 | for node in collected_nodes: 74 | name = node.name 75 | input_shape = ' '.join(['{:>3d}'] * len(node.input_shape)).format( 76 | *[e for e in node.input_shape]) 77 | output_shape = ' '.join(['{:>3d}'] * len(node.output_shape)).format( 78 | *[e for e in node.output_shape]) 79 | parameter_quantity = node.parameter_quantity 80 | inference_memory = node.inference_memory 81 | MAdd = node.MAdd 82 | duration = node.duration 83 | data.append([name, input_shape, output_shape, 84 | parameter_quantity, inference_memory, MAdd, duration]) 85 | df = pd.DataFrame(data) 86 | df.columns = ['module name', 'input shape', 'output shape', 87 | 'parameter quantity', 'inference memory(MB)', 88 | 'MAdd', 'duration'] 89 | df['duration percent'] = df['duration'] / df['duration'].sum() 90 | total_parameters_quantity = df['parameter quantity'].sum() 91 | total_memory = df['inference memory(MB)'].sum() 92 | total_operation_quantity = df['MAdd'].sum() 93 | del df['duration'] 94 | df = df.fillna(' ') 95 | df['inference memory(MB)'] = df['inference memory(MB)'].apply( 96 | lambda x: '{:.2f}MB'.format(x)) 97 | df['duration percent'] = df['duration percent'].apply(lambda x: '{:.2%}'.format(x)) 98 | df['MAdd'] = df['MAdd'].apply(lambda x: '{:,}'.format(x)) 99 | 100 | summary = str(df) + '\n' 101 | summary += "=" * len(str(df).split('\n')[0]) 102 | summary += '\n' 103 | summary += "total parameters quantity: {:,}\n".format(total_parameters_quantity) 104 | summary += "total memory: {:.2f}MB\n".format(total_memory) 105 | summary += "total MAdd: {:,}\n".format(total_operation_quantity) 106 | print(summary) 107 | return summary 108 | 109 | 110 | def model_summary(model, input_size, query_granularity=1): 111 | assert isinstance(model, nn.Module) 112 | assert isinstance(input_size, (list, tuple)) and len(input_size) == 3 113 | 114 | model_hook = CModelHook(model, input_size) 115 | leaf_modules = model_hook.retrieve_leaf_modules() 116 | summary_tree = convert_leaf_modules_to_summary_tree(leaf_modules) 117 | collected_nodes = summary_tree.get_collected_summary_nodes(query_granularity) 118 | summary = pretty_format(collected_nodes) 119 | return summary 120 | -------------------------------------------------------------------------------- /summary/module_mac.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | """ 3 | compute Multiply-Adds(MAdd) of each leaf module 4 | """ 5 | 6 | import torch.nn as nn 7 | 8 | 9 | def compute_Conv2d_mac(module, inp, out): 10 | assert isinstance(module, nn.Conv2d) 11 | assert len(inp.size()) == 4 and len(inp.size()) == len(out.size()) 12 | 13 | in_c = inp.size(1) 14 | k_h, k_w = module.kernel_size 15 | out_c, out_h, out_w = out.size()[1:] 16 | groups = module.groups 17 | 18 | # ops per output element 19 | kernel_mul = k_h * k_w * (in_c // groups) 20 | kernel_add = kernel_mul - 1 + (0 if module.bias is None else 1) 21 | 22 | kernel_mul_group = kernel_mul * out_h * out_w * (out_c // groups) 23 | kernel_add_group = kernel_add * out_h * out_w * (out_c // groups) 24 | 25 | total_mul = kernel_mul_group * groups 26 | total_add = kernel_add_group * groups 27 | 28 | # return total_mul + total_add 29 | return total_mul 30 | 31 | 32 | def compute_ConvTranspose2d_mac(module, inp, out): 33 | assert isinstance(module, nn.ConvTranspose2d) 34 | assert len(inp.size()) == 4 and len(inp.size()) == len(out.size()) 35 | 36 | in_c, in_h, in_w = inp.size()[1:] 37 | k_h, k_w = module.kernel_size 38 | out_c, out_h, out_w = out.size()[1:] 39 | groups = module.groups 40 | 41 | kernel_mul = k_h * k_w * (in_c // groups) 42 | kernel_add = kernel_mul - 1 + (0 if module.bias is None else 1) 43 | 44 | kernel_mul_group = kernel_mul * in_h * in_w * (out_c // groups) 45 | kernel_add_group = kernel_add * in_h * in_w * (out_c // groups) 46 | 47 | total_mul = kernel_mul_group * groups 48 | total_add = kernel_add_group * groups 49 | 50 | # return total_mul + total_add 51 | return total_mul 52 | 53 | 54 | def compute_BatchNorm2d_mac(module, inp, out): 55 | assert isinstance(module, nn.BatchNorm2d) 56 | assert len(inp.size()) == 4 and len(inp.size()) == len(out.size()) 57 | 58 | in_c, in_h, in_w = inp.size()[1:] 59 | 60 | # 1. sub mean 61 | # 2. div standard deviation 62 | # 3. mul alpha 63 | # 4. add beta 64 | return 4 * in_c * in_h * in_w 65 | 66 | 67 | def compute_MaxPool2d_mac(module, inp, out): 68 | assert isinstance(module, nn.MaxPool2d) 69 | assert len(inp.size()) == 4 and len(inp.size()) == len(out.size()) 70 | 71 | if isinstance(module.kernel_size, (tuple, list)): 72 | k_h, k_w = module.kernel_size 73 | else: 74 | k_h, k_w = module.kernel_size, module.kernel_size 75 | out_c, out_h, out_w = out.size()[1:] 76 | 77 | return (k_h * k_w - 1) * out_h * out_w * out_c 78 | 79 | 80 | def compute_AvgPool2d_mac(module, inp, out): 81 | assert isinstance(module, nn.AvgPool2d) 82 | assert len(inp.size()) == 4 and len(inp.size()) == len(out.size()) 83 | 84 | if isinstance(module.kernel_size, (tuple, list)): 85 | k_h, k_w = module.kernel_size 86 | else: 87 | k_h, k_w = module.kernel_size, module.kernel_size 88 | out_c, out_h, out_w = out.size()[1:] 89 | 90 | kernel_add = k_h * k_w - 1 91 | kernel_avg = 1 92 | 93 | return (kernel_add + kernel_avg) * (out_h * out_w) * out_c 94 | 95 | 96 | def compute_ReLU_mac(module, inp, out): 97 | assert isinstance(module, (nn.ReLU, nn.ReLU6)) 98 | 99 | count = 1 100 | for i in inp.size()[1:]: 101 | count *= i 102 | return count 103 | 104 | 105 | def compute_Softmax_mac(module, inp, out): 106 | assert isinstance(module, nn.Softmax) 107 | assert len(inp.size()) > 1 108 | 109 | count = 1 110 | for s in inp.size()[1:]: 111 | count *= s 112 | exp = count 113 | add = count - 1 114 | div = count 115 | return exp + add + div 116 | 117 | 118 | def compute_Linear_mac(module, inp, out): 119 | assert isinstance(module, nn.Linear) 120 | assert len(inp.size()) == 2 and len(out.size()) == 2 121 | 122 | num_in_features = inp.size(1) 123 | num_out_features = out.size(1) 124 | 125 | mul = num_in_features 126 | add = num_in_features - 1 127 | # return num_out_features * (mul + add) 128 | return num_out_features * mul 129 | 130 | 131 | def compute_module_mac(module, inp, out): 132 | if isinstance(module, nn.Conv2d): 133 | return compute_Conv2d_mac(module, inp, out) 134 | elif isinstance(module, nn.ConvTranspose2d): 135 | return compute_ConvTranspose2d_mac(module, inp, out) 136 | # elif isinstance(module, nn.BatchNorm2d): 137 | # return compute_BatchNorm2d_mac(module, inp, out) 138 | # elif isinstance(module, nn.MaxPool2d): 139 | # return compute_MaxPool2d_mac(module, inp, out) 140 | # elif isinstance(module, nn.AvgPool2d): 141 | # return compute_AvgPool2d_mac(module, inp, out) 142 | # elif isinstance(module, (nn.ReLU, nn.ReLU6)): 143 | # return compute_ReLU_mac(module, inp, out) 144 | # elif isinstance(module, nn.Softmax): 145 | # return compute_Softmax_mac(module, inp, out) 146 | elif isinstance(module, nn.Linear): 147 | return compute_Linear_mac(module, inp, out) 148 | else: 149 | return 0 150 | -------------------------------------------------------------------------------- /summary/summary_tree.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import queue 4 | 5 | 6 | class CSummaryTree(object): 7 | def __init__(self, root_node): 8 | assert isinstance(root_node, CSummaryNode) 9 | 10 | self.root_node = root_node 11 | 12 | def get_same_level_max_node_depth(self, query_node): 13 | if query_node.name == self.root_node.name: 14 | return 0 15 | same_level_depth = max([child.depth for child in query_node.parent.children]) 16 | return same_level_depth 17 | 18 | def update_summary_nodes_granularity(self): 19 | q = queue.Queue() 20 | q.put(self.root_node) 21 | while not q.empty(): 22 | node = q.get() 23 | node.granularity = self.get_same_level_max_node_depth(node) 24 | for child in node.children: 25 | q.put(child) 26 | 27 | def get_collected_summary_nodes(self, query_granularity): 28 | self.update_summary_nodes_granularity() 29 | 30 | collected_nodes = [] 31 | stack = list() 32 | stack.append(self.root_node) 33 | while len(stack) > 0: 34 | node = stack.pop() 35 | for child in reversed(node.children): 36 | stack.append(child) 37 | if node.depth == query_granularity: 38 | collected_nodes.append(node) 39 | if node.depth < query_granularity <= node.granularity: 40 | collected_nodes.append(node) 41 | return collected_nodes 42 | 43 | 44 | class CSummaryNode(object): 45 | def __init__(self, name=str(), parent=None): 46 | self._name = name 47 | self._input_shape = None 48 | self._output_shape = None 49 | self._parameter_quantity = 0 50 | self._inference_memory = 0 51 | self._MAdd = 0 52 | self._duration = 0 53 | self._duration_percent = 0 54 | 55 | self._granularity = 1 56 | self._depth = 1 57 | self.parent = parent 58 | self.children = list() 59 | 60 | @property 61 | def name(self): 62 | return self._name 63 | 64 | @name.setter 65 | def name(self, name): 66 | self._name = name 67 | 68 | @property 69 | def granularity(self): 70 | return self._granularity 71 | 72 | @granularity.setter 73 | def granularity(self, g): 74 | self._granularity = g 75 | 76 | @property 77 | def depth(self): 78 | d = self._depth 79 | if len(self.children) > 0: 80 | d += max([child.depth for child in self.children]) 81 | return d 82 | 83 | @property 84 | def input_shape(self): 85 | if len(self.children) == 0: # leaf 86 | return self._input_shape 87 | else: 88 | return self.children[0].input_shape 89 | 90 | @input_shape.setter 91 | def input_shape(self, input_shape): 92 | assert isinstance(input_shape, (list, tuple)) 93 | self._input_shape = input_shape 94 | 95 | @property 96 | def output_shape(self): 97 | if len(self.children) == 0: # leaf 98 | return self._output_shape 99 | else: 100 | return self.children[-1].output_shape 101 | 102 | @output_shape.setter 103 | def output_shape(self, output_shape): 104 | assert isinstance(output_shape, (list, tuple)) 105 | self._output_shape = output_shape 106 | 107 | @property 108 | def parameter_quantity(self): 109 | # return self.parameters_quantity 110 | total_parameter_quantity = self._parameter_quantity 111 | for child in self.children: 112 | total_parameter_quantity += child.parameter_quantity 113 | return total_parameter_quantity 114 | 115 | @parameter_quantity.setter 116 | def parameter_quantity(self, parameter_quantity): 117 | assert parameter_quantity >= 0 118 | self._parameter_quantity = parameter_quantity 119 | 120 | @property 121 | def inference_memory(self): 122 | total_inference_memory = self._inference_memory 123 | for child in self.children: 124 | total_inference_memory += child.inference_memory 125 | return total_inference_memory 126 | 127 | @inference_memory.setter 128 | def inference_memory(self, inference_memory): 129 | self._inference_memory = inference_memory 130 | 131 | @property 132 | def MAdd(self): 133 | total_MAdd = self._MAdd 134 | for child in self.children: 135 | total_MAdd += child.MAdd 136 | return total_MAdd 137 | 138 | @MAdd.setter 139 | def MAdd(self, MAdd): 140 | self._MAdd = MAdd 141 | 142 | @property 143 | def duration(self): 144 | total_duration = self._duration 145 | for child in self.children: 146 | total_duration += child.duration 147 | return total_duration 148 | 149 | @duration.setter 150 | def duration(self, duration): 151 | self._duration = duration 152 | 153 | def find_child_index(self, child_name): 154 | assert isinstance(child_name, str) 155 | 156 | index = -1 157 | for i in range(len(self.children)): 158 | if child_name == self.children[i].name: 159 | index = i 160 | return index 161 | 162 | def add_child(self, node): 163 | assert isinstance(node, CSummaryNode) 164 | 165 | if self.find_child_index(node.name) == -1: # not exist 166 | self.children.append(node) 167 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.optim as optim 4 | from torch.optim import lr_scheduler 5 | from torch.autograd import Variable 6 | import torchvision 7 | from torchvision import datasets, models, transforms 8 | import time 9 | import os 10 | from PIL import Image 11 | import sys 12 | import torch.nn.functional as F 13 | from shufflenetv2 import ShuffleNetV2 14 | import scipy.io as scio 15 | import cv2 16 | 17 | #config 18 | matFile = 'pScores.mat' 19 | fiiqaWeight = './model/97_160_2.pth' 20 | detectFace = './model/haarcascade_frontalface_default.xml' 21 | imagePath = './image/test.jpg' 22 | facePath = './image/crop/test_face.jpg' 23 | inputSize = 160 24 | 25 | #crop face from img 26 | faceCascade = cv2.CascadeClassifier(detectFace) 27 | image = cv2.imread(imagePath) 28 | faces = faceCascade.detectMultiScale( 29 | image, 30 | scaleFactor=1.1, 31 | minNeighbors=5, 32 | minSize=(10, 10) 33 | ) 34 | for (x, y, w, h) in faces: 35 | cv2.imwrite('./image/crop/' + 'test_face.jpg',image[y:y+h,x:x+w]) 36 | cv2.waitKey(0) 37 | 38 | #transfer img to tensor 39 | dataTransforms = transforms.Compose([ 40 | transforms.Resize(inputSize), 41 | transforms.ToTensor(), 42 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 43 | ]) 44 | 45 | #load net 46 | net = ShuffleNetV2(inputSize) 47 | checkpoint = torch.load(fiiqaWeight) 48 | net.load_state_dict(checkpoint['net']) 49 | net.eval() 50 | 51 | #load face and get expect num 52 | face = Image.open(facePath) 53 | imgblob = dataTransforms(face).unsqueeze(0) 54 | imgblob = Variable(imgblob) 55 | torch.no_grad() 56 | predict = F.softmax(net(imgblob),dim=1) 57 | expect = torch.sum(Variable(torch.arange(0,200)).float()*predict, 1) 58 | expect = int(expect) 59 | 60 | #load matFile and get score 61 | data = scio.loadmat(matFile) 62 | scores = data['pScores'] 63 | score = scores[:,expect] 64 | 65 | print('expect: %d' % expect) 66 | print('score: %.3f' % score) 67 | -------------------------------------------------------------------------------- /test/__pycache__/shufflenetv2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/__pycache__/shufflenetv2.cpython-36.pyc -------------------------------------------------------------------------------- /test/image/crop/00921_960627_fa_illu_cafe-inside-2_extracted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/crop/00921_960627_fa_illu_cafe-inside-2_extracted.jpg -------------------------------------------------------------------------------- /test/image/crop/00921_960627_fa_illu_cafe-inside-3_extracted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/crop/00921_960627_fa_illu_cafe-inside-3_extracted.jpg -------------------------------------------------------------------------------- /test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-1_extracted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-1_extracted.jpg -------------------------------------------------------------------------------- /test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-2_extracted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-2_extracted.jpg -------------------------------------------------------------------------------- /test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-3_extracted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/crop/00921_960627_fa_illu_cafe-sunshade-2pm-3_extracted.jpg -------------------------------------------------------------------------------- /test/image/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/test.jpg -------------------------------------------------------------------------------- /test/image/test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/test1.jpg -------------------------------------------------------------------------------- /test/image/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/image/test2.jpg -------------------------------------------------------------------------------- /test/model/97_160_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/model/97_160_2.pth -------------------------------------------------------------------------------- /test/pScores.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test/pScores.mat -------------------------------------------------------------------------------- /test/shufflenetv2.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Variable 5 | from collections import OrderedDict 6 | from torch.nn import init 7 | import math 8 | 9 | 10 | def conv_bn(inp, oup, stride): 11 | return nn.Sequential( 12 | nn.Conv2d(inp, oup, 3, stride, 1, bias=False), 13 | nn.BatchNorm2d(oup), 14 | nn.ReLU(inplace=True) 15 | ) 16 | 17 | 18 | def conv_1x1_bn(inp, oup): 19 | return nn.Sequential( 20 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 21 | nn.BatchNorm2d(oup), 22 | nn.ReLU(inplace=True) 23 | ) 24 | 25 | 26 | def channel_shuffle(x, groups): 27 | batchsize, num_channels, height, width = x.data.size() 28 | 29 | channels_per_group = num_channels // groups 30 | 31 | # reshape 32 | x = x.view(batchsize, groups, channels_per_group, height, width) 33 | 34 | x = torch.transpose(x, 1, 2).contiguous() 35 | 36 | # flatten 37 | x = x.view(batchsize, -1, height, width) 38 | 39 | return x 40 | 41 | 42 | class InvertedResidual(nn.Module): 43 | def __init__(self, inp, oup, stride, benchmodel): 44 | super(InvertedResidual, self).__init__() 45 | self.benchmodel = benchmodel 46 | self.stride = stride 47 | assert stride in [1, 2] 48 | 49 | oup_inc = oup // 2 50 | 51 | if self.benchmodel == 1: 52 | # assert inp == oup_inc 53 | self.banch2 = nn.Sequential( 54 | # pw 55 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 56 | nn.BatchNorm2d(oup_inc), 57 | nn.ReLU(inplace=True), 58 | # dw 59 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 60 | 1, groups=oup_inc, bias=False), 61 | nn.BatchNorm2d(oup_inc), 62 | # pw-linear 63 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 64 | nn.BatchNorm2d(oup_inc), 65 | nn.ReLU(inplace=True), 66 | ) 67 | else: 68 | self.banch1 = nn.Sequential( 69 | # dw 70 | nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), 71 | nn.BatchNorm2d(inp), 72 | # pw-linear 73 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 74 | nn.BatchNorm2d(oup_inc), 75 | nn.ReLU(inplace=True), 76 | ) 77 | 78 | self.banch2 = nn.Sequential( 79 | # pw 80 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 81 | nn.BatchNorm2d(oup_inc), 82 | nn.ReLU(inplace=True), 83 | # dw 84 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 85 | 1, groups=oup_inc, bias=False), 86 | nn.BatchNorm2d(oup_inc), 87 | # pw-linear 88 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 89 | nn.BatchNorm2d(oup_inc), 90 | nn.ReLU(inplace=True), 91 | ) 92 | 93 | @staticmethod 94 | def _concat(x, out): 95 | # concatenate along channel axis 96 | return torch.cat((x, out), 1) 97 | 98 | def forward(self, x): 99 | if 1 == self.benchmodel: 100 | # x1 = x[:, :(x.shape[1] // 2), :, :] 101 | # x2 = x[:, (x.shape[1] // 2):, :, :] 102 | x1, x2 = torch.split(x, x.shape[1] // 2, dim=1) 103 | out = self._concat(x1, self.banch2(x2)) 104 | elif 2 == self.benchmodel: 105 | out = self._concat(self.banch1(x), self.banch2(x)) 106 | 107 | return channel_shuffle(out, 2) 108 | 109 | 110 | class ShuffleNetV2(nn.Module): 111 | def __init__(self, input_size, n_class=200, width_mult=1): #1,0 112 | super(ShuffleNetV2, self).__init__() 113 | 114 | assert input_size % 32 == 0 115 | 116 | self.stage_repeats = [4, 8, 4] 117 | # index 0 is invalid and should never be called. 118 | # only used for indexing convenience. 119 | if width_mult == 0.5: 120 | self.stage_out_channels = [-1, 24, 48, 96, 192, 192] #175 121 | elif width_mult == 1.0: 122 | self.stage_out_channels = [-1, 24, 116, 232, 464, 1024] # 1024 123 | elif width_mult == 1.5: 124 | self.stage_out_channels = [-1, 24, 176, 352, 704, 1024] 125 | elif width_mult == 2.0: 126 | self.stage_out_channels = [-1, 24, 224, 488, 976, 2048] 127 | else: 128 | raise ValueError( 129 | """width_mult = {} is not supported""".format(width_mult)) 130 | 131 | # building first layer 132 | input_channel = self.stage_out_channels[1] 133 | self.conv1 = conv_bn(3, input_channel, 2) 134 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 135 | 136 | self.features = [] 137 | # building inverted residual blocks 138 | for idxstage in range(len(self.stage_repeats)): 139 | numrepeat = self.stage_repeats[idxstage] 140 | output_channel = self.stage_out_channels[idxstage + 2] 141 | for i in range(numrepeat): 142 | if i == 0: 143 | # inp, oup, stride, benchmodel): 144 | self.features.append(InvertedResidual( 145 | input_channel, output_channel, 2, 2)) 146 | else: 147 | self.features.append(InvertedResidual( 148 | input_channel, output_channel, 1, 1)) 149 | input_channel = output_channel 150 | 151 | # make it nn.Sequential 152 | self.features = nn.Sequential(*self.features) 153 | 154 | # building last several layers 155 | self.conv_last = conv_1x1_bn( 156 | input_channel, self.stage_out_channels[-1]) 157 | self.globalpool = nn.Sequential(nn.AvgPool2d(int(input_size / 32))) 158 | 159 | # building classifier 160 | self.classifier = nn.Sequential( 161 | nn.Linear(self.stage_out_channels[-1], n_class)) 162 | 163 | def forward(self, x): 164 | x = self.conv1(x) 165 | x = self.maxpool(x) 166 | x = self.features(x) 167 | x = self.conv_last(x) 168 | x = self.globalpool(x) 169 | x = x.view(-1, self.stage_out_channels[-1]) 170 | x = self.classifier(x) 171 | return x 172 | 173 | 174 | def shufflenetv2(width_mult=1.): 175 | model = ShuffleNetV2(width_mult=width_mult) 176 | return model 177 | 178 | 179 | if __name__ == "__main__": 180 | """Testing 181 | """ 182 | model = ShuffleNetV2() 183 | print(model) 184 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.optim as optim 4 | from torch.optim import lr_scheduler 5 | from torch.autograd import Variable 6 | import torchvision 7 | from torchvision import datasets, models, transforms 8 | import time 9 | import os 10 | from PIL import Image 11 | import sys 12 | import torch.nn.functional as F 13 | from shufflenetv2 import ShuffleNetV2 14 | import scipy.io as scio 15 | import cv2 16 | 17 | #config 18 | matFile = 'pScores.mat' 19 | fiiqaWeight = './model/97_160_2.pth' 20 | detectFace = './model/haarcascade_frontalface_default.xml' 21 | imagePath = './image/00921_960627_fa_illu_cafe-sunshade-2pm-2_extracted.jpg' 22 | facePath = './image/crop/test_face.jpg' 23 | inputSize = 160 24 | 25 | #crop face from img 26 | faceCascade = cv2.CascadeClassifier(detectFace) 27 | image = cv2.imread(imagePath) 28 | faces = faceCascade.detectMultiScale( 29 | image, 30 | scaleFactor=1.1, 31 | minNeighbors=5, 32 | minSize=(10, 10) 33 | ) 34 | for (x, y, w, h) in faces: 35 | cv2.imwrite('./image/crop/' + 'test_face.jpg',image[y:y+h,x:x+w]) 36 | cv2.waitKey(0) 37 | 38 | #transfer img to tensor 39 | dataTransforms = transforms.Compose([ 40 | transforms.Resize(inputSize), 41 | transforms.ToTensor(), 42 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 43 | ]) 44 | 45 | #load net 46 | net = ShuffleNetV2(inputSize) 47 | checkpoint = torch.load(fiiqaWeight) 48 | net.load_state_dict(checkpoint['net']) 49 | net.eval() 50 | 51 | #load face and get expect num 52 | face = Image.open(facePath) 53 | imgblob = dataTransforms(face).unsqueeze(0) 54 | #imgblob = Variable(imgblob) 55 | torch.no_grad() 56 | predict = F.softmax(net(imgblob),dim=1) 57 | expect = torch.sum(Variable(torch.arange(0,200)).float()*predict, 1) 58 | print('expect: %.4f' % expect) 59 | expect = int(expect) 60 | 61 | #load matFile and get score 62 | data = scio.loadmat(matFile) 63 | scores = data['pScores'] 64 | score = scores[:,expect] 65 | 66 | print('expect: %d' % expect) 67 | print('score: %.3f' % score) 68 | -------------------------------------------------------------------------------- /test/test_without_crop.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.optim as optim 4 | from torch.optim import lr_scheduler 5 | from torch.autograd import Variable 6 | import torchvision 7 | from torchvision import datasets, models, transforms 8 | import time 9 | import os 10 | from PIL import Image 11 | import sys 12 | import torch.nn.functional as F 13 | from shufflenetv2 import ShuffleNetV2 14 | import scipy.io as scio 15 | import cv2 16 | 17 | #config 18 | matFile = 'pScores.mat' 19 | fiiqaWeight = './model/97_160_2.pth' 20 | detectFace = './model/haarcascade_frontalface_default.xml' 21 | imagePath = './image/00921_960627_fa_illu_cafe-sunshade-2pm-2_extracted.jpg' 22 | facePath = './image/crop/00921_960627_fa_illu_cafe-inside-2_extracted.jpg' 23 | inputSize = 160 24 | 25 | ''' 26 | #crop face from img 27 | faceCascade = cv2.CascadeClassifier(detectFace) 28 | image = cv2.imread(imagePath) 29 | faces = faceCascade.detectMultiScale( 30 | image, 31 | scaleFactor=1.1, 32 | minNeighbors=5, 33 | minSize=(10, 10) 34 | ) 35 | for (x, y, w, h) in faces: 36 | cv2.imwrite('./image/crop/' + 'test_face.jpg',image[y:y+h,x:x+w]) 37 | cv2.waitKey(0) 38 | ''' 39 | 40 | #transfer img to tensor 41 | dataTransforms = transforms.Compose([ 42 | transforms.Resize(inputSize), 43 | transforms.ToTensor(), 44 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 45 | ]) 46 | 47 | #load net 48 | net = ShuffleNetV2(inputSize) 49 | checkpoint = torch.load(fiiqaWeight) 50 | net.load_state_dict(checkpoint['net']) 51 | net.eval() 52 | 53 | #load face and get expect num 54 | face = Image.open(facePath) 55 | imgblob = dataTransforms(face).unsqueeze(0) 56 | imgblob = Variable(imgblob) 57 | torch.no_grad() 58 | predict = F.softmax(net(imgblob),dim=1) 59 | expect = torch.sum(Variable(torch.arange(0,200)).float()*predict, 1) 60 | print('expect: %.4f' % expect) 61 | expect = int(expect) 62 | 63 | #load matFile and get score 64 | data = scio.loadmat(matFile) 65 | scores = data['pScores'] 66 | score = scores[:,expect] 67 | 68 | print('expect: %d' % expect) 69 | print('score: %.3f' % score) 70 | -------------------------------------------------------------------------------- /test_convert_to_caffe/__pycache__/shufflenetv2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/__pycache__/shufflenetv2.cpython-36.pyc -------------------------------------------------------------------------------- /test_convert_to_caffe/httpClient.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | 4 | if __name__ == "__main__": 5 | restUri = 'http://172.16.16.169:8081/facedetect' 6 | PostParam = './image/test2.jpg' 7 | DATA = PostParam.encode('utf8') 8 | req = urllib.request.Request(url = restUri, data=DATA, method='POST') 9 | req.add_header('Content-type', 'application/form-data') 10 | r = urllib.request.urlopen(req).read() 11 | print(r.decode('utf8')) 12 | org_obj = json.loads(r.decode('utf8')) 13 | print(org_obj['token']) -------------------------------------------------------------------------------- /test_convert_to_caffe/image/crop/test_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/image/crop/test_face.jpg -------------------------------------------------------------------------------- /test_convert_to_caffe/image/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/image/test.jpg -------------------------------------------------------------------------------- /test_convert_to_caffe/image/test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/image/test1.jpg -------------------------------------------------------------------------------- /test_convert_to_caffe/image/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/image/test2.jpg -------------------------------------------------------------------------------- /test_convert_to_caffe/model/97_160_2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/model/97_160_2.pth -------------------------------------------------------------------------------- /test_convert_to_caffe/model/fiiqa_shufflenetv2_1.0x.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/model/fiiqa_shufflenetv2_1.0x.caffemodel -------------------------------------------------------------------------------- /test_convert_to_caffe/model/fiiqa_shufflenetv2_1.0x.prototxt: -------------------------------------------------------------------------------- 1 | name: "shufflenetv2_1.0x" 2 | layer { 3 | name: "data1" 4 | type: "Input" 5 | top: "data1" 6 | input_param { 7 | shape { 8 | dim: 1 9 | dim: 3 10 | dim: 160 11 | dim: 160 12 | } 13 | } 14 | } 15 | layer { 16 | name: "conv1" 17 | type: "Convolution" 18 | bottom: "data1" 19 | top: "conv1" 20 | convolution_param { 21 | num_output: 24 22 | bias_term: false 23 | pad: 1 24 | kernel_size: 3 25 | group: 1 26 | stride: 2 27 | weight_filler { 28 | type: "xavier" 29 | } 30 | dilation: 1 31 | } 32 | } 33 | layer { 34 | name: "batch_norm1" 35 | type: "BatchNorm" 36 | bottom: "conv1" 37 | top: "batch_norm1" 38 | batch_norm_param { 39 | use_global_stats: true 40 | eps: 9.999999747378752e-06 41 | } 42 | } 43 | layer { 44 | name: "bn_scale1" 45 | type: "Scale" 46 | bottom: "batch_norm1" 47 | top: "batch_norm1" 48 | scale_param { 49 | bias_term: true 50 | } 51 | } 52 | layer { 53 | name: "relu1" 54 | type: "ReLU" 55 | bottom: "batch_norm1" 56 | top: "relu1" 57 | } 58 | layer { 59 | name: "max_pool1" 60 | type: "Pooling" 61 | bottom: "relu1" 62 | top: "max_pool1" 63 | pooling_param { 64 | pool: MAX 65 | kernel_size: 3 66 | stride: 2 67 | pad: 1 68 | round_mode: FLOOR 69 | } 70 | } 71 | layer { 72 | name: "conv2" 73 | type: "ConvolutionDepthwise" 74 | bottom: "max_pool1" 75 | top: "conv2" 76 | convolution_param { 77 | num_output: 24 78 | bias_term: false 79 | pad: 1 80 | kernel_size: 3 81 | stride: 2 82 | weight_filler { 83 | type: "xavier" 84 | } 85 | dilation: 1 86 | } 87 | } 88 | layer { 89 | name: "batch_norm2" 90 | type: "BatchNorm" 91 | bottom: "conv2" 92 | top: "batch_norm2" 93 | batch_norm_param { 94 | use_global_stats: true 95 | eps: 9.999999747378752e-06 96 | } 97 | } 98 | layer { 99 | name: "bn_scale2" 100 | type: "Scale" 101 | bottom: "batch_norm2" 102 | top: "batch_norm2" 103 | scale_param { 104 | bias_term: true 105 | } 106 | } 107 | layer { 108 | name: "conv3" 109 | type: "Convolution" 110 | bottom: "batch_norm2" 111 | top: "conv3" 112 | convolution_param { 113 | num_output: 58 114 | bias_term: false 115 | pad: 0 116 | kernel_size: 1 117 | group: 1 118 | stride: 1 119 | weight_filler { 120 | type: "xavier" 121 | } 122 | dilation: 1 123 | } 124 | } 125 | layer { 126 | name: "batch_norm3" 127 | type: "BatchNorm" 128 | bottom: "conv3" 129 | top: "batch_norm3" 130 | batch_norm_param { 131 | use_global_stats: true 132 | eps: 9.999999747378752e-06 133 | } 134 | } 135 | layer { 136 | name: "bn_scale3" 137 | type: "Scale" 138 | bottom: "batch_norm3" 139 | top: "batch_norm3" 140 | scale_param { 141 | bias_term: true 142 | } 143 | } 144 | layer { 145 | name: "relu2" 146 | type: "ReLU" 147 | bottom: "batch_norm3" 148 | top: "relu2" 149 | } 150 | layer { 151 | name: "conv4" 152 | type: "Convolution" 153 | bottom: "max_pool1" 154 | top: "conv4" 155 | convolution_param { 156 | num_output: 58 157 | bias_term: false 158 | pad: 0 159 | kernel_size: 1 160 | group: 1 161 | stride: 1 162 | weight_filler { 163 | type: "xavier" 164 | } 165 | dilation: 1 166 | } 167 | } 168 | layer { 169 | name: "batch_norm4" 170 | type: "BatchNorm" 171 | bottom: "conv4" 172 | top: "batch_norm4" 173 | batch_norm_param { 174 | use_global_stats: true 175 | eps: 9.999999747378752e-06 176 | } 177 | } 178 | layer { 179 | name: "bn_scale4" 180 | type: "Scale" 181 | bottom: "batch_norm4" 182 | top: "batch_norm4" 183 | scale_param { 184 | bias_term: true 185 | } 186 | } 187 | layer { 188 | name: "relu3" 189 | type: "ReLU" 190 | bottom: "batch_norm4" 191 | top: "relu3" 192 | } 193 | layer { 194 | name: "conv5" 195 | type: "ConvolutionDepthwise" 196 | bottom: "relu3" 197 | top: "conv5" 198 | convolution_param { 199 | num_output: 58 200 | bias_term: false 201 | pad: 1 202 | kernel_size: 3 203 | stride: 2 204 | weight_filler { 205 | type: "xavier" 206 | } 207 | dilation: 1 208 | } 209 | } 210 | layer { 211 | name: "batch_norm5" 212 | type: "BatchNorm" 213 | bottom: "conv5" 214 | top: "batch_norm5" 215 | batch_norm_param { 216 | use_global_stats: true 217 | eps: 9.999999747378752e-06 218 | } 219 | } 220 | layer { 221 | name: "bn_scale5" 222 | type: "Scale" 223 | bottom: "batch_norm5" 224 | top: "batch_norm5" 225 | scale_param { 226 | bias_term: true 227 | } 228 | } 229 | layer { 230 | name: "conv6" 231 | type: "Convolution" 232 | bottom: "batch_norm5" 233 | top: "conv6" 234 | convolution_param { 235 | num_output: 58 236 | bias_term: false 237 | pad: 0 238 | kernel_size: 1 239 | group: 1 240 | stride: 1 241 | weight_filler { 242 | type: "xavier" 243 | } 244 | dilation: 1 245 | } 246 | } 247 | layer { 248 | name: "batch_norm6" 249 | type: "BatchNorm" 250 | bottom: "conv6" 251 | top: "batch_norm6" 252 | batch_norm_param { 253 | use_global_stats: true 254 | eps: 9.999999747378752e-06 255 | } 256 | } 257 | layer { 258 | name: "bn_scale6" 259 | type: "Scale" 260 | bottom: "batch_norm6" 261 | top: "batch_norm6" 262 | scale_param { 263 | bias_term: true 264 | } 265 | } 266 | layer { 267 | name: "relu4" 268 | type: "ReLU" 269 | bottom: "batch_norm6" 270 | top: "relu4" 271 | } 272 | layer { 273 | name: "concat1" 274 | type: "Concat" 275 | bottom: "relu2" 276 | bottom: "relu4" 277 | top: "concat1" 278 | concat_param { 279 | axis: 1 280 | } 281 | } 282 | layer { 283 | name: "shuffle_channel1" 284 | type: "ShuffleChannel" 285 | bottom: "concat1" 286 | top: "shuffle_channel1" 287 | shuffle_channel_param { 288 | group: 2 289 | } 290 | } 291 | layer { 292 | name: "split1" 293 | type: "Slice" 294 | bottom: "shuffle_channel1" 295 | top: "split1" 296 | top: "split2" 297 | slice_param { 298 | slice_point: 58 299 | axis: 1 300 | } 301 | } 302 | layer { 303 | name: "conv7" 304 | type: "Convolution" 305 | bottom: "split2" 306 | top: "conv7" 307 | convolution_param { 308 | num_output: 58 309 | bias_term: false 310 | pad: 0 311 | kernel_size: 1 312 | group: 1 313 | stride: 1 314 | weight_filler { 315 | type: "xavier" 316 | } 317 | dilation: 1 318 | } 319 | } 320 | layer { 321 | name: "batch_norm7" 322 | type: "BatchNorm" 323 | bottom: "conv7" 324 | top: "batch_norm7" 325 | batch_norm_param { 326 | use_global_stats: true 327 | eps: 9.999999747378752e-06 328 | } 329 | } 330 | layer { 331 | name: "bn_scale7" 332 | type: "Scale" 333 | bottom: "batch_norm7" 334 | top: "batch_norm7" 335 | scale_param { 336 | bias_term: true 337 | } 338 | } 339 | layer { 340 | name: "relu5" 341 | type: "ReLU" 342 | bottom: "batch_norm7" 343 | top: "relu5" 344 | } 345 | layer { 346 | name: "conv8" 347 | type: "ConvolutionDepthwise" 348 | bottom: "relu5" 349 | top: "conv8" 350 | convolution_param { 351 | num_output: 58 352 | bias_term: false 353 | pad: 1 354 | kernel_size: 3 355 | stride: 1 356 | weight_filler { 357 | type: "xavier" 358 | } 359 | dilation: 1 360 | } 361 | } 362 | layer { 363 | name: "batch_norm8" 364 | type: "BatchNorm" 365 | bottom: "conv8" 366 | top: "batch_norm8" 367 | batch_norm_param { 368 | use_global_stats: true 369 | eps: 9.999999747378752e-06 370 | } 371 | } 372 | layer { 373 | name: "bn_scale8" 374 | type: "Scale" 375 | bottom: "batch_norm8" 376 | top: "batch_norm8" 377 | scale_param { 378 | bias_term: true 379 | } 380 | } 381 | layer { 382 | name: "conv9" 383 | type: "Convolution" 384 | bottom: "batch_norm8" 385 | top: "conv9" 386 | convolution_param { 387 | num_output: 58 388 | bias_term: false 389 | pad: 0 390 | kernel_size: 1 391 | group: 1 392 | stride: 1 393 | weight_filler { 394 | type: "xavier" 395 | } 396 | dilation: 1 397 | } 398 | } 399 | layer { 400 | name: "batch_norm9" 401 | type: "BatchNorm" 402 | bottom: "conv9" 403 | top: "batch_norm9" 404 | batch_norm_param { 405 | use_global_stats: true 406 | eps: 9.999999747378752e-06 407 | } 408 | } 409 | layer { 410 | name: "bn_scale9" 411 | type: "Scale" 412 | bottom: "batch_norm9" 413 | top: "batch_norm9" 414 | scale_param { 415 | bias_term: true 416 | } 417 | } 418 | layer { 419 | name: "relu6" 420 | type: "ReLU" 421 | bottom: "batch_norm9" 422 | top: "relu6" 423 | } 424 | layer { 425 | name: "concat2" 426 | type: "Concat" 427 | bottom: "split1" 428 | bottom: "relu6" 429 | top: "concat2" 430 | concat_param { 431 | axis: 1 432 | } 433 | } 434 | layer { 435 | name: "shuffle_channel2" 436 | type: "ShuffleChannel" 437 | bottom: "concat2" 438 | top: "shuffle_channel2" 439 | shuffle_channel_param { 440 | group: 2 441 | } 442 | } 443 | layer { 444 | name: "split2" 445 | type: "Slice" 446 | bottom: "shuffle_channel2" 447 | top: "split3" 448 | top: "split4" 449 | slice_param { 450 | slice_point: 58 451 | axis: 1 452 | } 453 | } 454 | layer { 455 | name: "conv10" 456 | type: "Convolution" 457 | bottom: "split4" 458 | top: "conv10" 459 | convolution_param { 460 | num_output: 58 461 | bias_term: false 462 | pad: 0 463 | kernel_size: 1 464 | group: 1 465 | stride: 1 466 | weight_filler { 467 | type: "xavier" 468 | } 469 | dilation: 1 470 | } 471 | } 472 | layer { 473 | name: "batch_norm10" 474 | type: "BatchNorm" 475 | bottom: "conv10" 476 | top: "batch_norm10" 477 | batch_norm_param { 478 | use_global_stats: true 479 | eps: 9.999999747378752e-06 480 | } 481 | } 482 | layer { 483 | name: "bn_scale10" 484 | type: "Scale" 485 | bottom: "batch_norm10" 486 | top: "batch_norm10" 487 | scale_param { 488 | bias_term: true 489 | } 490 | } 491 | layer { 492 | name: "relu7" 493 | type: "ReLU" 494 | bottom: "batch_norm10" 495 | top: "relu7" 496 | } 497 | layer { 498 | name: "conv11" 499 | type: "ConvolutionDepthwise" 500 | bottom: "relu7" 501 | top: "conv11" 502 | convolution_param { 503 | num_output: 58 504 | bias_term: false 505 | pad: 1 506 | kernel_size: 3 507 | stride: 1 508 | weight_filler { 509 | type: "xavier" 510 | } 511 | dilation: 1 512 | } 513 | } 514 | layer { 515 | name: "batch_norm11" 516 | type: "BatchNorm" 517 | bottom: "conv11" 518 | top: "batch_norm11" 519 | batch_norm_param { 520 | use_global_stats: true 521 | eps: 9.999999747378752e-06 522 | } 523 | } 524 | layer { 525 | name: "bn_scale11" 526 | type: "Scale" 527 | bottom: "batch_norm11" 528 | top: "batch_norm11" 529 | scale_param { 530 | bias_term: true 531 | } 532 | } 533 | layer { 534 | name: "conv12" 535 | type: "Convolution" 536 | bottom: "batch_norm11" 537 | top: "conv12" 538 | convolution_param { 539 | num_output: 58 540 | bias_term: false 541 | pad: 0 542 | kernel_size: 1 543 | group: 1 544 | stride: 1 545 | weight_filler { 546 | type: "xavier" 547 | } 548 | dilation: 1 549 | } 550 | } 551 | layer { 552 | name: "batch_norm12" 553 | type: "BatchNorm" 554 | bottom: "conv12" 555 | top: "batch_norm12" 556 | batch_norm_param { 557 | use_global_stats: true 558 | eps: 9.999999747378752e-06 559 | } 560 | } 561 | layer { 562 | name: "bn_scale12" 563 | type: "Scale" 564 | bottom: "batch_norm12" 565 | top: "batch_norm12" 566 | scale_param { 567 | bias_term: true 568 | } 569 | } 570 | layer { 571 | name: "relu8" 572 | type: "ReLU" 573 | bottom: "batch_norm12" 574 | top: "relu8" 575 | } 576 | layer { 577 | name: "concat3" 578 | type: "Concat" 579 | bottom: "split3" 580 | bottom: "relu8" 581 | top: "concat3" 582 | concat_param { 583 | axis: 1 584 | } 585 | } 586 | layer { 587 | name: "shuffle_channel3" 588 | type: "ShuffleChannel" 589 | bottom: "concat3" 590 | top: "shuffle_channel3" 591 | shuffle_channel_param { 592 | group: 2 593 | } 594 | } 595 | layer { 596 | name: "split3" 597 | type: "Slice" 598 | bottom: "shuffle_channel3" 599 | top: "split5" 600 | top: "split6" 601 | slice_param { 602 | slice_point: 58 603 | axis: 1 604 | } 605 | } 606 | layer { 607 | name: "conv13" 608 | type: "Convolution" 609 | bottom: "split6" 610 | top: "conv13" 611 | convolution_param { 612 | num_output: 58 613 | bias_term: false 614 | pad: 0 615 | kernel_size: 1 616 | group: 1 617 | stride: 1 618 | weight_filler { 619 | type: "xavier" 620 | } 621 | dilation: 1 622 | } 623 | } 624 | layer { 625 | name: "batch_norm13" 626 | type: "BatchNorm" 627 | bottom: "conv13" 628 | top: "batch_norm13" 629 | batch_norm_param { 630 | use_global_stats: true 631 | eps: 9.999999747378752e-06 632 | } 633 | } 634 | layer { 635 | name: "bn_scale13" 636 | type: "Scale" 637 | bottom: "batch_norm13" 638 | top: "batch_norm13" 639 | scale_param { 640 | bias_term: true 641 | } 642 | } 643 | layer { 644 | name: "relu9" 645 | type: "ReLU" 646 | bottom: "batch_norm13" 647 | top: "relu9" 648 | } 649 | layer { 650 | name: "conv14" 651 | type: "ConvolutionDepthwise" 652 | bottom: "relu9" 653 | top: "conv14" 654 | convolution_param { 655 | num_output: 58 656 | bias_term: false 657 | pad: 1 658 | kernel_size: 3 659 | stride: 1 660 | weight_filler { 661 | type: "xavier" 662 | } 663 | dilation: 1 664 | } 665 | } 666 | layer { 667 | name: "batch_norm14" 668 | type: "BatchNorm" 669 | bottom: "conv14" 670 | top: "batch_norm14" 671 | batch_norm_param { 672 | use_global_stats: true 673 | eps: 9.999999747378752e-06 674 | } 675 | } 676 | layer { 677 | name: "bn_scale14" 678 | type: "Scale" 679 | bottom: "batch_norm14" 680 | top: "batch_norm14" 681 | scale_param { 682 | bias_term: true 683 | } 684 | } 685 | layer { 686 | name: "conv15" 687 | type: "Convolution" 688 | bottom: "batch_norm14" 689 | top: "conv15" 690 | convolution_param { 691 | num_output: 58 692 | bias_term: false 693 | pad: 0 694 | kernel_size: 1 695 | group: 1 696 | stride: 1 697 | weight_filler { 698 | type: "xavier" 699 | } 700 | dilation: 1 701 | } 702 | } 703 | layer { 704 | name: "batch_norm15" 705 | type: "BatchNorm" 706 | bottom: "conv15" 707 | top: "batch_norm15" 708 | batch_norm_param { 709 | use_global_stats: true 710 | eps: 9.999999747378752e-06 711 | } 712 | } 713 | layer { 714 | name: "bn_scale15" 715 | type: "Scale" 716 | bottom: "batch_norm15" 717 | top: "batch_norm15" 718 | scale_param { 719 | bias_term: true 720 | } 721 | } 722 | layer { 723 | name: "relu10" 724 | type: "ReLU" 725 | bottom: "batch_norm15" 726 | top: "relu10" 727 | } 728 | layer { 729 | name: "concat4" 730 | type: "Concat" 731 | bottom: "split5" 732 | bottom: "relu10" 733 | top: "concat4" 734 | concat_param { 735 | axis: 1 736 | } 737 | } 738 | layer { 739 | name: "shuffle_channel4" 740 | type: "ShuffleChannel" 741 | bottom: "concat4" 742 | top: "shuffle_channel4" 743 | shuffle_channel_param { 744 | group: 2 745 | } 746 | } 747 | layer { 748 | name: "conv16" 749 | type: "ConvolutionDepthwise" 750 | bottom: "shuffle_channel4" 751 | top: "conv16" 752 | convolution_param { 753 | num_output: 116 754 | bias_term: false 755 | pad: 1 756 | kernel_size: 3 757 | stride: 2 758 | weight_filler { 759 | type: "xavier" 760 | } 761 | dilation: 1 762 | } 763 | } 764 | layer { 765 | name: "batch_norm16" 766 | type: "BatchNorm" 767 | bottom: "conv16" 768 | top: "batch_norm16" 769 | batch_norm_param { 770 | use_global_stats: true 771 | eps: 9.999999747378752e-06 772 | } 773 | } 774 | layer { 775 | name: "bn_scale16" 776 | type: "Scale" 777 | bottom: "batch_norm16" 778 | top: "batch_norm16" 779 | scale_param { 780 | bias_term: true 781 | } 782 | } 783 | layer { 784 | name: "conv17" 785 | type: "Convolution" 786 | bottom: "batch_norm16" 787 | top: "conv17" 788 | convolution_param { 789 | num_output: 116 790 | bias_term: false 791 | pad: 0 792 | kernel_size: 1 793 | group: 1 794 | stride: 1 795 | weight_filler { 796 | type: "xavier" 797 | } 798 | dilation: 1 799 | } 800 | } 801 | layer { 802 | name: "batch_norm17" 803 | type: "BatchNorm" 804 | bottom: "conv17" 805 | top: "batch_norm17" 806 | batch_norm_param { 807 | use_global_stats: true 808 | eps: 9.999999747378752e-06 809 | } 810 | } 811 | layer { 812 | name: "bn_scale17" 813 | type: "Scale" 814 | bottom: "batch_norm17" 815 | top: "batch_norm17" 816 | scale_param { 817 | bias_term: true 818 | } 819 | } 820 | layer { 821 | name: "relu11" 822 | type: "ReLU" 823 | bottom: "batch_norm17" 824 | top: "relu11" 825 | } 826 | layer { 827 | name: "conv18" 828 | type: "Convolution" 829 | bottom: "shuffle_channel4" 830 | top: "conv18" 831 | convolution_param { 832 | num_output: 116 833 | bias_term: false 834 | pad: 0 835 | kernel_size: 1 836 | group: 1 837 | stride: 1 838 | weight_filler { 839 | type: "xavier" 840 | } 841 | dilation: 1 842 | } 843 | } 844 | layer { 845 | name: "batch_norm18" 846 | type: "BatchNorm" 847 | bottom: "conv18" 848 | top: "batch_norm18" 849 | batch_norm_param { 850 | use_global_stats: true 851 | eps: 9.999999747378752e-06 852 | } 853 | } 854 | layer { 855 | name: "bn_scale18" 856 | type: "Scale" 857 | bottom: "batch_norm18" 858 | top: "batch_norm18" 859 | scale_param { 860 | bias_term: true 861 | } 862 | } 863 | layer { 864 | name: "relu12" 865 | type: "ReLU" 866 | bottom: "batch_norm18" 867 | top: "relu12" 868 | } 869 | layer { 870 | name: "conv19" 871 | type: "ConvolutionDepthwise" 872 | bottom: "relu12" 873 | top: "conv19" 874 | convolution_param { 875 | num_output: 116 876 | bias_term: false 877 | pad: 1 878 | kernel_size: 3 879 | stride: 2 880 | weight_filler { 881 | type: "xavier" 882 | } 883 | dilation: 1 884 | } 885 | } 886 | layer { 887 | name: "batch_norm19" 888 | type: "BatchNorm" 889 | bottom: "conv19" 890 | top: "batch_norm19" 891 | batch_norm_param { 892 | use_global_stats: true 893 | eps: 9.999999747378752e-06 894 | } 895 | } 896 | layer { 897 | name: "bn_scale19" 898 | type: "Scale" 899 | bottom: "batch_norm19" 900 | top: "batch_norm19" 901 | scale_param { 902 | bias_term: true 903 | } 904 | } 905 | layer { 906 | name: "conv20" 907 | type: "Convolution" 908 | bottom: "batch_norm19" 909 | top: "conv20" 910 | convolution_param { 911 | num_output: 116 912 | bias_term: false 913 | pad: 0 914 | kernel_size: 1 915 | group: 1 916 | stride: 1 917 | weight_filler { 918 | type: "xavier" 919 | } 920 | dilation: 1 921 | } 922 | } 923 | layer { 924 | name: "batch_norm20" 925 | type: "BatchNorm" 926 | bottom: "conv20" 927 | top: "batch_norm20" 928 | batch_norm_param { 929 | use_global_stats: true 930 | eps: 9.999999747378752e-06 931 | } 932 | } 933 | layer { 934 | name: "bn_scale20" 935 | type: "Scale" 936 | bottom: "batch_norm20" 937 | top: "batch_norm20" 938 | scale_param { 939 | bias_term: true 940 | } 941 | } 942 | layer { 943 | name: "relu13" 944 | type: "ReLU" 945 | bottom: "batch_norm20" 946 | top: "relu13" 947 | } 948 | layer { 949 | name: "concat5" 950 | type: "Concat" 951 | bottom: "relu11" 952 | bottom: "relu13" 953 | top: "concat5" 954 | concat_param { 955 | axis: 1 956 | } 957 | } 958 | layer { 959 | name: "shuffle_channel5" 960 | type: "ShuffleChannel" 961 | bottom: "concat5" 962 | top: "shuffle_channel5" 963 | shuffle_channel_param { 964 | group: 2 965 | } 966 | } 967 | layer { 968 | name: "split4" 969 | type: "Slice" 970 | bottom: "shuffle_channel5" 971 | top: "split7" 972 | top: "split8" 973 | slice_param { 974 | slice_point: 116 975 | axis: 1 976 | } 977 | } 978 | layer { 979 | name: "conv21" 980 | type: "Convolution" 981 | bottom: "split8" 982 | top: "conv21" 983 | convolution_param { 984 | num_output: 116 985 | bias_term: false 986 | pad: 0 987 | kernel_size: 1 988 | group: 1 989 | stride: 1 990 | weight_filler { 991 | type: "xavier" 992 | } 993 | dilation: 1 994 | } 995 | } 996 | layer { 997 | name: "batch_norm21" 998 | type: "BatchNorm" 999 | bottom: "conv21" 1000 | top: "batch_norm21" 1001 | batch_norm_param { 1002 | use_global_stats: true 1003 | eps: 9.999999747378752e-06 1004 | } 1005 | } 1006 | layer { 1007 | name: "bn_scale21" 1008 | type: "Scale" 1009 | bottom: "batch_norm21" 1010 | top: "batch_norm21" 1011 | scale_param { 1012 | bias_term: true 1013 | } 1014 | } 1015 | layer { 1016 | name: "relu14" 1017 | type: "ReLU" 1018 | bottom: "batch_norm21" 1019 | top: "relu14" 1020 | } 1021 | layer { 1022 | name: "conv22" 1023 | type: "ConvolutionDepthwise" 1024 | bottom: "relu14" 1025 | top: "conv22" 1026 | convolution_param { 1027 | num_output: 116 1028 | bias_term: false 1029 | pad: 1 1030 | kernel_size: 3 1031 | stride: 1 1032 | weight_filler { 1033 | type: "xavier" 1034 | } 1035 | dilation: 1 1036 | } 1037 | } 1038 | layer { 1039 | name: "batch_norm22" 1040 | type: "BatchNorm" 1041 | bottom: "conv22" 1042 | top: "batch_norm22" 1043 | batch_norm_param { 1044 | use_global_stats: true 1045 | eps: 9.999999747378752e-06 1046 | } 1047 | } 1048 | layer { 1049 | name: "bn_scale22" 1050 | type: "Scale" 1051 | bottom: "batch_norm22" 1052 | top: "batch_norm22" 1053 | scale_param { 1054 | bias_term: true 1055 | } 1056 | } 1057 | layer { 1058 | name: "conv23" 1059 | type: "Convolution" 1060 | bottom: "batch_norm22" 1061 | top: "conv23" 1062 | convolution_param { 1063 | num_output: 116 1064 | bias_term: false 1065 | pad: 0 1066 | kernel_size: 1 1067 | group: 1 1068 | stride: 1 1069 | weight_filler { 1070 | type: "xavier" 1071 | } 1072 | dilation: 1 1073 | } 1074 | } 1075 | layer { 1076 | name: "batch_norm23" 1077 | type: "BatchNorm" 1078 | bottom: "conv23" 1079 | top: "batch_norm23" 1080 | batch_norm_param { 1081 | use_global_stats: true 1082 | eps: 9.999999747378752e-06 1083 | } 1084 | } 1085 | layer { 1086 | name: "bn_scale23" 1087 | type: "Scale" 1088 | bottom: "batch_norm23" 1089 | top: "batch_norm23" 1090 | scale_param { 1091 | bias_term: true 1092 | } 1093 | } 1094 | layer { 1095 | name: "relu15" 1096 | type: "ReLU" 1097 | bottom: "batch_norm23" 1098 | top: "relu15" 1099 | } 1100 | layer { 1101 | name: "concat6" 1102 | type: "Concat" 1103 | bottom: "split7" 1104 | bottom: "relu15" 1105 | top: "concat6" 1106 | concat_param { 1107 | axis: 1 1108 | } 1109 | } 1110 | layer { 1111 | name: "shuffle_channel6" 1112 | type: "ShuffleChannel" 1113 | bottom: "concat6" 1114 | top: "shuffle_channel6" 1115 | shuffle_channel_param { 1116 | group: 2 1117 | } 1118 | } 1119 | layer { 1120 | name: "split5" 1121 | type: "Slice" 1122 | bottom: "shuffle_channel6" 1123 | top: "split9" 1124 | top: "split10" 1125 | slice_param { 1126 | slice_point: 116 1127 | axis: 1 1128 | } 1129 | } 1130 | layer { 1131 | name: "conv24" 1132 | type: "Convolution" 1133 | bottom: "split10" 1134 | top: "conv24" 1135 | convolution_param { 1136 | num_output: 116 1137 | bias_term: false 1138 | pad: 0 1139 | kernel_size: 1 1140 | group: 1 1141 | stride: 1 1142 | weight_filler { 1143 | type: "xavier" 1144 | } 1145 | dilation: 1 1146 | } 1147 | } 1148 | layer { 1149 | name: "batch_norm24" 1150 | type: "BatchNorm" 1151 | bottom: "conv24" 1152 | top: "batch_norm24" 1153 | batch_norm_param { 1154 | use_global_stats: true 1155 | eps: 9.999999747378752e-06 1156 | } 1157 | } 1158 | layer { 1159 | name: "bn_scale24" 1160 | type: "Scale" 1161 | bottom: "batch_norm24" 1162 | top: "batch_norm24" 1163 | scale_param { 1164 | bias_term: true 1165 | } 1166 | } 1167 | layer { 1168 | name: "relu16" 1169 | type: "ReLU" 1170 | bottom: "batch_norm24" 1171 | top: "relu16" 1172 | } 1173 | layer { 1174 | name: "conv25" 1175 | type: "ConvolutionDepthwise" 1176 | bottom: "relu16" 1177 | top: "conv25" 1178 | convolution_param { 1179 | num_output: 116 1180 | bias_term: false 1181 | pad: 1 1182 | kernel_size: 3 1183 | stride: 1 1184 | weight_filler { 1185 | type: "xavier" 1186 | } 1187 | dilation: 1 1188 | } 1189 | } 1190 | layer { 1191 | name: "batch_norm25" 1192 | type: "BatchNorm" 1193 | bottom: "conv25" 1194 | top: "batch_norm25" 1195 | batch_norm_param { 1196 | use_global_stats: true 1197 | eps: 9.999999747378752e-06 1198 | } 1199 | } 1200 | layer { 1201 | name: "bn_scale25" 1202 | type: "Scale" 1203 | bottom: "batch_norm25" 1204 | top: "batch_norm25" 1205 | scale_param { 1206 | bias_term: true 1207 | } 1208 | } 1209 | layer { 1210 | name: "conv26" 1211 | type: "Convolution" 1212 | bottom: "batch_norm25" 1213 | top: "conv26" 1214 | convolution_param { 1215 | num_output: 116 1216 | bias_term: false 1217 | pad: 0 1218 | kernel_size: 1 1219 | group: 1 1220 | stride: 1 1221 | weight_filler { 1222 | type: "xavier" 1223 | } 1224 | dilation: 1 1225 | } 1226 | } 1227 | layer { 1228 | name: "batch_norm26" 1229 | type: "BatchNorm" 1230 | bottom: "conv26" 1231 | top: "batch_norm26" 1232 | batch_norm_param { 1233 | use_global_stats: true 1234 | eps: 9.999999747378752e-06 1235 | } 1236 | } 1237 | layer { 1238 | name: "bn_scale26" 1239 | type: "Scale" 1240 | bottom: "batch_norm26" 1241 | top: "batch_norm26" 1242 | scale_param { 1243 | bias_term: true 1244 | } 1245 | } 1246 | layer { 1247 | name: "relu17" 1248 | type: "ReLU" 1249 | bottom: "batch_norm26" 1250 | top: "relu17" 1251 | } 1252 | layer { 1253 | name: "concat7" 1254 | type: "Concat" 1255 | bottom: "split9" 1256 | bottom: "relu17" 1257 | top: "concat7" 1258 | concat_param { 1259 | axis: 1 1260 | } 1261 | } 1262 | layer { 1263 | name: "shuffle_channel7" 1264 | type: "ShuffleChannel" 1265 | bottom: "concat7" 1266 | top: "shuffle_channel7" 1267 | shuffle_channel_param { 1268 | group: 2 1269 | } 1270 | } 1271 | layer { 1272 | name: "split6" 1273 | type: "Slice" 1274 | bottom: "shuffle_channel7" 1275 | top: "split11" 1276 | top: "split12" 1277 | slice_param { 1278 | slice_point: 116 1279 | axis: 1 1280 | } 1281 | } 1282 | layer { 1283 | name: "conv27" 1284 | type: "Convolution" 1285 | bottom: "split12" 1286 | top: "conv27" 1287 | convolution_param { 1288 | num_output: 116 1289 | bias_term: false 1290 | pad: 0 1291 | kernel_size: 1 1292 | group: 1 1293 | stride: 1 1294 | weight_filler { 1295 | type: "xavier" 1296 | } 1297 | dilation: 1 1298 | } 1299 | } 1300 | layer { 1301 | name: "batch_norm27" 1302 | type: "BatchNorm" 1303 | bottom: "conv27" 1304 | top: "batch_norm27" 1305 | batch_norm_param { 1306 | use_global_stats: true 1307 | eps: 9.999999747378752e-06 1308 | } 1309 | } 1310 | layer { 1311 | name: "bn_scale27" 1312 | type: "Scale" 1313 | bottom: "batch_norm27" 1314 | top: "batch_norm27" 1315 | scale_param { 1316 | bias_term: true 1317 | } 1318 | } 1319 | layer { 1320 | name: "relu18" 1321 | type: "ReLU" 1322 | bottom: "batch_norm27" 1323 | top: "relu18" 1324 | } 1325 | layer { 1326 | name: "conv28" 1327 | type: "ConvolutionDepthwise" 1328 | bottom: "relu18" 1329 | top: "conv28" 1330 | convolution_param { 1331 | num_output: 116 1332 | bias_term: false 1333 | pad: 1 1334 | kernel_size: 3 1335 | stride: 1 1336 | weight_filler { 1337 | type: "xavier" 1338 | } 1339 | dilation: 1 1340 | } 1341 | } 1342 | layer { 1343 | name: "batch_norm28" 1344 | type: "BatchNorm" 1345 | bottom: "conv28" 1346 | top: "batch_norm28" 1347 | batch_norm_param { 1348 | use_global_stats: true 1349 | eps: 9.999999747378752e-06 1350 | } 1351 | } 1352 | layer { 1353 | name: "bn_scale28" 1354 | type: "Scale" 1355 | bottom: "batch_norm28" 1356 | top: "batch_norm28" 1357 | scale_param { 1358 | bias_term: true 1359 | } 1360 | } 1361 | layer { 1362 | name: "conv29" 1363 | type: "Convolution" 1364 | bottom: "batch_norm28" 1365 | top: "conv29" 1366 | convolution_param { 1367 | num_output: 116 1368 | bias_term: false 1369 | pad: 0 1370 | kernel_size: 1 1371 | group: 1 1372 | stride: 1 1373 | weight_filler { 1374 | type: "xavier" 1375 | } 1376 | dilation: 1 1377 | } 1378 | } 1379 | layer { 1380 | name: "batch_norm29" 1381 | type: "BatchNorm" 1382 | bottom: "conv29" 1383 | top: "batch_norm29" 1384 | batch_norm_param { 1385 | use_global_stats: true 1386 | eps: 9.999999747378752e-06 1387 | } 1388 | } 1389 | layer { 1390 | name: "bn_scale29" 1391 | type: "Scale" 1392 | bottom: "batch_norm29" 1393 | top: "batch_norm29" 1394 | scale_param { 1395 | bias_term: true 1396 | } 1397 | } 1398 | layer { 1399 | name: "relu19" 1400 | type: "ReLU" 1401 | bottom: "batch_norm29" 1402 | top: "relu19" 1403 | } 1404 | layer { 1405 | name: "concat8" 1406 | type: "Concat" 1407 | bottom: "split11" 1408 | bottom: "relu19" 1409 | top: "concat8" 1410 | concat_param { 1411 | axis: 1 1412 | } 1413 | } 1414 | layer { 1415 | name: "shuffle_channel8" 1416 | type: "ShuffleChannel" 1417 | bottom: "concat8" 1418 | top: "shuffle_channel8" 1419 | shuffle_channel_param { 1420 | group: 2 1421 | } 1422 | } 1423 | layer { 1424 | name: "split7" 1425 | type: "Slice" 1426 | bottom: "shuffle_channel8" 1427 | top: "split13" 1428 | top: "split14" 1429 | slice_param { 1430 | slice_point: 116 1431 | axis: 1 1432 | } 1433 | } 1434 | layer { 1435 | name: "conv30" 1436 | type: "Convolution" 1437 | bottom: "split14" 1438 | top: "conv30" 1439 | convolution_param { 1440 | num_output: 116 1441 | bias_term: false 1442 | pad: 0 1443 | kernel_size: 1 1444 | group: 1 1445 | stride: 1 1446 | weight_filler { 1447 | type: "xavier" 1448 | } 1449 | dilation: 1 1450 | } 1451 | } 1452 | layer { 1453 | name: "batch_norm30" 1454 | type: "BatchNorm" 1455 | bottom: "conv30" 1456 | top: "batch_norm30" 1457 | batch_norm_param { 1458 | use_global_stats: true 1459 | eps: 9.999999747378752e-06 1460 | } 1461 | } 1462 | layer { 1463 | name: "bn_scale30" 1464 | type: "Scale" 1465 | bottom: "batch_norm30" 1466 | top: "batch_norm30" 1467 | scale_param { 1468 | bias_term: true 1469 | } 1470 | } 1471 | layer { 1472 | name: "relu20" 1473 | type: "ReLU" 1474 | bottom: "batch_norm30" 1475 | top: "relu20" 1476 | } 1477 | layer { 1478 | name: "conv31" 1479 | type: "ConvolutionDepthwise" 1480 | bottom: "relu20" 1481 | top: "conv31" 1482 | convolution_param { 1483 | num_output: 116 1484 | bias_term: false 1485 | pad: 1 1486 | kernel_size: 3 1487 | stride: 1 1488 | weight_filler { 1489 | type: "xavier" 1490 | } 1491 | dilation: 1 1492 | } 1493 | } 1494 | layer { 1495 | name: "batch_norm31" 1496 | type: "BatchNorm" 1497 | bottom: "conv31" 1498 | top: "batch_norm31" 1499 | batch_norm_param { 1500 | use_global_stats: true 1501 | eps: 9.999999747378752e-06 1502 | } 1503 | } 1504 | layer { 1505 | name: "bn_scale31" 1506 | type: "Scale" 1507 | bottom: "batch_norm31" 1508 | top: "batch_norm31" 1509 | scale_param { 1510 | bias_term: true 1511 | } 1512 | } 1513 | layer { 1514 | name: "conv32" 1515 | type: "Convolution" 1516 | bottom: "batch_norm31" 1517 | top: "conv32" 1518 | convolution_param { 1519 | num_output: 116 1520 | bias_term: false 1521 | pad: 0 1522 | kernel_size: 1 1523 | group: 1 1524 | stride: 1 1525 | weight_filler { 1526 | type: "xavier" 1527 | } 1528 | dilation: 1 1529 | } 1530 | } 1531 | layer { 1532 | name: "batch_norm32" 1533 | type: "BatchNorm" 1534 | bottom: "conv32" 1535 | top: "batch_norm32" 1536 | batch_norm_param { 1537 | use_global_stats: true 1538 | eps: 9.999999747378752e-06 1539 | } 1540 | } 1541 | layer { 1542 | name: "bn_scale32" 1543 | type: "Scale" 1544 | bottom: "batch_norm32" 1545 | top: "batch_norm32" 1546 | scale_param { 1547 | bias_term: true 1548 | } 1549 | } 1550 | layer { 1551 | name: "relu21" 1552 | type: "ReLU" 1553 | bottom: "batch_norm32" 1554 | top: "relu21" 1555 | } 1556 | layer { 1557 | name: "concat9" 1558 | type: "Concat" 1559 | bottom: "split13" 1560 | bottom: "relu21" 1561 | top: "concat9" 1562 | concat_param { 1563 | axis: 1 1564 | } 1565 | } 1566 | layer { 1567 | name: "shuffle_channel9" 1568 | type: "ShuffleChannel" 1569 | bottom: "concat9" 1570 | top: "shuffle_channel9" 1571 | shuffle_channel_param { 1572 | group: 2 1573 | } 1574 | } 1575 | layer { 1576 | name: "split8" 1577 | type: "Slice" 1578 | bottom: "shuffle_channel9" 1579 | top: "split15" 1580 | top: "split16" 1581 | slice_param { 1582 | slice_point: 116 1583 | axis: 1 1584 | } 1585 | } 1586 | layer { 1587 | name: "conv33" 1588 | type: "Convolution" 1589 | bottom: "split16" 1590 | top: "conv33" 1591 | convolution_param { 1592 | num_output: 116 1593 | bias_term: false 1594 | pad: 0 1595 | kernel_size: 1 1596 | group: 1 1597 | stride: 1 1598 | weight_filler { 1599 | type: "xavier" 1600 | } 1601 | dilation: 1 1602 | } 1603 | } 1604 | layer { 1605 | name: "batch_norm33" 1606 | type: "BatchNorm" 1607 | bottom: "conv33" 1608 | top: "batch_norm33" 1609 | batch_norm_param { 1610 | use_global_stats: true 1611 | eps: 9.999999747378752e-06 1612 | } 1613 | } 1614 | layer { 1615 | name: "bn_scale33" 1616 | type: "Scale" 1617 | bottom: "batch_norm33" 1618 | top: "batch_norm33" 1619 | scale_param { 1620 | bias_term: true 1621 | } 1622 | } 1623 | layer { 1624 | name: "relu22" 1625 | type: "ReLU" 1626 | bottom: "batch_norm33" 1627 | top: "relu22" 1628 | } 1629 | layer { 1630 | name: "conv34" 1631 | type: "ConvolutionDepthwise" 1632 | bottom: "relu22" 1633 | top: "conv34" 1634 | convolution_param { 1635 | num_output: 116 1636 | bias_term: false 1637 | pad: 1 1638 | kernel_size: 3 1639 | stride: 1 1640 | weight_filler { 1641 | type: "xavier" 1642 | } 1643 | dilation: 1 1644 | } 1645 | } 1646 | layer { 1647 | name: "batch_norm34" 1648 | type: "BatchNorm" 1649 | bottom: "conv34" 1650 | top: "batch_norm34" 1651 | batch_norm_param { 1652 | use_global_stats: true 1653 | eps: 9.999999747378752e-06 1654 | } 1655 | } 1656 | layer { 1657 | name: "bn_scale34" 1658 | type: "Scale" 1659 | bottom: "batch_norm34" 1660 | top: "batch_norm34" 1661 | scale_param { 1662 | bias_term: true 1663 | } 1664 | } 1665 | layer { 1666 | name: "conv35" 1667 | type: "Convolution" 1668 | bottom: "batch_norm34" 1669 | top: "conv35" 1670 | convolution_param { 1671 | num_output: 116 1672 | bias_term: false 1673 | pad: 0 1674 | kernel_size: 1 1675 | group: 1 1676 | stride: 1 1677 | weight_filler { 1678 | type: "xavier" 1679 | } 1680 | dilation: 1 1681 | } 1682 | } 1683 | layer { 1684 | name: "batch_norm35" 1685 | type: "BatchNorm" 1686 | bottom: "conv35" 1687 | top: "batch_norm35" 1688 | batch_norm_param { 1689 | use_global_stats: true 1690 | eps: 9.999999747378752e-06 1691 | } 1692 | } 1693 | layer { 1694 | name: "bn_scale35" 1695 | type: "Scale" 1696 | bottom: "batch_norm35" 1697 | top: "batch_norm35" 1698 | scale_param { 1699 | bias_term: true 1700 | } 1701 | } 1702 | layer { 1703 | name: "relu23" 1704 | type: "ReLU" 1705 | bottom: "batch_norm35" 1706 | top: "relu23" 1707 | } 1708 | layer { 1709 | name: "concat10" 1710 | type: "Concat" 1711 | bottom: "split15" 1712 | bottom: "relu23" 1713 | top: "concat10" 1714 | concat_param { 1715 | axis: 1 1716 | } 1717 | } 1718 | layer { 1719 | name: "shuffle_channel10" 1720 | type: "ShuffleChannel" 1721 | bottom: "concat10" 1722 | top: "shuffle_channel10" 1723 | shuffle_channel_param { 1724 | group: 2 1725 | } 1726 | } 1727 | layer { 1728 | name: "split9" 1729 | type: "Slice" 1730 | bottom: "shuffle_channel10" 1731 | top: "split17" 1732 | top: "split18" 1733 | slice_param { 1734 | slice_point: 116 1735 | axis: 1 1736 | } 1737 | } 1738 | layer { 1739 | name: "conv36" 1740 | type: "Convolution" 1741 | bottom: "split18" 1742 | top: "conv36" 1743 | convolution_param { 1744 | num_output: 116 1745 | bias_term: false 1746 | pad: 0 1747 | kernel_size: 1 1748 | group: 1 1749 | stride: 1 1750 | weight_filler { 1751 | type: "xavier" 1752 | } 1753 | dilation: 1 1754 | } 1755 | } 1756 | layer { 1757 | name: "batch_norm36" 1758 | type: "BatchNorm" 1759 | bottom: "conv36" 1760 | top: "batch_norm36" 1761 | batch_norm_param { 1762 | use_global_stats: true 1763 | eps: 9.999999747378752e-06 1764 | } 1765 | } 1766 | layer { 1767 | name: "bn_scale36" 1768 | type: "Scale" 1769 | bottom: "batch_norm36" 1770 | top: "batch_norm36" 1771 | scale_param { 1772 | bias_term: true 1773 | } 1774 | } 1775 | layer { 1776 | name: "relu24" 1777 | type: "ReLU" 1778 | bottom: "batch_norm36" 1779 | top: "relu24" 1780 | } 1781 | layer { 1782 | name: "conv37" 1783 | type: "ConvolutionDepthwise" 1784 | bottom: "relu24" 1785 | top: "conv37" 1786 | convolution_param { 1787 | num_output: 116 1788 | bias_term: false 1789 | pad: 1 1790 | kernel_size: 3 1791 | stride: 1 1792 | weight_filler { 1793 | type: "xavier" 1794 | } 1795 | dilation: 1 1796 | } 1797 | } 1798 | layer { 1799 | name: "batch_norm37" 1800 | type: "BatchNorm" 1801 | bottom: "conv37" 1802 | top: "batch_norm37" 1803 | batch_norm_param { 1804 | use_global_stats: true 1805 | eps: 9.999999747378752e-06 1806 | } 1807 | } 1808 | layer { 1809 | name: "bn_scale37" 1810 | type: "Scale" 1811 | bottom: "batch_norm37" 1812 | top: "batch_norm37" 1813 | scale_param { 1814 | bias_term: true 1815 | } 1816 | } 1817 | layer { 1818 | name: "conv38" 1819 | type: "Convolution" 1820 | bottom: "batch_norm37" 1821 | top: "conv38" 1822 | convolution_param { 1823 | num_output: 116 1824 | bias_term: false 1825 | pad: 0 1826 | kernel_size: 1 1827 | group: 1 1828 | stride: 1 1829 | weight_filler { 1830 | type: "xavier" 1831 | } 1832 | dilation: 1 1833 | } 1834 | } 1835 | layer { 1836 | name: "batch_norm38" 1837 | type: "BatchNorm" 1838 | bottom: "conv38" 1839 | top: "batch_norm38" 1840 | batch_norm_param { 1841 | use_global_stats: true 1842 | eps: 9.999999747378752e-06 1843 | } 1844 | } 1845 | layer { 1846 | name: "bn_scale38" 1847 | type: "Scale" 1848 | bottom: "batch_norm38" 1849 | top: "batch_norm38" 1850 | scale_param { 1851 | bias_term: true 1852 | } 1853 | } 1854 | layer { 1855 | name: "relu25" 1856 | type: "ReLU" 1857 | bottom: "batch_norm38" 1858 | top: "relu25" 1859 | } 1860 | layer { 1861 | name: "concat11" 1862 | type: "Concat" 1863 | bottom: "split17" 1864 | bottom: "relu25" 1865 | top: "concat11" 1866 | concat_param { 1867 | axis: 1 1868 | } 1869 | } 1870 | layer { 1871 | name: "shuffle_channel11" 1872 | type: "ShuffleChannel" 1873 | bottom: "concat11" 1874 | top: "shuffle_channel11" 1875 | shuffle_channel_param { 1876 | group: 2 1877 | } 1878 | } 1879 | layer { 1880 | name: "split10" 1881 | type: "Slice" 1882 | bottom: "shuffle_channel11" 1883 | top: "split19" 1884 | top: "split20" 1885 | slice_param { 1886 | slice_point: 116 1887 | axis: 1 1888 | } 1889 | } 1890 | layer { 1891 | name: "conv39" 1892 | type: "Convolution" 1893 | bottom: "split20" 1894 | top: "conv39" 1895 | convolution_param { 1896 | num_output: 116 1897 | bias_term: false 1898 | pad: 0 1899 | kernel_size: 1 1900 | group: 1 1901 | stride: 1 1902 | weight_filler { 1903 | type: "xavier" 1904 | } 1905 | dilation: 1 1906 | } 1907 | } 1908 | layer { 1909 | name: "batch_norm39" 1910 | type: "BatchNorm" 1911 | bottom: "conv39" 1912 | top: "batch_norm39" 1913 | batch_norm_param { 1914 | use_global_stats: true 1915 | eps: 9.999999747378752e-06 1916 | } 1917 | } 1918 | layer { 1919 | name: "bn_scale39" 1920 | type: "Scale" 1921 | bottom: "batch_norm39" 1922 | top: "batch_norm39" 1923 | scale_param { 1924 | bias_term: true 1925 | } 1926 | } 1927 | layer { 1928 | name: "relu26" 1929 | type: "ReLU" 1930 | bottom: "batch_norm39" 1931 | top: "relu26" 1932 | } 1933 | layer { 1934 | name: "conv40" 1935 | type: "ConvolutionDepthwise" 1936 | bottom: "relu26" 1937 | top: "conv40" 1938 | convolution_param { 1939 | num_output: 116 1940 | bias_term: false 1941 | pad: 1 1942 | kernel_size: 3 1943 | stride: 1 1944 | weight_filler { 1945 | type: "xavier" 1946 | } 1947 | dilation: 1 1948 | } 1949 | } 1950 | layer { 1951 | name: "batch_norm40" 1952 | type: "BatchNorm" 1953 | bottom: "conv40" 1954 | top: "batch_norm40" 1955 | batch_norm_param { 1956 | use_global_stats: true 1957 | eps: 9.999999747378752e-06 1958 | } 1959 | } 1960 | layer { 1961 | name: "bn_scale40" 1962 | type: "Scale" 1963 | bottom: "batch_norm40" 1964 | top: "batch_norm40" 1965 | scale_param { 1966 | bias_term: true 1967 | } 1968 | } 1969 | layer { 1970 | name: "conv41" 1971 | type: "Convolution" 1972 | bottom: "batch_norm40" 1973 | top: "conv41" 1974 | convolution_param { 1975 | num_output: 116 1976 | bias_term: false 1977 | pad: 0 1978 | kernel_size: 1 1979 | group: 1 1980 | stride: 1 1981 | weight_filler { 1982 | type: "xavier" 1983 | } 1984 | dilation: 1 1985 | } 1986 | } 1987 | layer { 1988 | name: "batch_norm41" 1989 | type: "BatchNorm" 1990 | bottom: "conv41" 1991 | top: "batch_norm41" 1992 | batch_norm_param { 1993 | use_global_stats: true 1994 | eps: 9.999999747378752e-06 1995 | } 1996 | } 1997 | layer { 1998 | name: "bn_scale41" 1999 | type: "Scale" 2000 | bottom: "batch_norm41" 2001 | top: "batch_norm41" 2002 | scale_param { 2003 | bias_term: true 2004 | } 2005 | } 2006 | layer { 2007 | name: "relu27" 2008 | type: "ReLU" 2009 | bottom: "batch_norm41" 2010 | top: "relu27" 2011 | } 2012 | layer { 2013 | name: "concat12" 2014 | type: "Concat" 2015 | bottom: "split19" 2016 | bottom: "relu27" 2017 | top: "concat12" 2018 | concat_param { 2019 | axis: 1 2020 | } 2021 | } 2022 | layer { 2023 | name: "shuffle_channel12" 2024 | type: "ShuffleChannel" 2025 | bottom: "concat12" 2026 | top: "shuffle_channel12" 2027 | shuffle_channel_param { 2028 | group: 2 2029 | } 2030 | } 2031 | layer { 2032 | name: "conv42" 2033 | type: "ConvolutionDepthwise" 2034 | bottom: "shuffle_channel12" 2035 | top: "conv42" 2036 | convolution_param { 2037 | num_output: 232 2038 | bias_term: false 2039 | pad: 1 2040 | kernel_size: 3 2041 | stride: 2 2042 | weight_filler { 2043 | type: "xavier" 2044 | } 2045 | dilation: 1 2046 | } 2047 | } 2048 | layer { 2049 | name: "batch_norm42" 2050 | type: "BatchNorm" 2051 | bottom: "conv42" 2052 | top: "batch_norm42" 2053 | batch_norm_param { 2054 | use_global_stats: true 2055 | eps: 9.999999747378752e-06 2056 | } 2057 | } 2058 | layer { 2059 | name: "bn_scale42" 2060 | type: "Scale" 2061 | bottom: "batch_norm42" 2062 | top: "batch_norm42" 2063 | scale_param { 2064 | bias_term: true 2065 | } 2066 | } 2067 | layer { 2068 | name: "conv43" 2069 | type: "Convolution" 2070 | bottom: "batch_norm42" 2071 | top: "conv43" 2072 | convolution_param { 2073 | num_output: 232 2074 | bias_term: false 2075 | pad: 0 2076 | kernel_size: 1 2077 | group: 1 2078 | stride: 1 2079 | weight_filler { 2080 | type: "xavier" 2081 | } 2082 | dilation: 1 2083 | } 2084 | } 2085 | layer { 2086 | name: "batch_norm43" 2087 | type: "BatchNorm" 2088 | bottom: "conv43" 2089 | top: "batch_norm43" 2090 | batch_norm_param { 2091 | use_global_stats: true 2092 | eps: 9.999999747378752e-06 2093 | } 2094 | } 2095 | layer { 2096 | name: "bn_scale43" 2097 | type: "Scale" 2098 | bottom: "batch_norm43" 2099 | top: "batch_norm43" 2100 | scale_param { 2101 | bias_term: true 2102 | } 2103 | } 2104 | layer { 2105 | name: "relu28" 2106 | type: "ReLU" 2107 | bottom: "batch_norm43" 2108 | top: "relu28" 2109 | } 2110 | layer { 2111 | name: "conv44" 2112 | type: "Convolution" 2113 | bottom: "shuffle_channel12" 2114 | top: "conv44" 2115 | convolution_param { 2116 | num_output: 232 2117 | bias_term: false 2118 | pad: 0 2119 | kernel_size: 1 2120 | group: 1 2121 | stride: 1 2122 | weight_filler { 2123 | type: "xavier" 2124 | } 2125 | dilation: 1 2126 | } 2127 | } 2128 | layer { 2129 | name: "batch_norm44" 2130 | type: "BatchNorm" 2131 | bottom: "conv44" 2132 | top: "batch_norm44" 2133 | batch_norm_param { 2134 | use_global_stats: true 2135 | eps: 9.999999747378752e-06 2136 | } 2137 | } 2138 | layer { 2139 | name: "bn_scale44" 2140 | type: "Scale" 2141 | bottom: "batch_norm44" 2142 | top: "batch_norm44" 2143 | scale_param { 2144 | bias_term: true 2145 | } 2146 | } 2147 | layer { 2148 | name: "relu29" 2149 | type: "ReLU" 2150 | bottom: "batch_norm44" 2151 | top: "relu29" 2152 | } 2153 | layer { 2154 | name: "conv45" 2155 | type: "ConvolutionDepthwise" 2156 | bottom: "relu29" 2157 | top: "conv45" 2158 | convolution_param { 2159 | num_output: 232 2160 | bias_term: false 2161 | pad: 1 2162 | kernel_size: 3 2163 | stride: 2 2164 | weight_filler { 2165 | type: "xavier" 2166 | } 2167 | dilation: 1 2168 | } 2169 | } 2170 | layer { 2171 | name: "batch_norm45" 2172 | type: "BatchNorm" 2173 | bottom: "conv45" 2174 | top: "batch_norm45" 2175 | batch_norm_param { 2176 | use_global_stats: true 2177 | eps: 9.999999747378752e-06 2178 | } 2179 | } 2180 | layer { 2181 | name: "bn_scale45" 2182 | type: "Scale" 2183 | bottom: "batch_norm45" 2184 | top: "batch_norm45" 2185 | scale_param { 2186 | bias_term: true 2187 | } 2188 | } 2189 | layer { 2190 | name: "conv46" 2191 | type: "Convolution" 2192 | bottom: "batch_norm45" 2193 | top: "conv46" 2194 | convolution_param { 2195 | num_output: 232 2196 | bias_term: false 2197 | pad: 0 2198 | kernel_size: 1 2199 | group: 1 2200 | stride: 1 2201 | weight_filler { 2202 | type: "xavier" 2203 | } 2204 | dilation: 1 2205 | } 2206 | } 2207 | layer { 2208 | name: "batch_norm46" 2209 | type: "BatchNorm" 2210 | bottom: "conv46" 2211 | top: "batch_norm46" 2212 | batch_norm_param { 2213 | use_global_stats: true 2214 | eps: 9.999999747378752e-06 2215 | } 2216 | } 2217 | layer { 2218 | name: "bn_scale46" 2219 | type: "Scale" 2220 | bottom: "batch_norm46" 2221 | top: "batch_norm46" 2222 | scale_param { 2223 | bias_term: true 2224 | } 2225 | } 2226 | layer { 2227 | name: "relu30" 2228 | type: "ReLU" 2229 | bottom: "batch_norm46" 2230 | top: "relu30" 2231 | } 2232 | layer { 2233 | name: "concat13" 2234 | type: "Concat" 2235 | bottom: "relu28" 2236 | bottom: "relu30" 2237 | top: "concat13" 2238 | concat_param { 2239 | axis: 1 2240 | } 2241 | } 2242 | layer { 2243 | name: "shuffle_channel13" 2244 | type: "ShuffleChannel" 2245 | bottom: "concat13" 2246 | top: "shuffle_channel13" 2247 | shuffle_channel_param { 2248 | group: 2 2249 | } 2250 | } 2251 | layer { 2252 | name: "split11" 2253 | type: "Slice" 2254 | bottom: "shuffle_channel13" 2255 | top: "split21" 2256 | top: "split22" 2257 | slice_param { 2258 | slice_point: 232 2259 | axis: 1 2260 | } 2261 | } 2262 | layer { 2263 | name: "conv47" 2264 | type: "Convolution" 2265 | bottom: "split22" 2266 | top: "conv47" 2267 | convolution_param { 2268 | num_output: 232 2269 | bias_term: false 2270 | pad: 0 2271 | kernel_size: 1 2272 | group: 1 2273 | stride: 1 2274 | weight_filler { 2275 | type: "xavier" 2276 | } 2277 | dilation: 1 2278 | } 2279 | } 2280 | layer { 2281 | name: "batch_norm47" 2282 | type: "BatchNorm" 2283 | bottom: "conv47" 2284 | top: "batch_norm47" 2285 | batch_norm_param { 2286 | use_global_stats: true 2287 | eps: 9.999999747378752e-06 2288 | } 2289 | } 2290 | layer { 2291 | name: "bn_scale47" 2292 | type: "Scale" 2293 | bottom: "batch_norm47" 2294 | top: "batch_norm47" 2295 | scale_param { 2296 | bias_term: true 2297 | } 2298 | } 2299 | layer { 2300 | name: "relu31" 2301 | type: "ReLU" 2302 | bottom: "batch_norm47" 2303 | top: "relu31" 2304 | } 2305 | layer { 2306 | name: "conv48" 2307 | type: "ConvolutionDepthwise" 2308 | bottom: "relu31" 2309 | top: "conv48" 2310 | convolution_param { 2311 | num_output: 232 2312 | bias_term: false 2313 | pad: 1 2314 | kernel_size: 3 2315 | stride: 1 2316 | weight_filler { 2317 | type: "xavier" 2318 | } 2319 | dilation: 1 2320 | } 2321 | } 2322 | layer { 2323 | name: "batch_norm48" 2324 | type: "BatchNorm" 2325 | bottom: "conv48" 2326 | top: "batch_norm48" 2327 | batch_norm_param { 2328 | use_global_stats: true 2329 | eps: 9.999999747378752e-06 2330 | } 2331 | } 2332 | layer { 2333 | name: "bn_scale48" 2334 | type: "Scale" 2335 | bottom: "batch_norm48" 2336 | top: "batch_norm48" 2337 | scale_param { 2338 | bias_term: true 2339 | } 2340 | } 2341 | layer { 2342 | name: "conv49" 2343 | type: "Convolution" 2344 | bottom: "batch_norm48" 2345 | top: "conv49" 2346 | convolution_param { 2347 | num_output: 232 2348 | bias_term: false 2349 | pad: 0 2350 | kernel_size: 1 2351 | group: 1 2352 | stride: 1 2353 | weight_filler { 2354 | type: "xavier" 2355 | } 2356 | dilation: 1 2357 | } 2358 | } 2359 | layer { 2360 | name: "batch_norm49" 2361 | type: "BatchNorm" 2362 | bottom: "conv49" 2363 | top: "batch_norm49" 2364 | batch_norm_param { 2365 | use_global_stats: true 2366 | eps: 9.999999747378752e-06 2367 | } 2368 | } 2369 | layer { 2370 | name: "bn_scale49" 2371 | type: "Scale" 2372 | bottom: "batch_norm49" 2373 | top: "batch_norm49" 2374 | scale_param { 2375 | bias_term: true 2376 | } 2377 | } 2378 | layer { 2379 | name: "relu32" 2380 | type: "ReLU" 2381 | bottom: "batch_norm49" 2382 | top: "relu32" 2383 | } 2384 | layer { 2385 | name: "concat14" 2386 | type: "Concat" 2387 | bottom: "split21" 2388 | bottom: "relu32" 2389 | top: "concat14" 2390 | concat_param { 2391 | axis: 1 2392 | } 2393 | } 2394 | layer { 2395 | name: "shuffle_channel14" 2396 | type: "ShuffleChannel" 2397 | bottom: "concat14" 2398 | top: "shuffle_channel14" 2399 | shuffle_channel_param { 2400 | group: 2 2401 | } 2402 | } 2403 | layer { 2404 | name: "split12" 2405 | type: "Slice" 2406 | bottom: "shuffle_channel14" 2407 | top: "split23" 2408 | top: "split24" 2409 | slice_param { 2410 | slice_point: 232 2411 | axis: 1 2412 | } 2413 | } 2414 | layer { 2415 | name: "conv50" 2416 | type: "Convolution" 2417 | bottom: "split24" 2418 | top: "conv50" 2419 | convolution_param { 2420 | num_output: 232 2421 | bias_term: false 2422 | pad: 0 2423 | kernel_size: 1 2424 | group: 1 2425 | stride: 1 2426 | weight_filler { 2427 | type: "xavier" 2428 | } 2429 | dilation: 1 2430 | } 2431 | } 2432 | layer { 2433 | name: "batch_norm50" 2434 | type: "BatchNorm" 2435 | bottom: "conv50" 2436 | top: "batch_norm50" 2437 | batch_norm_param { 2438 | use_global_stats: true 2439 | eps: 9.999999747378752e-06 2440 | } 2441 | } 2442 | layer { 2443 | name: "bn_scale50" 2444 | type: "Scale" 2445 | bottom: "batch_norm50" 2446 | top: "batch_norm50" 2447 | scale_param { 2448 | bias_term: true 2449 | } 2450 | } 2451 | layer { 2452 | name: "relu33" 2453 | type: "ReLU" 2454 | bottom: "batch_norm50" 2455 | top: "relu33" 2456 | } 2457 | layer { 2458 | name: "conv51" 2459 | type: "ConvolutionDepthwise" 2460 | bottom: "relu33" 2461 | top: "conv51" 2462 | convolution_param { 2463 | num_output: 232 2464 | bias_term: false 2465 | pad: 1 2466 | kernel_size: 3 2467 | stride: 1 2468 | weight_filler { 2469 | type: "xavier" 2470 | } 2471 | dilation: 1 2472 | } 2473 | } 2474 | layer { 2475 | name: "batch_norm51" 2476 | type: "BatchNorm" 2477 | bottom: "conv51" 2478 | top: "batch_norm51" 2479 | batch_norm_param { 2480 | use_global_stats: true 2481 | eps: 9.999999747378752e-06 2482 | } 2483 | } 2484 | layer { 2485 | name: "bn_scale51" 2486 | type: "Scale" 2487 | bottom: "batch_norm51" 2488 | top: "batch_norm51" 2489 | scale_param { 2490 | bias_term: true 2491 | } 2492 | } 2493 | layer { 2494 | name: "conv52" 2495 | type: "Convolution" 2496 | bottom: "batch_norm51" 2497 | top: "conv52" 2498 | convolution_param { 2499 | num_output: 232 2500 | bias_term: false 2501 | pad: 0 2502 | kernel_size: 1 2503 | group: 1 2504 | stride: 1 2505 | weight_filler { 2506 | type: "xavier" 2507 | } 2508 | dilation: 1 2509 | } 2510 | } 2511 | layer { 2512 | name: "batch_norm52" 2513 | type: "BatchNorm" 2514 | bottom: "conv52" 2515 | top: "batch_norm52" 2516 | batch_norm_param { 2517 | use_global_stats: true 2518 | eps: 9.999999747378752e-06 2519 | } 2520 | } 2521 | layer { 2522 | name: "bn_scale52" 2523 | type: "Scale" 2524 | bottom: "batch_norm52" 2525 | top: "batch_norm52" 2526 | scale_param { 2527 | bias_term: true 2528 | } 2529 | } 2530 | layer { 2531 | name: "relu34" 2532 | type: "ReLU" 2533 | bottom: "batch_norm52" 2534 | top: "relu34" 2535 | } 2536 | layer { 2537 | name: "concat15" 2538 | type: "Concat" 2539 | bottom: "split23" 2540 | bottom: "relu34" 2541 | top: "concat15" 2542 | concat_param { 2543 | axis: 1 2544 | } 2545 | } 2546 | layer { 2547 | name: "shuffle_channel15" 2548 | type: "ShuffleChannel" 2549 | bottom: "concat15" 2550 | top: "shuffle_channel15" 2551 | shuffle_channel_param { 2552 | group: 2 2553 | } 2554 | } 2555 | layer { 2556 | name: "split13" 2557 | type: "Slice" 2558 | bottom: "shuffle_channel15" 2559 | top: "split25" 2560 | top: "split26" 2561 | slice_param { 2562 | slice_point: 232 2563 | axis: 1 2564 | } 2565 | } 2566 | layer { 2567 | name: "conv53" 2568 | type: "Convolution" 2569 | bottom: "split26" 2570 | top: "conv53" 2571 | convolution_param { 2572 | num_output: 232 2573 | bias_term: false 2574 | pad: 0 2575 | kernel_size: 1 2576 | group: 1 2577 | stride: 1 2578 | weight_filler { 2579 | type: "xavier" 2580 | } 2581 | dilation: 1 2582 | } 2583 | } 2584 | layer { 2585 | name: "batch_norm53" 2586 | type: "BatchNorm" 2587 | bottom: "conv53" 2588 | top: "batch_norm53" 2589 | batch_norm_param { 2590 | use_global_stats: true 2591 | eps: 9.999999747378752e-06 2592 | } 2593 | } 2594 | layer { 2595 | name: "bn_scale53" 2596 | type: "Scale" 2597 | bottom: "batch_norm53" 2598 | top: "batch_norm53" 2599 | scale_param { 2600 | bias_term: true 2601 | } 2602 | } 2603 | layer { 2604 | name: "relu35" 2605 | type: "ReLU" 2606 | bottom: "batch_norm53" 2607 | top: "relu35" 2608 | } 2609 | layer { 2610 | name: "conv54" 2611 | type: "ConvolutionDepthwise" 2612 | bottom: "relu35" 2613 | top: "conv54" 2614 | convolution_param { 2615 | num_output: 232 2616 | bias_term: false 2617 | pad: 1 2618 | kernel_size: 3 2619 | stride: 1 2620 | weight_filler { 2621 | type: "xavier" 2622 | } 2623 | dilation: 1 2624 | } 2625 | } 2626 | layer { 2627 | name: "batch_norm54" 2628 | type: "BatchNorm" 2629 | bottom: "conv54" 2630 | top: "batch_norm54" 2631 | batch_norm_param { 2632 | use_global_stats: true 2633 | eps: 9.999999747378752e-06 2634 | } 2635 | } 2636 | layer { 2637 | name: "bn_scale54" 2638 | type: "Scale" 2639 | bottom: "batch_norm54" 2640 | top: "batch_norm54" 2641 | scale_param { 2642 | bias_term: true 2643 | } 2644 | } 2645 | layer { 2646 | name: "conv55" 2647 | type: "Convolution" 2648 | bottom: "batch_norm54" 2649 | top: "conv55" 2650 | convolution_param { 2651 | num_output: 232 2652 | bias_term: false 2653 | pad: 0 2654 | kernel_size: 1 2655 | group: 1 2656 | stride: 1 2657 | weight_filler { 2658 | type: "xavier" 2659 | } 2660 | dilation: 1 2661 | } 2662 | } 2663 | layer { 2664 | name: "batch_norm55" 2665 | type: "BatchNorm" 2666 | bottom: "conv55" 2667 | top: "batch_norm55" 2668 | batch_norm_param { 2669 | use_global_stats: true 2670 | eps: 9.999999747378752e-06 2671 | } 2672 | } 2673 | layer { 2674 | name: "bn_scale55" 2675 | type: "Scale" 2676 | bottom: "batch_norm55" 2677 | top: "batch_norm55" 2678 | scale_param { 2679 | bias_term: true 2680 | } 2681 | } 2682 | layer { 2683 | name: "relu36" 2684 | type: "ReLU" 2685 | bottom: "batch_norm55" 2686 | top: "relu36" 2687 | } 2688 | layer { 2689 | name: "concat16" 2690 | type: "Concat" 2691 | bottom: "split25" 2692 | bottom: "relu36" 2693 | top: "concat16" 2694 | concat_param { 2695 | axis: 1 2696 | } 2697 | } 2698 | layer { 2699 | name: "shuffle_channel16" 2700 | type: "ShuffleChannel" 2701 | bottom: "concat16" 2702 | top: "shuffle_channel16" 2703 | shuffle_channel_param { 2704 | group: 2 2705 | } 2706 | } 2707 | layer { 2708 | name: "conv56" 2709 | type: "Convolution" 2710 | bottom: "shuffle_channel16" 2711 | top: "conv56" 2712 | convolution_param { 2713 | num_output: 1024 2714 | bias_term: false 2715 | pad: 0 2716 | kernel_size: 1 2717 | group: 1 2718 | stride: 1 2719 | weight_filler { 2720 | type: "xavier" 2721 | } 2722 | dilation: 1 2723 | } 2724 | } 2725 | layer { 2726 | name: "batch_norm56" 2727 | type: "BatchNorm" 2728 | bottom: "conv56" 2729 | top: "batch_norm56" 2730 | batch_norm_param { 2731 | use_global_stats: true 2732 | eps: 9.999999747378752e-06 2733 | } 2734 | } 2735 | layer { 2736 | name: "bn_scale56" 2737 | type: "Scale" 2738 | bottom: "batch_norm56" 2739 | top: "batch_norm56" 2740 | scale_param { 2741 | bias_term: true 2742 | } 2743 | } 2744 | layer { 2745 | name: "relu37" 2746 | type: "ReLU" 2747 | bottom: "batch_norm56" 2748 | top: "relu37" 2749 | } 2750 | layer { 2751 | name: "ave_pool1" 2752 | type: "Pooling" 2753 | bottom: "relu37" 2754 | top: "ave_pool1" 2755 | pooling_param { 2756 | pool: AVE 2757 | global_pooling: true 2758 | } 2759 | } 2760 | layer { 2761 | name: "reshape1" 2762 | type: "Reshape" 2763 | bottom: "ave_pool1" 2764 | top: "reshape1" 2765 | reshape_param { 2766 | shape { 2767 | dim: 0 2768 | dim: 1024 2769 | } 2770 | } 2771 | } 2772 | layer { 2773 | name: "fc1" 2774 | type: "InnerProduct" 2775 | bottom: "reshape1" 2776 | top: "fc1" 2777 | inner_product_param { 2778 | num_output: 200 2779 | bias_term: true 2780 | weight_filler { 2781 | type: "xavier" 2782 | } 2783 | bias_filler { 2784 | type: "constant" 2785 | } 2786 | } 2787 | } 2788 | layer { 2789 | name: "softmax1" 2790 | type: "Softmax" 2791 | bottom: "fc1" 2792 | top: "softmax1" 2793 | softmax_param { 2794 | axis: 1 2795 | } 2796 | } 2797 | -------------------------------------------------------------------------------- /test_convert_to_caffe/pScores.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/pScores.mat -------------------------------------------------------------------------------- /test_convert_to_caffe/shufflenetv2.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Variable 5 | from collections import OrderedDict 6 | from torch.nn import init 7 | import math 8 | 9 | 10 | def conv_bn(inp, oup, stride): 11 | return nn.Sequential( 12 | nn.Conv2d(inp, oup, 3, stride, 1, bias=False), 13 | nn.BatchNorm2d(oup), 14 | nn.ReLU(inplace=True) 15 | ) 16 | 17 | 18 | def conv_1x1_bn(inp, oup): 19 | return nn.Sequential( 20 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 21 | nn.BatchNorm2d(oup), 22 | nn.ReLU(inplace=True) 23 | ) 24 | 25 | 26 | def channel_shuffle(x, groups): 27 | batchsize, num_channels, height, width = x.data.size() 28 | 29 | channels_per_group = num_channels // groups 30 | 31 | # reshape 32 | x = x.view(batchsize, groups, channels_per_group, height, width) 33 | 34 | x = torch.transpose(x, 1, 2).contiguous() 35 | 36 | # flatten 37 | x = x.view(batchsize, -1, height, width) 38 | 39 | return x 40 | 41 | 42 | class InvertedResidual(nn.Module): 43 | def __init__(self, inp, oup, stride, benchmodel): 44 | super(InvertedResidual, self).__init__() 45 | self.benchmodel = benchmodel 46 | self.stride = stride 47 | assert stride in [1, 2] 48 | 49 | oup_inc = oup // 2 50 | 51 | if self.benchmodel == 1: 52 | # assert inp == oup_inc 53 | self.banch2 = nn.Sequential( 54 | # pw 55 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 56 | nn.BatchNorm2d(oup_inc), 57 | nn.ReLU(inplace=True), 58 | # dw 59 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 60 | 1, groups=oup_inc, bias=False), 61 | nn.BatchNorm2d(oup_inc), 62 | # pw-linear 63 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 64 | nn.BatchNorm2d(oup_inc), 65 | nn.ReLU(inplace=True), 66 | ) 67 | else: 68 | self.banch1 = nn.Sequential( 69 | # dw 70 | nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), 71 | nn.BatchNorm2d(inp), 72 | # pw-linear 73 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 74 | nn.BatchNorm2d(oup_inc), 75 | nn.ReLU(inplace=True), 76 | ) 77 | 78 | self.banch2 = nn.Sequential( 79 | # pw 80 | nn.Conv2d(inp, oup_inc, 1, 1, 0, bias=False), 81 | nn.BatchNorm2d(oup_inc), 82 | nn.ReLU(inplace=True), 83 | # dw 84 | nn.Conv2d(oup_inc, oup_inc, 3, stride, 85 | 1, groups=oup_inc, bias=False), 86 | nn.BatchNorm2d(oup_inc), 87 | # pw-linear 88 | nn.Conv2d(oup_inc, oup_inc, 1, 1, 0, bias=False), 89 | nn.BatchNorm2d(oup_inc), 90 | nn.ReLU(inplace=True), 91 | ) 92 | 93 | @staticmethod 94 | def _concat(x, out): 95 | # concatenate along channel axis 96 | return torch.cat((x, out), 1) 97 | 98 | def forward(self, x): 99 | if 1 == self.benchmodel: 100 | # x1 = x[:, :(x.shape[1] // 2), :, :] 101 | # x2 = x[:, (x.shape[1] // 2):, :, :] 102 | x1, x2 = torch.split(x, x.shape[1] // 2, dim=1) 103 | out = self._concat(x1, self.banch2(x2)) 104 | elif 2 == self.benchmodel: 105 | out = self._concat(self.banch1(x), self.banch2(x)) 106 | 107 | return channel_shuffle(out, 2) 108 | 109 | 110 | class ShuffleNetV2(nn.Module): 111 | def __init__(self, input_size, n_class=200, width_mult=1): #1,0 112 | super(ShuffleNetV2, self).__init__() 113 | 114 | assert input_size % 32 == 0 115 | 116 | self.stage_repeats = [4, 8, 4] 117 | # index 0 is invalid and should never be called. 118 | # only used for indexing convenience. 119 | if width_mult == 0.5: 120 | self.stage_out_channels = [-1, 24, 48, 96, 192, 192] #175 121 | elif width_mult == 1.0: 122 | self.stage_out_channels = [-1, 24, 116, 232, 464, 1024] # 1024 123 | elif width_mult == 1.5: 124 | self.stage_out_channels = [-1, 24, 176, 352, 704, 1024] 125 | elif width_mult == 2.0: 126 | self.stage_out_channels = [-1, 24, 224, 488, 976, 2048] 127 | else: 128 | raise ValueError( 129 | """width_mult = {} is not supported""".format(width_mult)) 130 | 131 | # building first layer 132 | input_channel = self.stage_out_channels[1] 133 | self.conv1 = conv_bn(3, input_channel, 2) 134 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 135 | 136 | self.features = [] 137 | # building inverted residual blocks 138 | for idxstage in range(len(self.stage_repeats)): 139 | numrepeat = self.stage_repeats[idxstage] 140 | output_channel = self.stage_out_channels[idxstage + 2] 141 | for i in range(numrepeat): 142 | if i == 0: 143 | # inp, oup, stride, benchmodel): 144 | self.features.append(InvertedResidual( 145 | input_channel, output_channel, 2, 2)) 146 | else: 147 | self.features.append(InvertedResidual( 148 | input_channel, output_channel, 1, 1)) 149 | input_channel = output_channel 150 | 151 | # make it nn.Sequential 152 | self.features = nn.Sequential(*self.features) 153 | 154 | # building last several layers 155 | self.conv_last = conv_1x1_bn( 156 | input_channel, self.stage_out_channels[-1]) 157 | self.globalpool = nn.Sequential(nn.AdaptiveAvgPool2d(1)) 158 | 159 | # building classifier 160 | self.classifier = nn.Sequential( 161 | nn.Linear(self.stage_out_channels[-1], n_class)) 162 | 163 | def forward(self, x): 164 | x = self.conv1(x) 165 | x = self.maxpool(x) 166 | x = self.features(x) 167 | x = self.conv_last(x) 168 | x = self.globalpool(x) 169 | x = x.view(-1, self.stage_out_channels[-1]) 170 | x = self.classifier(x) 171 | return x 172 | 173 | 174 | def shufflenetv2(width_mult=1.): 175 | model = ShuffleNetV2(width_mult=width_mult) 176 | return model 177 | 178 | 179 | if __name__ == "__main__": 180 | """Testing 181 | """ 182 | model = ShuffleNetV2() 183 | print(model) 184 | -------------------------------------------------------------------------------- /test_convert_to_caffe/shufflenetv2_to_caffe.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path as osp 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | import argparse 7 | import caffe 8 | import numpy as np 9 | 10 | this_dir = '.' 11 | 12 | cpath = '/home/jinsy/2T/jinsy/code/tuya_sdk/Pytorch2Caffe' 13 | if cpath not in sys.path: 14 | sys.path.append(cpath) 15 | 16 | import converter 17 | from utils.load_test_image import load_test_image 18 | from utils.get_topk import get_topk 19 | from utils.load import load_troch_model2 20 | import shufflenetv2 as ShuffleNetV2 21 | 22 | 23 | def _channel_shuffle(raw, input, groups): 24 | x = input.clone() 25 | name = converter.log.add_layer(name='shuffle_channel') 26 | converter.log.add_blobs([x], name='shuffle_channel') 27 | layer = converter.caffe_net.Layer_param(name=name, type='ShuffleChannel', 28 | bottom=[converter.log.blobs(input)], top=[converter.log.blobs(x)]) 29 | layer.channel_shuffle_param(groups) 30 | converter.log.cnet.add_layer(layer) 31 | return x 32 | 33 | 34 | ShuffleNetV2.channel_shuffle = converter.Rp(ShuffleNetV2.channel_shuffle, _channel_shuffle) 35 | 36 | 37 | def parse(): 38 | parser = argparse.ArgumentParser(description='convert pytorch model to caffe') 39 | parser.add_argument('-c', '--convert', action='store_true', help='convert pytorch model to caffe') 40 | parser.add_argument('-t', '--test', action='store_true', help='test converted model') 41 | parser.add_argument('-wm', '--width-mult', type=float, choices=[0.5, 1.0], default=1.0, 42 | help='width mult') 43 | return parser.parse_args() 44 | 45 | 46 | def convert(pytorch_net, caffe_prototxt, caffe_model_file, name): 47 | pytorch_net.eval() 48 | input = torch.ones(1, 3, 160, 160) 49 | converter.trans_net(pytorch_net, input, name) 50 | converter.save_prototxt(caffe_prototxt) 51 | converter.save_caffemodel(caffe_model_file) 52 | 53 | 54 | def test(caffe_prototxt, caffe_model_file, pytorch_net, topk=5): 55 | pytorch_net.eval() 56 | input = load_test_image() 57 | with torch.no_grad(): 58 | x1 = pytorch_net(input) 59 | x1 = x1.numpy() 60 | 61 | caffe_net = caffe.Net(caffe_prototxt, caffe_model_file, caffe.TEST) 62 | caffe.set_mode_cpu() 63 | caffe_net.blobs['data1'].data.reshape(*input.size()) 64 | caffe_net.blobs['data1'].data[...] = input.numpy() 65 | x2 = caffe_net.forward()['softmax1'] 66 | idx = 0 67 | 68 | expect = torch.dot(torch.arange(0,200).float() ,torch.from_numpy(x1.flatten())) 69 | print('pytorch: ', expect) 70 | 71 | expect = torch.dot(torch.arange(0,200).float() ,torch.from_numpy(x2.flatten())) 72 | print('caffe: ', expect) 73 | 74 | 75 | class SoftmaxWrapper(nn.Module): 76 | def __init__(self, net): 77 | super(SoftmaxWrapper, self).__init__() 78 | self.net = net 79 | 80 | def forward(self, x): 81 | y = self.net(x) 82 | return F.softmax(y, dim=1) 83 | 84 | 85 | def shufflenetv2(width_mult=1., pretrained=True): 86 | model = ShuffleNetV2.ShuffleNetV2(input_size=160, width_mult=width_mult) 87 | if pretrained: 88 | if width_mult == 1.: 89 | model_file = osp.join(this_dir, 'model/97_160_2.pth') 90 | elif width_mult == .5: 91 | model_file = osp.join(this_dir, '../models/ShuffleNetV2/shufflenetv2_x0.5_60.646_81.696.pth.tar') 92 | else: 93 | raise ValueError('width_mult = {} is not support pretrained model'.format(width_mult)) 94 | assert osp.exists(model_file), '{} is not exists!'.format(model_file) 95 | print('shufflenetv2 load state dict: ', model_file) 96 | state = torch.load(model_file) 97 | model.load_state_dict(state['net'], strict=False) 98 | 99 | return model 100 | 101 | 102 | if __name__ == '__main__': 103 | args = parse() 104 | 105 | name = 'shufflenetv2_{:.1f}x'.format(args.width_mult) 106 | 107 | caffe_prototxt = osp.join(this_dir, 'model/') + '{}.prototxt'.format(name) 108 | caffe_model_file = osp.join(this_dir, 'model/') + '{}.caffemodel'.format(name) 109 | net = shufflenetv2(width_mult=args.width_mult, pretrained=True) 110 | net = SoftmaxWrapper(net) 111 | 112 | if args.convert: 113 | convert(net, caffe_prototxt, caffe_model_file, name) 114 | 115 | if args.test: 116 | test(caffe_prototxt, caffe_model_file, net) 117 | -------------------------------------------------------------------------------- /test_convert_to_caffe/test.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.optim as optim 4 | from torch.optim import lr_scheduler 5 | from torch.autograd import Variable 6 | import torchvision 7 | from torchvision import datasets, models, transforms 8 | import time 9 | import os 10 | from PIL import Image 11 | import sys 12 | import torch.nn.functional as F 13 | from shufflenetv2 import ShuffleNetV2 14 | import scipy.io as scio 15 | import cv2 16 | 17 | #config 18 | matFile = 'pScores.mat' 19 | fiiqaWeight = './model/97_160_2.pth' 20 | detectFace = './model/haarcascade_frontalface_default.xml' 21 | imagePath = './image/test1.jpg' 22 | facePath = './image/crop/test_face.jpg' 23 | inputSize = 160 24 | 25 | #crop face from img 26 | faceCascade = cv2.CascadeClassifier(detectFace) 27 | image = cv2.imread(imagePath) 28 | faces = faceCascade.detectMultiScale( 29 | image, 30 | scaleFactor=1.1, 31 | minNeighbors=5, 32 | minSize=(10, 10) 33 | ) 34 | for (x, y, w, h) in faces: 35 | cv2.imwrite('./image/crop/' + 'test_face.jpg',image[y:y+h,x:x+w]) 36 | cv2.waitKey(0) 37 | 38 | #transfer img to tensor 39 | dataTransforms = transforms.Compose([ 40 | transforms.Resize(inputSize), 41 | transforms.ToTensor(), 42 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 43 | ]) 44 | 45 | #load net 46 | net = ShuffleNetV2(inputSize) 47 | checkpoint = torch.load(fiiqaWeight) 48 | net.load_state_dict(checkpoint['net']) 49 | net.eval() 50 | 51 | #load face and get expect num 52 | face = Image.open(facePath) 53 | imgblob = dataTransforms(face).unsqueeze(0) 54 | imgblob = Variable(imgblob) 55 | torch.no_grad() 56 | predict = F.softmax(net(imgblob),dim=1) 57 | expect = torch.sum(Variable(torch.arange(0,200)).float()*predict, 1) 58 | 59 | print(predict, expect) 60 | 61 | expect = int(expect) 62 | 63 | #load matFile and get score 64 | data = scio.loadmat(matFile) 65 | scores = data['pScores'] 66 | score = scores[:,expect] 67 | 68 | print('expect: %d' % expect) 69 | print('score: %.3f' % score) 70 | -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/utils/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/__pycache__/get_topk.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/utils/__pycache__/get_topk.cpython-36.pyc -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/__pycache__/load.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/utils/__pycache__/load.cpython-36.pyc -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/__pycache__/load_test_image.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangyuke001/FIIQA-PyTorch/29ab6af25a4e5beeffc6709752ff983fc6e7f4a6/test_convert_to_caffe/utils/__pycache__/load_test_image.cpython-36.pyc -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/get_topk.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def get_topk(prob, k=5): 5 | size = prob.shape[0] 6 | k = min(k, size) 7 | sorted_idx = np.argsort(prob)[::-1] 8 | topk_idx = sorted_idx[:k] 9 | topk_prob = prob[sorted_idx[:k]] 10 | return topk_idx, topk_prob 11 | -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/load.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from collections import OrderedDict 3 | 4 | 5 | def load_troch_model(filename): 6 | def _process_state(state): 7 | new_state_dict = OrderedDict() 8 | for k, v in state.items(): 9 | if k.startswith('module.'): 10 | k = k.replace('module.', '') 11 | new_state_dict[k] = v 12 | return new_state_dict 13 | state = torch.load(filename, map_location=lambda storage, location: storage) 14 | state['state_dict'] = _process_state(state['state_dict']) 15 | return state 16 | 17 | 18 | def load_troch_model2(filename): 19 | def _process_state(state): 20 | new_state_dict = OrderedDict() 21 | for k, v in state.items(): 22 | if k.startswith('module.'): 23 | k = k.replace('module.', '') 24 | new_state_dict[k] = v 25 | return new_state_dict 26 | state = torch.load(filename, map_location=lambda storage, location: storage) 27 | state = _process_state(state) 28 | return state 29 | -------------------------------------------------------------------------------- /test_convert_to_caffe/utils/load_test_image.py: -------------------------------------------------------------------------------- 1 | import os.path as osp 2 | import cv2 3 | from torchvision import transforms 4 | import torch 5 | import numpy as np 6 | from PIL import Image 7 | 8 | this_dir = osp.abspath(osp.dirname(__file__)) 9 | 10 | 11 | def load_test_image(filename='test_face.jpg', image_size=(3, 160, 160)): 12 | full_filename = osp.join(this_dir, '../image/crop', filename) 13 | print(full_filename) 14 | rgb_image = Image.open(full_filename) 15 | tf = transforms.Compose([ 16 | transforms.Resize(160), 17 | transforms.ToTensor(), 18 | transforms.Normalize(mean=[0.485, 0.456, 0.406], 19 | std=[0.229, 0.224, 0.225]) 20 | 21 | ]) 22 | tensor = tf(rgb_image) 23 | return tensor.view(1, *image_size) 24 | 25 | 26 | def load_test_image2(filename='cat_224x224.jpg', image_size=(3, 224, 224)): 27 | full_filename = osp.join(this_dir, '../data', filename) 28 | bgr_image = cv2.imread(full_filename) 29 | bgr_image2 = torch.from_numpy(cv2.resize(bgr_image, image_size[1:]).astype(np.float32)) 30 | return bgr_image2.view(1, *image_size) 31 | -------------------------------------------------------------------------------- /test_model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import DataLoader 3 | from torch.autograd import Variable 4 | 5 | from shufflenetv2 import ShuffleNetV2 6 | import torchvision 7 | import torchvision.transforms as transforms 8 | from datagen import ListDataset 9 | import csv 10 | import os 11 | from PIL import Image 12 | 13 | test_data = './data/test-faces/' 14 | list_file = './data/new_4people_test_standard.txt' 15 | checkpoint = torch.load('./checkpoint/97_160_2.pth') 16 | 17 | def write_csv(header, write_data, filename): 18 | # header-标题 write_data-写入数据 filename-文件名 19 | with open(filename, 'a', newline='',encoding='utf-8-sig') as csvFile: 20 | writer = csv.writer(csvFile) 21 | if os.path.getsize(filename) == False: 22 | # 先写columns_name 23 | writer.writerow(header) 24 | # 写入多行用writerows 25 | writer.writerows(write_data) 26 | 27 | def test(): 28 | # configure model 29 | net= ShuffleNetV2(input_size=160) 30 | net.load_state_dict(checkpoint['net']) 31 | net.eval() 32 | 33 | transform_test = transforms.Compose([ 34 | transforms.Resize(160), 35 | transforms.CenterCrop(160), 36 | transforms.ToTensor(), 37 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 38 | ]) 39 | testset = ListDataset(root=test_data, list_file=list_file, \ 40 | transform=transform_test) 41 | testloader = torch.utils.data.DataLoader(testset, batch_size=64, \ 42 | shuffle=False, num_workers=4, pin_memory = True) 43 | torch.multiprocessing.set_sharing_strategy('file_system') 44 | 45 | results = [] 46 | for ii,(data,path) in enumerate(testloader): 47 | 48 | #input = torch.autograd.Variable(data) 49 | with torch.no_grad(): 50 | score = net(data) 51 | 52 | probability = torch.nn.functional.softmax(score,dim=1)#[:,0].data.tolist() 53 | # label = score.max(dim = 1)[1].data.tolist() 54 | expect = torch.sum(torch.arange(0,200).float()*probability, 1) 55 | #print('expect: %.4f' % expect.numpy()) 56 | batch_results = [(path_,expect_) for path_,expect_ in zip(path,expect) ] 57 | print('batch_results: ',batch_results) 58 | results += batch_results 59 | write_csv('FIIQA',results,'result.csv') 60 | 61 | return results 62 | 63 | 64 | if __name__ == "__main__": 65 | """Testing 66 | """ 67 | test() -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import argparse 5 | 6 | import torch 7 | import torch.nn as nn 8 | import torch.optim as optim 9 | 10 | import torch.nn.functional as F 11 | import torch.backends.cudnn as cudnn 12 | import torchvision 13 | import torchvision.transforms as transforms 14 | from net import AGNet 15 | from loss import FIIQALoss 16 | from datagen import ListDataset 17 | from torch.autograd import Variable 18 | from adabound import AdaBound 19 | from shufflenetv2 import ShuffleNetV2 20 | from flops_counter_pytorch.ptflops import get_model_complexity_info 21 | from summary import model_summary 22 | 23 | parser = argparse.ArgumentParser(description='PyTorch AGNet Training') 24 | parser.add_argument('--lr', default=1e-3, type=float, help='learning rate') 25 | parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') 26 | args = parser.parse_args() 27 | 28 | assert torch.cuda.is_available(), 'Error: CUDA not found!' 29 | best_correct = 0 # best number of fiiqa_correct 30 | start_epoch = 0 # start from epoch 0 or last epoch 31 | best_test_acc_epoch = 0 32 | batch_size=128 33 | path = './checkpoint/' 34 | TOLERANCE = 2 35 | input_size=32 36 | train_epoch=500 37 | 38 | # Data 39 | print('==> Preparing data..') 40 | transform_train = transforms.Compose([ 41 | transforms.Resize(input_size), 42 | transforms.CenterCrop(input_size), 43 | #transforms.RandomCrop(160, padding=4), 44 | transforms.RandomHorizontalFlip(), 45 | transforms.ToTensor(), 46 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 47 | ]) 48 | 49 | transform_test = transforms.Compose([ 50 | transforms.Resize(input_size), 51 | transforms.CenterCrop(input_size), 52 | transforms.ToTensor(), 53 | transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 54 | ]) 55 | 56 | trainset = ListDataset(root='./data/trainingset/train-faces/', list_file='./data/trainingset/new_4people_train_standard.txt', transform=transform_train) 57 | trainloader = torch.utils.data.DataLoader(trainset, batch_size, shuffle=True, num_workers=12) 58 | testset = ListDataset(root='./data/validationset/val-faces/', list_file='./data/validationset/new_4people_val_standard.txt', transform=transform_test) 59 | testloader = torch.utils.data.DataLoader(testset, batch_size, shuffle=False, num_workers=12) 60 | 61 | # Model 62 | net = ShuffleNetV2(input_size) 63 | ''' 64 | model_summary(net,input_size=(3,input_size,input_size)) 65 | flops, params = get_model_complexity_info(net, (input_size, input_size), as_strings=True, print_per_layer_stat=False) 66 | print('Flops: ' + flops) 67 | print('Params: ' + params) 68 | ''' 69 | 70 | if args.resume: 71 | print('==> Resuming from checkpoint..') 72 | checkpoint = torch.load('./checkpoint/ckpt.pth') 73 | net.load_state_dict(checkpoint['net']) 74 | best_correct = checkpoint['correct'] 75 | start_epoch = checkpoint['epoch'] 76 | net = torch.nn.DataParallel(net, device_ids=range(torch.cuda.device_count())) #多gpu并行训练 77 | net.cuda() 78 | 79 | criterion = FIIQALoss() 80 | #criterion = nn.CrossEntropyLoss() 81 | optimizer = optim.AdaBound(net.parameters(),lr=args.lr,final_lr=0.1) 82 | 83 | #optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=0.9, weight_decay=1e-4) 84 | 85 | # Training 86 | def train(epoch): 87 | print('\nEpoch: %d' % epoch) 88 | net.train() 89 | train_loss = 0 90 | total = 0 91 | fiiqa_correct = 0 92 | for batch_idx, (inputs, fiiqa_targets) in enumerate(trainloader): 93 | inputs = Variable(inputs.cuda()) 94 | fiiqa_targets = Variable(fiiqa_targets.cuda()) 95 | optimizer.zero_grad() 96 | fiiqa_preds = net(inputs) 97 | loss = criterion(fiiqa_preds.float(), fiiqa_targets) 98 | loss.backward() 99 | optimizer.step() 100 | train_loss += loss.item() 101 | fiiqa_correct_i = accuracy(fiiqa_preds, fiiqa_targets) 102 | fiiqa_correct += fiiqa_correct_i 103 | total += len(inputs) 104 | print('train_loss: %.3f | fiiqa_prec: %.3f (%d/%d) | [%d/%d]' \ 105 | % (loss.item(), \ 106 | 100.*fiiqa_correct/total, fiiqa_correct, total, \ 107 | batch_idx+1, len(trainloader))) 108 | 109 | # Test 110 | def test(epoch): 111 | global Test_acc 112 | global best_correct 113 | global best_test_acc_epoch 114 | print('\nTest') 115 | net.eval() 116 | test_loss = 0 117 | total = 0 118 | fiiqa_correct = 0 119 | for batch_idx, (inputs, fiiqa_targets) in enumerate(testloader): 120 | inputs = Variable(inputs.cuda()) 121 | fiiqa_targets = Variable(fiiqa_targets.cuda()) 122 | fiiqa_preds = net(inputs) 123 | loss = criterion(fiiqa_preds, fiiqa_targets) 124 | test_loss += loss.item() 125 | fiiqa_correct_i = accuracy(fiiqa_preds, fiiqa_targets) 126 | fiiqa_correct += fiiqa_correct_i 127 | total += len(inputs) 128 | print('test_loss: %.3f | fiiqa_prec: %.3f (%d/%d) | [%d/%d]' \ 129 | % (loss.item(), \ 130 | 100.*fiiqa_correct/total, fiiqa_correct, total, \ 131 | batch_idx+1, len(testloader))) 132 | 133 | # Save checkpoint 134 | Test_acc = 100.*fiiqa_correct/total 135 | 136 | if Test_acc > best_correct: 137 | print('Saving..') 138 | print("best_test_acc: %0.3f" % Test_acc) 139 | best_correct = Test_acc 140 | best_test_acc_epoch = epoch 141 | 142 | state = { 143 | 'net': net.module.state_dict(), 144 | 'correct': best_correct, 145 | 'epoch': epoch, 146 | } 147 | 148 | 149 | if not os.path.isdir('checkpoint'): 150 | os.mkdir('checkpoint') 151 | torch.save(state, os.path.join(path,str(best_correct)+'_'+str(input_size)+'_'+str(TOLERANCE) +'.pth')) 152 | 153 | def accuracy(fiiqa_preds, fiiqa_targets): 154 | '''Measure batch accuracy.''' 155 | fiiqa_prob = F.softmax(fiiqa_preds,dim=1) 156 | fiiqa_expect = torch.sum(Variable(torch.arange(0,200)).cuda().float()*fiiqa_prob, 1) 157 | fiiqa_correct = ((fiiqa_expect-fiiqa_targets.float()).abs() < TOLERANCE).long().sum().cpu().item() 158 | return fiiqa_correct 159 | 160 | for epoch in range(start_epoch, start_epoch+train_epoch): 161 | train(epoch) 162 | test(epoch) 163 | print('best_test_acc: %0.3f' % best_correct) 164 | print('best_test_acc_epoch: %d' % best_test_acc_epoch) 165 | -------------------------------------------------------------------------------- /train_affectnet.py: -------------------------------------------------------------------------------- 1 | '''Train CK+ with PyTorch.''' 2 | # 10 crop for data enhancement 3 | from __future__ import print_function 4 | 5 | import torch 6 | import torch.nn as nn 7 | import torch.optim as optim 8 | import torch.nn.functional as F 9 | import torch.backends.cudnn as cudnn 10 | import torchvision 11 | from torchvision import transforms,utils 12 | from torch.utils.data import DataLoader 13 | import transforms as transforms 14 | import numpy as np 15 | import os 16 | import argparse 17 | import utils 18 | from CK import CK 19 | from torch.autograd import Variable 20 | from models import * 21 | from ShuffleNetV2 import ShuffleNetV2 22 | from flops_counter_pytorch.ptflops import get_model_complexity_info 23 | from summary import model_summary 24 | from datagen import ListDataset 25 | 26 | 27 | train_data = '../train_val_imgs/Manually/Manually_train_croped' 28 | test_data = '../train_val_imgs/Manually/Manually_validation_croped' 29 | 30 | parser = argparse.ArgumentParser(description='PyTorch CK+ CNN Training') 31 | #parser.add_argument('--model', type=str, default='VGG19', help='CNN architecture') 32 | parser.add_argument('--dataset', type=str, default='CK+', help='dataset') 33 | parser.add_argument('--fold', default=1, type=int, help='k fold number') 34 | parser.add_argument('--bs', default=128, type=int, help='batch_size') 35 | parser.add_argument('--lr', default=0.001, type=float, help='learning rate') 36 | parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') 37 | opt = parser.parse_args() 38 | 39 | use_cuda = torch.cuda.is_available() 40 | 41 | best_Test_acc = 0 # best PrivateTest accuracy 42 | best_Test_acc_epoch = 0 43 | start_epoch = 0 # start from epoch 0 or last checkpoint epoch 44 | 45 | learning_rate_decay_start = 20 # 50 46 | learning_rate_decay_every = 1 # 5 47 | learning_rate_decay_rate = 0.8 # 0.9 48 | 49 | 50 | total_epoch = 500 51 | bs = 128 52 | input_size = 64 53 | cut_size = input_size - 1 54 | n_class=7 55 | 56 | #path = os.path.join(opt.dataset + '_' + opt.model, str(opt.fold)) 57 | path = './AffectNet+ShuffleNetV2/' 58 | 59 | # Data 60 | print('==> Preparing data..') 61 | transform_train = transforms.Compose([ 62 | transforms.Resize(input_size), 63 | transforms.RandomCrop(cut_size), 64 | transforms.RandomHorizontalFlip(), 65 | transforms.ToTensor(), 66 | #transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 67 | ]) 68 | 69 | transform_test = transforms.Compose([ 70 | transforms.Resize(input_size), 71 | #transforms.RandomCrop(cut_size), 72 | #transforms.RandomHorizontalFlip(), 73 | transforms.TenCrop(cut_size), 74 | transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), 75 | #transforms.ToTensor(), 76 | #transforms.Normalize((0.485,0.456,0.406), (0.229,0.224,0.225)) 77 | ]) 78 | 79 | #trainset=torchvision.datasets.ImageFolder(train_data,transform_train) 80 | trainset = ListDataset(root='../train_val_imgs/Manually/Manually_train_croped/', list_file='./AffectNet/train.txt', transform=transform_train) 81 | trainloader=DataLoader(trainset,bs,shuffle=True, num_workers=12) 82 | #testset=torchvision.datasets.ImageFolder(test_data,transform_test) 83 | testset = ListDataset(root='../train_val_imgs/Manually/Manually_validation_croped/', list_file='./AffectNet/val.txt', transform=transform_test) 84 | testloader=DataLoader(testset,batch_size=128,shuffle=True, num_workers=12) 85 | 86 | 87 | net = ShuffleNetV2(input_size,n_class) 88 | ''' 89 | model_summary(net,input_size=(3,input_size,input_size)) 90 | flops, params = get_model_complexity_info(net, (input_size, input_size), as_strings=True, print_per_layer_stat=False) 91 | print('Flops: ' + flops) 92 | print('Params: ' + params) 93 | #net = net.to(device=my_device) 94 | ''' 95 | 96 | if opt.resume: 97 | # Load checkpoint. 98 | print('==> Resuming from checkpoint..') 99 | assert os.path.isdir(path), 'Error: no checkpoint directory found!' 100 | checkpoint = torch.load(os.path.join(path,'ShuffleNetV2.pth')) 101 | 102 | net.load_state_dict(checkpoint['net']) 103 | best_Test_acc = checkpoint['best_Test_acc'] 104 | best_Test_acc_epoch = checkpoint['best_Test_acc_epoch'] 105 | start_epoch = best_Test_acc_epoch + 1 106 | else: 107 | print('==> Building model..') 108 | 109 | if use_cuda: 110 | net.cuda() 111 | 112 | criterion = nn.CrossEntropyLoss() 113 | optimizer=optim.AdaBound(net.parameters(), lr=opt.lr, final_lr=0.1) 114 | #optimizer = optim.SGD(net.parameters(), lr=opt.lr, momentum=0.9, weight_decay=1e-4) 115 | 116 | # Training 117 | def train(epoch): 118 | print('\nEpoch: %d' % epoch) 119 | global Train_acc 120 | net.train() 121 | train_loss = 0 122 | correct = 0 123 | total = 0 124 | 125 | for batch_idx, (inputs, targets) in enumerate(trainloader): 126 | if use_cuda: 127 | inputs, targets = inputs.cuda(), targets.cuda() 128 | optimizer.zero_grad() 129 | #inputs, targets = Variable(inputs), Variable(targets) 130 | outputs = net(inputs) 131 | loss = criterion(outputs, targets) 132 | loss.backward() 133 | utils.clip_gradient(optimizer, 0.1) #clip_gradient能有效了控制梯度爆炸的影响,使得最终的loss能下降到满意的结果 134 | optimizer.step() 135 | 136 | train_loss += loss.item() 137 | _, predicted = torch.max(outputs.data, 1) 138 | total += targets.size(0) 139 | correct += predicted.eq(targets.data).cpu().sum() 140 | 141 | utils.progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' 142 | % (train_loss/(batch_idx+1), 100.*correct/total, correct, total)) 143 | 144 | Train_acc = 100.*correct/total 145 | 146 | # test 147 | def test(epoch): 148 | global Test_acc 149 | global best_Test_acc 150 | global best_Test_acc_epoch 151 | net.eval() 152 | PrivateTest_loss = 0 153 | correct = 0 154 | total = 0 155 | for batch_idx, (inputs, targets) in enumerate(testloader): 156 | bs, ncrops, c, h, w = np.shape(inputs) 157 | inputs = inputs.view(-1, c, h, w) 158 | 159 | if use_cuda: 160 | inputs, targets = inputs.cuda(), targets.cuda() 161 | 162 | inputs, targets = Variable(inputs), Variable(targets) 163 | outputs = net(inputs) 164 | outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops 165 | 166 | loss = criterion(outputs_avg, targets) 167 | PrivateTest_loss += loss.item() 168 | _, predicted = torch.max(outputs_avg.data, 1) 169 | total += targets.size(0) 170 | correct += predicted.eq(targets.data).cpu().sum() 171 | 172 | utils.progress_bar(batch_idx, len(testloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' 173 | % (PrivateTest_loss / (batch_idx + 1), \ 174 | 100. * correct / total, correct, total)) 175 | # Save checkpoint. 176 | Test_acc = 100.*correct/total 177 | 178 | if Test_acc > best_Test_acc: 179 | print('Saving..') 180 | print("best_Test_acc: %0.3f" % Test_acc) 181 | state = {'net': net.state_dict() if use_cuda else net, 182 | 'best_Test_acc': Test_acc, 183 | 'best_Test_acc_epoch': epoch, 184 | } 185 | if not os.path.isdir(opt.dataset + '_' + 'ShuffleNetV2'): 186 | os.mkdir(opt.dataset + '_' + 'ShuffleNetV2') 187 | if not os.path.isdir(path): 188 | os.mkdir(path) 189 | #torch.save(state, os.path.join(path, str(best_Test_acc) + '_ShuffleNetV2.pth')) 190 | best_Test_acc = Test_acc 191 | best_Test_acc_epoch = epoch 192 | torch.save(state, os.path.join(path, str(best_Test_acc) + '_'+str(input_size)+'_ShuffleNetV2.pth')) 193 | 194 | for epoch in range(start_epoch, total_epoch): 195 | train(epoch) 196 | test(epoch) 197 | 198 | print("best_Test_acc: %0.3f" % best_Test_acc) 199 | print("best_Test_acc_epoch: %d" % best_Test_acc_epoch) --------------------------------------------------------------------------------