├── ThiNet_TPAMI ├── VGG16 │ ├── delete_tmp_files.sh │ ├── cp_net.py │ ├── run_this.sh │ ├── parse_log │ │ ├── parse_log.sh │ │ ├── extract_seconds.py │ │ └── plot_training_log.py.example │ ├── net_generator.py │ └── compress_model.py └── ResNet50 │ ├── delete_tmp_files.sh │ ├── cp_net.py │ ├── run_this.sh │ ├── parse_log │ ├── parse_log.sh │ ├── extract_seconds.py │ └── plot_training_log.py.example │ ├── compress_model.py │ └── net_generator.py ├── ThiNet_ICCV ├── cp_net.py ├── run_this.sh ├── parse_log │ ├── parse_log.sh │ ├── extract_seconds.py │ └── plot_training_log.py.example ├── net_generator.py └── compress_model.py ├── LICENSE ├── ToolKit ├── caffe_lmdb_keep_ratio │ ├── create_lmdb.sh │ └── io.cpp └── FLOPs_and_size.py └── README.md /ThiNet_TPAMI/VGG16/delete_tmp_files.sh: -------------------------------------------------------------------------------- 1 | find . -name "*.caffemodel" | xargs rm -f 2 | find . -name "*.solverstate" | xargs rm -f -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/delete_tmp_files.sh: -------------------------------------------------------------------------------- 1 | find . -name "*.caffemodel" | xargs rm -f 2 | find . -name "*.solverstate" | xargs rm -f -------------------------------------------------------------------------------- /ThiNet_ICCV/cp_net.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import re 4 | import sys 5 | 6 | if __name__ == '__main__': 7 | compress_layer = int(sys.argv[1]) 8 | layers = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 9 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 10 | FileNames = os.listdir(layers[compress_layer]+'/snapshot/') 11 | max_value = 0 12 | for i in range(len(FileNames)): 13 | name = re.findall(r"_iter_(.+?).caffemodel", FileNames[i]) 14 | if len(name) > 0: 15 | if int(name[0]) > max_value: 16 | max_value = int(name[0]) 17 | filename = layers[compress_layer]+'/snapshot/_iter_'+str(max_value)+".caffemodel" 18 | shutil.copyfile(filename, "model.caffemodel") 19 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/cp_net.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import re 4 | import sys 5 | 6 | if __name__ == '__main__': 7 | compress_layer = int(sys.argv[1]) 8 | compress_block = int(sys.argv[2]) 9 | layers = ['2a', '2b', '2c', '3a', '3b', '3c', '3d', '4a', '4b', '4c', '4d', '4e', '4f', '5a', '5b', '5c'] 10 | FileNames = os.listdir(layers[compress_layer]+'_'+str(compress_block)+'/snapshot/') 11 | max_value = 0 12 | for i in range(len(FileNames)): 13 | name = re.findall(r"_iter_(.+?).caffemodel", FileNames[i]) 14 | if len(name) > 0: 15 | if int(name[0]) > max_value: 16 | max_value = int(name[0]) 17 | filename = layers[compress_layer]+'_'+str(compress_block)+'/snapshot/_iter_'+str(max_value)+".caffemodel" 18 | shutil.copyfile(filename, "model.caffemodel") 19 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/cp_net.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import re 4 | import sys 5 | 6 | if __name__ == '__main__': 7 | compress_layer = int(sys.argv[1]) 8 | layers = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 9 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 10 | FileNames = os.listdir(layers[compress_layer]+'/snapshot/') 11 | max_value = 0 12 | for i in range(len(FileNames)): 13 | name = re.findall(r"_iter_(.+?).caffemodel", FileNames[i]) 14 | if len(name) > 0: 15 | if int(name[0]) > max_value: 16 | max_value = int(name[0]) 17 | filename = layers[compress_layer]+'/snapshot/_iter_'+str(max_value)+".caffemodel" 18 | shutil.copyfile(filename, "model.caffemodel") 19 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/run_this.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp /data/luojh/net/caffe/VGG16/VGG_ILSVRC_16_layers.caffemodel model.caffemodel 3 | layers=(conv1_1 conv1_2 conv2_1 conv2_2 conv3_1 conv3_2 conv3_3 conv4_1 conv4_2 conv4_3 conv5_1 conv5_2 conv5_3 fc6 fc7) 4 | TOOLS=/home/luojh2/Software/caffe-master/build/tools 5 | gpus=0,1,2,3 6 | gpu=0 7 | compression_rate=0.5 8 | 9 | for compress_layer in $(seq 0 9) 10 | do 11 | python compress_model.py ${compress_layer} ${gpu} ${compression_rate} 12 | 13 | log_name="value_sum_vgg.log" 14 | LOG=${layers[compress_layer]}/logs/${log_name} 15 | if [ ! -d "${layers[compress_layer]}/logs" ]; then 16 | mkdir ${layers[compress_layer]}/logs 17 | fi 18 | 19 | solver_path=${layers[compress_layer]}/solver.prototxt 20 | $TOOLS/caffe train --solver=$solver_path -weights model.caffemodel -gpu ${gpus} 2>&1 | tee $LOG 21 | 22 | cd ${layers[compress_layer]}/logs/ 23 | ../../parse_log/parse_log.sh "$log_name" 24 | cd ../.. 25 | 26 | python cp_net.py ${compress_layer} 27 | done 28 | -------------------------------------------------------------------------------- /ThiNet_ICCV/run_this.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp /data/luojh/net/caffe/VGG16/VGG_ILSVRC_16_layers.caffemodel model.caffemodel 3 | layers=(conv1_1 conv1_2 conv2_1 conv2_2 conv3_1 conv3_2 conv3_3 conv4_1 conv4_2 conv4_3 conv5_1 conv5_2 conv5_3 fc6 fc7) 4 | TOOLS=/home/luojh2/Software/caffe-master/build/tools 5 | gpus=0,1,2,3 6 | gpu=0 7 | compression_rate=0.5 8 | 9 | # prune layer by layer 10 | for compress_layer in $(seq 0 9) 11 | do 12 | # prune 13 | python compress_model.py ${compress_layer} ${gpu} ${compression_rate} 14 | # fine-tune 15 | log_name="value_sum_vgg.log" 16 | LOG=${layers[compress_layer]}/logs/${log_name} 17 | if [ ! -d "${layers[compress_layer]}/logs" ]; then 18 | mkdir ${layers[compress_layer]}/logs 19 | fi 20 | 21 | solver_path=${layers[compress_layer]}/solver.prototxt 22 | $TOOLS/caffe train --solver=$solver_path -weights model.caffemodel -gpu ${gpus} 2>&1 | tee $LOG 23 | 24 | cd ${layers[compress_layer]}/logs/ 25 | ../../parse_log/parse_log.sh "$log_name" 26 | cd ../.. 27 | 28 | python cp_net.py ${compress_layer} 29 | done 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jian-Hao 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 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/run_this.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp /data/luojh/net/caffe/ResNet-50-model.caffemodel model.caffemodel 3 | layers=(2a 2b 2c 3a 3b 3c 3d 4a 4b 4c 4d 4e 4f 5a 5b 5c) 4 | TOOLS=/home/luojh2/Software/caffe-master/build/tools 5 | gpu=4 6 | gpus=4,5,6,7 7 | compression_rate=0.7 8 | 9 | for compress_layer in $(seq 0 15) 10 | do 11 | python compress_model.py ${compress_layer} 0 ${compression_rate} ${gpu} 12 | python compress_model.py ${compress_layer} 1 ${compression_rate} ${gpu} 13 | 14 | compress_block=1 15 | log_name="ResNet_50.log" 16 | LOG=${layers[compress_layer]}_$compress_block/logs/${log_name} 17 | if [ ! -d "${layers[compress_layer]}_$compress_block/logs" ]; then 18 | mkdir ${layers[compress_layer]}_$compress_block/logs 19 | fi 20 | 21 | solver_path=${layers[compress_layer]}_$compress_block/solver.prototxt 22 | $TOOLS/caffe train --solver=$solver_path -weights model.caffemodel -gpu ${gpus} 2>&1 | tee $LOG 23 | 24 | cd ${layers[compress_layer]}_$compress_block/logs/ 25 | ../../parse_log/parse_log.sh "$log_name" 26 | cd ../.. 27 | 28 | python cp_net.py ${compress_layer} ${compress_block} 29 | done 30 | -------------------------------------------------------------------------------- /ToolKit/caffe_lmdb_keep_ratio/create_lmdb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Create the imagenet lmdb inputs 3 | # N.B. set the path to the imagenet train + val data dirs 4 | 5 | EXAMPLE=/opt/luojh/Dataset/ImageNet/keep/lmdb 6 | DATA=/opt/luojh/Dataset/ImageNet/images/image_labels 7 | TOOLS=/home/luojh2/Software/caffe/build/tools 8 | 9 | TRAIN_DATA_ROOT=/opt/luojh/Dataset/ImageNet/images/train/ 10 | VAL_DATA_ROOT=/opt/luojh/Dataset/ImageNet/images/val/ 11 | 12 | # Shoter side=256 13 | RESIZE_HEIGHT=-1 14 | RESIZE_WIDTH=-1 15 | 16 | if [ ! -d "$TRAIN_DATA_ROOT" ]; then 17 | echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT" 18 | echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \ 19 | "where the ImageNet training data is stored." 20 | exit 1 21 | fi 22 | 23 | if [ ! -d "$VAL_DATA_ROOT" ]; then 24 | echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT" 25 | echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \ 26 | "where the ImageNet validation data is stored." 27 | exit 1 28 | fi 29 | 30 | echo "Creating train lmdb..." 31 | 32 | GLOG_logtostderr=1 $TOOLS/convert_imageset \ 33 | --resize_height=$RESIZE_HEIGHT \ 34 | --resize_width=$RESIZE_WIDTH \ 35 | --shuffle \ 36 | --backend="lmdb" \ 37 | $TRAIN_DATA_ROOT \ 38 | $DATA/train.txt \ 39 | $EXAMPLE/ilsvrc12_train_lmdb 40 | 41 | echo "Creating val lmdb..." 42 | 43 | GLOG_logtostderr=1 $TOOLS/convert_imageset \ 44 | --resize_height=$RESIZE_HEIGHT \ 45 | --resize_width=$RESIZE_WIDTH \ 46 | --shuffle \ 47 | --backend="lmdb" \ 48 | $VAL_DATA_ROOT \ 49 | $DATA/val.txt \ 50 | $EXAMPLE/ilsvrc12_val_lmdb 51 | 52 | echo "Done." 53 | -------------------------------------------------------------------------------- /ThiNet_ICCV/parse_log/parse_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usage parse_log.sh caffe.log 3 | # It creates the following two text files, each containing a table: 4 | # caffe.log.test (columns: '#Iters Seconds TestAccuracy TestLoss') 5 | # caffe.log.train (columns: '#Iters Seconds TrainingLoss LearningRate') 6 | 7 | 8 | # get the dirname of the script 9 | DIR="$( cd "$(dirname "$0")" ; pwd -P )" 10 | 11 | if [ "$#" -lt 1 ] 12 | then 13 | echo "Usage parse_log.sh /path/to/your.log" 14 | exit 15 | fi 16 | LOG=`basename $1` 17 | sed -n '/Iteration .* Testing net/,/Iteration *. loss/p' $1 > aux.txt 18 | sed -i '/Waiting for data/d' aux.txt 19 | sed -i '/prefetch queue empty/d' aux.txt 20 | sed -i '/Iteration .* loss/d' aux.txt 21 | sed -i '/Iteration .* lr/d' aux.txt 22 | sed -i '/Train net/d' aux.txt 23 | grep 'Testing net (#0)' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 24 | grep 'Test net output #0' aux.txt | awk '{print $11}' > aux1.txt 25 | grep 'Test net output #1' aux.txt | awk '{print $11}' > aux2.txt 26 | 27 | # Extracting elapsed seconds 28 | # For extraction of time since this line contains the start time 29 | grep '] Solving ' $1 > aux3.txt 30 | grep 'Testing net' $1 >> aux3.txt 31 | $DIR/extract_seconds.py aux3.txt aux4.txt 32 | 33 | # Generating 34 | echo '#Iters Seconds TestAccuracy TestLoss'> $LOG.test 35 | paste aux0.txt aux4.txt aux1.txt aux2.txt | column -t >> $LOG.test 36 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt aux4.txt 37 | 38 | # For extraction of time since this line contains the start time 39 | grep '] Solving ' $1 > aux.txt 40 | grep ', loss = ' $1 >> aux.txt 41 | grep 'Iteration ' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 42 | grep ', loss = ' $1 | awk '{print $9}' > aux1.txt 43 | grep ', lr = ' $1 | awk '{print $9}' > aux2.txt 44 | 45 | # Extracting elapsed seconds 46 | $DIR/extract_seconds.py aux.txt aux3.txt 47 | 48 | # Generating 49 | echo '#Iters Seconds TrainingLoss LearningRate'> $LOG.train 50 | paste aux0.txt aux3.txt aux1.txt aux2.txt | column -t >> $LOG.train 51 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt 52 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/parse_log/parse_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usage parse_log.sh caffe.log 3 | # It creates the following two text files, each containing a table: 4 | # caffe.log.test (columns: '#Iters Seconds TestAccuracy TestLoss') 5 | # caffe.log.train (columns: '#Iters Seconds TrainingLoss LearningRate') 6 | 7 | 8 | # get the dirname of the script 9 | DIR="$( cd "$(dirname "$0")" ; pwd -P )" 10 | 11 | if [ "$#" -lt 1 ] 12 | then 13 | echo "Usage parse_log.sh /path/to/your.log" 14 | exit 15 | fi 16 | LOG=`basename $1` 17 | sed -n '/Iteration .* Testing net/,/Iteration *. loss/p' $1 > aux.txt 18 | sed -i '/Waiting for data/d' aux.txt 19 | sed -i '/prefetch queue empty/d' aux.txt 20 | sed -i '/Iteration .* loss/d' aux.txt 21 | sed -i '/Iteration .* lr/d' aux.txt 22 | sed -i '/Train net/d' aux.txt 23 | grep 'Testing net (#0)' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 24 | grep 'Test net output #0' aux.txt | awk '{print $11}' > aux1.txt 25 | grep 'Test net output #1' aux.txt | awk '{print $11}' > aux2.txt 26 | 27 | # Extracting elapsed seconds 28 | # For extraction of time since this line contains the start time 29 | grep '] Solving ' $1 > aux3.txt 30 | grep 'Testing net' $1 >> aux3.txt 31 | $DIR/extract_seconds.py aux3.txt aux4.txt 32 | 33 | # Generating 34 | echo '#Iters Seconds TestAccuracy TestLoss'> $LOG.test 35 | paste aux0.txt aux4.txt aux1.txt aux2.txt | column -t >> $LOG.test 36 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt aux4.txt 37 | 38 | # For extraction of time since this line contains the start time 39 | grep '] Solving ' $1 > aux.txt 40 | grep ', loss = ' $1 >> aux.txt 41 | grep 'Iteration ' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 42 | grep ', loss = ' $1 | awk '{print $9}' > aux1.txt 43 | grep ', lr = ' $1 | awk '{print $9}' > aux2.txt 44 | 45 | # Extracting elapsed seconds 46 | $DIR/extract_seconds.py aux.txt aux3.txt 47 | 48 | # Generating 49 | echo '#Iters Seconds TrainingLoss LearningRate'> $LOG.train 50 | paste aux0.txt aux3.txt aux1.txt aux2.txt | column -t >> $LOG.train 51 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt 52 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/parse_log/parse_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usage parse_log.sh caffe.log 3 | # It creates the following two text files, each containing a table: 4 | # caffe.log.test (columns: '#Iters Seconds TestAccuracy TestLoss') 5 | # caffe.log.train (columns: '#Iters Seconds TrainingLoss LearningRate') 6 | 7 | 8 | # get the dirname of the script 9 | DIR="$( cd "$(dirname "$0")" ; pwd -P )" 10 | 11 | if [ "$#" -lt 1 ] 12 | then 13 | echo "Usage parse_log.sh /path/to/your.log" 14 | exit 15 | fi 16 | LOG=`basename $1` 17 | sed -n '/Iteration .* Testing net/,/Iteration *. loss/p' $1 > aux.txt 18 | sed -i '/Waiting for data/d' aux.txt 19 | sed -i '/prefetch queue empty/d' aux.txt 20 | sed -i '/Iteration .* loss/d' aux.txt 21 | sed -i '/Iteration .* lr/d' aux.txt 22 | sed -i '/Train net/d' aux.txt 23 | grep 'Testing net (#0)' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 24 | grep 'Test net output #0' aux.txt | awk '{print $11}' > aux1.txt 25 | grep 'Test net output #1' aux.txt | awk '{print $11}' > aux2.txt 26 | 27 | # Extracting elapsed seconds 28 | # For extraction of time since this line contains the start time 29 | grep '] Solving ' $1 > aux3.txt 30 | grep 'Testing net' $1 >> aux3.txt 31 | $DIR/extract_seconds.py aux3.txt aux4.txt 32 | 33 | # Generating 34 | echo '#Iters Seconds TestAccuracy TestLoss'> $LOG.test 35 | paste aux0.txt aux4.txt aux1.txt aux2.txt | column -t >> $LOG.test 36 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt aux4.txt 37 | 38 | # For extraction of time since this line contains the start time 39 | grep '] Solving ' $1 > aux.txt 40 | grep ', loss = ' $1 >> aux.txt 41 | grep 'Iteration ' aux.txt | sed 's/.*Iteration \([[:digit:]]*\).*/\1/g' > aux0.txt 42 | grep ', loss = ' $1 | awk '{print $9}' > aux1.txt 43 | grep ', lr = ' $1 | awk '{print $9}' > aux2.txt 44 | 45 | # Extracting elapsed seconds 46 | $DIR/extract_seconds.py aux.txt aux3.txt 47 | 48 | # Generating 49 | echo '#Iters Seconds TrainingLoss LearningRate'> $LOG.train 50 | paste aux0.txt aux3.txt aux1.txt aux2.txt | column -t >> $LOG.train 51 | rm aux.txt aux0.txt aux1.txt aux2.txt aux3.txt 52 | -------------------------------------------------------------------------------- /ThiNet_ICCV/parse_log/extract_seconds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import datetime 3 | import os 4 | import sys 5 | 6 | def extract_datetime_from_line(line, year): 7 | # Expected format: I0210 13:39:22.381027 25210 solver.cpp:204] Iteration 100, lr = 0.00992565 8 | line = line.strip().split() 9 | month = int(line[0][1:3]) 10 | day = int(line[0][3:]) 11 | timestamp = line[1] 12 | pos = timestamp.rfind('.') 13 | ts = [int(x) for x in timestamp[:pos].split(':')] 14 | hour = ts[0] 15 | minute = ts[1] 16 | second = ts[2] 17 | microsecond = int(timestamp[pos + 1:]) 18 | dt = datetime.datetime(year, month, day, hour, minute, second, microsecond) 19 | return dt 20 | 21 | 22 | def get_log_created_year(input_file): 23 | """Get year from log file system timestamp 24 | """ 25 | 26 | log_created_time = os.path.getctime(input_file) 27 | log_created_year = datetime.datetime.fromtimestamp(log_created_time).year 28 | return log_created_year 29 | 30 | 31 | def get_start_time(line_iterable, year): 32 | """Find start time from group of lines 33 | """ 34 | 35 | start_datetime = None 36 | for line in line_iterable: 37 | line = line.strip() 38 | if line.find('Solving') != -1: 39 | start_datetime = extract_datetime_from_line(line, year) 40 | break 41 | return start_datetime 42 | 43 | 44 | def extract_seconds(input_file, output_file): 45 | with open(input_file, 'r') as f: 46 | lines = f.readlines() 47 | log_created_year = get_log_created_year(input_file) 48 | start_datetime = get_start_time(lines, log_created_year) 49 | assert start_datetime, 'Start time not found' 50 | 51 | out = open(output_file, 'w') 52 | for line in lines: 53 | line = line.strip() 54 | if line.find('Iteration') != -1: 55 | dt = extract_datetime_from_line(line, log_created_year) 56 | elapsed_seconds = (dt - start_datetime).total_seconds() 57 | out.write('%f\n' % elapsed_seconds) 58 | out.close() 59 | 60 | if __name__ == '__main__': 61 | if len(sys.argv) < 3: 62 | print('Usage: ./extract_seconds input_file output_file') 63 | exit(1) 64 | extract_seconds(sys.argv[1], sys.argv[2]) 65 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/parse_log/extract_seconds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import datetime 3 | import os 4 | import sys 5 | 6 | def extract_datetime_from_line(line, year): 7 | # Expected format: I0210 13:39:22.381027 25210 solver.cpp:204] Iteration 100, lr = 0.00992565 8 | line = line.strip().split() 9 | month = int(line[0][1:3]) 10 | day = int(line[0][3:]) 11 | timestamp = line[1] 12 | pos = timestamp.rfind('.') 13 | ts = [int(x) for x in timestamp[:pos].split(':')] 14 | hour = ts[0] 15 | minute = ts[1] 16 | second = ts[2] 17 | microsecond = int(timestamp[pos + 1:]) 18 | dt = datetime.datetime(year, month, day, hour, minute, second, microsecond) 19 | return dt 20 | 21 | 22 | def get_log_created_year(input_file): 23 | """Get year from log file system timestamp 24 | """ 25 | 26 | log_created_time = os.path.getctime(input_file) 27 | log_created_year = datetime.datetime.fromtimestamp(log_created_time).year 28 | return log_created_year 29 | 30 | 31 | def get_start_time(line_iterable, year): 32 | """Find start time from group of lines 33 | """ 34 | 35 | start_datetime = None 36 | for line in line_iterable: 37 | line = line.strip() 38 | if line.find('Solving') != -1: 39 | start_datetime = extract_datetime_from_line(line, year) 40 | break 41 | return start_datetime 42 | 43 | 44 | def extract_seconds(input_file, output_file): 45 | with open(input_file, 'r') as f: 46 | lines = f.readlines() 47 | log_created_year = get_log_created_year(input_file) 48 | start_datetime = get_start_time(lines, log_created_year) 49 | assert start_datetime, 'Start time not found' 50 | 51 | out = open(output_file, 'w') 52 | for line in lines: 53 | line = line.strip() 54 | if line.find('Iteration') != -1: 55 | dt = extract_datetime_from_line(line, log_created_year) 56 | elapsed_seconds = (dt - start_datetime).total_seconds() 57 | out.write('%f\n' % elapsed_seconds) 58 | out.close() 59 | 60 | if __name__ == '__main__': 61 | if len(sys.argv) < 3: 62 | print('Usage: ./extract_seconds input_file output_file') 63 | exit(1) 64 | extract_seconds(sys.argv[1], sys.argv[2]) 65 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/parse_log/extract_seconds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import datetime 3 | import os 4 | import sys 5 | 6 | def extract_datetime_from_line(line, year): 7 | # Expected format: I0210 13:39:22.381027 25210 solver.cpp:204] Iteration 100, lr = 0.00992565 8 | line = line.strip().split() 9 | month = int(line[0][1:3]) 10 | day = int(line[0][3:]) 11 | timestamp = line[1] 12 | pos = timestamp.rfind('.') 13 | ts = [int(x) for x in timestamp[:pos].split(':')] 14 | hour = ts[0] 15 | minute = ts[1] 16 | second = ts[2] 17 | microsecond = int(timestamp[pos + 1:]) 18 | dt = datetime.datetime(year, month, day, hour, minute, second, microsecond) 19 | return dt 20 | 21 | 22 | def get_log_created_year(input_file): 23 | """Get year from log file system timestamp 24 | """ 25 | 26 | log_created_time = os.path.getctime(input_file) 27 | log_created_year = datetime.datetime.fromtimestamp(log_created_time).year 28 | return log_created_year 29 | 30 | 31 | def get_start_time(line_iterable, year): 32 | """Find start time from group of lines 33 | """ 34 | 35 | start_datetime = None 36 | for line in line_iterable: 37 | line = line.strip() 38 | if line.find('Solving') != -1: 39 | start_datetime = extract_datetime_from_line(line, year) 40 | break 41 | return start_datetime 42 | 43 | 44 | def extract_seconds(input_file, output_file): 45 | with open(input_file, 'r') as f: 46 | lines = f.readlines() 47 | log_created_year = get_log_created_year(input_file) 48 | start_datetime = get_start_time(lines, log_created_year) 49 | assert start_datetime, 'Start time not found' 50 | 51 | out = open(output_file, 'w') 52 | for line in lines: 53 | line = line.strip() 54 | if line.find('Iteration') != -1: 55 | dt = extract_datetime_from_line(line, log_created_year) 56 | elapsed_seconds = (dt - start_datetime).total_seconds() 57 | out.write('%f\n' % elapsed_seconds) 58 | out.close() 59 | 60 | if __name__ == '__main__': 61 | if len(sys.argv) < 3: 62 | print('Usage: ./extract_seconds input_file output_file') 63 | exit(1) 64 | extract_seconds(sys.argv[1], sys.argv[2]) 65 | -------------------------------------------------------------------------------- /ToolKit/FLOPs_and_size.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2016 Yahoo Inc. 3 | Licensed under the terms of the 2 clause BSD license. 4 | Please see LICENSE file in the project root for terms. 5 | """ 6 | import sys 7 | import os 8 | if os.path.isfile('../caffe_path.txt'): 9 | fid = open('../caffe_path.txt', 'r') 10 | caffe_root = fid.readline().strip('\n') 11 | fid.close() 12 | else: 13 | caffe_root = '/home/luojh2/Software/caffe-master/python/' 14 | sys.path.insert(0, caffe_root) 15 | import caffe 16 | from caffe.proto import caffe_pb2 17 | from google.protobuf import text_format 18 | import tempfile 19 | 20 | caffe.set_mode_cpu() 21 | 22 | 23 | def _create_file_from_netspec(netspec): 24 | f = tempfile.NamedTemporaryFile(mode='w+', delete=False) 25 | f.write(str(netspec.to_proto())) 26 | return f.name 27 | 28 | 29 | def get_complexity(netspec=None, prototxt_file=None, mode=None): 30 | # One of netspec, or prototxt_path params should not be None 31 | assert (netspec is not None) or (prototxt_file is not None) 32 | 33 | if netspec is not None: 34 | prototxt_file = _create_file_from_netspec(netspec) 35 | 36 | net = caffe.Net(prototxt_file, caffe.TEST) 37 | 38 | total_params = 0 39 | total_flops = 0 40 | 41 | net_params = caffe_pb2.NetParameter() 42 | text_format.Merge(open(prototxt_file).read(), net_params) 43 | print '\n ########### output ###########' 44 | for layer in net_params.layer: 45 | if layer.name in net.params: 46 | 47 | params = net.params[layer.name][0].data.size 48 | # If convolution layer, multiply flops with receptive field 49 | # i.e. #params * datawidth * dataheight 50 | if layer.type == 'Convolution': # 'conv' in layer: 51 | data_width = net.blobs[layer.name].data.shape[2] 52 | data_height = net.blobs[layer.name].data.shape[3] 53 | flops = net.params[layer.name][ 54 | 0].data.size * data_width * data_height 55 | # print >> sys.stderr, layer.name, params, flops 56 | else: 57 | flops = net.params[layer.name][0].data.size 58 | flops *= 2 59 | print('%s: #params: %s, #FLOPs: %s') % ( 60 | layer.name, 61 | digit2string(params), 62 | digit2string(flops)) 63 | total_params += params 64 | total_flops += flops 65 | 66 | if netspec is not None: 67 | os.remove(prototxt_file) 68 | 69 | return total_params, total_flops 70 | 71 | 72 | def digit2string(x): 73 | x = float(x) 74 | if x < 10 ** 3: 75 | return "%.2f" % float(x) 76 | elif x < 10 ** 6: 77 | x = x / 10 ** 3 78 | return "%.2f" % float(x) + 'K' 79 | elif x < 10 ** 9: 80 | x = x / 10 ** 6 81 | return "%.2f" % float(x) + 'M' 82 | else: 83 | x = x / 10 ** 9 84 | return "%.2f" % float(x) + 'B' 85 | 86 | 87 | if __name__ == '__main__': 88 | length = len(sys.argv) 89 | if length == 1: 90 | filepath = 'deploy.prototxt' 91 | else: 92 | filepath = sys.argv[1] 93 | params, flops = get_complexity(prototxt_file=filepath, mode='Test') 94 | print '\n ########### result ###########' 95 | print '#params=%s, #FLOPs=%s' % (digit2string(params), 96 | digit2string(flops)) 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caffe Implementation of ThiNet 2 | * ThiNet: A Filter Level Pruning Method for Deep Neural Network Compression, ICCV 2017. 3 | * ThiNet: Pruning CNN Filters for a Thinner Net, TPAMI 2018. 4 | * [[ICCV Project Page]](http://lamda.nju.edu.cn/luojh/project/ThiNet_ICCV17/ThiNet_ICCV17.html) [[Pretrained Models]](https://github.com/Roll920/ThiNet) 5 | 6 | ## Requirements 7 | Python 2.6 & Caffe environment: 8 | * Python2.6 9 | * Caffe & Caffe's Python interface 10 | 11 | ## Usage 12 | 1. Clone the ThiNet repository. 13 | 2. select ThiNet_ICCV or ThiNet_TPAMI subfolder: 14 | ``` 15 | cd ThiNet_ICCV 16 | ``` 17 | 3. modify your configuration path: 18 | + modify the *caffe* path (caffe_root) at the beginning of `net_generator.py` and `compress_model.py` 19 | + modify ImageNet *lmdb* file path in line 212 and line 217 of `net_generator.py` 20 | + modify ImageNet *dataset* path in line 54, 55, 60 of `compress_model.py` 21 | + modify line 2 and 4 in `run_this.sh` with correct file path. 22 | 4. Run the pruning demo: 23 | ``` 24 | ./run_this.sh 25 | ``` 26 | 27 | ## Other Toolkits 28 | * Image Resize: 29 | + Note that there are two different strategies to organize ImageNet dataset: 30 | 1. fixed size: each image is firstly resized to 256×256, then center-cropped to obtain a 224×224 regin; 31 | 2. keep aspect ratio: each image is firstly resized with shorter side=256, then center-cropped; 32 | + The default caffe `create_lmdb.sh` file will convert images into 256x256. If you want to keep the original ratio: 33 | 1. replace `caffe/src/caffe/util/io.cpp` with `toolkit/caffe_lmdb_keep_ratio/io.cpp` 34 | 2. rebuild caffe 35 | 3. use the provided script `toolkit/caffe_lmdb_keep_ratio/create_lmdb.sh` to create the lmdb file 36 | 4. and, do not forget to modify the configuration path of this script. 37 | 38 | * FLOPs Calculation: 39 | ``` 40 | cd toolkit 41 | modify the caffe_root at the beginning of FLOPs_and_size.py file. 42 | python FLOPs_and_size.py [the path of *.prototxt file] 43 | ``` 44 | **NOTE:** we regard the vector multiplication as **TWO** float-point operations (multiplication and addition). In some paper, it is calculated as **ONE** operation. Do not be confused if the result is twice larger. 45 | 46 | ## Results 47 | We prune the [VGG_ILSVRC_16_layers model](https://gist.github.com/ksimonyan/211839e770f7b538e2d8) on ImageNet dataset with ratio=0.5: 48 | 49 | | Method | Top-1 Acc. | Top-5 Acc. | #Param. | #FLOPs | 50 | | ------------- | ------------- | ------------- | ------------- | ------------- | 51 | | original VGG16 | 71.50% | 90.01% | 138.24M | 30.94B | 52 | | ThiNet_ICCV | 69.80% | 89.53% | 131.44M | 9.58B | 53 | | ThiNet_TPAMI | 69.74% | 89.41% | 131.44M | 9.58B | 54 | 55 | There are no difference on [VGG16](https://gist.github.com/ksimonyan/211839e770f7b538e2d8), but ThiNet_TPAMI is much better on [ResNet50](https://github.com/KaimingHe/deep-residual-networks): 56 | 57 | | Method | Top-1 Acc. | Top-5 Acc. | #Param. | #FLOPs | 58 | | ------------- | ------------- | ------------- | ------------- | ------------- | 59 | | original ResNet50 | 75.30% | 92.20% | 25.56M | 7.72B | 60 | | ThiNet_ICCV | 72.04% | 90.67% | 16.94M | 4.88B | 61 | | ThiNet_TPAMI | 74.03% | 92.11% | 16.94M | 4.88B | 62 | 63 | ## Citation 64 | If you find this work is useful for your research, please cite: 65 | ``` 66 | @CONFERENCE{ThiNet_ICCV17, 67 | author={Jian-Hao Luo, Jianxin Wu, and Weiyao Lin}, 68 | title={ThiNet: A Filter Level Pruning Method for Deep Neural Network Compression}, 69 | booktitle={ICCV}, 70 | year = {2017}, 71 | pages={5058-5066}, 72 | } 73 | ``` 74 | ``` 75 | @article{ThiNet_TPAMI, 76 | author = {Jian-Hao Luo, Hao Zhang, Hong-Yu Zhou, Chen-Wei Xie, Jianxin Wu, and Weiyao Lin}, 77 | title = {ThiNet: Pruning CNN Filters for a Thinner Net}, 78 | journal = {IEEE Trans. on Pattern Analysis and Machine Intelligence}, 79 | year = {2008}, 80 | } 81 | ``` 82 | 83 | ## Contact 84 | Feel free to contact me if you have any question (Jian-Hao Luo luojh@lamda.nju.edu.cn or jianhao920@gmail.com). 85 | 86 | -------------------------------------------------------------------------------- /ThiNet_ICCV/parse_log/plot_training_log.py.example: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import inspect 3 | import os 4 | import random 5 | import sys 6 | import matplotlib.cm as cmx 7 | import matplotlib.colors as colors 8 | import matplotlib.pyplot as plt 9 | import matplotlib.legend as lgd 10 | import matplotlib.markers as mks 11 | 12 | def get_log_parsing_script(): 13 | dirname = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 14 | return dirname + '/parse_log.sh' 15 | 16 | def get_log_file_suffix(): 17 | return '.log' 18 | 19 | def get_chart_type_description_separator(): 20 | return ' vs. ' 21 | 22 | def is_x_axis_field(field): 23 | x_axis_fields = ['Iters', 'Seconds'] 24 | return field in x_axis_fields 25 | 26 | def create_field_index(): 27 | train_key = 'Train' 28 | test_key = 'Test' 29 | field_index = {train_key:{'Iters':0, 'Seconds':1, train_key + ' loss':2, 30 | train_key + ' learning rate':3}, 31 | test_key:{'Iters':0, 'Seconds':1, test_key + ' accuracy':2, 32 | test_key + ' loss':3}} 33 | fields = set() 34 | for data_file_type in field_index.keys(): 35 | fields = fields.union(set(field_index[data_file_type].keys())) 36 | fields = list(fields) 37 | fields.sort() 38 | return field_index, fields 39 | 40 | def get_supported_chart_types(): 41 | field_index, fields = create_field_index() 42 | num_fields = len(fields) 43 | supported_chart_types = [] 44 | for i in xrange(num_fields): 45 | if not is_x_axis_field(fields[i]): 46 | for j in xrange(num_fields): 47 | if i != j and is_x_axis_field(fields[j]): 48 | supported_chart_types.append('%s%s%s' % ( 49 | fields[i], get_chart_type_description_separator(), 50 | fields[j])) 51 | return supported_chart_types 52 | 53 | def get_chart_type_description(chart_type): 54 | supported_chart_types = get_supported_chart_types() 55 | chart_type_description = supported_chart_types[chart_type] 56 | return chart_type_description 57 | 58 | def get_data_file_type(chart_type): 59 | description = get_chart_type_description(chart_type) 60 | data_file_type = description.split()[0] 61 | return data_file_type 62 | 63 | def get_data_file(chart_type, path_to_log): 64 | return os.path.basename(path_to_log) + '.' + get_data_file_type(chart_type).lower() 65 | 66 | def get_field_descriptions(chart_type): 67 | description = get_chart_type_description(chart_type).split( 68 | get_chart_type_description_separator()) 69 | y_axis_field = description[0] 70 | x_axis_field = description[1] 71 | return x_axis_field, y_axis_field 72 | 73 | def get_field_indecies(x_axis_field, y_axis_field): 74 | data_file_type = get_data_file_type(chart_type) 75 | fields = create_field_index()[0][data_file_type] 76 | return fields[x_axis_field], fields[y_axis_field] 77 | 78 | def load_data(data_file, field_idx0, field_idx1): 79 | data = [[], []] 80 | with open(data_file, 'r') as f: 81 | for line in f: 82 | line = line.strip() 83 | if line[0] != '#': 84 | fields = line.split() 85 | data[0].append(float(fields[field_idx0].strip())) 86 | data[1].append(float(fields[field_idx1].strip())) 87 | return data 88 | 89 | def random_marker(): 90 | markers = mks.MarkerStyle.markers 91 | num = len(markers.values()) 92 | idx = random.randint(0, num - 1) 93 | return markers.values()[idx] 94 | 95 | def get_data_label(path_to_log): 96 | label = path_to_log[path_to_log.rfind('/')+1 : path_to_log.rfind( 97 | get_log_file_suffix())] 98 | return label 99 | 100 | def get_legend_loc(chart_type): 101 | x_axis, y_axis = get_field_descriptions(chart_type) 102 | loc = 'lower right' 103 | if y_axis.find('accuracy') != -1: 104 | pass 105 | if y_axis.find('loss') != -1 or y_axis.find('learning rate') != -1: 106 | loc = 'upper right' 107 | return loc 108 | 109 | def plot_chart(chart_type, path_to_png, path_to_log_list): 110 | for path_to_log in path_to_log_list: 111 | os.system('%s %s' % (get_log_parsing_script(), path_to_log)) 112 | data_file = get_data_file(chart_type, path_to_log) 113 | x_axis_field, y_axis_field = get_field_descriptions(chart_type) 114 | x, y = get_field_indecies(x_axis_field, y_axis_field) 115 | data = load_data(data_file, x, y) 116 | ## TODO: more systematic color cycle for lines 117 | color = [random.random(), random.random(), random.random()] 118 | label = get_data_label(path_to_log) 119 | linewidth = 0.75 120 | ## If there too many datapoints, do not use marker. 121 | ## use_marker = False 122 | use_marker = True 123 | if not use_marker: 124 | plt.plot(data[0], data[1], label = label, color = color, 125 | linewidth = linewidth) 126 | else: 127 | ok = False 128 | ## Some markers throw ValueError: Unrecognized marker style 129 | while not ok: 130 | try: 131 | marker = random_marker() 132 | plt.plot(data[0], data[1], label = label, color = color, 133 | marker = marker, linewidth = linewidth) 134 | ok = True 135 | except: 136 | pass 137 | legend_loc = get_legend_loc(chart_type) 138 | plt.legend(loc = legend_loc, ncol = 1) # ajust ncol to fit the space 139 | plt.title(get_chart_type_description(chart_type)) 140 | plt.xlabel(x_axis_field) 141 | plt.ylabel(y_axis_field) 142 | plt.savefig(path_to_png) 143 | plt.show() 144 | 145 | def print_help(): 146 | print """This script mainly serves as the basis of your customizations. 147 | Customization is a must. 148 | You can copy, paste, edit them in whatever way you want. 149 | Be warned that the fields in the training log may change in the future. 150 | You had better check the data files and change the mapping from field name to 151 | field index in create_field_index before designing your own plots. 152 | Usage: 153 | ./plot_training_log.py chart_type[0-%s] /where/to/save.png /path/to/first.log ... 154 | Notes: 155 | 1. Supporting multiple logs. 156 | 2. Log file name must end with the lower-cased "%s". 157 | Supported chart types:""" % (len(get_supported_chart_types()) - 1, 158 | get_log_file_suffix()) 159 | supported_chart_types = get_supported_chart_types() 160 | num = len(supported_chart_types) 161 | for i in xrange(num): 162 | print ' %d: %s' % (i, supported_chart_types[i]) 163 | exit 164 | 165 | def is_valid_chart_type(chart_type): 166 | return chart_type >= 0 and chart_type < len(get_supported_chart_types()) 167 | 168 | if __name__ == '__main__': 169 | if len(sys.argv) < 4: 170 | print_help() 171 | else: 172 | chart_type = int(sys.argv[1]) 173 | if not is_valid_chart_type(chart_type): 174 | print_help() 175 | path_to_png = sys.argv[2] 176 | if not path_to_png.endswith('.png'): 177 | print 'Path must ends with png' % path_to_png 178 | exit 179 | path_to_logs = sys.argv[3:] 180 | for path_to_log in path_to_logs: 181 | if not os.path.exists(path_to_log): 182 | print 'Path does not exist: %s' % path_to_log 183 | exit 184 | if not path_to_log.endswith(get_log_file_suffix()): 185 | print_help() 186 | ## plot_chart accpets multiple path_to_logs 187 | plot_chart(chart_type, path_to_png, path_to_logs) 188 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/parse_log/plot_training_log.py.example: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import inspect 3 | import os 4 | import random 5 | import sys 6 | import matplotlib.cm as cmx 7 | import matplotlib.colors as colors 8 | import matplotlib.pyplot as plt 9 | import matplotlib.legend as lgd 10 | import matplotlib.markers as mks 11 | 12 | def get_log_parsing_script(): 13 | dirname = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 14 | return dirname + '/parse_log.sh' 15 | 16 | def get_log_file_suffix(): 17 | return '.log' 18 | 19 | def get_chart_type_description_separator(): 20 | return ' vs. ' 21 | 22 | def is_x_axis_field(field): 23 | x_axis_fields = ['Iters', 'Seconds'] 24 | return field in x_axis_fields 25 | 26 | def create_field_index(): 27 | train_key = 'Train' 28 | test_key = 'Test' 29 | field_index = {train_key:{'Iters':0, 'Seconds':1, train_key + ' loss':2, 30 | train_key + ' learning rate':3}, 31 | test_key:{'Iters':0, 'Seconds':1, test_key + ' accuracy':2, 32 | test_key + ' loss':3}} 33 | fields = set() 34 | for data_file_type in field_index.keys(): 35 | fields = fields.union(set(field_index[data_file_type].keys())) 36 | fields = list(fields) 37 | fields.sort() 38 | return field_index, fields 39 | 40 | def get_supported_chart_types(): 41 | field_index, fields = create_field_index() 42 | num_fields = len(fields) 43 | supported_chart_types = [] 44 | for i in xrange(num_fields): 45 | if not is_x_axis_field(fields[i]): 46 | for j in xrange(num_fields): 47 | if i != j and is_x_axis_field(fields[j]): 48 | supported_chart_types.append('%s%s%s' % ( 49 | fields[i], get_chart_type_description_separator(), 50 | fields[j])) 51 | return supported_chart_types 52 | 53 | def get_chart_type_description(chart_type): 54 | supported_chart_types = get_supported_chart_types() 55 | chart_type_description = supported_chart_types[chart_type] 56 | return chart_type_description 57 | 58 | def get_data_file_type(chart_type): 59 | description = get_chart_type_description(chart_type) 60 | data_file_type = description.split()[0] 61 | return data_file_type 62 | 63 | def get_data_file(chart_type, path_to_log): 64 | return os.path.basename(path_to_log) + '.' + get_data_file_type(chart_type).lower() 65 | 66 | def get_field_descriptions(chart_type): 67 | description = get_chart_type_description(chart_type).split( 68 | get_chart_type_description_separator()) 69 | y_axis_field = description[0] 70 | x_axis_field = description[1] 71 | return x_axis_field, y_axis_field 72 | 73 | def get_field_indecies(x_axis_field, y_axis_field): 74 | data_file_type = get_data_file_type(chart_type) 75 | fields = create_field_index()[0][data_file_type] 76 | return fields[x_axis_field], fields[y_axis_field] 77 | 78 | def load_data(data_file, field_idx0, field_idx1): 79 | data = [[], []] 80 | with open(data_file, 'r') as f: 81 | for line in f: 82 | line = line.strip() 83 | if line[0] != '#': 84 | fields = line.split() 85 | data[0].append(float(fields[field_idx0].strip())) 86 | data[1].append(float(fields[field_idx1].strip())) 87 | return data 88 | 89 | def random_marker(): 90 | markers = mks.MarkerStyle.markers 91 | num = len(markers.values()) 92 | idx = random.randint(0, num - 1) 93 | return markers.values()[idx] 94 | 95 | def get_data_label(path_to_log): 96 | label = path_to_log[path_to_log.rfind('/')+1 : path_to_log.rfind( 97 | get_log_file_suffix())] 98 | return label 99 | 100 | def get_legend_loc(chart_type): 101 | x_axis, y_axis = get_field_descriptions(chart_type) 102 | loc = 'lower right' 103 | if y_axis.find('accuracy') != -1: 104 | pass 105 | if y_axis.find('loss') != -1 or y_axis.find('learning rate') != -1: 106 | loc = 'upper right' 107 | return loc 108 | 109 | def plot_chart(chart_type, path_to_png, path_to_log_list): 110 | for path_to_log in path_to_log_list: 111 | os.system('%s %s' % (get_log_parsing_script(), path_to_log)) 112 | data_file = get_data_file(chart_type, path_to_log) 113 | x_axis_field, y_axis_field = get_field_descriptions(chart_type) 114 | x, y = get_field_indecies(x_axis_field, y_axis_field) 115 | data = load_data(data_file, x, y) 116 | ## TODO: more systematic color cycle for lines 117 | color = [random.random(), random.random(), random.random()] 118 | label = get_data_label(path_to_log) 119 | linewidth = 0.75 120 | ## If there too many datapoints, do not use marker. 121 | ## use_marker = False 122 | use_marker = True 123 | if not use_marker: 124 | plt.plot(data[0], data[1], label = label, color = color, 125 | linewidth = linewidth) 126 | else: 127 | ok = False 128 | ## Some markers throw ValueError: Unrecognized marker style 129 | while not ok: 130 | try: 131 | marker = random_marker() 132 | plt.plot(data[0], data[1], label = label, color = color, 133 | marker = marker, linewidth = linewidth) 134 | ok = True 135 | except: 136 | pass 137 | legend_loc = get_legend_loc(chart_type) 138 | plt.legend(loc = legend_loc, ncol = 1) # ajust ncol to fit the space 139 | plt.title(get_chart_type_description(chart_type)) 140 | plt.xlabel(x_axis_field) 141 | plt.ylabel(y_axis_field) 142 | plt.savefig(path_to_png) 143 | plt.show() 144 | 145 | def print_help(): 146 | print """This script mainly serves as the basis of your customizations. 147 | Customization is a must. 148 | You can copy, paste, edit them in whatever way you want. 149 | Be warned that the fields in the training log may change in the future. 150 | You had better check the data files and change the mapping from field name to 151 | field index in create_field_index before designing your own plots. 152 | Usage: 153 | ./plot_training_log.py chart_type[0-%s] /where/to/save.png /path/to/first.log ... 154 | Notes: 155 | 1. Supporting multiple logs. 156 | 2. Log file name must end with the lower-cased "%s". 157 | Supported chart types:""" % (len(get_supported_chart_types()) - 1, 158 | get_log_file_suffix()) 159 | supported_chart_types = get_supported_chart_types() 160 | num = len(supported_chart_types) 161 | for i in xrange(num): 162 | print ' %d: %s' % (i, supported_chart_types[i]) 163 | exit 164 | 165 | def is_valid_chart_type(chart_type): 166 | return chart_type >= 0 and chart_type < len(get_supported_chart_types()) 167 | 168 | if __name__ == '__main__': 169 | if len(sys.argv) < 4: 170 | print_help() 171 | else: 172 | chart_type = int(sys.argv[1]) 173 | if not is_valid_chart_type(chart_type): 174 | print_help() 175 | path_to_png = sys.argv[2] 176 | if not path_to_png.endswith('.png'): 177 | print 'Path must ends with png' % path_to_png 178 | exit 179 | path_to_logs = sys.argv[3:] 180 | for path_to_log in path_to_logs: 181 | if not os.path.exists(path_to_log): 182 | print 'Path does not exist: %s' % path_to_log 183 | exit 184 | if not path_to_log.endswith(get_log_file_suffix()): 185 | print_help() 186 | ## plot_chart accpets multiple path_to_logs 187 | plot_chart(chart_type, path_to_png, path_to_logs) 188 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/parse_log/plot_training_log.py.example: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import inspect 3 | import os 4 | import random 5 | import sys 6 | import matplotlib.cm as cmx 7 | import matplotlib.colors as colors 8 | import matplotlib.pyplot as plt 9 | import matplotlib.legend as lgd 10 | import matplotlib.markers as mks 11 | 12 | def get_log_parsing_script(): 13 | dirname = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 14 | return dirname + '/parse_log.sh' 15 | 16 | def get_log_file_suffix(): 17 | return '.log' 18 | 19 | def get_chart_type_description_separator(): 20 | return ' vs. ' 21 | 22 | def is_x_axis_field(field): 23 | x_axis_fields = ['Iters', 'Seconds'] 24 | return field in x_axis_fields 25 | 26 | def create_field_index(): 27 | train_key = 'Train' 28 | test_key = 'Test' 29 | field_index = {train_key:{'Iters':0, 'Seconds':1, train_key + ' loss':2, 30 | train_key + ' learning rate':3}, 31 | test_key:{'Iters':0, 'Seconds':1, test_key + ' accuracy':2, 32 | test_key + ' loss':3}} 33 | fields = set() 34 | for data_file_type in field_index.keys(): 35 | fields = fields.union(set(field_index[data_file_type].keys())) 36 | fields = list(fields) 37 | fields.sort() 38 | return field_index, fields 39 | 40 | def get_supported_chart_types(): 41 | field_index, fields = create_field_index() 42 | num_fields = len(fields) 43 | supported_chart_types = [] 44 | for i in xrange(num_fields): 45 | if not is_x_axis_field(fields[i]): 46 | for j in xrange(num_fields): 47 | if i != j and is_x_axis_field(fields[j]): 48 | supported_chart_types.append('%s%s%s' % ( 49 | fields[i], get_chart_type_description_separator(), 50 | fields[j])) 51 | return supported_chart_types 52 | 53 | def get_chart_type_description(chart_type): 54 | supported_chart_types = get_supported_chart_types() 55 | chart_type_description = supported_chart_types[chart_type] 56 | return chart_type_description 57 | 58 | def get_data_file_type(chart_type): 59 | description = get_chart_type_description(chart_type) 60 | data_file_type = description.split()[0] 61 | return data_file_type 62 | 63 | def get_data_file(chart_type, path_to_log): 64 | return os.path.basename(path_to_log) + '.' + get_data_file_type(chart_type).lower() 65 | 66 | def get_field_descriptions(chart_type): 67 | description = get_chart_type_description(chart_type).split( 68 | get_chart_type_description_separator()) 69 | y_axis_field = description[0] 70 | x_axis_field = description[1] 71 | return x_axis_field, y_axis_field 72 | 73 | def get_field_indecies(x_axis_field, y_axis_field): 74 | data_file_type = get_data_file_type(chart_type) 75 | fields = create_field_index()[0][data_file_type] 76 | return fields[x_axis_field], fields[y_axis_field] 77 | 78 | def load_data(data_file, field_idx0, field_idx1): 79 | data = [[], []] 80 | with open(data_file, 'r') as f: 81 | for line in f: 82 | line = line.strip() 83 | if line[0] != '#': 84 | fields = line.split() 85 | data[0].append(float(fields[field_idx0].strip())) 86 | data[1].append(float(fields[field_idx1].strip())) 87 | return data 88 | 89 | def random_marker(): 90 | markers = mks.MarkerStyle.markers 91 | num = len(markers.values()) 92 | idx = random.randint(0, num - 1) 93 | return markers.values()[idx] 94 | 95 | def get_data_label(path_to_log): 96 | label = path_to_log[path_to_log.rfind('/')+1 : path_to_log.rfind( 97 | get_log_file_suffix())] 98 | return label 99 | 100 | def get_legend_loc(chart_type): 101 | x_axis, y_axis = get_field_descriptions(chart_type) 102 | loc = 'lower right' 103 | if y_axis.find('accuracy') != -1: 104 | pass 105 | if y_axis.find('loss') != -1 or y_axis.find('learning rate') != -1: 106 | loc = 'upper right' 107 | return loc 108 | 109 | def plot_chart(chart_type, path_to_png, path_to_log_list): 110 | for path_to_log in path_to_log_list: 111 | os.system('%s %s' % (get_log_parsing_script(), path_to_log)) 112 | data_file = get_data_file(chart_type, path_to_log) 113 | x_axis_field, y_axis_field = get_field_descriptions(chart_type) 114 | x, y = get_field_indecies(x_axis_field, y_axis_field) 115 | data = load_data(data_file, x, y) 116 | ## TODO: more systematic color cycle for lines 117 | color = [random.random(), random.random(), random.random()] 118 | label = get_data_label(path_to_log) 119 | linewidth = 0.75 120 | ## If there too many datapoints, do not use marker. 121 | ## use_marker = False 122 | use_marker = True 123 | if not use_marker: 124 | plt.plot(data[0], data[1], label = label, color = color, 125 | linewidth = linewidth) 126 | else: 127 | ok = False 128 | ## Some markers throw ValueError: Unrecognized marker style 129 | while not ok: 130 | try: 131 | marker = random_marker() 132 | plt.plot(data[0], data[1], label = label, color = color, 133 | marker = marker, linewidth = linewidth) 134 | ok = True 135 | except: 136 | pass 137 | legend_loc = get_legend_loc(chart_type) 138 | plt.legend(loc = legend_loc, ncol = 1) # ajust ncol to fit the space 139 | plt.title(get_chart_type_description(chart_type)) 140 | plt.xlabel(x_axis_field) 141 | plt.ylabel(y_axis_field) 142 | plt.savefig(path_to_png) 143 | plt.show() 144 | 145 | def print_help(): 146 | print """This script mainly serves as the basis of your customizations. 147 | Customization is a must. 148 | You can copy, paste, edit them in whatever way you want. 149 | Be warned that the fields in the training log may change in the future. 150 | You had better check the data files and change the mapping from field name to 151 | field index in create_field_index before designing your own plots. 152 | Usage: 153 | ./plot_training_log.py chart_type[0-%s] /where/to/save.png /path/to/first.log ... 154 | Notes: 155 | 1. Supporting multiple logs. 156 | 2. Log file name must end with the lower-cased "%s". 157 | Supported chart types:""" % (len(get_supported_chart_types()) - 1, 158 | get_log_file_suffix()) 159 | supported_chart_types = get_supported_chart_types() 160 | num = len(supported_chart_types) 161 | for i in xrange(num): 162 | print ' %d: %s' % (i, supported_chart_types[i]) 163 | exit 164 | 165 | def is_valid_chart_type(chart_type): 166 | return chart_type >= 0 and chart_type < len(get_supported_chart_types()) 167 | 168 | if __name__ == '__main__': 169 | if len(sys.argv) < 4: 170 | print_help() 171 | else: 172 | chart_type = int(sys.argv[1]) 173 | if not is_valid_chart_type(chart_type): 174 | print_help() 175 | path_to_png = sys.argv[2] 176 | if not path_to_png.endswith('.png'): 177 | print 'Path must ends with png' % path_to_png 178 | exit 179 | path_to_logs = sys.argv[3:] 180 | for path_to_log in path_to_logs: 181 | if not os.path.exists(path_to_log): 182 | print 'Path does not exist: %s' % path_to_log 183 | exit 184 | if not path_to_log.endswith(get_log_file_suffix()): 185 | print_help() 186 | ## plot_chart accpets multiple path_to_logs 187 | plot_chart(chart_type, path_to_png, path_to_logs) 188 | -------------------------------------------------------------------------------- /ToolKit/caffe_lmdb_keep_ratio/io.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifdef USE_OPENCV 6 | #include 7 | #include 8 | #include 9 | #include 10 | #endif // USE_OPENCV 11 | #include 12 | 13 | #include 14 | #include // NOLINT(readability/streams) 15 | #include 16 | #include 17 | 18 | #include "caffe/common.hpp" 19 | #include "caffe/proto/caffe.pb.h" 20 | #include "caffe/util/io.hpp" 21 | 22 | const int kProtoReadBytesLimit = INT_MAX; // Max size of 2 GB minus 1 byte. 23 | 24 | namespace caffe { 25 | 26 | using google::protobuf::io::FileInputStream; 27 | using google::protobuf::io::FileOutputStream; 28 | using google::protobuf::io::ZeroCopyInputStream; 29 | using google::protobuf::io::CodedInputStream; 30 | using google::protobuf::io::ZeroCopyOutputStream; 31 | using google::protobuf::io::CodedOutputStream; 32 | using google::protobuf::Message; 33 | 34 | bool ReadProtoFromTextFile(const char* filename, Message* proto) { 35 | int fd = open(filename, O_RDONLY); 36 | CHECK_NE(fd, -1) << "File not found: " << filename; 37 | FileInputStream* input = new FileInputStream(fd); 38 | bool success = google::protobuf::TextFormat::Parse(input, proto); 39 | delete input; 40 | close(fd); 41 | return success; 42 | } 43 | 44 | void WriteProtoToTextFile(const Message& proto, const char* filename) { 45 | int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 46 | FileOutputStream* output = new FileOutputStream(fd); 47 | CHECK(google::protobuf::TextFormat::Print(proto, output)); 48 | delete output; 49 | close(fd); 50 | } 51 | 52 | bool ReadProtoFromBinaryFile(const char* filename, Message* proto) { 53 | int fd = open(filename, O_RDONLY); 54 | CHECK_NE(fd, -1) << "File not found: " << filename; 55 | ZeroCopyInputStream* raw_input = new FileInputStream(fd); 56 | CodedInputStream* coded_input = new CodedInputStream(raw_input); 57 | coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912); 58 | 59 | bool success = proto->ParseFromCodedStream(coded_input); 60 | 61 | delete coded_input; 62 | delete raw_input; 63 | close(fd); 64 | return success; 65 | } 66 | 67 | void WriteProtoToBinaryFile(const Message& proto, const char* filename) { 68 | fstream output(filename, ios::out | ios::trunc | ios::binary); 69 | CHECK(proto.SerializeToOstream(&output)); 70 | } 71 | 72 | #ifdef USE_OPENCV 73 | cv::Mat ReadImageToCVMat(const string& filename, 74 | const int height, const int width, const bool is_color) { 75 | cv::Mat cv_img; 76 | int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : 77 | CV_LOAD_IMAGE_GRAYSCALE); 78 | cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag); 79 | if (!cv_img_origin.data) { 80 | LOG(ERROR) << "Could not open or find file " << filename; 81 | return cv_img_origin; 82 | } 83 | 84 | if (height > 0 && width > 0) { 85 | cv::resize(cv_img_origin, cv_img, cv::Size(width, height)); 86 | } 87 | else if(height == -1 && width == -1){ 88 | double ratio = 256.0 / std::min(cv_img_origin.cols, cv_img_origin.rows); 89 | cv::resize(cv_img_origin, cv_img, cv::Size(ratio * cv_img_origin.cols, ratio * cv_img_origin.rows)); 90 | } 91 | else { 92 | cv_img = cv_img_origin; 93 | } 94 | return cv_img; 95 | } 96 | 97 | cv::Mat ReadImageToCVMat(const string& filename, 98 | const int height, const int width) { 99 | return ReadImageToCVMat(filename, height, width, true); 100 | } 101 | 102 | cv::Mat ReadImageToCVMat(const string& filename, 103 | const bool is_color) { 104 | return ReadImageToCVMat(filename, 0, 0, is_color); 105 | } 106 | 107 | cv::Mat ReadImageToCVMat(const string& filename) { 108 | return ReadImageToCVMat(filename, 0, 0, true); 109 | } 110 | 111 | // Do the file extension and encoding match? 112 | static bool matchExt(const std::string & fn, 113 | std::string en) { 114 | size_t p = fn.rfind('.'); 115 | std::string ext = p != fn.npos ? fn.substr(p) : fn; 116 | std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); 117 | std::transform(en.begin(), en.end(), en.begin(), ::tolower); 118 | if ( ext == en ) 119 | return true; 120 | if ( en == "jpg" && ext == "jpeg" ) 121 | return true; 122 | return false; 123 | } 124 | 125 | bool ReadImageToDatum(const string& filename, const int label, 126 | const int height, const int width, const bool is_color, 127 | const std::string & encoding, Datum* datum) { 128 | cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color); 129 | if (cv_img.data) { 130 | if (encoding.size()) { 131 | if ( (cv_img.channels() == 3) == is_color && !height && !width && 132 | matchExt(filename, encoding) ) 133 | return ReadFileToDatum(filename, label, datum); 134 | std::vector buf; 135 | cv::imencode("."+encoding, cv_img, buf); 136 | datum->set_data(std::string(reinterpret_cast(&buf[0]), 137 | buf.size())); 138 | datum->set_label(label); 139 | datum->set_encoded(true); 140 | return true; 141 | } 142 | CVMatToDatum(cv_img, datum); 143 | datum->set_label(label); 144 | return true; 145 | } else { 146 | return false; 147 | } 148 | } 149 | #endif // USE_OPENCV 150 | 151 | bool ReadFileToDatum(const string& filename, const int label, 152 | Datum* datum) { 153 | std::streampos size; 154 | 155 | fstream file(filename.c_str(), ios::in|ios::binary|ios::ate); 156 | if (file.is_open()) { 157 | size = file.tellg(); 158 | std::string buffer(size, ' '); 159 | file.seekg(0, ios::beg); 160 | file.read(&buffer[0], size); 161 | file.close(); 162 | datum->set_data(buffer); 163 | datum->set_label(label); 164 | datum->set_encoded(true); 165 | return true; 166 | } else { 167 | return false; 168 | } 169 | } 170 | 171 | #ifdef USE_OPENCV 172 | cv::Mat DecodeDatumToCVMatNative(const Datum& datum) { 173 | cv::Mat cv_img; 174 | CHECK(datum.encoded()) << "Datum not encoded"; 175 | const string& data = datum.data(); 176 | std::vector vec_data(data.c_str(), data.c_str() + data.size()); 177 | cv_img = cv::imdecode(vec_data, -1); 178 | if (!cv_img.data) { 179 | LOG(ERROR) << "Could not decode datum "; 180 | } 181 | return cv_img; 182 | } 183 | cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) { 184 | cv::Mat cv_img; 185 | CHECK(datum.encoded()) << "Datum not encoded"; 186 | const string& data = datum.data(); 187 | std::vector vec_data(data.c_str(), data.c_str() + data.size()); 188 | int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : 189 | CV_LOAD_IMAGE_GRAYSCALE); 190 | cv_img = cv::imdecode(vec_data, cv_read_flag); 191 | if (!cv_img.data) { 192 | LOG(ERROR) << "Could not decode datum "; 193 | } 194 | return cv_img; 195 | } 196 | 197 | // If Datum is encoded will decoded using DecodeDatumToCVMat and CVMatToDatum 198 | // If Datum is not encoded will do nothing 199 | bool DecodeDatumNative(Datum* datum) { 200 | if (datum->encoded()) { 201 | cv::Mat cv_img = DecodeDatumToCVMatNative((*datum)); 202 | CVMatToDatum(cv_img, datum); 203 | return true; 204 | } else { 205 | return false; 206 | } 207 | } 208 | bool DecodeDatum(Datum* datum, bool is_color) { 209 | if (datum->encoded()) { 210 | cv::Mat cv_img = DecodeDatumToCVMat((*datum), is_color); 211 | CVMatToDatum(cv_img, datum); 212 | return true; 213 | } else { 214 | return false; 215 | } 216 | } 217 | 218 | void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) { 219 | CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte"; 220 | datum->set_channels(cv_img.channels()); 221 | datum->set_height(cv_img.rows); 222 | datum->set_width(cv_img.cols); 223 | datum->clear_data(); 224 | datum->clear_float_data(); 225 | datum->set_encoded(false); 226 | int datum_channels = datum->channels(); 227 | int datum_height = datum->height(); 228 | int datum_width = datum->width(); 229 | int datum_size = datum_channels * datum_height * datum_width; 230 | std::string buffer(datum_size, ' '); 231 | for (int h = 0; h < datum_height; ++h) { 232 | const uchar* ptr = cv_img.ptr(h); 233 | int img_index = 0; 234 | for (int w = 0; w < datum_width; ++w) { 235 | for (int c = 0; c < datum_channels; ++c) { 236 | int datum_index = (c * datum_height + h) * datum_width + w; 237 | buffer[datum_index] = static_cast(ptr[img_index++]); 238 | } 239 | } 240 | } 241 | datum->set_data(buffer); 242 | } 243 | #endif // USE_OPENCV 244 | } // namespace caffe 245 | -------------------------------------------------------------------------------- /ThiNet_ICCV/net_generator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | caffe_root = '/home/luojh2/Software/caffe-master/' 3 | sys.path.insert(0, caffe_root + 'python') 4 | import caffe 5 | from caffe import layers as L 6 | from caffe import params as P 7 | from caffe.proto import caffe_pb2 8 | import numpy as np 9 | import os.path as osp 10 | import os 11 | 12 | 13 | class Solver: 14 | 15 | def __init__(self, solver_name=None, folder=None, b=0): 16 | self.solver_name = solver_name 17 | self.folder = folder 18 | 19 | if self.folder is not None: 20 | self.name = osp.join(self.folder, 'solver.prototxt') 21 | if self.name is None: 22 | self.name = 'solver.pt' 23 | else: 24 | filepath, ext = osp.splitext(self.name) 25 | if ext == '': 26 | ext = '.prototxt' 27 | self.name = filepath + ext 28 | 29 | self.p = caffe_pb2.SolverParameter() 30 | 31 | class Method: 32 | nesterov = "Nesterov" 33 | SGD = "SGD" 34 | AdaGrad = "AdaGrad" 35 | RMSProp = "RMSProp" 36 | AdaDelta = "AdaDelta" 37 | Adam = "Adam" 38 | self.method = Method() 39 | 40 | class Policy: 41 | """ - fixed: always return base_lr.""" 42 | fixed = 'fixed' 43 | """ - step: return base_lr * gamma ^ (floor(iter / step))""" 44 | """ - exp: return base_lr * gamma ^ iter""" 45 | """ - inv: return base_lr * (1 + gamma * iter) ^ (- power)""" 46 | """ - multistep: similar to step but it allows non uniform steps defined by stepvalue""" 47 | multistep = 'multistep' 48 | """ - poly: the effective learning rate follows a polynomial decay, to be zero by the max_iter. return base_lr (1 - iter/max_iter) ^ (power)""" 49 | """ - sigmoid: the effective learning rate follows a sigmod decay""" 50 | """ return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))""" 51 | self.policy = Policy() 52 | 53 | class Machine: 54 | GPU = self.p.GPU 55 | CPU = self.p.GPU 56 | self.machine = Machine() 57 | 58 | # defaults 59 | self.p.test_iter.extend([1000]) 60 | self.p.test_interval = 10000 61 | self.p.test_initialization = True 62 | if b == 9: # the final layer conv4_3 63 | self.p.max_iter = 120000 64 | self.p.stepvalue.extend([40000, 80000]) 65 | elif b in [1, 3, 6]: 66 | self.p.max_iter = 20000 67 | self.p.stepvalue.extend([10000]) 68 | else: 69 | self.p.max_iter = 10000 70 | self.p.base_lr = 0.001 71 | self.p.lr_policy = self.policy.multistep 72 | 73 | self.p.gamma = 0.1 74 | self.p.momentum = 0.9 75 | self.p.weight_decay = 0.0005 76 | self.p.display = 20 77 | 78 | self.p.snapshot = 10000 79 | self.p.snapshot_prefix = osp.join(self.folder, "snapshot/") 80 | self.p.solver_mode = self.machine.GPU 81 | 82 | self.p.net = osp.join(self.folder, "trainval.prototxt") 83 | 84 | def write(self): 85 | if not osp.exists(self.p.snapshot_prefix): 86 | os.mkdir(self.p.snapshot_prefix) 87 | with open(self.name, 'wb') as f: 88 | f.write(str(self.p)) 89 | 90 | 91 | # helper functions for common structures 92 | def conv_relu(bottom, ks, nout, pad=0): 93 | conv = L.Convolution(bottom, kernel_size=ks, num_output=nout, pad=pad, param=[ 94 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 95 | return conv, L.ReLU(conv, in_place=False) 96 | 97 | 98 | def fc_relu(bottom, nout): 99 | fc = L.InnerProduct(bottom, num_output=nout, param=[ 100 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 101 | return fc, L.ReLU(fc, in_place=False) 102 | 103 | 104 | def max_pool(bottom, ks, stride=1): 105 | return L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride) 106 | 107 | 108 | def ave_pool(bottom, ks, stride=1): 109 | return L.Pooling(bottom, pool=P.Pooling.AVE, kernel_size=ks, stride=stride) 110 | 111 | 112 | def vgg_16(lmdb, bs_train=16, bs_val=50, rate=0, lmdb_flag=False, not_deploy=True): 113 | n = caffe.NetSpec() 114 | if not_deploy: 115 | if lmdb_flag: 116 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_train_lmdb', backend=P.Data.LMDB, 117 | include=dict(phase=caffe_pb2.TRAIN), batch_size=bs_train, ntop=2, 118 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=True)) 119 | data_str = n.to_proto() 120 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_val_lmdb', backend=P.Data.LMDB, 121 | include=dict(phase=caffe_pb2.TEST), batch_size=bs_val, ntop=2, 122 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=False)) 123 | else: 124 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_train_leveldb', backend=P.Data.LEVELDB, 125 | include=dict(phase=caffe_pb2.TRAIN), batch_size=bs_train, ntop=2, 126 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=True)) 127 | data_str = n.to_proto() 128 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_val_leveldb', backend=P.Data.LEVELDB, 129 | include=dict(phase=caffe_pb2.TEST), batch_size=bs_val, ntop=2, 130 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=False)) 131 | else: 132 | data_str = 'input: "data"\ninput_dim: 1\ninput_dim: 3\ninput_dim: 224\ninput_dim: 224' 133 | n.data = L.Data() 134 | 135 | # the net itself 136 | n.conv1_1, n.relu1_1 = conv_relu( 137 | n.data, nout=int(rate[0] * 64), pad=1, ks=3) 138 | n.conv1_2, n.relu1_2 = conv_relu( 139 | n.relu1_1, nout=int(rate[1] * 64), pad=1, ks=3) 140 | n.pool1 = max_pool(n.relu1_2, ks=2, stride=2) 141 | 142 | n.conv2_1, n.relu2_1 = conv_relu( 143 | n.pool1, nout=int(rate[2] * 128), pad=1, ks=3) 144 | n.conv2_2, n.relu2_2 = conv_relu( 145 | n.relu2_1, nout=int(rate[3] * 128), pad=1, ks=3) 146 | n.pool2 = max_pool(n.relu2_2, ks=2, stride=2) 147 | 148 | n.conv3_1, n.relu3_1 = conv_relu( 149 | n.pool2, nout=int(rate[4] * 256), pad=1, ks=3) 150 | n.conv3_2, n.relu3_2 = conv_relu( 151 | n.relu3_1, nout=int(rate[5] * 256), pad=1, ks=3) 152 | n.conv3_3, n.relu3_3 = conv_relu( 153 | n.relu3_2, nout=int(rate[6] * 256), pad=1, ks=3) 154 | n.pool3 = max_pool(n.relu3_3, ks=2, stride=2) 155 | 156 | n.conv4_1, n.relu4_1 = conv_relu( 157 | n.pool3, nout=int(rate[7] * 512), pad=1, ks=3) 158 | n.conv4_2, n.relu4_2 = conv_relu( 159 | n.relu4_1, nout=int(rate[8] * 512), pad=1, ks=3) 160 | n.conv4_3, n.relu4_3 = conv_relu( 161 | n.relu4_2, nout=int(rate[9] * 512), pad=1, ks=3) 162 | n.pool4 = max_pool(n.relu4_3, ks=2, stride=2) 163 | 164 | n.conv5_1, n.relu5_1 = conv_relu( 165 | n.pool4, nout=int(rate[10] * 512), pad=1, ks=3) 166 | n.conv5_2, n.relu5_2 = conv_relu( 167 | n.relu5_1, nout=int(rate[11] * 512), pad=1, ks=3) 168 | n.conv5_3, n.relu5_3 = conv_relu( 169 | n.relu5_2, nout=int(rate[12] * 512), pad=1, ks=3) 170 | n.pool5 = max_pool(n.relu5_3, ks=2, stride=2) 171 | 172 | n.fc6, n.relu6 = fc_relu(n.pool5, nout=4096) 173 | n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True) 174 | n.fc7, n.relu7 = fc_relu(n.relu6, nout=4096) 175 | n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True) 176 | 177 | n.fc8 = L.InnerProduct(n.relu7, num_output=1000, param=[ 178 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 179 | 180 | if not_deploy: 181 | n.loss = L.SoftmaxWithLoss(n.fc8, n.label) 182 | n.acc_top_1 = L.Accuracy(n.fc8, n.label, top_k=1) 183 | n.acc_top_5 = L.Accuracy(n.fc8, n.label, top_k=5) 184 | else: 185 | n.prob = L.Softmax(n.fc8) 186 | model_str = str(n.to_proto()) 187 | if not not_deploy: 188 | model_str = model_str[54:-1] 189 | return str(data_str) + '\n' + model_str 190 | 191 | 192 | def solver_and_prototxt(compress_layer, compress_rate): 193 | compress_rate_tmp = np.ones(13) 194 | compress_rate_old = compress_rate_tmp 195 | for i in range(compress_layer): 196 | compress_rate_old[i] = compress_rate 197 | compress_rate_new = np.array(compress_rate_old) 198 | compress_rate_new[compress_layer] = compress_rate 199 | 200 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 201 | 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 202 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3'] 203 | 204 | pt_folder = osp.join(candidate[compress_layer]) 205 | if not os.path.exists(pt_folder): 206 | os.mkdir(pt_folder) 207 | solver = Solver(folder=pt_folder, b=compress_layer) 208 | solver.write() 209 | 210 | with open(candidate[compress_layer] + '/trainval.prototxt', 'w') as f: 211 | f.write( 212 | vgg_16('/opt/luojh/Dataset/ImageNet/keep/lmdb/', bs_train=32, 213 | bs_val=50, rate=compress_rate_new, lmdb_flag=True)) 214 | 215 | with open(candidate[compress_layer] + '/deploy.prototxt', 'w') as f: 216 | f.write( 217 | vgg_16('/opt/luojh/Dataset/ImageNet/keep/lmdb/', 218 | rate=compress_rate_old, lmdb_flag=True, not_deploy=False)) 219 | 220 | 221 | if __name__ == '__main__': 222 | compress_layer = 12 223 | compress_rate = 0.25 224 | solver_and_prototxt(compress_layer, compress_rate) 225 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/net_generator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | caffe_root = '/home/luojh2/Software/caffe-master/' 3 | sys.path.insert(0, caffe_root + 'python') 4 | import caffe 5 | from caffe import layers as L 6 | from caffe import params as P 7 | from caffe.proto import caffe_pb2 8 | import numpy as np 9 | import os.path as osp 10 | import os 11 | 12 | 13 | class Solver: 14 | 15 | def __init__(self, solver_name=None, folder=None, b=0): 16 | self.solver_name = solver_name 17 | self.folder = folder 18 | 19 | if self.folder is not None: 20 | self.name = osp.join(self.folder, 'solver.prototxt') 21 | if self.name is None: 22 | self.name = 'solver.pt' 23 | else: 24 | filepath, ext = osp.splitext(self.name) 25 | if ext == '': 26 | ext = '.prototxt' 27 | self.name = filepath + ext 28 | 29 | self.p = caffe_pb2.SolverParameter() 30 | 31 | class Method: 32 | nesterov = "Nesterov" 33 | SGD = "SGD" 34 | AdaGrad = "AdaGrad" 35 | RMSProp = "RMSProp" 36 | AdaDelta = "AdaDelta" 37 | Adam = "Adam" 38 | self.method = Method() 39 | 40 | class Policy: 41 | """ - fixed: always return base_lr.""" 42 | fixed = 'fixed' 43 | """ - step: return base_lr * gamma ^ (floor(iter / step))""" 44 | """ - exp: return base_lr * gamma ^ iter""" 45 | """ - inv: return base_lr * (1 + gamma * iter) ^ (- power)""" 46 | """ - multistep: similar to step but it allows non uniform steps defined by stepvalue""" 47 | multistep = 'multistep' 48 | """ - poly: the effective learning rate follows a polynomial decay, to be zero by the max_iter. return base_lr (1 - iter/max_iter) ^ (power)""" 49 | """ - sigmoid: the effective learning rate follows a sigmod decay""" 50 | """ return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))""" 51 | self.policy = Policy() 52 | 53 | class Machine: 54 | GPU = self.p.GPU 55 | CPU = self.p.GPU 56 | self.machine = Machine() 57 | 58 | # defaults 59 | self.p.test_iter.extend([1000]) 60 | self.p.test_interval = 10000 61 | self.p.test_initialization = True 62 | if b == 9: # the final layer 63 | self.p.max_iter = 120000 64 | self.p.stepvalue.extend([40000, 80000]) 65 | elif b in [1, 3, 6]: 66 | self.p.max_iter = 20000 67 | self.p.stepvalue.extend([10000]) 68 | else: 69 | self.p.max_iter = 10000 70 | self.p.base_lr = 0.001 71 | self.p.lr_policy = self.policy.multistep 72 | 73 | self.p.gamma = 0.1 74 | self.p.momentum = 0.9 75 | self.p.weight_decay = 0.0005 76 | self.p.display = 20 77 | 78 | self.p.snapshot = 10000 79 | self.p.snapshot_prefix = osp.join(self.folder, "snapshot/") 80 | self.p.solver_mode = self.machine.GPU 81 | 82 | self.p.net = osp.join(self.folder, "trainval.prototxt") 83 | 84 | def write(self): 85 | if not osp.exists(self.p.snapshot_prefix): 86 | os.mkdir(self.p.snapshot_prefix) 87 | with open(self.name, 'wb') as f: 88 | f.write(str(self.p)) 89 | 90 | 91 | # helper functions for common structures 92 | def conv_relu(bottom, ks, nout, pad=0): 93 | conv = L.Convolution(bottom, kernel_size=ks, num_output=nout, pad=pad, param=[ 94 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 95 | return conv, L.ReLU(conv, in_place=False) 96 | 97 | 98 | def fc_relu(bottom, nout): 99 | fc = L.InnerProduct(bottom, num_output=nout, param=[ 100 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 101 | return fc, L.ReLU(fc, in_place=False) 102 | 103 | 104 | def max_pool(bottom, ks, stride=1): 105 | return L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride) 106 | 107 | 108 | def ave_pool(bottom, ks, stride=1): 109 | return L.Pooling(bottom, pool=P.Pooling.AVE, kernel_size=ks, stride=stride) 110 | 111 | 112 | def vgg_16(lmdb, bs_train=16, bs_val=50, rate=0, lmdb_flag=False, not_deploy=True): 113 | n = caffe.NetSpec() 114 | if not_deploy: 115 | if lmdb_flag: 116 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_train_lmdb', backend=P.Data.LMDB, 117 | include=dict(phase=caffe_pb2.TRAIN), batch_size=bs_train, ntop=2, 118 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=True)) 119 | data_str = n.to_proto() 120 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_val_lmdb', backend=P.Data.LMDB, 121 | include=dict(phase=caffe_pb2.TEST), batch_size=bs_val, ntop=2, 122 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=False)) 123 | else: 124 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_train_leveldb', backend=P.Data.LEVELDB, 125 | include=dict(phase=caffe_pb2.TRAIN), batch_size=bs_train, ntop=2, 126 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=True)) 127 | data_str = n.to_proto() 128 | n.data, n.label = L.Data(source=lmdb + 'ilsvrc12_val_leveldb', backend=P.Data.LEVELDB, 129 | include=dict(phase=caffe_pb2.TEST), batch_size=bs_val, ntop=2, 130 | transform_param=dict(crop_size=224, mean_value=[104, 117, 123], mirror=False)) 131 | else: 132 | data_str = 'input: "data"\ninput_dim: 1\ninput_dim: 3\ninput_dim: 224\ninput_dim: 224' 133 | n.data = L.Data() 134 | 135 | # the net itself 136 | n.conv1_1, n.relu1_1 = conv_relu( 137 | n.data, nout=int(rate[0] * 64), pad=1, ks=3) 138 | n.conv1_2, n.relu1_2 = conv_relu( 139 | n.relu1_1, nout=int(rate[1] * 64), pad=1, ks=3) 140 | n.pool1 = max_pool(n.relu1_2, ks=2, stride=2) 141 | 142 | n.conv2_1, n.relu2_1 = conv_relu( 143 | n.pool1, nout=int(rate[2] * 128), pad=1, ks=3) 144 | n.conv2_2, n.relu2_2 = conv_relu( 145 | n.relu2_1, nout=int(rate[3] * 128), pad=1, ks=3) 146 | n.pool2 = max_pool(n.relu2_2, ks=2, stride=2) 147 | 148 | n.conv3_1, n.relu3_1 = conv_relu( 149 | n.pool2, nout=int(rate[4] * 256), pad=1, ks=3) 150 | n.conv3_2, n.relu3_2 = conv_relu( 151 | n.relu3_1, nout=int(rate[5] * 256), pad=1, ks=3) 152 | n.conv3_3, n.relu3_3 = conv_relu( 153 | n.relu3_2, nout=int(rate[6] * 256), pad=1, ks=3) 154 | n.pool3 = max_pool(n.relu3_3, ks=2, stride=2) 155 | 156 | n.conv4_1, n.relu4_1 = conv_relu( 157 | n.pool3, nout=int(rate[7] * 512), pad=1, ks=3) 158 | n.conv4_2, n.relu4_2 = conv_relu( 159 | n.relu4_1, nout=int(rate[8] * 512), pad=1, ks=3) 160 | n.conv4_3, n.relu4_3 = conv_relu( 161 | n.relu4_2, nout=int(rate[9] * 512), pad=1, ks=3) 162 | n.pool4 = max_pool(n.relu4_3, ks=2, stride=2) 163 | 164 | n.conv5_1, n.relu5_1 = conv_relu( 165 | n.pool4, nout=int(rate[10] * 512), pad=1, ks=3) 166 | n.conv5_2, n.relu5_2 = conv_relu( 167 | n.relu5_1, nout=int(rate[11] * 512), pad=1, ks=3) 168 | n.conv5_3, n.relu5_3 = conv_relu( 169 | n.relu5_2, nout=int(rate[12] * 512), pad=1, ks=3) 170 | n.pool5 = max_pool(n.relu5_3, ks=2, stride=2) 171 | 172 | n.fc6, n.relu6 = fc_relu(n.pool5, nout=4096) 173 | n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True) 174 | n.fc7, n.relu7 = fc_relu(n.relu6, nout=4096) 175 | n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True) 176 | 177 | n.fc8 = L.InnerProduct(n.relu7, num_output=1000, param=[ 178 | dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)]) 179 | 180 | if not_deploy: 181 | n.loss = L.SoftmaxWithLoss(n.fc8, n.label) 182 | n.acc_top_1 = L.Accuracy(n.fc8, n.label, top_k=1) 183 | n.acc_top_5 = L.Accuracy(n.fc8, n.label, top_k=5) 184 | else: 185 | n.prob = L.Softmax(n.fc8) 186 | model_str = str(n.to_proto()) 187 | if not not_deploy: 188 | model_str = model_str[54:-1] 189 | return str(data_str) + '\n' + model_str 190 | 191 | 192 | def solver_and_prototxt(compress_layer, compress_rate): 193 | compress_rate_tmp = np.ones(13) 194 | compress_rate_old = compress_rate_tmp 195 | for i in range(compress_layer): 196 | compress_rate_old[i] = compress_rate 197 | compress_rate_new = np.array(compress_rate_old) 198 | compress_rate_new[compress_layer] = compress_rate 199 | 200 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 201 | 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 202 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3'] 203 | 204 | pt_folder = osp.join(candidate[compress_layer]) 205 | if not os.path.exists(pt_folder): 206 | os.mkdir(pt_folder) 207 | solver = Solver(folder=pt_folder, b=compress_layer) 208 | solver.write() 209 | 210 | with open(candidate[compress_layer] + '/trainval.prototxt', 'w') as f: 211 | f.write( 212 | vgg_16('/opt/luojh/Dataset/ImageNet/keep/lmdb/', bs_train=32, 213 | bs_val=50, rate=compress_rate_new, lmdb_flag=True)) 214 | 215 | with open(candidate[compress_layer] + '/deploy.prototxt', 'w') as f: 216 | f.write( 217 | vgg_16('/opt/luojh/Dataset/ImageNet/keep/lmdb/', 218 | rate=compress_rate_old, lmdb_flag=True, not_deploy=False)) 219 | 220 | 221 | if __name__ == '__main__': 222 | compress_layer = 9 223 | compress_rate = 0.4 224 | solver_and_prototxt(compress_layer, compress_rate) 225 | -------------------------------------------------------------------------------- /ThiNet_ICCV/compress_model.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | caffe_root = '/home/luojh2/Software/caffe-master/' 4 | sys.path.insert(0, caffe_root + 'python') 5 | import caffe 6 | from net_generator import solver_and_prototxt 7 | import numpy as np 8 | from PIL import Image 9 | import random 10 | import time 11 | import os 12 | 13 | 14 | def im_resize(im, height=224, width=224): 15 | d_type = im.dtype 16 | im = Image.fromarray(im) 17 | im = im.resize([height, width], Image.BICUBIC) 18 | im = np.array(im, d_type) 19 | return im 20 | 21 | 22 | def convert2rgb(im): 23 | if len(im.shape) == 2: 24 | im = im.reshape((im.shape[0], im.shape[1], 1)) 25 | im = np.concatenate((im, im, im), axis=2) 26 | if im.shape[2] == 4: 27 | im = np.array(Image.fromarray(im).convert('RGB')) 28 | return im 29 | 30 | 31 | def get_index(compress_rate, compress_layer, gpu): 32 | # set parameters 33 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 34 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 35 | relu_candidate = ['relu1_1', 'pool1', 'relu2_1', 'pool2', 'relu3_1', 'relu3_2', 'pool3', 'relu4_1', 36 | 'relu4_2', 'pool4', 'relu5_1', 'relu5_2', 'pool5', 'relu6', 'relu7'] 37 | 38 | # load net 39 | model_def = candidate[compress_layer] + '/deploy.prototxt' 40 | model_weights = 'model.caffemodel' 41 | caffe.set_device(gpu) 42 | caffe.set_mode_gpu() 43 | net = caffe.Net(model_def, model_weights, caffe.TEST) 44 | 45 | mean_value = np.array([104, 117, 123], dtype=np.float32) 46 | mean_value = mean_value.reshape([3, 1, 1]) 47 | 48 | # extract feature 49 | count = 0 50 | sample_num = 10 # for each category, we sample 10 images 51 | channel_num = 10 # for each image, we sample 10 locations 52 | padding = 1 53 | kernel_size = 3 # for vgg-16, the padding and kernel_size are same in each layer 54 | for foldername in os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train'): 55 | img_list = os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train/' + foldername) 56 | img_index = random.sample(range(len(img_list)), sample_num) 57 | for file_index in img_index: 58 | time_start = time.time() 59 | 60 | file_path = '/opt/luojh/Dataset/ImageNet/images/train/' + foldername + '/' + img_list[file_index] 61 | im = Image.open(file_path) 62 | im = convert2rgb(np.array(im)) 63 | im = im_resize(im, 256, 256) 64 | im = np.array(im, np.float64) 65 | im = im[:, :, ::-1] # convert RGB to BGR 66 | im = im.transpose((2, 0, 1)) # convert to 3x256x256 67 | im -= mean_value 68 | 69 | # shape for input (data blob is N x C x H x W), set data 70 | # center crop 71 | im = im[:, 16:240, 16:240] 72 | net.blobs['data'].reshape(1, *im.shape) 73 | net.blobs['data'].data[...] = im 74 | # run net and take argmax for prediction 75 | net.forward() 76 | 77 | Activation = net.blobs[candidate[compress_layer + 1]].data 78 | Input = net.blobs[relu_candidate[compress_layer]].data 79 | Filters = net.params[candidate[compress_layer + 1]][0].data 80 | Bias = net.params[candidate[compress_layer + 1]][1].data 81 | 82 | if compress_layer < 12: 83 | # conv1_1 to conv 5_2 84 | if count == 0: 85 | X = np.zeros( 86 | [channel_num * 1000 * sample_num, Filters.shape[1]]) 87 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 88 | 89 | padded = np.zeros((Input.shape[0], Input.shape[1], Input.shape[ 90 | 2] + 2 * padding, Input.shape[3] + 2 * padding), dtype=np.float32) 91 | padded[:, :, padding:-padding, padding:-padding] = Input 92 | Input = padded 93 | 94 | for tmp in range(channel_num): 95 | filter_num = random.randint(0, Filters.shape[0] - 1) 96 | i = random.randint(0, Input.shape[2] - kernel_size) 97 | j = random.randint(0, Input.shape[3] - kernel_size) 98 | In_ = Input[:, :, i:i + kernel_size, j:j + kernel_size] 99 | In_ = In_.reshape([In_.shape[1], -1]) 100 | F_ = Filters[filter_num, :, :, :] 101 | F_ = F_.reshape([F_.shape[0], -1]) 102 | Out_ = Activation[0, filter_num, i, j] - Bias[filter_num] 103 | X[count, :] = np.reshape(np.sum(F_ * In_, axis=1), [1, -1]) 104 | Y[count, 0] = np.reshape(Out_, [1, -1]) 105 | count += 1 106 | elif compress_layer == 12: 107 | # conv 5_3 108 | if count == 0: 109 | X = np.zeros( 110 | [channel_num * 1000 * sample_num, 512]) 111 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 112 | 113 | for tmp in range(channel_num): 114 | filter_num = random.randint(0, Filters.shape[0] - 1) 115 | In_ = Input.reshape([Input.shape[1], -1]) 116 | F_ = Filters[filter_num, :] 117 | F_ = F_.reshape([512, -1]) 118 | Out_ = Activation[:, filter_num] - Bias[filter_num] 119 | X[count, :] = np.reshape(np.sum(F_ * In_, axis=1), [1, -1]) 120 | Y[count, 0] = np.reshape(Out_, [1, -1]) 121 | count += 1 122 | else: 123 | # fc6 fc7 124 | if count == 0: 125 | X = np.zeros( 126 | [channel_num * 1000 * sample_num, Filters.shape[1]]) 127 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 128 | 129 | for tmp in range(channel_num): 130 | filter_num = random.randint(0, Filters.shape[0] - 1) 131 | In_ = Input.reshape(-1) 132 | F_ = Filters[filter_num, :] 133 | Out_ = Activation[:, filter_num] - Bias[filter_num] 134 | X[count, :] = np.reshape(F_ * In_, [1, -1]) 135 | Y[count, 0] = np.reshape(Out_, [1, -1]) 136 | count += 1 137 | 138 | time_end = time.time() 139 | print 'Done! use %f second, %d image' % (time_end - time_start, count / channel_num) 140 | 141 | # select filters 142 | return value_sum(X, Y, compress_rate) 143 | 144 | 145 | # use greedy method to select filters 146 | # x:N*64 matrix, N is the instance number, 64 is channel number 147 | def value_sum(x, y, compress_rate): 148 | # 1. set parameters 149 | time_s = time.time() 150 | x = np.mat(x) 151 | y = np.mat(y) 152 | goal_num = int(x.shape[1] * compress_rate) 153 | discard_num = int(x.shape[1]) - goal_num 154 | discard_index = [] 155 | 156 | # 2. select 157 | x_tmp = 0 158 | for i in range(discard_num): 159 | min_value = float("inf") 160 | for j in range(x.shape[1]): 161 | if j not in discard_index: 162 | tmp_value = np.linalg.norm(x_tmp + x[:, j]) 163 | if tmp_value < min_value: 164 | min_value = tmp_value 165 | min_index = j 166 | discard_index.append(min_index) 167 | x_tmp += x[:, min_index] 168 | print('discard num={0}, channel num={1}, i={2}, loss={3:.3f}'.format(discard_num, x.shape[1], i, min_value)) 169 | 170 | # 3. return index 171 | index = set(range(x.shape[1])) - set(discard_index) 172 | index = np.array(list(index)) 173 | index = np.sort(index) 174 | 175 | # 4.least square 176 | selected_x = x[:, index] 177 | w = (selected_x.T * selected_x).I * (selected_x.T * y) 178 | w = np.array(w) 179 | 180 | loss = np.linalg.norm(y - selected_x*w) 181 | print('loss before w={0:.3f}, loss with w={1:.3f}'.format(np.linalg.norm(y - np.sum(selected_x, 1)), loss)) 182 | print 'Time used: %f s' % (time.time()-time_s) 183 | return index, w 184 | 185 | 186 | def compress_net(index, w, compress_layer): 187 | # other layers 188 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 189 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 190 | 191 | model_def = candidate[compress_layer] + '/deploy.prototxt' 192 | model_weights = 'model.caffemodel' 193 | net = caffe.Net(model_def, # defines the structure of the matrix 194 | model_weights, # contains the trained weights 195 | caffe.TEST) # use test mode (e.g., don't perform dropout) 196 | 197 | model_def = candidate[compress_layer] + '/trainval.prototxt' 198 | # use test mode (e.g., don't perform dropout) 199 | net_new = caffe.Net(model_def, caffe.TEST) 200 | 201 | current_layer = candidate[compress_layer] 202 | next_layer = candidate[compress_layer + 1] 203 | for i in range(0, len(candidate)): 204 | if candidate[i] != current_layer and candidate[i] != next_layer: 205 | net_new.params[candidate[i]][ 206 | 0].data[...] = net.params[candidate[i]][0].data 207 | net_new.params[candidate[i]][ 208 | 1].data[...] = net.params[candidate[i]][1].data 209 | 210 | weight = net.params[current_layer][0].data 211 | bias = net.params[current_layer][1].data 212 | if len(weight.shape) == 4: 213 | # conv layer 214 | weight = weight[index, :, :, :] 215 | else: 216 | # fc layer 217 | weight = weight[index, :] 218 | 219 | bias = bias[index] 220 | net_new.params[current_layer][0].data[...] = weight 221 | net_new.params[current_layer][1].data[...] = bias 222 | # next 223 | weight = net.params[next_layer][0].data 224 | bias = net.params[next_layer][1].data 225 | if len(weight.shape) == 4: 226 | # conv layer 227 | weight = weight[:, index, :, :] 228 | for i in range(weight.shape[1]): 229 | weight[:, i, :, :] *= w[i] 230 | elif next_layer == 'fc6': 231 | # fc6 232 | weight = weight.reshape([4096, 512, 7, 7]) 233 | weight = weight[:, index, :, :] 234 | for i in range(weight.shape[1]): 235 | weight[:, i, :, :] *= w[i] 236 | weight = weight.reshape([4096, -1]) 237 | else: 238 | # fc7 or fc8 layer 239 | weight = weight[:, index] 240 | for i in range(weight.shape[1]): 241 | weight[:, i] *= w[i] 242 | 243 | net_new.params[next_layer][0].data[...] = weight 244 | net_new.params[next_layer][1].data[...] = bias 245 | 246 | net_new.save('model.caffemodel') 247 | print 'OK!' 248 | 249 | 250 | if __name__ == '__main__': 251 | compress_layer = int(sys.argv[1]) 252 | gpu = int(sys.argv[2]) 253 | compress_rate = float(sys.argv[3]) 254 | 255 | solver_and_prototxt(compress_layer, compress_rate) 256 | index, w = get_index(compress_rate, compress_layer, gpu) 257 | 258 | compress_net(index, w, compress_layer) 259 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/VGG16/compress_model.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | caffe_root = '/home/luojh2/Software/caffe-master/' 4 | sys.path.insert(0, caffe_root + 'python') 5 | import caffe 6 | from net_generator import solver_and_prototxt 7 | import numpy as np 8 | from PIL import Image 9 | import random 10 | import time 11 | import os 12 | 13 | 14 | def im_resize(im, height=224, width=224): 15 | d_type = im.dtype 16 | im = Image.fromarray(im) 17 | im = im.resize([height, width], Image.BICUBIC) 18 | im = np.array(im, d_type) 19 | return im 20 | 21 | 22 | def convert2rgb(im): 23 | if len(im.shape) == 2: 24 | im = im.reshape((im.shape[0], im.shape[1], 1)) 25 | im = np.concatenate((im, im, im), axis=2) 26 | if im.shape[2] == 4: 27 | im = np.array(Image.fromarray(im).convert('RGB')) 28 | return im 29 | 30 | 31 | def get_index(compress_rate, compress_layer, gpu): 32 | # set parameters 33 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 34 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 35 | relu_candidate = ['relu1_1', 'pool1', 'relu2_1', 'pool2', 'relu3_1', 'relu3_2', 'pool3', 'relu4_1', 36 | 'relu4_2', 'pool4', 'relu5_1', 'relu5_2', 'pool5', 'relu6', 'relu7'] 37 | 38 | # load net 39 | model_def = candidate[compress_layer] + '/deploy.prototxt' 40 | model_weights = 'model.caffemodel' 41 | caffe.set_device(gpu) 42 | caffe.set_mode_gpu() 43 | net = caffe.Net(model_def, model_weights, caffe.TEST) 44 | 45 | mean_value = np.array([104, 117, 123], dtype=np.float32) 46 | mean_value = mean_value.reshape([3, 1, 1]) 47 | 48 | # extract feature 49 | count = 0 50 | sample_num = 10 # 1000 categories sample sample_num images 51 | channel_num = 10 # sample channel number 52 | padding = 1 53 | kernel_size = 3 54 | for foldername in os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train'): 55 | img_list = os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train/' + foldername) 56 | img_index = random.sample(range(len(img_list)), sample_num) 57 | for file_index in img_index: 58 | time_start = time.time() 59 | 60 | file_path = '/opt/luojh/Dataset/ImageNet/images/train/' + foldername + '/' + img_list[file_index] 61 | im = Image.open(file_path) 62 | im = convert2rgb(np.array(im)) 63 | im = im_resize(im, 256, 256) 64 | im = np.array(im, np.float64) 65 | im = im[:, :, ::-1] # convert RGB to BGR 66 | im = im.transpose((2, 0, 1)) # convert to 3x256x256 67 | im -= mean_value 68 | 69 | # shape for input (data blob is N x C x H x W), set data 70 | # center crop 71 | im = im[:, 16:240, 16:240] 72 | net.blobs['data'].reshape(1, *im.shape) 73 | net.blobs['data'].data[...] = im 74 | # run net and take argmax for prediction 75 | net.forward() 76 | 77 | Activation = net.blobs[candidate[compress_layer + 1]].data 78 | Input = net.blobs[relu_candidate[compress_layer]].data 79 | Filters = net.params[candidate[compress_layer + 1]][0].data 80 | Bias = net.params[candidate[compress_layer + 1]][1].data 81 | 82 | if compress_layer < 12: 83 | # conv1_1 to conv 5_2 84 | if count == 0: 85 | X = np.zeros( 86 | [channel_num * 1000 * sample_num, Filters.shape[1]]) 87 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 88 | 89 | padded = np.zeros((Input.shape[0], Input.shape[1], Input.shape[ 90 | 2] + 2 * padding, Input.shape[3] + 2 * padding), dtype=np.float32) 91 | padded[:, :, padding:-padding, padding:-padding] = Input 92 | Input = padded 93 | 94 | for tmp in range(channel_num): 95 | filter_num = random.randint(0, Filters.shape[0] - 1) 96 | i = random.randint(0, Input.shape[2] - kernel_size) 97 | j = random.randint(0, Input.shape[3] - kernel_size) 98 | In_ = Input[:, :, i:i + kernel_size, j:j + kernel_size] 99 | In_ = In_.reshape([In_.shape[1], -1]) 100 | F_ = Filters[filter_num, :, :, :] 101 | F_ = F_.reshape([F_.shape[0], -1]) 102 | Out_ = Activation[0, filter_num, i, j] - Bias[filter_num] 103 | X[count, :] = np.reshape(np.sum(F_ * In_, axis=1), [1, -1]) 104 | Y[count, 0] = np.reshape(Out_, [1, -1]) 105 | count += 1 106 | elif compress_layer == 12: 107 | # conv 5_3 108 | if count == 0: 109 | X = np.zeros( 110 | [channel_num * 1000 * sample_num, 512]) 111 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 112 | 113 | for tmp in range(channel_num): 114 | filter_num = random.randint(0, Filters.shape[0] - 1) 115 | In_ = Input.reshape([Input.shape[1], -1]) 116 | F_ = Filters[filter_num, :] 117 | F_ = F_.reshape([512, -1]) 118 | Out_ = Activation[:, filter_num] - Bias[filter_num] 119 | X[count, :] = np.reshape(np.sum(F_ * In_, axis=1), [1, -1]) 120 | Y[count, 0] = np.reshape(Out_, [1, -1]) 121 | count += 1 122 | else: 123 | # fc6 fc7 124 | if count == 0: 125 | X = np.zeros( 126 | [channel_num * 1000 * sample_num, Filters.shape[1]]) 127 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 128 | 129 | for tmp in range(channel_num): 130 | filter_num = random.randint(0, Filters.shape[0] - 1) 131 | In_ = Input.reshape(-1) 132 | F_ = Filters[filter_num, :] 133 | Out_ = Activation[:, filter_num] - Bias[filter_num] 134 | X[count, :] = np.reshape(F_ * In_, [1, -1]) 135 | Y[count, 0] = np.reshape(Out_, [1, -1]) 136 | count += 1 137 | 138 | time_end = time.time() 139 | print 'Done! use %f second, %d image' % (time_end - time_start, count / channel_num) 140 | 141 | # sort index 142 | # np.save('X.npy', X) 143 | # np.save('Y.npy', Y) 144 | if compress_layer < 13: 145 | return value_sum(X, Y, compress_rate) 146 | else: 147 | return value_sum_another(X, Y, compress_rate) 148 | 149 | 150 | # use greedy method to select index 151 | # x:N*64 matrix, N is the instance number, 64 is channel number 152 | def value_sum(x, y, compress_rate): 153 | # 1. set parameters 154 | x = np.mat(x) 155 | y = np.mat(y) 156 | goal_num = int(x.shape[1] * compress_rate) 157 | index = [] 158 | 159 | # 2. select 160 | y_tmp = y 161 | for i in range(goal_num): 162 | min_value = float("inf") 163 | s = time.time() 164 | for j in range(x.shape[1]): 165 | if j not in index: 166 | tmp_w = (x[:, j].T*y_tmp)[0, 0]/(x[:,j].T*x[:,j])[0,0] 167 | tmp_value = np.linalg.norm(y_tmp-tmp_w*x[:,j]) 168 | if tmp_value < min_value: 169 | min_value = tmp_value 170 | min_index = j 171 | index.append(min_index) 172 | selected_x = x[:, index] 173 | w = np.linalg.pinv(selected_x.T * selected_x) * selected_x.T * y 174 | y_tmp = y - selected_x * w 175 | print('goal num={0}, channel num={1}, i={2}, loss={3:.3f}, time={4:.3f}'.format(goal_num, x.shape[1], i, 176 | min_value, time.time() - s)) 177 | 178 | # 3. return index 179 | index = np.array(list(index)) 180 | index = np.sort(index) 181 | 182 | # 4.least square 183 | selected_x = x[:, index] 184 | w = (selected_x.T * selected_x).I * (selected_x.T * y) 185 | w = np.array(w) 186 | 187 | loss = np.linalg.norm(y - selected_x * w) 188 | print('loss with w={0:.3f}'.format(loss)) 189 | return index, w 190 | 191 | 192 | # use greedy method to select index 193 | # x:N*64 matrix, N is the instance number, 64 is channel number 194 | def value_sum_another(x, y, compress_rate): 195 | # 1. set parameters 196 | goal_num = int(x.shape[1] * compress_rate) 197 | index = [] 198 | 199 | # 2. select 200 | for i in range(goal_num): 201 | min_value = float("inf") 202 | print('goal num=%d, channel num=%d, i=%d') % ( 203 | goal_num, x.shape[1], i) 204 | old_sum = np.sum(np.take(x, index, axis=1), axis=1) 205 | for j in range(x.shape[1]): 206 | if j not in index: 207 | tmp_value = np.sum((old_sum + np.take(x, j, axis=1) - y.reshape(-1)) ** 2) 208 | if tmp_value < min_value: 209 | min_value = tmp_value 210 | min_index = index[:] 211 | min_index.append(j) 212 | index = min_index 213 | 214 | # 3. return index 215 | index = np.array(list(index)) 216 | index = np.sort(index) 217 | 218 | # 4.least square 219 | selected_x = np.mat(x[:, index]) 220 | w = (selected_x.T * selected_x).I * (selected_x.T * y) 221 | w = np.array(w) 222 | return index, w 223 | 224 | 225 | def compress_net(index, w, compress_layer): 226 | # other layers 227 | candidate = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 228 | 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3', 'fc6', 'fc7', 'fc8'] 229 | 230 | model_def = candidate[compress_layer] + '/deploy.prototxt' 231 | model_weights = 'model.caffemodel' 232 | net = caffe.Net(model_def, # defines the structure of the matrix 233 | model_weights, # contains the trained weights 234 | caffe.TEST) # use test mode (e.g., don't perform dropout) 235 | 236 | model_def = candidate[compress_layer] + '/trainval.prototxt' 237 | # use test mode (e.g., don't perform dropout) 238 | net_new = caffe.Net(model_def, caffe.TEST) 239 | 240 | current_layer = candidate[compress_layer] 241 | next_layer = candidate[compress_layer + 1] 242 | for i in range(0, len(candidate)): 243 | if candidate[i] != current_layer and candidate[i] != next_layer: 244 | net_new.params[candidate[i]][ 245 | 0].data[...] = net.params[candidate[i]][0].data 246 | net_new.params[candidate[i]][ 247 | 1].data[...] = net.params[candidate[i]][1].data 248 | 249 | weight = net.params[current_layer][0].data 250 | bias = net.params[current_layer][1].data 251 | if len(weight.shape) == 4: 252 | # conv layer 253 | weight = weight[index, :, :, :] 254 | else: 255 | # fc layer 256 | weight = weight[index, :] 257 | 258 | bias = bias[index] 259 | net_new.params[current_layer][0].data[...] = weight 260 | net_new.params[current_layer][1].data[...] = bias 261 | # next 262 | weight = net.params[next_layer][0].data 263 | bias = net.params[next_layer][1].data 264 | if len(weight.shape) == 4: 265 | # conv layer 266 | weight = weight[:, index, :, :] 267 | for i in range(weight.shape[1]): 268 | weight[:, i, :, :] *= w[i] 269 | elif next_layer == 'fc6': 270 | # fc6 271 | weight = weight.reshape([4096, 512, 7, 7]) 272 | weight = weight[:, index, :, :] 273 | for i in range(weight.shape[1]): 274 | weight[:, i, :, :] *= w[i] 275 | weight = weight.reshape([4096, -1]) 276 | else: 277 | # fc7 or fc8 layer 278 | weight = weight[:, index] 279 | for i in range(weight.shape[1]): 280 | weight[:, i] *= w[i] 281 | 282 | net_new.params[next_layer][0].data[...] = weight 283 | net_new.params[next_layer][1].data[...] = bias 284 | 285 | net_new.save('model.caffemodel') 286 | print 'OK!' 287 | 288 | 289 | if __name__ == '__main__': 290 | compress_layer = int(sys.argv[1]) 291 | gpu = int(sys.argv[2]) 292 | compress_rate = float(sys.argv[3]) 293 | 294 | solver_and_prototxt(compress_layer, compress_rate) 295 | index, w = get_index(compress_rate, compress_layer, gpu) 296 | 297 | compress_net(index, w, compress_layer) 298 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/compress_model.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | caffe_root = '/home/luojh2/Software/caffe-master/' 4 | sys.path.insert(0, caffe_root + 'python') 5 | import caffe 6 | import numpy as np 7 | from PIL import Image 8 | from net_generator import solver_and_prototxt 9 | import random 10 | import time 11 | import os 12 | 13 | 14 | def im_resize(im, height=224, width=224): 15 | d_type = im.dtype 16 | im = Image.fromarray(im) 17 | im = im.resize([height, width], Image.BICUBIC) 18 | im = np.array(im, d_type) 19 | return im 20 | 21 | 22 | def convert2rgb(im): 23 | if len(im.shape) == 2: 24 | im = im.reshape((im.shape[0], im.shape[1], 1)) 25 | im = np.concatenate((im, im, im), axis=2) 26 | if im.shape[2] == 4: 27 | im = np.array(Image.fromarray(im).convert('RGB')) 28 | return im 29 | 30 | 31 | def get_index(compress_rate, compress_layer, gpu, compress_block): 32 | # set parameters 33 | sample_num = 10 # 1000 categories sample sample_num images 34 | channel_num = 10 # sample channel number 35 | 36 | layers = ['2a', '2b', '2c', '3a', '3b', '3c', '3d', '4a', '4b', '4c', '4d', '4e', '4f', '5a', '5b', '5c'] 37 | 38 | # load net 39 | caffe.set_device(gpu) 40 | caffe.set_mode_gpu() 41 | model_def = layers[compress_layer] + '_' + str(compress_block) +'/deploy.prototxt' 42 | model_weights = 'model.caffemodel' 43 | net = caffe.Net(model_def, model_weights, caffe.TEST) 44 | # load the mean ImageNet image (as distributed with Caffe) for subtraction 45 | mean_value = np.array([104, 117, 123], dtype=np.float32) 46 | mean_value = mean_value.reshape([3, 1, 1]) 47 | 48 | if compress_block == 0: 49 | input_layer = 'bn' + layers[compress_layer] + '_branch2a' 50 | output_layer = 'res' + layers[compress_layer] + '_branch2b' 51 | kernel_size = 3 52 | padding = 1 53 | else: 54 | input_layer = 'bn' + layers[compress_layer] + '_branch2b' 55 | output_layer = 'res' + layers[compress_layer] + '_branch2c' 56 | kernel_size = 1 57 | padding = 0 58 | 59 | # extract feature 60 | count = 0 61 | for foldername in os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train'): 62 | img_list = os.listdir(r'/opt/luojh/Dataset/ImageNet/images/train/' + foldername) 63 | img_index = random.sample(range(len(img_list)), sample_num) 64 | for file_index in img_index: 65 | time_start = time.time() 66 | 67 | file_path = '/opt/luojh/Dataset/ImageNet/images/train/' + foldername + '/' + img_list[file_index] 68 | im = Image.open(file_path) 69 | im = convert2rgb(np.array(im)) 70 | im = im_resize(im, 256, 256) 71 | im = np.array(im, np.float64) 72 | im = im[:, :, ::-1] # convert RGB to BGR 73 | im = im.transpose((2, 0, 1)) # convert to 3x256x256 74 | im -= mean_value 75 | 76 | # shape for input (data blob is N x C x H x W), set data 77 | # center crop 78 | im = im[:, 16:240, 16:240] 79 | net.blobs['data'].reshape(1, *im.shape) 80 | net.blobs['data'].data[...] = im 81 | # run net and take argmax for prediction 82 | net.forward() 83 | 84 | Activation = net.blobs[output_layer].data # res2a_branch2c 85 | Input = net.blobs[input_layer].data # bn2a_branch2b 86 | Filters = net.params[output_layer][0].data # res2a_branch2c 87 | 88 | if padding > 0: 89 | padded = np.zeros((Input.shape[0], Input.shape[1], Input.shape[ 90 | 2] + 2 * padding, Input.shape[3] + 2 * padding), dtype=np.float32) 91 | padded[:, :, padding:-padding, padding:-padding] = Input 92 | Input = padded 93 | 94 | if count == 0: 95 | X = np.zeros([channel_num * 1000 * sample_num, Filters.shape[1]]) 96 | Y = np.zeros([channel_num * 1000 * sample_num, 1]) 97 | 98 | for tmp in range(channel_num): 99 | filter_num = random.randint(0, Filters.shape[0] - 1) 100 | i = random.randint(0, Input.shape[2] - kernel_size) 101 | j = random.randint(0, Input.shape[3] - kernel_size) 102 | In_ = Input[:, :, i:i + kernel_size, j:j + kernel_size] 103 | In_ = In_.reshape([In_.shape[1], -1]) 104 | F_ = Filters[filter_num, :, :, :] 105 | F_ = F_.reshape([F_.shape[0], -1]) 106 | Out_ = Activation[0, filter_num, i, j] 107 | X[count, :] = np.reshape(np.sum(F_ * In_, axis=1), [1, -1]) 108 | Y[count, 0] = np.reshape(Out_, [1, -1]) 109 | count += 1 110 | 111 | time_end = time.time() 112 | print 'Done! use %f second, %d image' % (time_end - time_start, count / channel_num) 113 | # sort index 114 | return value_sum(X, Y, compress_rate) 115 | 116 | 117 | # use greedy method to select index 118 | # x:N*64 matrix, N is the instance number, 64 is channel number 119 | def value_sum(x, y, compress_rate): 120 | # 1. set parameters 121 | x = np.mat(x) 122 | y = np.mat(y) 123 | goal_num = int(x.shape[1] * compress_rate) 124 | index = [] 125 | 126 | # 2. select 127 | y_tmp = y 128 | for i in range(goal_num): 129 | min_value = float("inf") 130 | s = time.time() 131 | for j in range(x.shape[1]): 132 | if j not in index: 133 | tmp_w = (x[:, j].T*y_tmp)[0, 0]/(x[:,j].T*x[:,j])[0,0] 134 | tmp_value = np.linalg.norm(y_tmp-tmp_w*x[:,j]) 135 | if tmp_value < min_value: 136 | min_value = tmp_value 137 | min_index = j 138 | index.append(min_index) 139 | selected_x = x[:, index] 140 | w = np.linalg.pinv(selected_x.T * selected_x) * selected_x.T * y 141 | y_tmp = y - selected_x * w 142 | print('goal num={0}, channel num={1}, i={2}, loss={3:.3f}, time={4:.3f}'.format(goal_num, x.shape[1], i, 143 | min_value, time.time() - s)) 144 | 145 | # 3. return index 146 | index = np.array(list(index)) 147 | index = np.sort(index) 148 | 149 | # 4.least square 150 | selected_x = x[:, index] 151 | w = (selected_x.T * selected_x).I * (selected_x.T * y) 152 | w = np.array(w) 153 | 154 | loss = np.linalg.norm(y - selected_x * w) 155 | print('loss with w={0:.3f}'.format(loss)) 156 | return index, w 157 | 158 | 159 | def copy_net(net_new, net, layer_name): 160 | net_new.params[ 161 | 'res' + layer_name][0].data[...] = net.params['res' + layer_name][0].data 162 | net_new.params[ 163 | 'bn' + layer_name][0].data[...] = net.params['bn' + layer_name][0].data 164 | net_new.params[ 165 | 'bn' + layer_name][1].data[...] = net.params['bn' + layer_name][1].data 166 | net_new.params['bn' + layer_name][2] = net.params['bn' + layer_name][2] 167 | net_new.params[ 168 | 'scale' + layer_name][0].data[...] = net.params['scale' + layer_name][0].data 169 | net_new.params[ 170 | 'scale' + layer_name][1].data[...] = net.params['scale' + layer_name][1].data 171 | return net_new 172 | 173 | 174 | def compress_2c(net_new, net, layer_name, index, w): 175 | weight = net.params['res' + layer_name][0].data 176 | weight = weight[:, index, :, :] 177 | # important !!!!!!!!!!!! 178 | for i in range(weight.shape[1]): 179 | weight[:, i, :, :] *= w[i] 180 | # 181 | net_new.params['res' + layer_name][0].data[...] = weight 182 | 183 | weight = net.params['bn' + layer_name][0].data 184 | bias = net.params['bn' + layer_name][1].data 185 | net_new.params['bn' + layer_name][0].data[...] = weight 186 | net_new.params['bn' + layer_name][1].data[...] = bias 187 | net_new.params['bn' + layer_name][2] = net.params['bn' + layer_name][2] 188 | 189 | weight = net.params['scale' + layer_name][0].data 190 | bias = net.params['scale' + layer_name][1].data 191 | net_new.params['scale' + layer_name][0].data[...] = weight 192 | net_new.params['scale' + layer_name][1].data[...] = bias 193 | return net_new 194 | 195 | 196 | def compress_2b(net_new, net, layer_name, index): 197 | weight = net.params['res' + layer_name][0].data 198 | net_new.params['res' + layer_name][0].data[...] = weight[index, :, :, :] 199 | 200 | weight = net.params['bn' + layer_name][0].data 201 | bias = net.params['bn' + layer_name][1].data 202 | net_new.params['bn' + layer_name][0].data[...] = weight[index] 203 | net_new.params['bn' + layer_name][1].data[...] = bias[index] 204 | net_new.params['bn' + layer_name][2] = net.params['bn' + layer_name][2] 205 | 206 | weight = net.params['scale' + layer_name][0].data 207 | bias = net.params['scale' + layer_name][1].data 208 | net_new.params['scale' + layer_name][0].data[...] = weight[index] 209 | net_new.params['scale' + layer_name][1].data[...] = bias[index] 210 | return net_new 211 | 212 | 213 | def compress_net(index, w, compress_layer, compress_block): 214 | # other layers 215 | layers = ['2a', '2b', '2c', '3a', '3b', '3c', '3d', 216 | '4a', '4b', '4c', '4d', '4e', '4f', '5a', '5b', '5c'] 217 | 218 | model_def = layers[compress_layer] + '_' + str(compress_block) + '/deploy.prototxt' 219 | model_weights = 'model.caffemodel' 220 | net = caffe.Net(model_def, # defines the structure of the matrix 221 | model_weights, # contains the trained weights 222 | caffe.TEST) # use test mode (e.g., don't perform dropout) 223 | 224 | # use test mode (e.g., don't perform dropout) 225 | net_new = caffe.Net(layers[compress_layer] + '_' + str(compress_block) + 226 | '/trainval.prototxt', caffe.TEST) 227 | 228 | # layer 0 229 | layer_name = 'conv1' 230 | net_new.params[layer_name][0].data[...] = net.params[layer_name][0].data 231 | net_new.params[layer_name][1].data[...] = net.params[layer_name][1].data 232 | net_new.params[ 233 | 'bn_' + layer_name][0].data[...] = net.params['bn_' + layer_name][0].data 234 | net_new.params[ 235 | 'bn_' + layer_name][1].data[...] = net.params['bn_' + layer_name][1].data 236 | net_new.params['bn_' + layer_name][2] = net.params['bn_' + layer_name][2] 237 | net_new.params[ 238 | 'scale_' + layer_name][0].data[...] = net.params['scale_' + layer_name][0].data 239 | net_new.params[ 240 | 'scale_' + layer_name][1].data[...] = net.params['scale_' + layer_name][1].data 241 | 242 | # media 243 | for i in range(0, 16): 244 | layer_name = layers[i] 245 | if i == compress_layer: 246 | # compress block 247 | if compress_block == 0: 248 | net_new = compress_2b( 249 | net_new, net, layer_name + '_branch2a', index) 250 | net_new = compress_2c( 251 | net_new, net, layer_name + '_branch2b', index, w) 252 | net_new = copy_net(net_new, net, layer_name + '_branch2c') 253 | else: 254 | net_new = copy_net(net_new, net, layer_name + '_branch2a') 255 | net_new = compress_2b( 256 | net_new, net, layer_name + '_branch2b', index) 257 | net_new = compress_2c( 258 | net_new, net, layer_name + '_branch2c', index, w) 259 | else: 260 | # copy block 261 | net_new = copy_net(net_new, net, layer_name + '_branch2a') 262 | net_new = copy_net(net_new, net, layer_name + '_branch2b') 263 | net_new = copy_net(net_new, net, layer_name + '_branch2c') 264 | 265 | # branch 1 266 | candidate = ['2a', '3a', '4a', '5a'] 267 | for i in range(0, 4): 268 | layer_name = candidate[i] 269 | net_new = copy_net(net_new, net, layer_name + '_branch1') 270 | 271 | # fc 272 | net_new.params['fc1000'][0].data[...] = net.params['fc1000'][0].data 273 | net_new.params['fc1000'][1].data[...] = net.params['fc1000'][1].data 274 | net_new.save('model.caffemodel') 275 | print 'OK!' 276 | 277 | 278 | if __name__ == '__main__': 279 | compress_layer = int(sys.argv[1]) 280 | compress_block = int(sys.argv[2]) 281 | compress_rate = float(sys.argv[3]) 282 | gpu = int(sys.argv[4]) 283 | 284 | solver_and_prototxt(compress_layer, compress_rate, compress_block) 285 | index, w = get_index(compress_rate, compress_layer, gpu, compress_block) 286 | 287 | compress_net(index, w, compress_layer, compress_block) 288 | -------------------------------------------------------------------------------- /ThiNet_TPAMI/ResNet50/net_generator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | caffe_root = '/home/luojh2/Software/caffe-master/' 3 | sys.path.insert(0, caffe_root + 'python') 4 | from caffe.proto import caffe_pb2 5 | import os.path as osp 6 | import os 7 | import numpy as np 8 | 9 | 10 | class Solver: 11 | 12 | def __init__(self, solver_name=None, folder=None, b=0, compress_block=0): 13 | self.solver_name = solver_name 14 | self.folder = folder 15 | 16 | if self.folder is not None: 17 | self.name = osp.join(self.folder, 'solver.prototxt') 18 | if self.name is None: 19 | self.name = 'solver.pt' 20 | else: 21 | filepath, ext = osp.splitext(self.name) 22 | if ext == '': 23 | ext = '.prototxt' 24 | self.name = filepath + ext 25 | 26 | self.p = caffe_pb2.SolverParameter() 27 | 28 | class Method: 29 | nesterov = "Nesterov" 30 | SGD = "SGD" 31 | AdaGrad = "AdaGrad" 32 | RMSProp = "RMSProp" 33 | AdaDelta = "AdaDelta" 34 | Adam = "Adam" 35 | self.method = Method() 36 | 37 | class Policy: 38 | """ - fixed: always return base_lr.""" 39 | fixed = 'fixed' 40 | """ - step: return base_lr * gamma ^ (floor(iter / step))""" 41 | """ - exp: return base_lr * gamma ^ iter""" 42 | """ - inv: return base_lr * (1 + gamma * iter) ^ (- power)""" 43 | """ - multistep: similar to step but it allows non uniform steps defined by stepvalue""" 44 | multistep = 'multistep' 45 | """ - poly: the effective learning rate follows a polynomial decay, to be zero by the max_iter. return base_lr (1 - iter/max_iter) ^ (power)""" 46 | """ - sigmoid: the effective learning rate follows a sigmod decay""" 47 | """ return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))""" 48 | self.policy = Policy() 49 | 50 | class Machine: 51 | GPU = self.p.GPU 52 | CPU = self.p.GPU 53 | self.machine = Machine() 54 | 55 | # defaults 56 | self.p.test_iter.extend([5000]) 57 | self.p.test_interval = 10000 58 | self.p.test_initialization = True 59 | 60 | if compress_block==0: 61 | self.p.base_lr = 0.0001 62 | else: 63 | self.p.base_lr = 0.0001 64 | 65 | if b == 15 and compress_block==1: # the final layer 66 | self.p.base_lr = 0.001 67 | self.p.max_iter = 90000 68 | self.p.stepvalue.extend([30000, 60000]) 69 | else: 70 | self.p.max_iter = 10000 71 | 72 | self.p.lr_policy = self.policy.multistep 73 | self.p.gamma = 0.1 74 | self.p.momentum = 0.9 75 | self.p.weight_decay = 0.0005 76 | self.p.display = 20 77 | 78 | self.p.snapshot = 10000 79 | self.p.snapshot_prefix = osp.join(self.folder, "snapshot/") 80 | self.p.solver_mode = self.machine.GPU 81 | 82 | # self.p.type = self.method.nesterov 83 | self.p.net = osp.join(self.folder, "trainval.prototxt") 84 | 85 | def write(self): 86 | if not osp.exists(self.p.snapshot_prefix): 87 | os.mkdir(self.p.snapshot_prefix) 88 | with open(self.name, 'wb') as f: 89 | f.write(str(self.p)) 90 | 91 | 92 | class Net: 93 | 94 | def __init__(self, name="network"): 95 | self.net = caffe_pb2.NetParameter() 96 | self.net.name = name 97 | self.bottom = None 98 | self.cur = None 99 | self.this = None 100 | 101 | def setup(self, name, layer_type, bottom=[], top=[], inplace=False): 102 | 103 | self.bottom = self.cur 104 | 105 | new_layer = self.net.layer.add() 106 | 107 | new_layer.name = name 108 | new_layer.type = layer_type 109 | 110 | if self.bottom is not None and new_layer.type != 'Data': 111 | bottom_name = [self.bottom.name] 112 | if len(bottom) == 0: 113 | bottom = bottom_name 114 | new_layer.bottom.extend(bottom) 115 | 116 | if inplace: 117 | top = bottom_name 118 | elif len(top) == 0: 119 | top = [name] 120 | new_layer.top.extend(top) 121 | 122 | self.this = new_layer 123 | if not inplace: 124 | self.cur = new_layer 125 | 126 | def suffix(self, name, self_name=None): 127 | if self_name is None: 128 | return self.cur.name + '_' + name 129 | else: 130 | return self_name 131 | 132 | def write(self, name=None, folder=None, deploy=False): 133 | # dirname = osp.dirname(name) 134 | # if not osp.exists(dirname): 135 | # os.mkdir(dirname) 136 | if folder is not None: 137 | name = osp.join(folder, name) 138 | elif name is None: 139 | name = 'trainval.pt' 140 | else: 141 | filepath, ext = osp.splitext(name) 142 | if ext == '': 143 | ext = '.prototxt' 144 | name = filepath + ext 145 | with open(name, 'wb') as f: 146 | if deploy: 147 | f.write('name: "resnet-50"\n') 148 | f.write('input: "data"\ninput_dim: 1\ninput_dim: 3\n') 149 | f.write('input_dim: 224\ninput_dim: 224\n') 150 | net_str = str(self.net) 151 | net_str = net_str[85:-1] 152 | f.write(net_str) 153 | else: 154 | f.write(str(self.net)) 155 | 156 | def show(self): 157 | print self.net 158 | #************************** params ************************** 159 | 160 | def param(self, lr_mult=1, decay_mult=0): 161 | new_param = self.this.param.add() 162 | new_param.lr_mult = lr_mult 163 | new_param.decay_mult = decay_mult 164 | 165 | def transform_param(self, mean_value=128, batch_size=128, scale=.0078125, mirror=1, crop_size=None, 166 | mean_file_size=None, phase=None): 167 | new_transform_param = self.this.transform_param 168 | new_transform_param.mean_value.extend([104]) 169 | new_transform_param.mean_value.extend([117]) 170 | new_transform_param.mean_value.extend([123]) 171 | 172 | new_transform_param.mirror = mirror 173 | if crop_size is not None: 174 | new_transform_param.crop_size = crop_size 175 | 176 | def data_param(self, source, backend='LMDB', batch_size=30): 177 | new_data_param = self.this.data_param 178 | new_data_param.source = source 179 | if backend == 'LEVELDB': 180 | new_data_param.backend = new_data_param.LEVELDB 181 | else: 182 | new_data_param.backend = new_data_param.LMDB 183 | new_data_param.batch_size = batch_size 184 | 185 | def weight_filler(self, filler='msra'): 186 | """xavier""" 187 | if self.this.type == 'InnerProduct': 188 | self.this.inner_product_param.weight_filler.type = filler 189 | else: 190 | self.this.convolution_param.weight_filler.type = filler 191 | 192 | def bias_filler(self, filler='constant', value=0): 193 | if self.this.type == 'InnerProduct': 194 | self.this.inner_product_param.bias_filler.type = filler 195 | self.this.inner_product_param.bias_filler.value = value 196 | else: 197 | self.this.convolution_param.bias_filler.type = filler 198 | self.this.convolution_param.bias_filler.value = value 199 | 200 | def include(self, phase='TRAIN'): 201 | if phase is not None: 202 | includes = self.this.include.add() 203 | if phase == 'TRAIN': 204 | includes.phase = caffe_pb2.TRAIN 205 | elif phase == 'TEST': 206 | includes.phase = caffe_pb2.TEST 207 | else: 208 | NotImplementedError 209 | 210 | #************************** inplace ************************** 211 | def ReLU(self, name=None): 212 | 213 | self.setup(self.suffix('relu', name), 'ReLU', inplace=True) 214 | 215 | def BatchNorm(self, name=None): 216 | 217 | self.setup(self.suffix('bn', name), 'BatchNorm', inplace=False) 218 | # self.this.batch_norm_param.use_global_stats = True 219 | batch_norm_param = self.this.batch_norm_param 220 | 221 | def Scale(self, name=None): 222 | self.setup(self.suffix('scale', name), 'Scale', inplace=True) 223 | self.this.scale_param.bias_term = True 224 | 225 | #************************** layers ************************** 226 | 227 | def Data(self, source, backend, top=['data', 'label'], name="data", batch_size=30, phase=None, **kwargs): 228 | self.setup(name, 'Data', top=top) 229 | 230 | self.include(phase) 231 | 232 | self.data_param(source, batch_size=batch_size, backend=backend) 233 | self.transform_param(phase=phase, **kwargs) 234 | 235 | def Convolution(self, name, bottom=[], num_output=None, kernel_size=3, pad=1, stride=1, decay=True, bias=False, freeze=False, bias_term=None): 236 | self.setup(name, 'Convolution', bottom=bottom, top=[name]) 237 | 238 | conv_param = self.this.convolution_param 239 | if num_output is None: 240 | num_output = self.bottom.convolution_param.num_output 241 | 242 | conv_param.num_output = num_output 243 | conv_param.kernel_size.extend([kernel_size]) 244 | conv_param.pad.extend([pad]) 245 | conv_param.stride.extend([stride]) 246 | 247 | if freeze: 248 | lr_mult = 0 249 | else: 250 | lr_mult = 1 251 | if decay: 252 | decay_mult = 1 253 | else: 254 | decay_mult = 0 255 | self.param(lr_mult=lr_mult, decay_mult=decay_mult) 256 | self.weight_filler() 257 | 258 | if bias: 259 | if decay: 260 | decay_mult = 2 261 | else: 262 | decay_mult = 0 263 | self.param(lr_mult=lr_mult, decay_mult=decay_mult) 264 | self.bias_filler() 265 | if bias_term is not None: 266 | conv_param.bias_term = bias_term 267 | 268 | def SoftmaxWithLoss(self, name='loss', label='label'): 269 | self.setup(name, 'SoftmaxWithLoss', bottom=[self.cur.name, label]) 270 | 271 | def Softmax(self, bottom=[], name='softmax'): 272 | self.setup(name, 'Softmax', bottom=bottom) 273 | 274 | def Accuracy(self, name='Accuracy', label='label'): 275 | cur_bottom = 'fc1000' 276 | self.setup(name + '/top1', 'Accuracy', 277 | bottom=[cur_bottom, label], top=['accuracy@1']) 278 | self.this.accuracy_param.top_k = 1 279 | self.setup(name + '/top5', 'Accuracy', 280 | bottom=[cur_bottom, label], top=['accuracy@5']) 281 | self.this.accuracy_param.top_k = 5 282 | 283 | def InnerProduct(self, name='fc', num_output=10): 284 | self.setup(name, 'InnerProduct') 285 | self.param(lr_mult=1, decay_mult=1) 286 | self.param(lr_mult=2, decay_mult=0) 287 | inner_product_param = self.this.inner_product_param 288 | inner_product_param.num_output = num_output 289 | self.weight_filler() 290 | self.bias_filler() 291 | 292 | def Pooling(self, name, pool='AVE', global_pooling=False, kernel_size=3, stride=2): 293 | """MAX AVE """ 294 | self.setup(name, 'Pooling') 295 | if pool == 'AVE': 296 | self.this.pooling_param.pool = self.this.pooling_param.AVE 297 | else: 298 | self.this.pooling_param.pool = self.this.pooling_param.MAX 299 | if global_pooling: 300 | self.this.pooling_param.global_pooling = global_pooling 301 | else: 302 | self.this.pooling_param.kernel_size = kernel_size 303 | self.this.pooling_param.stride = stride 304 | 305 | def Eltwise(self, name, bottom1, operation='SUM'): 306 | bottom0 = self.bottom.name 307 | self.setup(name, 'Eltwise', bottom=[bottom0, bottom1]) 308 | 309 | #************************** DIY ************************** 310 | def conv_relu(self, name, relu_name=None, **kwargs): 311 | self.Convolution(name, **kwargs) 312 | self.ReLU(relu_name) 313 | 314 | def conv_bn_relu(self, name, bn_name=None, scale_name=None, relu_name=None, **kwargs): 315 | self.Convolution(name, **kwargs) 316 | self.BatchNorm(bn_name) 317 | self.Scale(scale_name) 318 | self.ReLU(relu_name) 319 | 320 | def conv_bn(self, name, bn_name=None, scale_name=None, **kwargs): 321 | self.Convolution(name, **kwargs) 322 | self.BatchNorm(bn_name) 323 | self.Scale(scale_name) 324 | 325 | def softmax_acc(self, bottom, **kwargs): 326 | self.Softmax(bottom=[bottom]) 327 | 328 | has_label = None 329 | for name, value in kwargs.items(): 330 | if name == 'label': 331 | has_label = value 332 | if has_label is None: 333 | self.Accuracy() 334 | else: 335 | self.Accuracy(label=has_label) 336 | 337 | #************************** network blocks ************************** 338 | def res_block(self, name, rate1, rate2, num_output, proj=False, p_stride=1): 339 | bottom = self.cur.name 340 | 341 | self.conv_bn_relu('res' + name + '_branch2a', bn_name='bn' + name + '_branch2a', 342 | scale_name='scale' + name + '_branch2a', relu_name='res' + name + '_branch2a' + '_relu', 343 | num_output=int(rate1 * num_output), kernel_size=1, pad=0, stride=p_stride, bias_term=False) 344 | self.conv_bn_relu('res' + name + '_branch2b', bn_name='bn' + name + '_branch2b', 345 | scale_name='scale' + name + '_branch2b', relu_name='res' + name + '_branch2b' + '_relu', 346 | num_output=int(rate2 * num_output), kernel_size=3, pad=1, stride=1, bias_term=False) 347 | self.conv_bn('res' + name + '_branch2c', bn_name='bn' + name + '_branch2c', 348 | scale_name='scale' + name + '_branch2c', 349 | num_output=4 * num_output, kernel_size=1, pad=0, stride=1, bias_term=False) 350 | 351 | if proj: 352 | self.conv_bn('res' + name + '_branch1', bn_name='bn' + name + '_branch1', 353 | scale_name='scale' + name + '_branch1', 354 | num_output=4 * num_output, bottom=[bottom], kernel_size=1, pad=0, stride=p_stride, bias_term=False) 355 | # Important modify!! 356 | self.Eltwise('res' + name, bottom1='bn' + name + '_branch2c') 357 | self.setup('res' + name + '_relu', 'ReLU', inplace=True) 358 | else: 359 | self.Eltwise('res' + name, bottom1=bottom) 360 | self.setup('res' + name + '_relu', 'ReLU', inplace=True) 361 | 362 | #************************** networks ************************** 363 | def resnet_50(self, layers, compress_layer, compress_rate, compress_block, deploy=False): 364 | self.conv_bn_relu('conv1', bn_name='bn_conv1', scale_name='scale_conv1', relu_name='conv1_relu', 365 | num_output=64, kernel_size=7, pad=3, stride=2) 366 | self.Pooling("pool1", pool='max', global_pooling=False, 367 | kernel_size=3, stride=2) 368 | 369 | if compress_block == 0: 370 | # compress 1, not 2 371 | rate1 = np.ones([1, 16]) 372 | for i in range(0, compress_layer+1): 373 | rate1[0, i] = rate1[0, i] * compress_rate 374 | rate2 = np.ones([1, 16]) 375 | for i in range(0, compress_layer): 376 | rate2[0, i] = rate2[0, i] * compress_rate 377 | else: 378 | # both 379 | rate1 = np.ones([1, 16]) 380 | for i in range(0, compress_layer + 1): 381 | rate1[0, i] = rate1[0, i] * compress_rate 382 | rate2 = rate1.copy() 383 | 384 | # 2 385 | output = 64 386 | self.res_block(layers[0], rate1[0, 0], rate2[0, 0], output, proj=True) 387 | self.res_block(layers[1], rate1[0, 1], rate2[0, 1], output, proj=False) 388 | self.res_block(layers[2], rate1[0, 2], rate2[0, 2], output, proj=False) 389 | # 3 390 | output = 128 391 | self.res_block(layers[3], rate1[0, 3], rate2[0, 3], output, proj=True, p_stride=2) 392 | self.res_block(layers[4], rate1[0, 4], rate2[0, 4], output, proj=False) 393 | self.res_block(layers[5], rate1[0, 5], rate2[0, 5], output, proj=False) 394 | self.res_block(layers[6], rate1[0, 6], rate2[0, 6], output, proj=False) 395 | # 4 396 | output = 256 397 | self.res_block(layers[7], rate1[0, 7], rate2[0, 7], output, proj=True, p_stride=2) 398 | self.res_block(layers[8], rate1[0, 8], rate2[0, 8], output, proj=False) 399 | self.res_block(layers[9], rate1[0, 9], rate2[0, 9], output, proj=False) 400 | self.res_block(layers[10], rate1[0, 10], rate2[0, 10], output, proj=False) 401 | self.res_block(layers[11], rate1[0, 11], rate2[0, 11], output, proj=False) 402 | self.res_block(layers[12], rate1[0, 12], rate2[0, 12], output, proj=False) 403 | # 5 404 | output = 512 405 | self.res_block(layers[13], rate1[0, 13], rate2[0, 13], output, proj=True, p_stride=2) 406 | self.res_block(layers[14], rate1[0, 14], rate2[0, 14], output, proj=False) 407 | self.res_block(layers[15], rate1[0, 15], rate2[0, 15], output, proj=False) 408 | 409 | self.Pooling("pool5", pool='AVE', global_pooling=False, 410 | kernel_size=7, stride=1) 411 | self.InnerProduct(name='fc1000', num_output=1000) 412 | if deploy: 413 | self.Softmax() 414 | else: 415 | self.SoftmaxWithLoss() 416 | self.Accuracy() 417 | 418 | 419 | def solver_and_prototxt(compress_layer, compress_rate, compress_block): 420 | layers = ['2a', '2b', '2c', '3a', '3b', '3c', '3d', 421 | '4a', '4b', '4c', '4d', '4e', '4f', '5a', '5b', '5c'] 422 | pt_folder = layers[compress_layer] + '_' + str(compress_block) 423 | if not os.path.exists(pt_folder): 424 | os.mkdir(pt_folder) 425 | name = 'resnet-' + layers[compress_layer] + str(compress_block) +'-ImageNet' 426 | 427 | solver = Solver(folder=pt_folder, b=compress_layer, compress_block=compress_block) 428 | solver.write() 429 | 430 | builder = Net(name) 431 | builder.Data('/opt/luojh/Dataset/ImageNet/lmdb/ilsvrc12_train_lmdb', backend='LMDB', phase='TRAIN', mirror=True, 432 | crop_size=224, batch_size=32) 433 | builder.Data('/opt/luojh/Dataset/ImageNet/lmdb/ilsvrc12_val_lmdb', backend='LMDB', phase='TEST', mirror=False, 434 | crop_size=224, batch_size=10) 435 | builder.resnet_50(layers, compress_layer, compress_rate, compress_block) 436 | builder.write(name='trainval.prototxt', folder=pt_folder) 437 | 438 | if compress_block == 0: 439 | compress_block = 1 440 | compress_layer -= 1 441 | else: 442 | compress_block =0 443 | 444 | builder = Net(name + '-old') 445 | builder.setup('data', 'Data', top=['data']) 446 | builder.resnet_50(layers, compress_layer, compress_rate, compress_block, deploy=True) 447 | builder.write(name='deploy.prototxt', folder=pt_folder, deploy=True) 448 | print "Finished net prototxt generation!" 449 | 450 | 451 | if __name__ == '__main__': 452 | compress_layer = 0 453 | compress_block = 0 454 | compress_rate = 0.5 455 | 456 | solver_and_prototxt(compress_layer, compress_rate, compress_block) 457 | --------------------------------------------------------------------------------