├── FAR_README.docx ├── README.md ├── dataset ├── images │ └── url.md └── labels │ ├── s1_label.csv │ ├── s1ab_label.csv │ └── s2_label.csv ├── experiment ├── CAM │ ├── __init__.py │ └── cam.py ├── MutiTask │ ├── __init__.py │ ├── predict.py │ └── train.py ├── Postprocess │ ├── __init__.py │ └── simple_ensemble.py ├── Preprocess │ ├── __init__.py │ ├── eval.csv │ ├── split_train_eval_data.py │ └── train.csv ├── SingleTask │ ├── __init__.py │ └── train.py ├── __init__.py ├── data_info.py └── hyperparams.py ├── fashion-ai.png ├── fashion-ai.vsdx ├── lib ├── __init__.py ├── datasets │ ├── __init__.py │ ├── data_loader.py │ └── transforms.py └── networks │ ├── __init__.py │ ├── my_inceptionv4.py │ └── slim │ ├── __init__.py │ └── nets │ ├── __init__.py │ ├── inception_resnet_v2.py │ ├── inception_utils.py │ └── inception_v4.py ├── model ├── MyInceptionV4 │ └── MultiTask │ │ └── url.md └── Pretrain │ └── model.md └── utils ├── __init__.py └── utils.py /FAR_README.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poemix/FashionAI-ATTR/912a9823fbaece1e00bf1bfe50b073766aff0fbe/FAR_README.docx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FashionAI-ATTR 2 | FashionAI全球挑战赛—服饰属性标签识别解决方案 3 | 4 | ![image](https://github.com/Aiyoj/FashionAI-ATTR/blob/master/fashion-ai.png) 5 | 6 | 针对数据集的missing-label问题,提出了8种属性循环交替多任务训练方案; -------------------------------------------------------------------------------- /dataset/images/url.md: -------------------------------------------------------------------------------- 1 | 链接:https://pan.baidu.com/s/12NvQNDMYEj6UzG7LCuTeqA 密码:orer -------------------------------------------------------------------------------- /experiment/CAM/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/CAM/cam.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import tensorflow as tf 10 | 11 | 12 | def grad_cam(logits, traget_conv): 13 | bt, nb_class = tf.shape(logits)[0], tf.shape(logits)[1] 14 | pred_class = tf.argmax(logits, axis=1) 15 | one_hot = tf.one_hot(pred_class, nb_class, on_value=1., off_value=0., axis=1) 16 | signal = tf.multiply(logits, one_hot) 17 | # print(signal) # Tensor("Mul:0", shape=(?, 8), dtype=float32) 18 | loss = tf.reduce_mean(signal, axis=1) 19 | grads = tf.gradients(loss, traget_conv)[0] 20 | # print(grads) # shape=(?, 8, 8, 1536) 21 | # Normalizing the gradients 22 | # [?, 8, 8, 1536] 23 | norm_grads = tf.divide(grads, tf.sqrt(tf.reduce_mean(tf.square(grads))) + tf.constant(1e-5)) 24 | weights = tf.reduce_mean(norm_grads, axis=[1, 2]) # [?, 1536] 25 | weights = tf.reshape(weights, [bt, 1, 1, -1]) 26 | 27 | # Taking a weighted average 28 | fuck = tf.multiply(weights, traget_conv) 29 | cam = tf.reduce_sum(fuck, axis=3) + tf.ones(tf.shape(traget_conv)[0: 3], dtype=tf.float32) 30 | 31 | # Passing through ReLU 32 | cam = tf.maximum(cam, 0) 33 | 34 | cam = cam / tf.reshape(tf.reduce_max(cam, axis=[1, 2]), [bt, 1, 1]) 35 | 36 | return cam 37 | 38 | 39 | def grad_cam_plus(logits, target_conv): 40 | # logits: [?, ?] 41 | # target_conv: [?, 8, 8, 1536] 42 | bt, nb_class = tf.shape(logits)[0], tf.shape(logits)[1] 43 | ch = tf.shape(target_conv)[3] 44 | pred_class = tf.cast(tf.argmax(logits, axis=1), tf.int32) 45 | 46 | # [?, ?] 47 | one_hot = tf.one_hot(pred_class, nb_class, on_value=1., off_value=0., axis=1) 48 | 49 | # [?, 8] 50 | signal = tf.multiply(logits, one_hot) 51 | 52 | # [?, 8, 8, 1536] 53 | target_grad = tf.gradients(signal, target_conv)[0] 54 | 55 | label = tf.expand_dims(pred_class, 1) 56 | index = tf.expand_dims(tf.range(0, bt), 1) 57 | indices = tf.concat([index, label], axis=1) 58 | fuck = tf.reshape(tf.gather_nd(tf.exp(signal), indices), [-1, 1, 1, 1]) 59 | 60 | # first derivative 61 | # [?, 8, 8, 1536] 62 | first_grad = fuck * target_grad 63 | 64 | # second derivative 65 | second_grad = fuck * target_grad * target_grad 66 | 67 | # third derivative 68 | third_grad = fuck * target_grad * target_grad * target_grad 69 | 70 | global_sum = tf.reduce_sum( 71 | tf.reshape(target_conv, [bt, -1, ch]), 72 | axis=1 73 | ) 74 | 75 | alpha_num = second_grad 76 | 77 | alpha_denom = second_grad * 2.0 + third_grad * tf.reshape(global_sum, [bt, 1, 1, ch]) 78 | alpha_denom = tf.where(alpha_denom != 0.0, alpha_denom, tf.ones(tf.shape(alpha_denom))) 79 | 80 | alphas = alpha_num / alpha_denom 81 | 82 | weights = tf.maximum(first_grad, 0.0) 83 | 84 | # [?, 1536] 85 | alpha_normalization_constant = tf.reduce_sum(tf.reduce_sum(alphas, axis=1), axis=1) 86 | alphas /= tf.reshape(alpha_normalization_constant, [bt, 1, 1, ch]) 87 | 88 | deep_linear_weights = tf.reduce_sum( 89 | tf.reshape(weights * alphas, [bt, -1, ch]), 90 | axis=1 91 | ) 92 | 93 | grad_cam_map = tf.reduce_sum(tf.reshape(deep_linear_weights, [bt, 1, 1, ch]) * target_conv, axis=3) 94 | 95 | # Passing through ReLU 96 | # [?, 8, 8] 97 | cam = tf.maximum(grad_cam_map, 0) 98 | cam = cam / tf.reshape(tf.reduce_max(cam, axis=[1, 2]), [bt, 1, 1]) # scale 0 to 1.0 99 | 100 | return cam 101 | 102 | 103 | if __name__ == "__main__": 104 | import multiprocessing 105 | from lib.networks.my_inceptionv4 import MyInceptionV4 106 | from lib.datasets.data_loader import MTCSVLoader 107 | from lib.datasets import transforms 108 | from experiment.hyperparams import HyperParams as hp 109 | from experiment.data_info import DataInfo as di 110 | from utils import session, vis_cam, cam_writer, roi_writer 111 | 112 | data = tf.placeholder(tf.float32, [None, 331, 331, 3]) 113 | label = tf.placeholder(tf.float32, [None, None]) 114 | dropout = tf.placeholder(tf.float32) 115 | phase = tf.placeholder(tf.bool) 116 | net = MyInceptionV4(data, label, dropout, phase) 117 | 118 | # batch data 119 | transformer = transforms.Sequential( 120 | [ 121 | transforms.Resize([331, 331]), 122 | transforms.Preprocess(), 123 | # transforms.RandomHorizontalFlip(), 124 | ] 125 | ) 126 | root = 'E:/fashion-dataset/base' 127 | mt_loader = MTCSVLoader(root=root, 128 | csv_path='{}/dataset/labels/s1_label.csv'.format(hp.pro_path), 129 | batch_size=hp.batch_size, 130 | transformer_fn=transformer, 131 | shuffle=False, 132 | num_epochs=1, 133 | allow_smaller_final_batch=True) 134 | sess = session() 135 | sess.run(tf.global_variables_initializer()) 136 | saver = tf.train.Saver() 137 | saver.restore(sess, '{}/model/MyInceptionV4/MultiTask/fashion-ai.ckpt'.format(hp.pro_path)) 138 | cam_queue = multiprocessing.Queue(maxsize=30) 139 | cam_writer_process = multiprocessing.Process(target=cam_writer, args=['E:/cam', cam_queue, 'stop']) 140 | cam_writer_process.start() 141 | 142 | roi_queue = multiprocessing.Queue(maxsize=30) 143 | roi_writer_process = multiprocessing.Process(target=roi_writer, args=['E:/roi', roi_queue, 'stop']) 144 | roi_writer_process.start() 145 | for attr_key, n_class in di.num_classes_v2.items(): 146 | print(attr_key) 147 | target_conv_layer = net.layers['PreGAP'] 148 | logits = net.layers['cls_score_{}'.format(attr_key)] 149 | y_pred = tf.argmax(logits, axis=1) 150 | grad_cam_plus = grad_cam_plus(logits, target_conv_layer) 151 | grad_cam = grad_cam(logits, target_conv_layer) 152 | try: 153 | while not mt_loader.coord.should_stop(): 154 | img_batch, label_batch, name_batch = mt_loader.batch(attr_key=attr_key) 155 | names = list(map(lambda v: bytes.decode(v), name_batch)) 156 | print(names) 157 | cams, cam_pluses, yp, prob = sess.run( 158 | [grad_cam, grad_cam_plus, y_pred, logits], 159 | feed_dict={ 160 | net.data: img_batch, 161 | net.is_training: False, 162 | net.keep_prob: 1 163 | }) 164 | cam_queue.put(('continue', names, cams)) 165 | roi_queue.put(('continue', root, names, cams)) 166 | print(cams.shape) 167 | # 可视化CAM 168 | vis_cam(root, names, cams) 169 | except tf.errors.OutOfRangeError: 170 | print('Done.') 171 | cam_queue.put(('stop', None, None)) 172 | cam_writer_process.join() 173 | 174 | roi_queue.put(('stop', None, None, None)) 175 | roi_writer_process.join() 176 | sess.close() 177 | -------------------------------------------------------------------------------- /experiment/MutiTask/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/MutiTask/predict.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import multiprocessing 10 | import tensorflow as tf 11 | from lib.networks.my_inceptionv4 import MyInceptionV4 12 | from lib.datasets.data_loader import MTCSVLoader 13 | from lib.datasets import transforms 14 | from experiment.hyperparams import HyperParams as hp 15 | from experiment.data_info import DataInfo as di 16 | from utils import session, csv_writer 17 | 18 | 19 | def predict(): 20 | data = tf.placeholder(tf.float32, [None, 331, 331, 3]) 21 | label = tf.placeholder(tf.float32, [None, None]) 22 | dropout = tf.placeholder(tf.float32) 23 | phase = tf.placeholder(tf.bool) 24 | net = MyInceptionV4(data, label, dropout, phase) 25 | 26 | # batch data 27 | transformer = transforms.Sequential( 28 | [ 29 | transforms.Resize([331, 331]), 30 | transforms.Preprocess(), 31 | # transforms.RandomHorizontalFlip(), 32 | ] 33 | ) 34 | 35 | mt_loader = MTCSVLoader(root='E:/fashion-dataset/rank', 36 | csv_path='E:\\fashion-dataset\\rank\\Tests\\question.csv', 37 | batch_size=64, 38 | transformer_fn=transformer, 39 | shuffle=False, 40 | num_epochs=1, 41 | allow_smaller_final_batch=True) 42 | sess = session() 43 | sess.run(tf.global_variables_initializer()) 44 | saver = tf.train.Saver() 45 | saver.restore(sess, '{}/model/MyInceptionV4/MultiTask/fashion-ai.ckpt'.format(hp.pro_path)) 46 | queue = multiprocessing.Queue(maxsize=30) 47 | writer_process = multiprocessing.Process(target=csv_writer, args=['{}/result/sub.csv'.format(hp.pro_path), queue, 'stop']) 48 | writer_process.start() 49 | for attr_key, n_class in di.num_classes_v2.items(): 50 | flat_logit = net.layers['cls_prob_{}'.format(attr_key)] 51 | y_pred = tf.argmax(flat_logit, axis=1) 52 | print('writing predictions...') 53 | try: 54 | while not mt_loader.coord.should_stop(): 55 | img_batch, label_batch, name_batch = mt_loader.batch(attr_key=attr_key) 56 | names = list(map(lambda v: bytes.decode(v), name_batch)) 57 | probs, preds = sess.run( 58 | [flat_logit, y_pred], 59 | feed_dict={ 60 | net.data: img_batch, 61 | net.is_training: False, 62 | net.keep_prob: 1 63 | }) 64 | queue.put(('continue', names, attr_key, probs)) 65 | print(probs.shape) 66 | 67 | except tf.errors.OutOfRangeError: 68 | print('Predict {} Done.'.format(attr_key)) 69 | queue.put(('stop', None, None, None)) 70 | writer_process.join() 71 | sess.close() 72 | 73 | 74 | if __name__ == '__main__': 75 | predict() 76 | -------------------------------------------------------------------------------- /experiment/MutiTask/train.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import datetime 10 | import numpy as np 11 | import tensorflow as tf 12 | from lib.networks.my_inceptionv4 import MyInceptionV4 13 | from lib.datasets import transforms 14 | from lib.datasets.data_loader import MTCSVLoader 15 | from experiment.hyperparams import HyperParams as hp 16 | from utils import session 17 | 18 | 19 | def train_net(): 20 | # default graph 21 | # placeholder 22 | data = tf.placeholder(tf.float32, [None, 331, 331, 3]) 23 | label = tf.placeholder(tf.float32, [None, None]) 24 | is_training = tf.placeholder(tf.bool) 25 | keep_prob = tf.placeholder(tf.float32) 26 | 27 | # network 28 | net = MyInceptionV4(data=data, label=label, keep_prob=keep_prob, is_training=is_training) 29 | 30 | # batch data 31 | transformer = transforms.Sequential( 32 | [ 33 | transforms.Resize([331, 331]), 34 | transforms.Preprocess(), 35 | transforms.RandomHorizontalFlip(), 36 | ] 37 | ) 38 | 39 | loader = MTCSVLoader(root='E:/fashion-dataset/base', csv_path='{}/dataset/labels/s1_label.csv'.format(hp.pro_path), 40 | batch_size=hp.batch_size, transformer_fn=transformer, 41 | shuffle=hp.shuffle, min_after_dequeue=hp.min_after_dequeue, 42 | num_threads=hp.num_threads, allow_smaller_final_batch=hp.allow_smaller_final_batch, 43 | seed=hp.seed, num_epochs=None) 44 | 45 | num_batch = sum(list(map(lambda x: x // hp.batch_size, loader.n_sample.values()))) // hp.n_task 46 | hp.display = 1 47 | hp.snapshot_iter = num_batch 48 | hp.stepsize = num_batch * 5 49 | 50 | flat_logits = {} 51 | y_preds = {} 52 | y_trues = {} 53 | accuracys = {} 54 | losses = {} 55 | train_ops = {} 56 | flat_label = net.layers['label'] 57 | 58 | global_step = tf.Variable(0, name='global_step', trainable=False) 59 | lr = tf.train.exponential_decay(hp.learning_rate, global_step, hp.stepsize, hp.lr_decay, staircase=True) 60 | opt1 = tf.train.MomentumOptimizer(lr, hp.momentum) 61 | opt2 = tf.train.MomentumOptimizer(hp.times * lr, hp.momentum) 62 | 63 | update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) 64 | update_op = tf.group(*update_ops) 65 | 66 | var1 = tf.trainable_variables()[0:-16] 67 | var2 = tf.trainable_variables()[-16:] 68 | 69 | for attr_key in ['coat_length_labels', 'collar_design_labels', 'lapel_design_labels', 'neck_design_labels', 70 | 'neckline_design_labels', 'pant_length_labels', 'skirt_length_labels', 'sleeve_length_labels']: 71 | # pred 72 | cls_score = 'cls_score_{}'.format(attr_key) 73 | flat_logit = net.layers[cls_score] 74 | flat_logits[attr_key] = flat_logit 75 | 76 | # acc 77 | y_pred = tf.argmax(flat_logit, axis=1) 78 | y_true = tf.argmax(flat_label, axis=1) 79 | accuracy = tf.reduce_mean(tf.cast(tf.equal(y_pred, y_true), tf.float32)) 80 | 81 | y_preds[attr_key] = y_pred 82 | y_trues[attr_key] = y_true 83 | accuracys[attr_key] = accuracy 84 | 85 | # loss 86 | loss = tf.reduce_mean( 87 | tf.nn.softmax_cross_entropy_with_logits( 88 | logits=flat_logit, 89 | labels=flat_label 90 | ) 91 | ) 92 | losses[attr_key] = loss 93 | 94 | with tf.control_dependencies([update_op]): 95 | cost = tf.identity(loss) 96 | # optimizer 97 | train_op1 = opt1.minimize(cost, global_step=global_step, var_list=var1) 98 | train_op2 = opt2.minimize(cost, var_list=var2) 99 | train_op = tf.group(train_op1, train_op2) 100 | train_ops[attr_key] = train_op 101 | 102 | # session 103 | sess = session() 104 | saver = tf.train.Saver(max_to_keep=50) 105 | sess.run(tf.global_variables_initializer()) 106 | net.load(sess, '{}/model/Pretrain/{}'.format(hp.pro_path, 'inception_v4.ckpt')) 107 | step = -1 108 | last_snapshot_iter = -1 109 | max_step = hp.num_epoch * num_batch 110 | print('num_batch', num_batch) 111 | now_ime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 112 | print('%s Start Training...iter: %d(%d) / %d(%d) lr: %s' % (now_ime, (step + 1), 0, max_step, hp.num_epoch, sess.run(lr))) 113 | 114 | AK = ['coat_length_labels', 'collar_design_labels', 'lapel_design_labels', 'neck_design_labels', 115 | 'neckline_design_labels', 'pant_length_labels', 'skirt_length_labels', 'sleeve_length_labels'] 116 | 117 | for epoch in range(hp.num_epoch): 118 | for batch in range((epoch * num_batch), ((epoch + 1) * num_batch)): 119 | np.random.shuffle(AK) 120 | for step in range((batch * hp.n_task), ((batch + 1) * hp.n_task)): 121 | j = step % hp.n_task 122 | ak = AK[j] 123 | print(ak) 124 | data_batch, label_batch, name_batch = loader.batch(ak) 125 | train_op = train_ops[ak] 126 | loss = losses[ak] 127 | y_pred = y_preds[ak] 128 | y_true = y_trues[ak] 129 | accuracy = accuracys[ak] 130 | 131 | _ = sess.run( 132 | train_op, 133 | feed_dict={ 134 | net.data: data_batch, 135 | net.label: label_batch, 136 | net.is_training: True, 137 | net.keep_prob: hp.keep_prob 138 | } 139 | ) 140 | if (step + 1) % hp.display == 0: 141 | loss_value, acc, y1, y2 = sess.run( 142 | [loss, accuracy, y_true, y_pred], 143 | feed_dict={ 144 | net.data: data_batch, 145 | net.label: label_batch, 146 | net.is_training: False, 147 | net.keep_prob: 1.0 148 | } 149 | ) 150 | print(y1) 151 | print(y2) 152 | now_ime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 153 | print('%s iter: %d(%d) / %d(%d), total loss: %.4f, acc: %.2f, lr: %s' 154 | % (now_ime, (step + 1), (epoch + 1), max_step, hp.num_epoch, loss_value, acc, sess.run(lr))) 155 | if (step + 1) % hp.snapshot_iter == 0: 156 | last_snapshot_iter = step 157 | net.save(sess, saver, step) 158 | 159 | if last_snapshot_iter != step: 160 | net.save(sess, saver, step) 161 | 162 | sess.close() 163 | 164 | 165 | if __name__ == '__main__': 166 | train_net() 167 | -------------------------------------------------------------------------------- /experiment/Postprocess/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/Postprocess/simple_ensemble.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import pandas as pd 10 | 11 | 12 | def simple_ensemble(save_name='sub_ensemble.csv'): 13 | df1 = pd.read_csv('sub1.csv', header=None) 14 | df2 = pd.read_csv('sub2.csv', header=None) 15 | 16 | names = [] 17 | aks = [] 18 | new_probs = [] 19 | 20 | for raw in df1.values: 21 | names.append(raw[0]) 22 | aks.append(raw[1]) 23 | 24 | prob = raw[2].split(';') 25 | prob2 = df2[df2[0].isin([raw[0]])].values[0][2].split(';') 26 | tmp_result = '' 27 | for idx, v in enumerate(prob): 28 | tmp_result += '{:.4f};'.format(0.5*float(v) + 0.5*float(prob2[idx])) 29 | new_probs.append(tmp_result[:-1]) 30 | 31 | sub_df = pd.DataFrame() 32 | sub_df['name'] = names 33 | sub_df['ak'] = aks 34 | sub_df['result'] = new_probs 35 | sub_df.to_csv(save_name, index=False, header=None) 36 | 37 | 38 | if __name__ == '__main__': 39 | simple_ensemble() 40 | -------------------------------------------------------------------------------- /experiment/Preprocess/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/Preprocess/split_train_eval_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import pandas as pd 10 | from sklearn.model_selection import StratifiedShuffleSplit 11 | from experiment.hyperparams import HyperParams as hp 12 | from experiment.data_info import DataInfo as di 13 | from utils import preprocess_label 14 | 15 | 16 | def split_dataset(phase='train'): 17 | path = '{}/dataset/labels/{}' 18 | s1_path = path.format(hp.pro_path, 's1_label.csv') 19 | s1ab_path = path.format(hp.pro_path, 's1ab_label.csv') 20 | s2_path = path.format(hp.pro_path, 's2_label.csv') 21 | 22 | s1_df = pd.read_csv(s1_path, header=None) 23 | s1ab_df = pd.read_csv(s1ab_path, header=None) 24 | s2_df = pd.read_csv(s2_path, header=None) 25 | 26 | s2_df = s2_df.sample(frac=1, random_state=hp.seed) 27 | 28 | datas = [] 29 | labels = [] 30 | attr_keys = [] 31 | singles = [] 32 | 33 | for attr_key, n_class in di.num_classes.items(): 34 | s1_data = s1_df[s1_df[1].isin([attr_key])][0].values 35 | s1_label = s1_df[s1_df[1].isin([attr_key])][2].values 36 | s1_single = s1_df[s1_df[1].isin([attr_key])][3].values 37 | 38 | s1ab_data = s1ab_df[s1ab_df[1].isin([attr_key])][0].values 39 | s1ab_label = s1ab_df[s1ab_df[1].isin([attr_key])][2].values 40 | s1ab_single = s1ab_df[s1ab_df[1].isin([attr_key])][3].values 41 | 42 | s2_data = s2_df[s2_df[1].isin([attr_key])][0].values 43 | s2_label = s2_df[s2_df[1].isin([attr_key])][2].values 44 | s2_single = s2_df[s2_df[1].isin([attr_key])][3].values 45 | 46 | # 对复赛数据进行9:1分层抽样(按类别数) 47 | s2_y = preprocess_label(s2_label, len(s2_label), n_class) 48 | sss = StratifiedShuffleSplit(n_splits=1, train_size=0.9, test_size=0.1, random_state=hp.seed) 49 | 50 | train_indices = [] 51 | eval_indices = [] 52 | 53 | for train_idx, eval_idx in sss.split(s2_data, s2_y): 54 | train_indices.append(train_idx) 55 | eval_indices.append(eval_idx) 56 | 57 | train_idx = train_indices[0] 58 | eval_idx = eval_indices[0] 59 | 60 | train_data = s2_data[train_idx] 61 | eval_data = s2_data[eval_idx] 62 | train_label = s2_label[train_idx] 63 | eval_label = s2_label[eval_idx] 64 | train_single = s2_single[train_idx] 65 | eval_single = s2_single[eval_idx] 66 | 67 | # 初赛数据 68 | for path in s1_data: 69 | datas.append(path) 70 | attr_keys.append(attr_key) 71 | for v in s1_label: 72 | labels.append(v) 73 | for s in s1_single: 74 | singles.append(s) 75 | 76 | # 初赛答案数据 77 | for path in s1ab_data: 78 | datas.append(path) 79 | attr_keys.append(attr_key) 80 | for v in s1ab_label: 81 | labels.append(v) 82 | for s in s1ab_single: 83 | singles.append(s) 84 | 85 | if phase == 'train': 86 | sdata = train_data 87 | slabel = train_label 88 | ssingle = train_single 89 | elif phase == 'eval': 90 | sdata = eval_data 91 | slabel = eval_label 92 | ssingle = eval_single 93 | else: 94 | raise ValueError('error.') 95 | 96 | # 复赛数据 97 | for path in sdata: 98 | datas.append(path) 99 | attr_keys.append(attr_key) 100 | for v in slabel: 101 | labels.append(v) 102 | for s in ssingle: 103 | singles.append(s) 104 | 105 | df = pd.DataFrame() 106 | df['name'] = datas 107 | df['attr_key'] = attr_keys 108 | df['label'] = labels 109 | df['is_single'] = singles 110 | df.to_csv('{}.csv'.format(phase), index=False, header=None) 111 | 112 | 113 | if __name__ == '__main__': 114 | # split_dataset('train') 115 | split_dataset('eval') 116 | -------------------------------------------------------------------------------- /experiment/SingleTask/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/SingleTask/train.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import datetime 10 | import tensorflow as tf 11 | from lib.datasets import transforms 12 | from lib.datasets.data_loader import STCSVLoader 13 | from lib.networks.my_inceptionv4 import MyInceptionV4 14 | from experiment.hyperparams import HyperParams as hp 15 | from utils import session 16 | 17 | 18 | def train_net(attr_key): 19 | with tf.Graph().as_default(): 20 | # placeholder 21 | data = tf.placeholder(tf.float32, [None, 331, 331, 3]) 22 | label = tf.placeholder(tf.float32, [None, None]) 23 | is_training = tf.placeholder(tf.bool) 24 | keep_prob = tf.placeholder(tf.float32) 25 | 26 | # network 27 | net = MyInceptionV4(data=data, label=label, keep_prob=keep_prob, is_training=is_training) 28 | 29 | # batch data 30 | transformer = transforms.Sequential( 31 | [ 32 | transforms.Resize([331, 331]), 33 | transforms.Preprocess(), 34 | transforms.RandomHorizontalFlip(), 35 | ] 36 | ) 37 | 38 | loader = STCSVLoader(root='E:/fashion-dataset/base', attr_key=attr_key, 39 | csv_path='{}/dataset/labels/s1_label.csv'.format(hp.pro_path), 40 | batch_size=hp.batch_size, transformer_fn=transformer, 41 | shuffle=hp.shuffle, min_after_dequeue=hp.min_after_dequeue, 42 | num_threads=hp.num_threads, allow_smaller_final_batch=hp.allow_smaller_final_batch, 43 | seed=hp.seed, num_epochs=None) 44 | 45 | num_batch = loader.n_sample // hp.batch_size 46 | hp.display = 1 47 | hp.snapshot_iter = num_batch 48 | hp.stepsize = num_batch * 5 49 | 50 | global_step = tf.Variable(0, name='global_step', trainable=False) 51 | lr = tf.train.exponential_decay(hp.learning_rate, global_step, hp.stepsize, hp.lr_decay, staircase=True) 52 | opt1 = tf.train.MomentumOptimizer(lr, hp.momentum) 53 | opt2 = tf.train.MomentumOptimizer(hp.times * lr, hp.momentum) 54 | 55 | update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) 56 | update_op = tf.group(*update_ops) 57 | 58 | var1 = tf.trainable_variables()[0:-16] 59 | var2 = tf.trainable_variables()[-16:] 60 | 61 | cls_score = 'cls_score_{}'.format(attr_key) 62 | flat_logit = net.layers[cls_score] 63 | flat_label = net.layers['label'] 64 | 65 | # acc 66 | y_pred = tf.argmax(flat_logit, axis=1) 67 | y_true = tf.argmax(flat_label, axis=1) 68 | accuracy = tf.reduce_mean(tf.cast(tf.equal(y_pred, y_true), tf.float32)) 69 | 70 | # loss 71 | loss = tf.reduce_mean( 72 | tf.nn.softmax_cross_entropy_with_logits( 73 | logits=flat_logit, 74 | labels=flat_label 75 | ) 76 | ) 77 | 78 | with tf.control_dependencies([update_op]): 79 | cost = tf.identity(loss) 80 | # optimizer 81 | train_op1 = opt1.minimize(cost, global_step=global_step, var_list=var1) 82 | train_op2 = opt2.minimize(cost, var_list=var2) 83 | train_op = tf.group(train_op1, train_op2) 84 | 85 | # session 86 | sess = session() 87 | saver = tf.train.Saver(max_to_keep=50) 88 | sess.run(tf.global_variables_initializer()) 89 | net.load(sess, '{}/model/Pretrain/{}'.format(hp.pro_path, 'inception_v4.ckpt')) 90 | step = -1 91 | last_snapshot_iter = -1 92 | max_step = hp.num_epoch * num_batch 93 | print('num_batch', num_batch) 94 | now_ime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 95 | print('%s Start Training...iter: %d(%d) / %d(%d) lr: %s' % ( 96 | now_ime, (step + 1), 0, max_step, hp.num_epoch, sess.run(lr))) 97 | 98 | for epoch in range(hp.num_epoch): 99 | for step in range((epoch * num_batch), ((epoch + 1) * num_batch)): 100 | data_batch, label_batch, name_batch = loader.batch() 101 | _ = sess.run( 102 | train_op, 103 | feed_dict={ 104 | net.data: data_batch, 105 | net.label: label_batch, 106 | net.is_training: True, 107 | net.keep_prob: hp.keep_prob 108 | } 109 | ) 110 | if (step + 1) % hp.display == 0: 111 | loss_value, acc, y1, y2 = sess.run( 112 | [loss, accuracy, y_true, y_pred], 113 | feed_dict={ 114 | net.data: data_batch, 115 | net.label: label_batch, 116 | net.is_training: False, 117 | net.keep_prob: 1.0 118 | } 119 | ) 120 | print(y1) 121 | print(y2) 122 | now_ime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 123 | print('%s iter: %d(%d) / %d(%d), total loss: %.4f, acc: %.2f, lr: %s' 124 | % (now_ime, (step + 1), (epoch + 1), max_step, hp.num_epoch, loss_value, acc, sess.run(lr))) 125 | if (step + 1) % hp.snapshot_iter == 0: 126 | last_snapshot_iter = step 127 | net.save(sess, saver, step) 128 | if last_snapshot_iter != step: 129 | net.save(sess, saver, step) 130 | 131 | sess.close() 132 | 133 | 134 | if __name__ == '__main__': 135 | AK = ['coat_length_labels', 'collar_design_labels', 'lapel_design_labels', 'neck_design_labels', 136 | 'neckline_design_labels', 'pant_length_labels', 'skirt_length_labels', 'sleeve_length_labels'] 137 | for ak in AK: 138 | train_net(attr_key=ak) 139 | -------------------------------------------------------------------------------- /experiment/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /experiment/data_info.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | class DataInfo(object): 10 | num_classes = dict(coat_length_labels=8, collar_design_labels=5, 11 | lapel_design_labels=5, neck_design_labels=5, 12 | neckline_design_labels=10, pant_length_labels=6, 13 | skirt_length_labels=6, sleeve_length_labels=9) 14 | 15 | num_classes_v2 = dict(coat_length_labels=8 * 2, collar_design_labels=5, 16 | lapel_design_labels=5, neck_design_labels=5, 17 | neckline_design_labels=10, pant_length_labels=6 * 2, 18 | skirt_length_labels=6 * 2, sleeve_length_labels=9 * 2) 19 | -------------------------------------------------------------------------------- /experiment/hyperparams.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import os 10 | 11 | 12 | class HyperParams(object): 13 | # project path 14 | pro_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")).replace('\\', '/') 15 | 16 | # random seed 17 | seed = 2018 18 | 19 | # optimizer 20 | learning_rate = 0.01 21 | stepsize = 5000 22 | lr_decay = 0.1 23 | momentum = 0.9 24 | keep_prob = 0.5 25 | 26 | num_epoch = 15 27 | snapshot_iter = 100 28 | display = 10 29 | 30 | # save model 31 | output_dir = '{}/model/{}' 32 | snapshot_infix = '' 33 | snapshot_prefix = 'fashion-ai' 34 | 35 | # data loader 36 | shuffle = True 37 | min_after_dequeue = 32 38 | allow_smaller_final_batch = False 39 | num_threads = 2 40 | batch_size = 12 41 | 42 | # session config 43 | allow_soft_placement = False 44 | log_device_placement = False 45 | allow_growth = True 46 | 47 | times = 5 48 | n_task = 8 49 | 50 | threshold = 64 51 | -------------------------------------------------------------------------------- /fashion-ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poemix/FashionAI-ATTR/912a9823fbaece1e00bf1bfe50b073766aff0fbe/fashion-ai.png -------------------------------------------------------------------------------- /fashion-ai.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poemix/FashionAI-ATTR/912a9823fbaece1e00bf1bfe50b073766aff0fbe/fashion-ai.vsdx -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /lib/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /lib/datasets/data_loader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import pandas as pd 10 | import tensorflow as tf 11 | from utils import session 12 | from experiment.data_info import DataInfo as di 13 | 14 | 15 | def csv_batch(root, data_path, label, n_class, batch_size, height=331, width=331, transformer_fn=None, 16 | num_epochs=None, shuffle=True, min_after_dequeue=50, allow_smaller_final_batch=False, 17 | num_threads=2, seed=None, scope=None): 18 | with tf.name_scope(scope, 'csv_batch'): 19 | n_sample = len(data_path) 20 | name = tf.convert_to_tensor(data_path, tf.string) 21 | data_path = tf.convert_to_tensor(list(map(lambda x: '{}{}'.format(root, x), data_path)), tf.string) 22 | return_label = True 23 | try: 24 | label = tf.convert_to_tensor(label, tf.int32) 25 | except Exception as e: 26 | print(e) 27 | label = tf.convert_to_tensor(label, tf.string) 28 | return_label = False 29 | 30 | data_path, label, name = tf.train.slice_input_producer([data_path, label, name], 31 | shuffle=shuffle, 32 | capacity=n_sample, seed=seed, 33 | num_epochs=num_epochs) 34 | 35 | image_value = tf.read_file(data_path) 36 | data = tf.image.decode_jpeg(image_value, channels=3) 37 | 38 | if return_label: 39 | label = tf.one_hot(label, n_class, on_value=1., off_value=0.) 40 | 41 | if transformer_fn is not None: 42 | data = transformer_fn(data) 43 | else: 44 | data = tf.image.resize_images(data, [height, width]) 45 | 46 | if shuffle: 47 | capacity = min_after_dequeue + (num_threads + 1) * batch_size 48 | data_batch, label_batch, name_batch = tf.train.shuffle_batch([data, label, name], 49 | batch_size=batch_size, 50 | capacity=capacity, 51 | min_after_dequeue=min_after_dequeue, 52 | num_threads=num_threads, 53 | allow_smaller_final_batch=allow_smaller_final_batch, 54 | seed=seed) 55 | else: 56 | capacity = (num_threads + 1) * batch_size 57 | data_batch, label_batch, name_batch = tf.train.batch([data, label, name], 58 | batch_size=batch_size, 59 | capacity=capacity, 60 | allow_smaller_final_batch=allow_smaller_final_batch) 61 | 62 | return [data_batch, label_batch, name_batch], n_sample 63 | 64 | 65 | class MTCSVLoader(object): 66 | def __init__(self, root, csv_path, batch_size, height=331, width=331, transformer_fn=None, num_epochs=None, 67 | shuffle=True, min_after_dequeue=25, allow_smaller_final_batch=False, num_threads=2, seed=None): 68 | root = root.replace('\\', '/') 69 | root = root if root[-1] == '/' else '{}/'.format(root) 70 | self.root = root 71 | self.csv_path = csv_path.replace('\\', '/') 72 | self.batch_size = batch_size 73 | self.height = height 74 | self.width = width 75 | self.transformer_fn = transformer_fn 76 | self.num_epochs = num_epochs 77 | self.shuffle = shuffle 78 | self.min_after_dequeue = min_after_dequeue 79 | self.allow_smaller_final_batch = allow_smaller_final_batch 80 | self.num_threads = num_threads 81 | self.seed = seed 82 | 83 | df = pd.read_csv(self.csv_path, header=None) 84 | 85 | if shuffle: 86 | df = df.sample(frac=1., random_state=seed) 87 | 88 | try: 89 | df[2] = df.apply(lambda line: line[2].index('y') + len(line[2]) if line[3] else line[2].index('y'), axis=1) 90 | except Exception as e: 91 | print(e) 92 | 93 | print('{}: create session!'.format(self.__class__.__name__)) 94 | self.batch_ops = {} 95 | self.n_sample = {} 96 | self.graph = tf.Graph() 97 | with self.graph.as_default(): 98 | with tf.device('/cpu:0'): 99 | for attr_key, n_class in di.num_classes_v2.items(): 100 | data_path = df[df[1].isin([attr_key])][0].values 101 | label = df[df[1].isin([attr_key])][2].values 102 | 103 | batch_ops, n_sample = csv_batch(root=self.root, data_path=data_path, label=label, 104 | n_class=n_class, batch_size=batch_size, 105 | height=height, width=width, 106 | transformer_fn=transformer_fn, num_epochs=num_epochs, 107 | shuffle=shuffle, min_after_dequeue=min_after_dequeue, 108 | allow_smaller_final_batch=allow_smaller_final_batch, 109 | num_threads=num_threads, seed=seed) 110 | self.batch_ops[attr_key] = batch_ops 111 | self.n_sample[attr_key] = n_sample 112 | if num_epochs is not None: 113 | self.init = tf.local_variables_initializer() 114 | self.sess = session(graph=self.graph) 115 | if num_epochs is not None: 116 | self.sess.run(self.init) 117 | self.coord = tf.train.Coordinator() 118 | self.threads = tf.train.start_queue_runners(sess=self.sess, coord=self.coord) 119 | 120 | def batch(self, attr_key): 121 | return self.sess.run(self.batch_ops[attr_key]) 122 | 123 | def __del__(self): 124 | print('{}: stop threads and close session!'.format(self.__class__.__name__)) 125 | self.coord.request_stop() 126 | self.coord.join(self.threads) 127 | self.sess.close() 128 | 129 | 130 | class STCSVLoader(object): 131 | def __init__(self, root, csv_path, attr_key, batch_size, height=331, width=331, transformer_fn=None, 132 | num_epochs=None, shuffle=True, min_after_dequeue=25, 133 | allow_smaller_final_batch=False, num_threads=2, seed=None): 134 | root = root.replace('\\', '/') 135 | root = root if root[-1] == '/' else '{}/'.format(root) 136 | self.root = root 137 | self.csv_path = csv_path.replace('\\', '/') 138 | self.attr_key = attr_key 139 | self.batch_size = batch_size 140 | self.height = height 141 | self.width = width 142 | self.transformer_fn = transformer_fn 143 | self.num_epochs = num_epochs 144 | self.shuffle = shuffle 145 | self.min_after_dequeue = min_after_dequeue 146 | self.allow_smaller_final_batch = allow_smaller_final_batch 147 | self.num_threads = num_threads 148 | self.seed = seed 149 | 150 | df = pd.read_csv(self.csv_path, header=None) 151 | df = df[df[1].isin([attr_key])] 152 | 153 | if shuffle: 154 | df = df.sample(frac=1., random_state=seed) 155 | 156 | try: 157 | df[2] = df.apply(lambda line: line[2].index('y') + len(line[2]) if line[3] else line[2].index('y'), axis=1) 158 | except Exception as e: 159 | print(e) 160 | 161 | data_path = df[0].values 162 | label = df[2].values 163 | 164 | print('{}: create session!'.format(self.__class__.__name__)) 165 | self.graph = tf.Graph() 166 | with self.graph.as_default(): 167 | with tf.device('/cpu:0'): 168 | 169 | self.batch_ops, self.n_sample = csv_batch(root=self.root, data_path=data_path, label=label, 170 | n_class=di.num_classes_v2[attr_key], 171 | batch_size=batch_size, 172 | height=height, width=width, 173 | transformer_fn=transformer_fn, num_epochs=num_epochs, 174 | shuffle=shuffle, min_after_dequeue=min_after_dequeue, 175 | allow_smaller_final_batch=allow_smaller_final_batch, 176 | num_threads=num_threads, seed=seed) 177 | if num_epochs is not None: 178 | self.init = tf.local_variables_initializer() 179 | self.sess = session(graph=self.graph) 180 | if num_epochs is not None: 181 | self.sess.run(self.init) 182 | self.coord = tf.train.Coordinator() 183 | self.threads = tf.train.start_queue_runners(sess=self.sess, coord=self.coord) 184 | 185 | def __len__(self): 186 | return self.n_sample 187 | 188 | def batch(self): 189 | return self.sess.run(self.batch_ops) 190 | 191 | def __del__(self): 192 | print('{}: stop threads and close session!'.format(self.__class__.__name__)) 193 | self.coord.request_stop() 194 | self.coord.join(self.threads) 195 | self.sess.close() 196 | 197 | 198 | if __name__ == '__main__': 199 | from lib.datasets import transforms 200 | from experiment.hyperparams import HyperParams as hp 201 | 202 | transformer = transforms.Sequential( 203 | [ 204 | transforms.Resize([331, 331]), 205 | transforms.SubtractMean([137.38, 131.21, 134.39]), 206 | transforms.RandomHorizontalFlip(), 207 | transforms.RandomVerticalFlip() 208 | ] 209 | ) 210 | # mt_loader = MTCSVLoader(root='E:/fashion-dataset/base', 211 | # csv_path='{}/dataset/labels/s1_label.csv'.format(hp.pro_path), 212 | # batch_size=16, 213 | # transformer_fn=transformer, 214 | # shuffle=True) 215 | st_loader = STCSVLoader(root='E:/fashion-dataset/base', attr_key='collar_design_labels', 216 | csv_path='{}/dataset/labels/s1_label.csv'.format(hp.pro_path), 217 | batch_size=16, 218 | transformer_fn=transformer, 219 | shuffle=True) 220 | # print(mt_loader.n_sample) 221 | print(st_loader.n_sample) 222 | 223 | for i in range(10): 224 | # batch1 = mt_loader.batch(attr_key='collar_design_labels') 225 | # batch2 = mt_loader.batch(attr_key='coat_length_labels') 226 | # print(batch1[0].shape, batch1[1].shape, list(map(lambda x: bytes.decode(x), batch1[2]))) 227 | # print(batch2[0].shape) 228 | batch = st_loader.batch() 229 | print(batch[0].shape, batch[1].shape) 230 | -------------------------------------------------------------------------------- /lib/datasets/transforms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import cv2 10 | import numbers 11 | import collections 12 | import numpy as np 13 | import tensorflow as tf 14 | from utils import apply_with_random_selector 15 | 16 | 17 | class Sequential(object): 18 | """Composes several transforms together.""" 19 | 20 | def __init__(self, transforms): 21 | self.transforms = transforms 22 | 23 | def __call__(self, img): 24 | for t in self.transforms: 25 | img = t(img) 26 | 27 | return img 28 | 29 | def __repr__(self): 30 | format_string = self.__class__.__name__ + '(' 31 | for t in self.transforms: 32 | format_string += '\n' 33 | format_string += ' {0}'.format(t) 34 | format_string += '\n)' 35 | return format_string 36 | 37 | 38 | class ToTensor(object): 39 | """Convert a ``image`` or ``numpy.ndarray`` to tensor.""" 40 | 41 | def __init__(self, dtype=tf.float32): 42 | self.dtype = dtype 43 | 44 | def __call__(self, img): 45 | return tf.convert_to_tensor(img, dtype=self.dtype) 46 | 47 | def __repr__(self): 48 | return self.__class__.__name__ + '()' 49 | 50 | 51 | class Normalize(object): 52 | """Normalize the given image with mean and standard deviation.""" 53 | 54 | def __init__(self, mean, std): 55 | assert (isinstance(mean, collections.Iterable)) 56 | assert (isinstance(std, collections.Iterable)) 57 | assert len(mean) == len(std) 58 | self.mean = mean 59 | self.std = std 60 | self.size = len(mean) 61 | 62 | def __call__(self, img): 63 | mean = tf.constant(self.mean, dtype=tf.float32, shape=[1, 1, self.size], name='img_mean') 64 | std = tf.constant(self.std, dtype=tf.float32, shape=[1, 1, self.size], name='img_std') 65 | return tf.divide(tf.subtract(img, mean), std) 66 | 67 | def __repr__(self): 68 | return self.__class__.__name__ + '(mean={0}, std={1})'.format(self.mean, self.std) 69 | 70 | 71 | class RandomHorizontalFlip(object): 72 | """Horizontally flip the given image randomly with a probability of 0.5.""" 73 | 74 | def __call__(self, img): 75 | re = tf.image.random_flip_left_right(img) 76 | return re 77 | 78 | def __repr__(self): 79 | return self.__class__.__name__ + '()' 80 | 81 | 82 | class HorizontalFlip(object): 83 | """Horizontally flip the given image.""" 84 | 85 | def __call__(self, img): 86 | re = tf.image.flip_left_right(img) 87 | return re 88 | 89 | def __repr__(self): 90 | return self.__class__.__name__ + '()' 91 | 92 | 93 | class RandomVerticalFlip(object): 94 | """Vertically flip the given image randomly with a probability of 0.5.""" 95 | 96 | def __call__(self, img): 97 | return tf.image.random_flip_up_down(img) 98 | 99 | def __repr__(self): 100 | return self.__class__.__name__ + '()' 101 | 102 | 103 | class VerticalFlip(object): 104 | """Vertically flip the given image.""" 105 | 106 | def __call__(self, img): 107 | return tf.image.flip_up_down(img) 108 | 109 | def __repr__(self): 110 | return self.__class__.__name__ + '()' 111 | 112 | 113 | class Reshape(object): 114 | """Resize the input image to the given shape.""" 115 | 116 | def __init__(self, shape): 117 | assert (isinstance(shape, collections.Iterable)) 118 | self.shape = shape 119 | 120 | def __call__(self, img): 121 | return tf.reshape(img, tf.stack(self.shape)) 122 | 123 | def __repr__(self): 124 | return self.__class__.__name__ + '(shape={0})'.format(self.shape) 125 | 126 | 127 | class Resize(object): 128 | """Resize the input image to the given size.""" 129 | 130 | def __init__(self, size, interpolation=0): 131 | assert (isinstance(size, collections.Iterable) and len(size) == 2) 132 | self.size = size 133 | self.interpolation = interpolation 134 | 135 | def __call__(self, img): 136 | return tf.image.resize_images(img, self.size, method=self.interpolation) 137 | 138 | def __repr__(self): 139 | return self.__class__.__name__ + '(size={0})'.format(self.size) 140 | 141 | 142 | class ColorJitter(object): 143 | """Randomly change the brightness, contrast and saturation of an image.""" 144 | 145 | def __init__(self, brightness=0, contrast=0, saturation=0, hue=0): 146 | self.brightness = brightness 147 | self.contrast = contrast 148 | self.saturation = saturation 149 | self.hue = hue 150 | 151 | @staticmethod 152 | def distort_color(image, color_ordering=0): 153 | if color_ordering == 0: 154 | image = tf.image.random_brightness(image, max_delta=32.) 155 | image = tf.image.random_saturation(image, lower=0.5, upper=1.5) 156 | image = tf.image.random_hue(image, max_delta=0.2) 157 | image = tf.image.random_contrast(image, lower=0.5, upper=1.5) 158 | elif color_ordering == 1: 159 | image = tf.image.random_saturation(image, lower=0.5, upper=1.5) 160 | image = tf.image.random_brightness(image, max_delta=32.) 161 | image = tf.image.random_contrast(image, lower=0.5, upper=1.5) 162 | image = tf.image.random_hue(image, max_delta=0.2) 163 | elif color_ordering == 2: 164 | image = tf.image.random_contrast(image, lower=0.5, upper=1.5) 165 | image = tf.image.random_hue(image, max_delta=0.2) 166 | image = tf.image.random_brightness(image, max_delta=32.) 167 | image = tf.image.random_saturation(image, lower=0.5, upper=1.5) 168 | elif color_ordering == 3: 169 | image = tf.image.random_hue(image, max_delta=0.2) 170 | image = tf.image.random_saturation(image, lower=0.5, upper=1.5) 171 | image = tf.image.random_contrast(image, lower=0.5, upper=1.5) 172 | image = tf.image.random_brightness(image, max_delta=32.) 173 | else: 174 | raise ValueError('color_ordering must be in [0, 3]') 175 | image = tf.clip_by_value(image, 0., 255.) 176 | return image 177 | 178 | def __call__(self, img): 179 | img = apply_with_random_selector( 180 | img, 181 | lambda x, ordering: self.distort_color(x, ordering), 182 | num_cases=4 183 | ) 184 | return img 185 | 186 | def __repr__(self): 187 | return self.__class__.__name__ + '()' 188 | 189 | 190 | class RandomRotation(object): 191 | """Random rotate the given image by angle.""" 192 | 193 | def __init__(self, degrees): 194 | if isinstance(degrees, numbers.Number): 195 | if degrees < 0: 196 | raise ValueError("If degrees is a single number, it must be positive.") 197 | self.degrees = (-degrees, degrees) 198 | else: 199 | if len(degrees) != 2: 200 | raise ValueError("If degrees is a sequence, it must be of len 2.") 201 | self.degrees = degrees 202 | 203 | @staticmethod 204 | def random_rotate(image, low, high): 205 | def py2tf_func(im, lo, hi): 206 | h, w, _ = im.shape 207 | # 旋转角度范围 208 | angle = np.random.uniform(low=lo, high=hi + 1) 209 | # print(angle) 210 | M = cv2.getRotationMatrix2D((w / 2, h / 2), angle=angle, scale=1) 211 | dst = cv2.warpAffine(im, M, dsize=(w, h), borderValue=(255., 255., 255.)) 212 | return dst 213 | 214 | ny, nx, _ = image.shape 215 | image = tf.py_func(py2tf_func, [image, low, high], tf.float32) 216 | image.set_shape([ny, nx, 3]) 217 | return image 218 | 219 | def __call__(self, img): 220 | return self.random_rotate(img, self.degrees[0], self.degrees[1]) 221 | 222 | def __repr__(self): 223 | return self.__class__.__name__ + '(degrees={0})'.format(self.degrees) 224 | 225 | 226 | class SubtractMean(object): 227 | """Zero-Center the given image.""" 228 | 229 | def __init__(self, mean): 230 | assert (isinstance(mean, collections.Iterable)) 231 | self.mean = mean 232 | self.size = len(mean) 233 | 234 | def __call__(self, img): 235 | re = tf.subtract(img, tf.constant(self.mean, dtype=tf.float32, shape=[1, 1, self.size], name='img_mean')) 236 | return re 237 | 238 | def __repr__(self): 239 | return self.__class__.__name__ + '(mean={0})'.format(self.mean) 240 | 241 | 242 | class Preprocess(object): 243 | """Preprocess.""" 244 | 245 | def __call__(self, img): 246 | re = tf.subtract(tf.divide(img, 127.5), 1) 247 | return re 248 | 249 | def __repr__(self): 250 | return self.__class__.__name__ + '()' 251 | -------------------------------------------------------------------------------- /lib/networks/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /lib/networks/my_inceptionv4.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import os 10 | import tensorflow as tf 11 | import tensorflow.contrib.slim as slim 12 | from lib.networks.slim.nets import inception_v4 13 | from experiment.hyperparams import HyperParams as hp 14 | 15 | 16 | class MyInceptionV4(object): 17 | def __init__(self, data, label, keep_prob, is_training): 18 | # placeholder 19 | self.data = data 20 | self.label = label 21 | self.keep_prob = keep_prob 22 | self.is_training = is_training 23 | 24 | self.layers = dict(data=data, label=label) 25 | self.setup() 26 | 27 | def setup(self): 28 | with tf.variable_scope(self.__class__.__name__): 29 | with slim.arg_scope(inception_v4.inception_v4_arg_scope()): 30 | net, end_points = inception_v4.inception_v4( 31 | self.data, 32 | num_classes=None, 33 | create_aux_logits=False, 34 | is_training=self.is_training) 35 | self.layers['PreGAP'] = end_points['PreGAP'] 36 | 37 | with tf.variable_scope('{}/logits'.format(self.__class__.__name__)): 38 | net = tf.squeeze(net, axis=[1, 2]) 39 | net = tf.nn.dropout(net, keep_prob=self.keep_prob) 40 | cls_score_coat = slim.fully_connected(net, 8*2, activation_fn=None, scope='coat_length_labels') 41 | cls_prob_coat = slim.softmax(cls_score_coat, scope='coat_length_labels') 42 | 43 | self.layers['cls_score_coat_length_labels'] = cls_score_coat 44 | self.layers['cls_prob_coat_length_labels'] = cls_prob_coat 45 | 46 | cls_score_collar = slim.fully_connected(net, 5, activation_fn=None, scope='collar_design_labels') 47 | cls_prob_collar = slim.softmax(cls_score_collar, scope='collar_design_labels') 48 | 49 | self.layers['cls_score_collar_design_labels'] = cls_score_collar 50 | self.layers['cls_prob_collar_design_labels'] = cls_prob_collar 51 | 52 | cls_score_lapel = slim.fully_connected(net, 5, activation_fn=None, scope='lapel_design_labels') 53 | cls_prob_lapel = slim.softmax(cls_score_lapel, scope='lapel_design_labels') 54 | 55 | self.layers['cls_score_lapel_design_labels'] = cls_score_lapel 56 | self.layers['cls_prob_lapel_design_labels'] = cls_prob_lapel 57 | 58 | cls_score_neck = slim.fully_connected(net, 5, activation_fn=None, scope='neck_design_labels') 59 | cls_prob_neck = slim.softmax(cls_score_neck, scope='neck_design_labels') 60 | 61 | self.layers['cls_score_neck_design_labels'] = cls_score_neck 62 | self.layers['cls_prob_neck_design_labels'] = cls_prob_neck 63 | 64 | cls_score_neckline = slim.fully_connected(net, 10, activation_fn=None, scope='neckline_design_labels') 65 | cls_prob_neckline = slim.softmax(cls_score_neckline, scope='neckline_design_labels') 66 | 67 | self.layers['cls_score_neckline_design_labels'] = cls_score_neckline 68 | self.layers['cls_prob_neckline_design_labels'] = cls_prob_neckline 69 | 70 | cls_score_pant = slim.fully_connected(net, 6 * 2, activation_fn=None, scope='pant_length_labels') 71 | cls_prob_pant = slim.softmax(cls_score_pant, scope='pant_length_labels') 72 | 73 | self.layers['cls_score_pant_length_labels'] = cls_score_pant 74 | self.layers['cls_prob_pant_length_labels'] = cls_prob_pant 75 | 76 | cls_score_skirt = slim.fully_connected(net, 6 * 2, activation_fn=None, scope='skirt_length_labels') 77 | cls_prob_skirt = slim.softmax(cls_score_skirt, scope='skirt_length_labels') 78 | 79 | self.layers['cls_score_skirt_length_labels'] = cls_score_skirt 80 | self.layers['cls_prob_skirt_length_labels'] = cls_prob_skirt 81 | 82 | cls_score_sleeve = slim.fully_connected(net, 9 * 2, activation_fn=None, scope='sleeve_length_labels') 83 | cls_prob_sleeve = slim.softmax(cls_score_sleeve, scope='sleeve_length_labels') 84 | 85 | self.layers['cls_score_sleeve_length_labels'] = cls_score_sleeve 86 | self.layers['cls_prob_sleeve_length_labels'] = cls_prob_sleeve 87 | 88 | def save(self, sess, saver, step, dir=None): 89 | if dir is None: 90 | output_dir = hp.output_dir.format(hp.pro_path, self.__class__.__name__) 91 | else: 92 | output_dir = hp.output_dir.format(hp.pro_path, dir) 93 | if not os.path.exists(output_dir): 94 | os.makedirs(output_dir) 95 | 96 | infix = ('_' + hp.snapshot_infix if hp.snapshot_infix != '' else '') 97 | filename = (hp.snapshot_prefix + infix + '_iter_{:d}'.format(step + 1) + '.ckpt') 98 | filename = os.path.join(output_dir, filename) 99 | 100 | saver.save(sess, filename) 101 | print('Wrote snapshot to: {:s}'.format(filename)) 102 | 103 | def load(self, sess, file, ignore=True): 104 | reader = tf.train.NewCheckpointReader(file) 105 | variables = reader.get_variable_to_shape_map() 106 | assign_ops = [] 107 | for name in variables: 108 | try: 109 | tensor = sess.graph.get_tensor_by_name('{}/{}:0'.format('MyInceptionV4', name)) 110 | weight = reader.get_tensor(name) 111 | assign_ops.append(tf.assign(tensor, weight)) 112 | print('{} assign success.'.format(name)) 113 | except KeyError as e: 114 | if ignore: 115 | print(e, name) 116 | else: 117 | print(e) 118 | raise e 119 | except Exception as e: 120 | print(e, name) 121 | raise e 122 | sess.run(assign_ops) 123 | print('Assign Done') 124 | 125 | 126 | if __name__ == '__main__': 127 | x = tf.placeholder(tf.float32, [None, 331, 331, 3]) 128 | y = tf.placeholder(tf.float32, [None, None]) 129 | dropout = tf.placeholder(tf.float32) 130 | phase = tf.placeholder(tf.bool) 131 | network = MyInceptionV4(x, y, dropout, phase) 132 | -------------------------------------------------------------------------------- /lib/networks/slim/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | -------------------------------------------------------------------------------- /lib/networks/slim/nets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm -------------------------------------------------------------------------------- /lib/networks/slim/nets/inception_resnet_v2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | # ============================================================================== 23 | """Contains the definition of the Inception Resnet V2 architecture. 24 | As described in http://arxiv.org/abs/1602.07261. 25 | Inception-v4, Inception-ResNet and the Impact of Residual Connections 26 | on Learning 27 | Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi 28 | """ 29 | from __future__ import absolute_import 30 | from __future__ import division 31 | from __future__ import print_function 32 | 33 | import tensorflow as tf 34 | 35 | slim = tf.contrib.slim 36 | 37 | 38 | def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None): 39 | """Builds the 35x35 resnet block.""" 40 | with tf.variable_scope(scope, 'Block35', [net], reuse=reuse): 41 | with tf.variable_scope('Branch_0'): 42 | tower_conv = slim.conv2d(net, 32, 1, scope='Conv2d_1x1') 43 | with tf.variable_scope('Branch_1'): 44 | tower_conv1_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1') 45 | tower_conv1_1 = slim.conv2d(tower_conv1_0, 32, 3, scope='Conv2d_0b_3x3') 46 | with tf.variable_scope('Branch_2'): 47 | tower_conv2_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1') 48 | tower_conv2_1 = slim.conv2d(tower_conv2_0, 48, 3, scope='Conv2d_0b_3x3') 49 | tower_conv2_2 = slim.conv2d(tower_conv2_1, 64, 3, scope='Conv2d_0c_3x3') 50 | mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_1, tower_conv2_2]) 51 | up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None, 52 | activation_fn=None, scope='Conv2d_1x1') 53 | scaled_up = up * scale 54 | if activation_fn == tf.nn.relu6: 55 | # Use clip_by_value to simulate bandpass activation. 56 | scaled_up = tf.clip_by_value(scaled_up, -6.0, 6.0) 57 | 58 | net += scaled_up 59 | if activation_fn: 60 | net = activation_fn(net) 61 | return net 62 | 63 | 64 | def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None): 65 | """Builds the 17x17 resnet block.""" 66 | with tf.variable_scope(scope, 'Block17', [net], reuse=reuse): 67 | with tf.variable_scope('Branch_0'): 68 | tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1') 69 | with tf.variable_scope('Branch_1'): 70 | tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1') 71 | tower_conv1_1 = slim.conv2d(tower_conv1_0, 160, [1, 7], 72 | scope='Conv2d_0b_1x7') 73 | tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [7, 1], 74 | scope='Conv2d_0c_7x1') 75 | mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2]) 76 | up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None, 77 | activation_fn=None, scope='Conv2d_1x1') 78 | 79 | scaled_up = up * scale 80 | if activation_fn == tf.nn.relu6: 81 | # Use clip_by_value to simulate bandpass activation. 82 | scaled_up = tf.clip_by_value(scaled_up, -6.0, 6.0) 83 | 84 | net += scaled_up 85 | if activation_fn: 86 | net = activation_fn(net) 87 | return net 88 | 89 | 90 | def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None): 91 | """Builds the 8x8 resnet block.""" 92 | with tf.variable_scope(scope, 'Block8', [net], reuse=reuse): 93 | with tf.variable_scope('Branch_0'): 94 | tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1') 95 | with tf.variable_scope('Branch_1'): 96 | tower_conv1_0 = slim.conv2d(net, 192, 1, scope='Conv2d_0a_1x1') 97 | tower_conv1_1 = slim.conv2d(tower_conv1_0, 224, [1, 3], 98 | scope='Conv2d_0b_1x3') 99 | tower_conv1_2 = slim.conv2d(tower_conv1_1, 256, [3, 1], 100 | scope='Conv2d_0c_3x1') 101 | mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2]) 102 | up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None, 103 | activation_fn=None, scope='Conv2d_1x1') 104 | 105 | scaled_up = up * scale 106 | if activation_fn == tf.nn.relu6: 107 | # Use clip_by_value to simulate bandpass activation. 108 | scaled_up = tf.clip_by_value(scaled_up, -6.0, 6.0) 109 | 110 | net += scaled_up 111 | if activation_fn: 112 | net = activation_fn(net) 113 | return net 114 | 115 | 116 | def inception_resnet_v2_base(inputs, 117 | final_endpoint='Conv2d_7b_1x1', 118 | output_stride=16, 119 | align_feature_maps=False, 120 | scope=None, 121 | activation_fn=tf.nn.relu): 122 | """Inception model from http://arxiv.org/abs/1602.07261. 123 | Constructs an Inception Resnet v2 network from inputs to the given final 124 | endpoint. This method can construct the network up to the final inception 125 | block Conv2d_7b_1x1. 126 | Args: 127 | inputs: a tensor of size [batch_size, height, width, channels]. 128 | final_endpoint: specifies the endpoint to construct the network up to. It 129 | can be one of ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3', 130 | 'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3', 'MaxPool_5a_3x3', 131 | 'Mixed_5b', 'Mixed_6a', 'PreAuxLogits', 'Mixed_7a', 'Conv2d_7b_1x1'] 132 | output_stride: A scalar that specifies the requested ratio of input to 133 | output spatial resolution. Only supports 8 and 16. 134 | align_feature_maps: When true, changes all the VALID paddings in the network 135 | to SAME padding so that the feature maps are aligned. 136 | scope: Optional variable_scope. 137 | activation_fn: Activation function for block scopes. 138 | Returns: 139 | tensor_out: output tensor corresponding to the final_endpoint. 140 | end_points: a set of activations for external use, for example summaries or 141 | losses. 142 | Raises: 143 | ValueError: if final_endpoint is not set to one of the predefined values, 144 | or if the output_stride is not 8 or 16, or if the output_stride is 8 and 145 | we request an end point after 'PreAuxLogits'. 146 | """ 147 | if output_stride != 8 and output_stride != 16: 148 | raise ValueError('output_stride must be 8 or 16.') 149 | 150 | padding = 'SAME' if align_feature_maps else 'VALID' 151 | 152 | end_points = {} 153 | 154 | def add_and_check_final(name, net): 155 | end_points[name] = net 156 | return name == final_endpoint 157 | 158 | with tf.variable_scope(scope, 'InceptionResnetV2', [inputs]): 159 | with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], 160 | stride=1, padding='SAME'): 161 | # 149 x 149 x 32 162 | net = slim.conv2d(inputs, 32, 3, stride=2, padding=padding, 163 | scope='Conv2d_1a_3x3') 164 | if add_and_check_final('Conv2d_1a_3x3', net): return net, end_points 165 | 166 | # 147 x 147 x 32 167 | net = slim.conv2d(net, 32, 3, padding=padding, 168 | scope='Conv2d_2a_3x3') 169 | if add_and_check_final('Conv2d_2a_3x3', net): return net, end_points 170 | # 147 x 147 x 64 171 | net = slim.conv2d(net, 64, 3, scope='Conv2d_2b_3x3') 172 | if add_and_check_final('Conv2d_2b_3x3', net): return net, end_points 173 | # 73 x 73 x 64 174 | net = slim.max_pool2d(net, 3, stride=2, padding=padding, 175 | scope='MaxPool_3a_3x3') 176 | if add_and_check_final('MaxPool_3a_3x3', net): return net, end_points 177 | # 73 x 73 x 80 178 | net = slim.conv2d(net, 80, 1, padding=padding, 179 | scope='Conv2d_3b_1x1') 180 | if add_and_check_final('Conv2d_3b_1x1', net): return net, end_points 181 | # 71 x 71 x 192 182 | net = slim.conv2d(net, 192, 3, padding=padding, 183 | scope='Conv2d_4a_3x3') 184 | if add_and_check_final('Conv2d_4a_3x3', net): return net, end_points 185 | # 35 x 35 x 192 186 | net = slim.max_pool2d(net, 3, stride=2, padding=padding, 187 | scope='MaxPool_5a_3x3') 188 | if add_and_check_final('MaxPool_5a_3x3', net): return net, end_points 189 | 190 | # 35 x 35 x 320 191 | with tf.variable_scope('Mixed_5b'): 192 | with tf.variable_scope('Branch_0'): 193 | tower_conv = slim.conv2d(net, 96, 1, scope='Conv2d_1x1') 194 | with tf.variable_scope('Branch_1'): 195 | tower_conv1_0 = slim.conv2d(net, 48, 1, scope='Conv2d_0a_1x1') 196 | tower_conv1_1 = slim.conv2d(tower_conv1_0, 64, 5, 197 | scope='Conv2d_0b_5x5') 198 | with tf.variable_scope('Branch_2'): 199 | tower_conv2_0 = slim.conv2d(net, 64, 1, scope='Conv2d_0a_1x1') 200 | tower_conv2_1 = slim.conv2d(tower_conv2_0, 96, 3, 201 | scope='Conv2d_0b_3x3') 202 | tower_conv2_2 = slim.conv2d(tower_conv2_1, 96, 3, 203 | scope='Conv2d_0c_3x3') 204 | with tf.variable_scope('Branch_3'): 205 | tower_pool = slim.avg_pool2d(net, 3, stride=1, padding='SAME', 206 | scope='AvgPool_0a_3x3') 207 | tower_pool_1 = slim.conv2d(tower_pool, 64, 1, 208 | scope='Conv2d_0b_1x1') 209 | net = tf.concat( 210 | [tower_conv, tower_conv1_1, tower_conv2_2, tower_pool_1], 3) 211 | 212 | if add_and_check_final('Mixed_5b', net): return net, end_points 213 | # TODO(alemi): Register intermediate endpoints 214 | net = slim.repeat(net, 10, block35, scale=0.17, 215 | activation_fn=activation_fn) 216 | 217 | # 17 x 17 x 1088 if output_stride == 8, 218 | # 33 x 33 x 1088 if output_stride == 16 219 | use_atrous = output_stride == 8 220 | 221 | with tf.variable_scope('Mixed_6a'): 222 | with tf.variable_scope('Branch_0'): 223 | tower_conv = slim.conv2d(net, 384, 3, stride=1 if use_atrous else 2, 224 | padding=padding, 225 | scope='Conv2d_1a_3x3') 226 | with tf.variable_scope('Branch_1'): 227 | tower_conv1_0 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1') 228 | tower_conv1_1 = slim.conv2d(tower_conv1_0, 256, 3, 229 | scope='Conv2d_0b_3x3') 230 | tower_conv1_2 = slim.conv2d(tower_conv1_1, 384, 3, 231 | stride=1 if use_atrous else 2, 232 | padding=padding, 233 | scope='Conv2d_1a_3x3') 234 | with tf.variable_scope('Branch_2'): 235 | tower_pool = slim.max_pool2d(net, 3, stride=1 if use_atrous else 2, 236 | padding=padding, 237 | scope='MaxPool_1a_3x3') 238 | net = tf.concat([tower_conv, tower_conv1_2, tower_pool], 3) 239 | 240 | if add_and_check_final('Mixed_6a', net): return net, end_points 241 | 242 | # TODO(alemi): register intermediate endpoints 243 | with slim.arg_scope([slim.conv2d], rate=2 if use_atrous else 1): 244 | net = slim.repeat(net, 20, block17, scale=0.10, 245 | activation_fn=activation_fn) 246 | if add_and_check_final('PreAuxLogits', net): return net, end_points 247 | 248 | if output_stride == 8: 249 | # TODO(gpapan): Properly support output_stride for the rest of the net. 250 | raise ValueError('output_stride==8 is only supported up to the ' 251 | 'PreAuxlogits end_point for now.') 252 | 253 | # 8 x 8 x 2080 254 | with tf.variable_scope('Mixed_7a'): 255 | with tf.variable_scope('Branch_0'): 256 | tower_conv = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1') 257 | tower_conv_1 = slim.conv2d(tower_conv, 384, 3, stride=2, 258 | padding=padding, 259 | scope='Conv2d_1a_3x3') 260 | with tf.variable_scope('Branch_1'): 261 | tower_conv1 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1') 262 | tower_conv1_1 = slim.conv2d(tower_conv1, 288, 3, stride=2, 263 | padding=padding, 264 | scope='Conv2d_1a_3x3') 265 | with tf.variable_scope('Branch_2'): 266 | tower_conv2 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1') 267 | tower_conv2_1 = slim.conv2d(tower_conv2, 288, 3, 268 | scope='Conv2d_0b_3x3') 269 | tower_conv2_2 = slim.conv2d(tower_conv2_1, 320, 3, stride=2, 270 | padding=padding, 271 | scope='Conv2d_1a_3x3') 272 | with tf.variable_scope('Branch_3'): 273 | tower_pool = slim.max_pool2d(net, 3, stride=2, 274 | padding=padding, 275 | scope='MaxPool_1a_3x3') 276 | net = tf.concat( 277 | [tower_conv_1, tower_conv1_1, tower_conv2_2, tower_pool], 3) 278 | 279 | if add_and_check_final('Mixed_7a', net): 280 | return net, end_points 281 | 282 | # TODO(alemi): register intermediate endpoints 283 | net = slim.repeat(net, 9, block8, scale=0.20, activation_fn=activation_fn) 284 | net = block8(net, activation_fn=None) 285 | 286 | # 8 x 8 x 1536 287 | net = slim.conv2d(net, 1536, 1, scope='Conv2d_7b_1x1') 288 | if add_and_check_final('Conv2d_7b_1x1', net): 289 | return net, end_points 290 | 291 | raise ValueError('final_endpoint (%s) not recognized', final_endpoint) 292 | 293 | 294 | def inception_resnet_v2(inputs, trainable=True, 295 | num_classes=1001, is_training=True, 296 | dropout_keep_prob=0.8, 297 | reuse=None, 298 | scope='InceptionResnetV2', 299 | create_aux_logits=True, 300 | activation_fn=tf.nn.relu): 301 | """Creates the Inception Resnet V2 model. 302 | Args: 303 | inputs: a 4-D tensor of size [batch_size, height, width, 3]. 304 | Dimension batch_size may be undefined. If create_aux_logits is false, 305 | also height and width may be undefined. 306 | num_classes: number of predicted classes. If 0 or None, the logits layer 307 | is omitted and the input features to the logits layer (before dropout) 308 | are returned instead. 309 | is_training: whether is training or not. 310 | dropout_keep_prob: float, the fraction to keep before final layer. 311 | reuse: whether or not the network and its variables should be reused. To be 312 | able to reuse 'scope' must be given. 313 | scope: Optional variable_scope. 314 | create_aux_logits: Whether to include the auxilliary logits. 315 | activation_fn: Activation function for conv2d. 316 | Returns: 317 | net: the output of the logits layer (if num_classes is a non-zero integer), 318 | or the non-dropped-out input to the logits layer (if num_classes is 0 or 319 | None). 320 | end_points: the set of end_points from the inception model. 321 | """ 322 | print(trainable) 323 | with tf.variable_scope(scope, 'InceptionResnetV2', [inputs], 324 | reuse=reuse) as scope: 325 | with slim.arg_scope([slim.conv2d], trainable=trainable): 326 | with slim.arg_scope([slim.batch_norm], trainable=trainable, is_training=is_training): 327 | # with slim.arg_scope([slim.batch_norm, slim.dropout], 328 | # is_training=is_training): 329 | 330 | net, end_points = inception_resnet_v2_base(inputs, scope=scope, 331 | activation_fn=activation_fn) 332 | 333 | if create_aux_logits and num_classes: 334 | with tf.variable_scope('AuxLogits'): 335 | aux = end_points['PreAuxLogits'] 336 | aux = slim.avg_pool2d(aux, 5, stride=3, padding='VALID', 337 | scope='Conv2d_1a_3x3') 338 | aux = slim.conv2d(aux, 128, 1, scope='Conv2d_1b_1x1') 339 | aux = slim.conv2d(aux, 768, aux.get_shape()[1:3], 340 | padding='VALID', scope='Conv2d_2a_5x5') 341 | aux = slim.flatten(aux) 342 | aux = slim.fully_connected(aux, num_classes, activation_fn=None, 343 | scope='Logits') 344 | end_points['AuxLogits'] = aux 345 | 346 | with tf.variable_scope('Logits'): 347 | # TODO(sguada,arnoegw): Consider adding a parameter global_pool which 348 | # can be set to False to disable pooling here (as in resnet_*()). 349 | # kernel_size = net.get_shape()[1:3] 350 | # print(net.get_shape()) 351 | # if kernel_size.is_fully_defined(): 352 | # print(3333333) 353 | # net = slim.avg_pool2d(net, kernel_size, padding='VALID', 354 | # scope='AvgPool_1a_8x8') 355 | # else: 356 | # print( 357 | # 111 358 | # ) 359 | end_points['PreGAP'] = net 360 | net = tf.reduce_mean(net, [1, 2], keep_dims=True, name='global_pool') 361 | end_points['global_pool'] = net 362 | if not num_classes: 363 | return net, end_points 364 | net = slim.flatten(net) 365 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 366 | scope='Dropout') 367 | end_points['PreLogitsFlatten'] = net 368 | logits = slim.fully_connected(net, num_classes, activation_fn=None, 369 | scope='Logits') 370 | end_points['Logits'] = logits 371 | end_points['Predictions'] = tf.nn.softmax(logits, name='Predictions') 372 | 373 | return logits, end_points 374 | 375 | 376 | inception_resnet_v2.default_image_size = 299 377 | 378 | 379 | def inception_resnet_v2_arg_scope(weight_decay=0.00004, 380 | batch_norm_decay=0.9997, 381 | batch_norm_epsilon=0.001, 382 | activation_fn=tf.nn.relu): 383 | """Returns the scope with the default parameters for inception_resnet_v2. 384 | Args: 385 | weight_decay: the weight decay for weights variables. 386 | batch_norm_decay: decay for the moving average of batch_norm momentums. 387 | batch_norm_epsilon: small float added to variance to avoid dividing by zero. 388 | activation_fn: Activation function for conv2d. 389 | Returns: 390 | a arg_scope with the parameters needed for inception_resnet_v2. 391 | """ 392 | # Set weight_decay for weights in conv2d and fully_connected layers. 393 | with slim.arg_scope([slim.conv2d, slim.fully_connected], 394 | weights_regularizer=slim.l2_regularizer(weight_decay), 395 | biases_regularizer=slim.l2_regularizer(weight_decay)): 396 | batch_norm_params = { 397 | 'decay': batch_norm_decay, 398 | 'epsilon': batch_norm_epsilon, 399 | 'fused': None, # Use fused batch norm if possible. 400 | } 401 | # Set activation_fn and parameters for batch_norm. 402 | with slim.arg_scope([slim.conv2d], activation_fn=activation_fn, 403 | normalizer_fn=slim.batch_norm, 404 | normalizer_params=batch_norm_params) as scope: 405 | return scope 406 | -------------------------------------------------------------------------------- /lib/networks/slim/nets/inception_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | # ============================================================================== 23 | """Contains common code shared by all inception models. 24 | Usage of arg scope: 25 | with slim.arg_scope(inception_arg_scope()): 26 | logits, end_points = inception.inception_v3(images, num_classes, 27 | is_training=is_training) 28 | """ 29 | from __future__ import absolute_import 30 | from __future__ import division 31 | from __future__ import print_function 32 | 33 | import tensorflow as tf 34 | 35 | slim = tf.contrib.slim 36 | 37 | 38 | def inception_arg_scope(weight_decay=0.00004, 39 | use_batch_norm=True, 40 | batch_norm_decay=0.9997, 41 | batch_norm_epsilon=0.001, 42 | activation_fn=tf.nn.relu): 43 | """Defines the default arg scope for inception models. 44 | Args: 45 | weight_decay: The weight decay to use for regularizing the model. 46 | use_batch_norm: "If `True`, batch_norm is applied after each convolution. 47 | batch_norm_decay: Decay for batch norm moving average. 48 | batch_norm_epsilon: Small float added to variance to avoid dividing by zero 49 | in batch norm. 50 | activation_fn: Activation function for conv2d. 51 | Returns: 52 | An `arg_scope` to use for the inception models. 53 | """ 54 | batch_norm_params = { 55 | # Decay for the moving averages. 56 | 'decay': batch_norm_decay, 57 | # epsilon to prevent 0s in variance. 58 | 'epsilon': batch_norm_epsilon, 59 | # collection containing update_ops. 60 | 'updates_collections': tf.GraphKeys.UPDATE_OPS, 61 | # use fused batch norm if possible. 62 | 'fused': None, 63 | } 64 | if use_batch_norm: 65 | normalizer_fn = slim.batch_norm 66 | normalizer_params = batch_norm_params 67 | else: 68 | normalizer_fn = None 69 | normalizer_params = {} 70 | # Set weight_decay for weights in Conv and FC layers. 71 | with slim.arg_scope([slim.conv2d, slim.fully_connected], 72 | weights_regularizer=slim.l2_regularizer(weight_decay)): 73 | with slim.arg_scope( 74 | [slim.conv2d], 75 | weights_initializer=slim.variance_scaling_initializer(), 76 | activation_fn=activation_fn, 77 | normalizer_fn=normalizer_fn, 78 | normalizer_params=normalizer_params) as sc: 79 | return sc 80 | -------------------------------------------------------------------------------- /lib/networks/slim/nets/inception_v4.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | # ============================================================================== 23 | """Contains the definition of the Inception V4 architecture. 24 | As described in http://arxiv.org/abs/1602.07261. 25 | Inception-v4, Inception-ResNet and the Impact of Residual Connections 26 | on Learning 27 | Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi 28 | """ 29 | from __future__ import absolute_import 30 | from __future__ import division 31 | from __future__ import print_function 32 | 33 | import tensorflow as tf 34 | from lib.networks.slim.nets import inception_utils 35 | 36 | slim = tf.contrib.slim 37 | 38 | 39 | def block_inception_a(inputs, scope=None, reuse=None): 40 | """Builds Inception-A block for Inception v4 network.""" 41 | # By default use stride=1 and SAME padding 42 | with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d], 43 | stride=1, padding='SAME'): 44 | with tf.variable_scope(scope, 'BlockInceptionA', [inputs], reuse=reuse): 45 | with tf.variable_scope('Branch_0'): 46 | branch_0 = slim.conv2d(inputs, 96, [1, 1], scope='Conv2d_0a_1x1') 47 | with tf.variable_scope('Branch_1'): 48 | branch_1 = slim.conv2d(inputs, 64, [1, 1], scope='Conv2d_0a_1x1') 49 | branch_1 = slim.conv2d(branch_1, 96, [3, 3], scope='Conv2d_0b_3x3') 50 | with tf.variable_scope('Branch_2'): 51 | branch_2 = slim.conv2d(inputs, 64, [1, 1], scope='Conv2d_0a_1x1') 52 | branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3') 53 | branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3') 54 | with tf.variable_scope('Branch_3'): 55 | branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3') 56 | branch_3 = slim.conv2d(branch_3, 96, [1, 1], scope='Conv2d_0b_1x1') 57 | return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3]) 58 | 59 | 60 | def block_reduction_a(inputs, scope=None, reuse=None): 61 | """Builds Reduction-A block for Inception v4 network.""" 62 | # By default use stride=1 and SAME padding 63 | with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d], 64 | stride=1, padding='SAME'): 65 | with tf.variable_scope(scope, 'BlockReductionA', [inputs], reuse=reuse): 66 | with tf.variable_scope('Branch_0'): 67 | branch_0 = slim.conv2d(inputs, 384, [3, 3], stride=2, padding='VALID', 68 | scope='Conv2d_1a_3x3') 69 | with tf.variable_scope('Branch_1'): 70 | branch_1 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1') 71 | branch_1 = slim.conv2d(branch_1, 224, [3, 3], scope='Conv2d_0b_3x3') 72 | branch_1 = slim.conv2d(branch_1, 256, [3, 3], stride=2, 73 | padding='VALID', scope='Conv2d_1a_3x3') 74 | with tf.variable_scope('Branch_2'): 75 | branch_2 = slim.max_pool2d(inputs, [3, 3], stride=2, padding='VALID', 76 | scope='MaxPool_1a_3x3') 77 | return tf.concat(axis=3, values=[branch_0, branch_1, branch_2]) 78 | 79 | 80 | def block_inception_b(inputs, scope=None, reuse=None): 81 | """Builds Inception-B block for Inception v4 network.""" 82 | # By default use stride=1 and SAME padding 83 | with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d], 84 | stride=1, padding='SAME'): 85 | with tf.variable_scope(scope, 'BlockInceptionB', [inputs], reuse=reuse): 86 | with tf.variable_scope('Branch_0'): 87 | branch_0 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1') 88 | with tf.variable_scope('Branch_1'): 89 | branch_1 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1') 90 | branch_1 = slim.conv2d(branch_1, 224, [1, 7], scope='Conv2d_0b_1x7') 91 | branch_1 = slim.conv2d(branch_1, 256, [7, 1], scope='Conv2d_0c_7x1') 92 | with tf.variable_scope('Branch_2'): 93 | branch_2 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1') 94 | branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d_0b_7x1') 95 | branch_2 = slim.conv2d(branch_2, 224, [1, 7], scope='Conv2d_0c_1x7') 96 | branch_2 = slim.conv2d(branch_2, 224, [7, 1], scope='Conv2d_0d_7x1') 97 | branch_2 = slim.conv2d(branch_2, 256, [1, 7], scope='Conv2d_0e_1x7') 98 | with tf.variable_scope('Branch_3'): 99 | branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3') 100 | branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1') 101 | return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3]) 102 | 103 | 104 | def block_reduction_b(inputs, scope=None, reuse=None): 105 | """Builds Reduction-B block for Inception v4 network.""" 106 | # By default use stride=1 and SAME padding 107 | with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d], 108 | stride=1, padding='SAME'): 109 | with tf.variable_scope(scope, 'BlockReductionB', [inputs], reuse=reuse): 110 | with tf.variable_scope('Branch_0'): 111 | branch_0 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1') 112 | branch_0 = slim.conv2d(branch_0, 192, [3, 3], stride=2, 113 | padding='VALID', scope='Conv2d_1a_3x3') 114 | with tf.variable_scope('Branch_1'): 115 | branch_1 = slim.conv2d(inputs, 256, [1, 1], scope='Conv2d_0a_1x1') 116 | branch_1 = slim.conv2d(branch_1, 256, [1, 7], scope='Conv2d_0b_1x7') 117 | branch_1 = slim.conv2d(branch_1, 320, [7, 1], scope='Conv2d_0c_7x1') 118 | branch_1 = slim.conv2d(branch_1, 320, [3, 3], stride=2, 119 | padding='VALID', scope='Conv2d_1a_3x3') 120 | with tf.variable_scope('Branch_2'): 121 | branch_2 = slim.max_pool2d(inputs, [3, 3], stride=2, padding='VALID', 122 | scope='MaxPool_1a_3x3') 123 | return tf.concat(axis=3, values=[branch_0, branch_1, branch_2]) 124 | 125 | 126 | def block_inception_c(inputs, scope=None, reuse=None): 127 | """Builds Inception-C block for Inception v4 network.""" 128 | # By default use stride=1 and SAME padding 129 | with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d], 130 | stride=1, padding='SAME'): 131 | with tf.variable_scope(scope, 'BlockInceptionC', [inputs], reuse=reuse): 132 | with tf.variable_scope('Branch_0'): 133 | branch_0 = slim.conv2d(inputs, 256, [1, 1], scope='Conv2d_0a_1x1') 134 | with tf.variable_scope('Branch_1'): 135 | branch_1 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1') 136 | branch_1 = tf.concat(axis=3, values=[ 137 | slim.conv2d(branch_1, 256, [1, 3], scope='Conv2d_0b_1x3'), 138 | slim.conv2d(branch_1, 256, [3, 1], scope='Conv2d_0c_3x1')]) 139 | with tf.variable_scope('Branch_2'): 140 | branch_2 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1') 141 | branch_2 = slim.conv2d(branch_2, 448, [3, 1], scope='Conv2d_0b_3x1') 142 | branch_2 = slim.conv2d(branch_2, 512, [1, 3], scope='Conv2d_0c_1x3') 143 | branch_2 = tf.concat(axis=3, values=[ 144 | slim.conv2d(branch_2, 256, [1, 3], scope='Conv2d_0d_1x3'), 145 | slim.conv2d(branch_2, 256, [3, 1], scope='Conv2d_0e_3x1')]) 146 | with tf.variable_scope('Branch_3'): 147 | branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3') 148 | branch_3 = slim.conv2d(branch_3, 256, [1, 1], scope='Conv2d_0b_1x1') 149 | return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3]) 150 | 151 | 152 | def inception_v4_base(inputs, final_endpoint='Mixed_7d', scope=None): 153 | """Creates the Inception V4 network up to the given final endpoint. 154 | Args: 155 | inputs: a 4-D tensor of size [batch_size, height, width, 3]. 156 | final_endpoint: specifies the endpoint to construct the network up to. 157 | It can be one of [ 'Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3', 158 | 'Mixed_3a', 'Mixed_4a', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d', 159 | 'Mixed_5e', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d', 'Mixed_6e', 160 | 'Mixed_6f', 'Mixed_6g', 'Mixed_6h', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c', 161 | 'Mixed_7d'] 162 | scope: Optional variable_scope. 163 | Returns: 164 | logits: the logits outputs of the model. 165 | end_points: the set of end_points from the inception model. 166 | Raises: 167 | ValueError: if final_endpoint is not set to one of the predefined values, 168 | """ 169 | end_points = {} 170 | 171 | def add_and_check_final(name, net): 172 | end_points[name] = net 173 | return name == final_endpoint 174 | 175 | with tf.variable_scope(scope, 'InceptionV4', [inputs]): 176 | with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], 177 | stride=1, padding='SAME'): 178 | # 299 x 299 x 3 179 | net = slim.conv2d(inputs, 32, [3, 3], stride=2, 180 | padding='VALID', scope='Conv2d_1a_3x3') 181 | if add_and_check_final('Conv2d_1a_3x3', net): 182 | return net, end_points 183 | # 149 x 149 x 32 184 | net = slim.conv2d(net, 32, [3, 3], padding='VALID', 185 | scope='Conv2d_2a_3x3') 186 | if add_and_check_final('Conv2d_2a_3x3', net): 187 | return net, end_points 188 | # 147 x 147 x 32 189 | net = slim.conv2d(net, 64, [3, 3], scope='Conv2d_2b_3x3') 190 | if add_and_check_final('Conv2d_2b_3x3', net): 191 | return net, end_points 192 | # 147 x 147 x 64 193 | with tf.variable_scope('Mixed_3a'): 194 | with tf.variable_scope('Branch_0'): 195 | branch_0 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', 196 | scope='MaxPool_0a_3x3') 197 | with tf.variable_scope('Branch_1'): 198 | branch_1 = slim.conv2d(net, 96, [3, 3], stride=2, padding='VALID', 199 | scope='Conv2d_0a_3x3') 200 | net = tf.concat(axis=3, values=[branch_0, branch_1]) 201 | if add_and_check_final('Mixed_3a', net): 202 | return net, end_points 203 | 204 | # 73 x 73 x 160 205 | with tf.variable_scope('Mixed_4a'): 206 | with tf.variable_scope('Branch_0'): 207 | branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') 208 | branch_0 = slim.conv2d(branch_0, 96, [3, 3], padding='VALID', 209 | scope='Conv2d_1a_3x3') 210 | with tf.variable_scope('Branch_1'): 211 | branch_1 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') 212 | branch_1 = slim.conv2d(branch_1, 64, [1, 7], scope='Conv2d_0b_1x7') 213 | branch_1 = slim.conv2d(branch_1, 64, [7, 1], scope='Conv2d_0c_7x1') 214 | branch_1 = slim.conv2d(branch_1, 96, [3, 3], padding='VALID', 215 | scope='Conv2d_1a_3x3') 216 | net = tf.concat(axis=3, values=[branch_0, branch_1]) 217 | if add_and_check_final('Mixed_4a', net): 218 | return net, end_points 219 | 220 | # 71 x 71 x 192 221 | with tf.variable_scope('Mixed_5a'): 222 | with tf.variable_scope('Branch_0'): 223 | branch_0 = slim.conv2d(net, 192, [3, 3], stride=2, padding='VALID', 224 | scope='Conv2d_1a_3x3') 225 | with tf.variable_scope('Branch_1'): 226 | branch_1 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', 227 | scope='MaxPool_1a_3x3') 228 | net = tf.concat(axis=3, values=[branch_0, branch_1]) 229 | if add_and_check_final('Mixed_5a', net): 230 | return net, end_points 231 | 232 | # 35 x 35 x 384 233 | # 4 x Inception-A blocks 234 | for idx in range(4): 235 | block_scope = 'Mixed_5' + chr(ord('b') + idx) 236 | net = block_inception_a(net, block_scope) 237 | if add_and_check_final(block_scope, net): 238 | return net, end_points 239 | 240 | # 35 x 35 x 384 241 | # Reduction-A block 242 | net = block_reduction_a(net, 'Mixed_6a') 243 | if add_and_check_final('Mixed_6a', net): 244 | return net, end_points 245 | 246 | # 17 x 17 x 1024 247 | # 7 x Inception-B blocks 248 | for idx in range(7): 249 | block_scope = 'Mixed_6' + chr(ord('b') + idx) 250 | net = block_inception_b(net, block_scope) 251 | if add_and_check_final(block_scope, net): 252 | return net, end_points 253 | 254 | # 17 x 17 x 1024 255 | # Reduction-B block 256 | net = block_reduction_b(net, 'Mixed_7a') 257 | if add_and_check_final('Mixed_7a', net): 258 | return net, end_points 259 | 260 | # 8 x 8 x 1536 261 | # 3 x Inception-C blocks 262 | for idx in range(3): 263 | block_scope = 'Mixed_7' + chr(ord('b') + idx) 264 | net = block_inception_c(net, block_scope) 265 | if add_and_check_final(block_scope, net): 266 | return net, end_points 267 | raise ValueError('Unknown final endpoint %s' % final_endpoint) 268 | 269 | 270 | def inception_v4(inputs, num_classes=1001, is_training=True, 271 | dropout_keep_prob=0.8, 272 | reuse=None, 273 | scope='InceptionV4', 274 | create_aux_logits=True): 275 | """Creates the Inception V4 model. 276 | Args: 277 | inputs: a 4-D tensor of size [batch_size, height, width, 3]. 278 | num_classes: number of predicted classes. If 0 or None, the logits layer 279 | is omitted and the input features to the logits layer (before dropout) 280 | are returned instead. 281 | is_training: whether is training or not. 282 | dropout_keep_prob: float, the fraction to keep before final layer. 283 | reuse: whether or not the network and its variables should be reused. To be 284 | able to reuse 'scope' must be given. 285 | scope: Optional variable_scope. 286 | create_aux_logits: Whether to include the auxiliary logits. 287 | Returns: 288 | net: a Tensor with the logits (pre-softmax activations) if num_classes 289 | is a non-zero integer, or the non-dropped input to the logits layer 290 | if num_classes is 0 or None. 291 | end_points: the set of end_points from the inception model. 292 | """ 293 | with tf.variable_scope(scope, 'InceptionV4', [inputs], reuse=reuse) as scope: 294 | with slim.arg_scope([slim.batch_norm, slim.dropout], 295 | is_training=is_training): 296 | net, end_points = inception_v4_base(inputs, scope=scope) 297 | end_points['PreGAP'] = net 298 | 299 | with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], 300 | stride=1, padding='SAME'): 301 | # Auxiliary Head logits 302 | if create_aux_logits and num_classes: 303 | with tf.variable_scope('AuxLogits'): 304 | # 17 x 17 x 1024 305 | aux_logits = end_points['Mixed_6h'] 306 | aux_logits = slim.avg_pool2d(aux_logits, [5, 5], stride=3, 307 | padding='VALID', 308 | scope='AvgPool_1a_5x5') 309 | aux_logits = slim.conv2d(aux_logits, 128, [1, 1], 310 | scope='Conv2d_1b_1x1') 311 | aux_logits = slim.conv2d(aux_logits, 768, 312 | aux_logits.get_shape()[1:3], 313 | padding='VALID', scope='Conv2d_2a') 314 | aux_logits = slim.flatten(aux_logits) 315 | aux_logits = slim.fully_connected(aux_logits, num_classes, 316 | activation_fn=None, 317 | scope='Aux_logits') 318 | end_points['AuxLogits'] = aux_logits 319 | 320 | # Final pooling and prediction 321 | # TODO(sguada,arnoegw): Consider adding a parameter global_pool which 322 | # can be set to False to disable pooling here (as in resnet_*()). 323 | with tf.variable_scope('Logits'): 324 | # 8 x 8 x 1536 325 | # kernel_size = net.get_shape()[1:3] 326 | # if kernel_size.is_fully_defined(): 327 | # net = slim.avg_pool2d(net, kernel_size, padding='VALID', 328 | # scope='AvgPool_1a') 329 | # else: 330 | # print(net) 331 | net = tf.reduce_mean(net, [1, 2], keepdims=True, name='global_pool') 332 | end_points['global_pool'] = net 333 | if not num_classes: 334 | return net, end_points 335 | # 1 x 1 x 1536 336 | net = slim.dropout(net, dropout_keep_prob, scope='Dropout_1b') 337 | net = slim.flatten(net, scope='PreLogitsFlatten') 338 | end_points['PreLogitsFlatten'] = net 339 | # 1536 340 | logits = slim.fully_connected(net, num_classes, activation_fn=None, 341 | scope='Logits') 342 | end_points['Logits'] = logits 343 | end_points['Predictions'] = tf.nn.softmax(logits, name='Predictions') 344 | return logits, end_points 345 | 346 | 347 | inception_v4.default_image_size = 299 348 | 349 | inception_v4_arg_scope = inception_utils.inception_arg_scope 350 | -------------------------------------------------------------------------------- /model/MyInceptionV4/MultiTask/url.md: -------------------------------------------------------------------------------- 1 | 链接:https://pan.baidu.com/s/12NvQNDMYEj6UzG7LCuTeqA 密码:orer -------------------------------------------------------------------------------- /model/Pretrain/model.md: -------------------------------------------------------------------------------- 1 | https://github.com/tensorflow/models/tree/master/research/slim -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | from utils.utils import * 10 | -------------------------------------------------------------------------------- /utils/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # @Env : windows python3.5 tensorflow1.4.0 4 | # @Author : xushiqi 5 | # @Email : xushiqitc@163.com 6 | # @Software : PyCharm 7 | 8 | 9 | import os 10 | import cv2 11 | import numpy as np 12 | import pandas as pd 13 | import tensorflow as tf 14 | from tensorflow.python.ops import control_flow_ops 15 | from experiment.data_info import DataInfo as di 16 | from experiment.hyperparams import HyperParams as hp 17 | 18 | 19 | def session(graph=None, allow_soft_placement=hp.allow_soft_placement, log_device_placement=hp.log_device_placement, 20 | allow_growth=hp.allow_growth): 21 | """return a session with simple config.""" 22 | config = tf.ConfigProto(allow_soft_placement=allow_soft_placement, log_device_placement=log_device_placement) 23 | config.gpu_options.allow_growth = allow_growth 24 | return tf.Session(graph=graph, config=config) 25 | 26 | 27 | def preprocess_label(label, n_sample, n_class): 28 | Y = np.zeros(n_sample, dtype=np.float32) 29 | for i, value in enumerate(label): 30 | for j in range(n_class): 31 | if value[j] == 'y': 32 | Y[i] = j 33 | return Y 34 | 35 | 36 | def apply_with_random_selector(x, func, num_cases): 37 | """Computes func(x, sel), with sel sampled from [0...num_cases-1]. 38 | Args: 39 | x: input Tensor. 40 | func: Python function to apply. 41 | num_cases: Python int32, number of cases to sample sel from. 42 | Returns: 43 | The result of func(x, sel), where func receives the value of the 44 | selector as a python integer, but sel is sampled dynamically. 45 | """ 46 | sel = tf.random_uniform([], maxval=num_cases, dtype=tf.int32) 47 | # Pass the real x only to one of the func calls. 48 | return control_flow_ops.merge( 49 | [func(control_flow_ops.switch(x, tf.equal(sel, case))[1], case) for case in range(num_cases)] 50 | )[0] 51 | 52 | 53 | def csv_writer(save_path, queue, stop_token='stop'): 54 | """Write predict prob to csv file.""" 55 | df = pd.DataFrame() 56 | names = [] 57 | attr_keys = [] 58 | probs = [] 59 | while True: 60 | token, name_batch, attr_key, prob_batch = queue.get() 61 | if token == stop_token: 62 | df['name'] = names 63 | df['attr_key'] = attr_keys 64 | df['prob'] = probs 65 | df.to_csv(save_path, index=False, header=False) 66 | return 67 | n_class = di.num_classes[attr_key] 68 | for idx, name in enumerate(name_batch): 69 | names.append(name) 70 | attr_keys.append(attr_key) 71 | prob = prob_batch[idx] 72 | k = np.argmax(prob) 73 | if k > n_class - 1: 74 | probs.append(';'.join(list(map(lambda x: '{:.4f}'.format(x), prob[n_class:])))) 75 | else: 76 | probs.append(';'.join(list(map(lambda x: '{:.4f}'.format(x), prob[:n_class])))) 77 | 78 | 79 | def cam_writer(save_path, queue, stop_token='stop'): 80 | """Write cam to npy file.""" 81 | while True: 82 | token, name_batch, cam_batch = queue.get() 83 | if token == stop_token: 84 | return 85 | for idx, name in enumerate(name_batch): 86 | path = '{}/{}'.format(save_path, '/'.join(name.split('/')[0:-1])) 87 | if not os.path.exists(path): 88 | os.makedirs(path) 89 | np.save('{}/{}.npy'.format(path, name.split('/')[-1].split('.')[0]), cam_batch[idx]) 90 | 91 | 92 | def roi_writer(save_path, queue, stop_token='stop'): 93 | """Write ROI image to jpg file.""" 94 | while True: 95 | token, root, name_batch, cam_batch = queue.get() 96 | if token == stop_token: 97 | return 98 | for idx, name in enumerate(name_batch): 99 | print(idx, name) 100 | cam = cam_batch[idx] 101 | path = '{}/{}'.format(save_path, '/'.join(name.split('/')[0:-1])) 102 | if not os.path.exists(path): 103 | os.makedirs(path) 104 | img = cv2.imread('{}/{}'.format(root, name), cv2.IMREAD_UNCHANGED) 105 | cam = cv2.resize((cam * 255).astype(np.uint8), (img.shape[1], img.shape[0]), interpolation=cv2.INTER_LINEAR) 106 | heatmap = cv2.applyColorMap(cam, cv2.COLORMAP_JET) 107 | heatmap[cam <= hp.threshold] = 0 108 | 109 | gray = cv2.cvtColor(heatmap, cv2.COLOR_BGR2GRAY) 110 | ret, thresh = cv2.threshold(gray, hp.threshold, 255, cv2.THRESH_BINARY) 111 | pos = np.where(thresh == 255) 112 | x, y, w, h = cv2.boundingRect(np.vstack((pos[1], pos[0])).T) 113 | cv2.imwrite('{}/{}'.format(save_path, name), img[y: y + h, x: x + w]) 114 | 115 | 116 | def vis_cam(root, names, cams): 117 | for idx, cam in enumerate(cams): 118 | name = names[idx] 119 | print(idx, name) 120 | img = cv2.imread('{}/{}'.format(root, name), cv2.IMREAD_UNCHANGED) 121 | cam = cv2.resize((cam * 255).astype(np.uint8), (img.shape[1], img.shape[0]), interpolation=cv2.INTER_LINEAR) 122 | heatmap = cv2.applyColorMap(cam, cv2.COLORMAP_JET) 123 | heatmap[cam <= hp.threshold] = 0 124 | 125 | gray = cv2.cvtColor(heatmap, cv2.COLOR_BGR2GRAY) 126 | ret, thresh = cv2.threshold(gray, hp.threshold, 255, cv2.THRESH_BINARY) 127 | pos = np.where(thresh == 255) 128 | x, y, w, h = cv2.boundingRect(np.vstack((pos[1], pos[0])).T) 129 | cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) 130 | out = cv2.addWeighted(img, 0.8, heatmap, 0.4, 0) 131 | cv2.imshow('img', out) 132 | cv2.waitKey(0) 133 | cv2.destroyAllWindows() 134 | --------------------------------------------------------------------------------