├── example.jpg ├── example_1.jpg ├── solver.prototxt ├── create_lmdb.sh ├── processlist.py ├── .github └── FUNDING.yml ├── README.md ├── face_attri.py ├── show.py ├── convert_multilabel.cpp ├── deploy_mcnn_Attri.prototxt └── mcnn_Attri.prototxt /example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HansRen1024/Face-Attributes-MultiTask-Classification/HEAD/example.jpg -------------------------------------------------------------------------------- /example_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HansRen1024/Face-Attributes-MultiTask-Classification/HEAD/example_1.jpg -------------------------------------------------------------------------------- /solver.prototxt: -------------------------------------------------------------------------------- 1 | test_iter: 100 2 | test_interval: 1000 3 | base_lr: 0.02 4 | display: 10 5 | max_iter: 200000 6 | iter_size: 2 7 | lr_policy: "poly" 8 | power: 1.0 9 | momentum: 0.9 10 | #type: "RMSProp" 11 | weight_decay: 0.0005 12 | snapshot: 5000 13 | snapshot_prefix: "./models/mcnn" 14 | solver_mode: GPU 15 | random_seed: 42 16 | net: "/home/hans/data/face/CelebA/attri/doc/mcnn_Attri.prototxt" 17 | test_initialization: true 18 | average_loss: 40 -------------------------------------------------------------------------------- /create_lmdb.sh: -------------------------------------------------------------------------------- 1 | echo "Creating train lmdb..." 2 | ~/caffe-multi/build/tools/convert_multilabel \ 3 | -resize_height=227 \ 4 | -resize_width=227 \ 5 | -shuffle=false \ 6 | /home/hans/data/face/CelebA/Img/img_align_celeba/ \ 7 | train.txt \ 8 | ./train_db \ 9 | ./train_lb \ 10 | 3 11 | 12 | echo "Creating val lmdb..." 13 | ~/caffe-multi/build/tools/convert_multilabel \ 14 | -resize_height=227 \ 15 | -resize_width=227 \ 16 | -shuffle=false \ 17 | /home/hans/data/face/CelebA/Img/img_align_celeba/ \ 18 | val.txt \ 19 | ./val_db \ 20 | ./val_lb \ 21 | 3 22 | -------------------------------------------------------------------------------- /processlist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Aug 20 16:57:52 2018 5 | 6 | @author: hans 7 | """ 8 | 9 | ReadTxt = 'list_attr_celeba.txt' 10 | WriteTxt = 'train.txt' 11 | r = open(ReadTxt,'r') 12 | w = open(WriteTxt,'w') 13 | rLine = r.readline().split('\n')[0] 14 | while rLine: 15 | rLine = r.readline().split('\n')[0] 16 | if not rLine: 17 | break 18 | # image,bangs,eyeglasses,gender, 19 | wLine = rLine.split(' ')[0]+' '+rLine.split(' ')[6]+' '+rLine.split(' ')[16]+' '+rLine.split(' ')[21]+'\n' 20 | w.write(wLine) 21 | r.close() 22 | w.close() -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://raw.githubusercontent.com/HansRen1024/HansRen1024.github.io/master/Get_paid_QR.jpg 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Face-Attributes-MultiTask-Classification 2 | Use Cafffe to do Face Attributes MultiTask Classification based on CelebA data sets 3 | 4 | ---- 5 | 1. Put **convert_multilabel.cpp** into caffe_root/tools/ 6 | 2. Remake caffe by running **make clean && make all -j8 && make py** 7 | 3. Find **list_attr_celeba.txt** in CelebA_root/Anno/ 8 | 4. Run **sed -i 's/ / /g' list_attr_celeba.txt** to replace double sapce to single space. 9 | 5. Use **processlist.py** to pick up which attributes you want. 10 | 6. Then, run **sed -i 's/-1/0/g' train.txt** 11 | 7. Next, use **create_lmdb.sh** to create lmdb datasets. 12 | 8. Finally, change **mcnn_Attri.prototxt** suited for your situation. 13 | 9. **show.py** is used for training output visulisation. 14 | ---- 15 | 16 | ![image](https://github.com/HansRen1024/Face-Attributes-MultiTask-Classification/blob/master/example.jpg) 17 | ![image](https://github.com/HansRen1024/Face-Attributes-MultiTask-Classification/blob/master/example_1.jpg) 18 | 19 | ---- 20 | 21 | **中文博客地址** 22 | 23 | https://blog.csdn.net/renhanchi/article/details/81903684 24 | 25 | ---- 26 | 27 | **References** 28 | 29 | https://github.com/HolidayXue/CodeSnap 30 | 31 | https://zhuanlan.zhihu.com/p/22190532 32 | -------------------------------------------------------------------------------- /face_attri.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Aug 21 18:13:22 2018 5 | 6 | @author: hans 7 | """ 8 | 9 | import sys 10 | sys.path.append('.') 11 | sys.path.append('/home/hans/caffe/python') 12 | import cv2 13 | import caffe 14 | import numpy as np 15 | deploy = './models/deploy_mcnn_Attri.prototxt' 16 | caffemodel = './models/mcnn_iter_5000.caffemodel' 17 | net_mcnn = caffe.Net(deploy,caffemodel,caffe.TEST) 18 | caffe.set_device(0) 19 | caffe.set_mode_gpu() 20 | def faceAttri(img): 21 | transformer = caffe.io.Transformer({'data': net_mcnn.blobs['data'].data.shape}) 22 | transformer.set_transpose('data', (2, 0, 1)) 23 | transformer.set_mean('data', np.array([127.5,127.5,127.5])) 24 | transformer.set_raw_scale('data', 127.5) 25 | caffe_img = transformer.preprocess('data', img) 26 | net_mcnn.blobs['data'].reshape(1,3,227,227) 27 | net_mcnn.blobs['data'].data[...]=caffe_img 28 | out = net_mcnn.forward() 29 | accuracy_Eyeglasses = out['accuracy_Eyeglasses'].reshape(2,) 30 | accuracy_Bangs = out['accuracy_Bangs'].reshape(2,) 31 | accuracy_Male = out['accuracy_Male'].reshape(2,) 32 | return accuracy_Eyeglasses,accuracy_Bangs,accuracy_Male 33 | if __name__=='__main__': 34 | FaceImg=cv2.imread('imgpath') 35 | accuracy_Eyeglasses,accuracy_Bangs,accuracy_Male = faceAttri(FaceImg) 36 | order_Eyeglasses = accuracy_Eyeglasses.argsort()[-1] 37 | order_Bangs = accuracy_Bangs.argsort()[-1] 38 | order_Male = accuracy_Male.argsort()[-1] 39 | if order_Eyeglasses==0: 40 | glasses='no glasses' 41 | else: 42 | glasses='with glasses' 43 | if order_Bangs==0: 44 | bangs='no bangs' 45 | else: 46 | bangs='with bangs' 47 | if order_Male==0: 48 | gender='female' 49 | else: 50 | gender='male' 51 | print glasses+','+bangs+','+gender 52 | -------------------------------------------------------------------------------- /show.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Thu Nov 2 14:35:42 2017 5 | 6 | @author: hans 7 | 8 | http://blog.csdn.net/renhanchi 9 | """ 10 | 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | import commands 14 | import argparse 15 | 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument( 18 | '-p','--log_path', 19 | type = str, 20 | default = 'mcnn-face-attri.log', 21 | help = """\ 22 | path to log file\ 23 | """ 24 | ) 25 | 26 | FLAGS = parser.parse_args() 27 | train_log_file = FLAGS.log_path 28 | display = 10 #solver 29 | test_interval = 1000 #solver 30 | time = 5 31 | def reduce_data(data): 32 | iteration = len(data)/time*time 33 | _data = data[0:iteration] 34 | ind=0 35 | if time > 1: 36 | data_ = [] 37 | for i in np.arange(len(data)/time): 38 | sum_data = 0 39 | for j in np.arange(time): 40 | ind = i*time + j 41 | sum_data += float(_data[ind]) 42 | data_.append(sum_data/float(time)) 43 | else: 44 | data_ = data 45 | return data_ 46 | 47 | def process(label,index): 48 | train_output = commands.getoutput("cat " + train_log_file + " | grep 'Train net output #%d' | awk '{print $11}'" %index) #train mbox_loss 49 | accu_output = commands.getoutput("cat " + train_log_file + " | grep 'Test net output #%d' | awk '{print $11}'" %index) #test detection_eval 50 | train_loss = train_output.split("\n") 51 | test_accu = accu_output.split("\n") 52 | _train_loss = reduce_data(train_loss) 53 | _test_accu = reduce_data(test_accu) 54 | _,ax1 = plt.subplots() 55 | ax1.set_title(label) 56 | ax2 = ax1.twinx() 57 | ax1.plot(time*display*np.arange(len(_train_loss)), _train_loss) 58 | ax2.plot(time*test_interval*np.arange(len(_test_accu)), _test_accu, 'r') 59 | ax1.set_xlabel('Iteration') 60 | ax1.set_ylabel('%s Train Loss' %label) 61 | ax2.set_ylabel('%s Test Accuracy' %label) 62 | if __name__ == '__main__': 63 | process('Bangs',0) 64 | process('Egeglasses',1) 65 | process('Gender',2) 66 | plt.show() 67 | 68 | -------------------------------------------------------------------------------- /convert_multilabel.cpp: -------------------------------------------------------------------------------- 1 | // This program converts a set of images to a lmdb/leveldb by storing them 2 | // as Datum proto buffers. 3 | // Usage: 4 | // convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME 5 | // 6 | // where ROOTFOLDER is the root folder that holds all the images, and LISTFILE 7 | // should be a list of files as well as their labels, in the format as 8 | // subfolder1/file1.JPEG 7 9 | // .... 10 | 11 | 12 | 13 | //#ifdef MULTILABEL 14 | 15 | 16 | 17 | #include 18 | #include // NOLINT(readability/streams) 19 | #include 20 | #include 21 | #include 22 | 23 | #include "boost/scoped_ptr.hpp" 24 | #include "gflags/gflags.h" 25 | #include "glog/logging.h" 26 | 27 | #include "caffe/proto/caffe.pb.h" 28 | #include "caffe/util/db.hpp" 29 | #include "caffe/util/format.hpp" 30 | #include "caffe/util/io.hpp" 31 | #include "caffe/util/rng.hpp" 32 | 33 | using namespace caffe; // NOLINT(build/namespaces) 34 | using std::pair; 35 | using boost::scoped_ptr; 36 | 37 | DEFINE_bool(gray, false, 38 | "When this option is on, treat images as grayscale ones"); 39 | DEFINE_bool(shuffle, false, 40 | "Randomly shuffle the order of images and their labels"); 41 | DEFINE_string(backend, "lmdb", 42 | "The backend {lmdb, leveldb} for storing the result"); 43 | DEFINE_int32(resize_width, 0, "Width images are resized to"); 44 | DEFINE_int32(resize_height, 0, "Height images are resized to"); 45 | DEFINE_bool(check_size, false, 46 | "When this option is on, check that all the datum have the same size"); 47 | DEFINE_bool(encoded, false, 48 | "When this option is on, the encoded image will be save in datum"); 49 | DEFINE_string(encode_type, "", 50 | "Optional: What type should we encode the image as ('png','jpg',...)."); 51 | 52 | int main(int argc, char** argv) { 53 | #ifdef USE_OPENCV 54 | ::google::InitGoogleLogging(argv[0]); 55 | // Print output to stderr (while still logging) 56 | FLAGS_alsologtostderr = 1; 57 | 58 | #ifndef GFLAGS_GFLAGS_H_ 59 | namespace gflags = google; 60 | #endif 61 | 62 | gflags::SetUsageMessage("Convert a set of images to the leveldb/lmdb\n" 63 | "format used as input for Caffe.\n" 64 | "Usage:\n" 65 | " convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME\n" 66 | "The ImageNet dataset for the training demo is at\n" 67 | " http://www.image-net.org/download-images\n"); 68 | gflags::ParseCommandLineFlags(&argc, &argv, true); 69 | 70 | if (argc < 6) { 71 | gflags::ShowUsageWithFlagsRestrict(argv[0], "tools/convert_imageset"); 72 | return 1; 73 | } 74 | 75 | const bool is_color = !FLAGS_gray; 76 | const bool check_size = FLAGS_check_size; 77 | const bool encoded = FLAGS_encoded; 78 | const string encode_type = FLAGS_encode_type; 79 | 80 | std::ifstream infile(argv[2]); 81 | std::vector > > lines; 82 | std::string filename; 83 | 84 | std::string label_count_string = argv[5]; 85 | int label_count = std::atoi(label_count_string.c_str()); 86 | 87 | std::vector label(label_count); 88 | 89 | while (infile >> filename) 90 | { 91 | for (int i = 0; i < label_count;i++) 92 | { 93 | infile >> label[i]; 94 | 95 | } 96 | lines.push_back(std::make_pair(filename, label)); 97 | } 98 | if (FLAGS_shuffle) { 99 | // randomly shuffle data 100 | LOG(INFO) << "Shuffling data"; 101 | shuffle(lines.begin(), lines.end()); 102 | } 103 | LOG(INFO) << "A total of " << lines.size() << " images."; 104 | 105 | if (encode_type.size() && !encoded) 106 | LOG(INFO) << "encode_type specified, assuming encoded=true."; 107 | 108 | int resize_height = std::max(0, FLAGS_resize_height); 109 | int resize_width = std::max(0, FLAGS_resize_width); 110 | 111 | // Create new DB 112 | scoped_ptr db_image(db::GetDB(FLAGS_backend)); 113 | scoped_ptr db_label(db::GetDB(FLAGS_backend)); 114 | db_image->Open(argv[3], db::NEW); 115 | db_label->Open(argv[4], db::NEW); 116 | scoped_ptr txn_image(db_image->NewTransaction()); 117 | scoped_ptr txn_label(db_label->NewTransaction()); 118 | 119 | // Storing to db 120 | std::string root_folder(argv[1]); 121 | Datum datum_label; 122 | Datum datum_image; 123 | int count = 0; 124 | int data_size_label = 0; 125 | int data_size_image = 0; 126 | bool data_size_initialized = false; 127 | 128 | for (int line_id = 0; line_id < lines.size(); ++line_id) { 129 | bool status; 130 | std::string enc = encode_type; 131 | if (encoded && !enc.size()) { 132 | // Guess the encoding type from the file name 133 | string fn = lines[line_id].first; 134 | size_t p = fn.rfind('.'); 135 | if (p == fn.npos) 136 | LOG(WARNING) << "Failed to guess the encoding of '" << fn << "'"; 137 | enc = fn.substr(p); 138 | std::transform(enc.begin(), enc.end(), enc.begin(), ::tolower); 139 | } 140 | 141 | status = ReadImageToDatum(root_folder + lines[line_id].first, 142 | lines[line_id].second[0], resize_height, resize_width, is_color, 143 | enc, &datum_image); 144 | if (status == false) continue; 145 | 146 | datum_label.set_height(1); 147 | datum_label.set_width(1); 148 | // datum_label.set_channels(label_count); 149 | int count_tmp = datum_label.float_data_size(); 150 | for (int index_label = 0; index_label < lines[line_id].second.size(); index_label++) 151 | { 152 | float tmp_float_value = lines[line_id].second[index_label]; 153 | datum_label.add_float_data(tmp_float_value); 154 | } 155 | 156 | if (check_size) { 157 | if (!data_size_initialized) { 158 | data_size_label = datum_label.channels() * datum_label.height() * datum_label.width(); 159 | data_size_image = datum_image.channels() * datum_image.height() * datum_image.width(); 160 | data_size_initialized = true; 161 | } 162 | else { 163 | const std::string& data_label = datum_label.data(); 164 | CHECK_EQ(data_label.size(), data_size_label) << "Incorrect data field size " 165 | << data_label.size(); 166 | 167 | const std::string& data_image = datum_image.data(); 168 | CHECK_EQ(data_image.size(), data_size_image) << "Incorrect data field size " 169 | << data_image.size(); 170 | } 171 | } 172 | // sequential 173 | string key_str_image = caffe::format_int(line_id, 8) + "_" + lines[line_id].first; 174 | string key_str_label = caffe::format_int(line_id, 8) + "label_" + lines[line_id].first; 175 | 176 | // Put in db 177 | string out_label; 178 | string out_image; 179 | CHECK(datum_label.SerializeToString(&out_label)); 180 | CHECK(datum_image.SerializeToString(&out_image)); 181 | 182 | datum_label.clear_float_data(); 183 | txn_label->Put(key_str_label, out_label); 184 | txn_image->Put(key_str_image, out_image); 185 | if (++count % 1000 == 0) { 186 | // Commit db 187 | txn_image->Commit(); 188 | txn_image.reset(db_image->NewTransaction()); 189 | 190 | txn_label->Commit(); 191 | txn_label.reset(db_label->NewTransaction()); 192 | LOG(INFO) << "Processed " << count << " files."; 193 | } 194 | 195 | } 196 | // write the last batch 197 | if (count % 1000 != 0) { 198 | txn_label->Commit(); 199 | txn_image->Commit(); 200 | LOG(INFO) << "Processed " << count << " files."; 201 | } 202 | #else 203 | LOG(FATAL) << "This tool requires OpenCV; compile with USE_OPENCV."; 204 | #endif // USE_OPENCV 205 | return 0; 206 | } 207 | 208 | 209 | //#endif 210 | -------------------------------------------------------------------------------- /deploy_mcnn_Attri.prototxt: -------------------------------------------------------------------------------- 1 | name: "MCNN_Attri" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 227 6 | input_dim: 227 7 | layer { 8 | name: "conv1" 9 | type: "Convolution" 10 | bottom: "data" 11 | top: "conv1" 12 | param { 13 | lr_mult: 1 14 | decay_mult: 0 15 | } 16 | param { 17 | lr_mult: 2 18 | decay_mult: 0 19 | } 20 | convolution_param { 21 | num_output: 75 22 | kernel_size: 7 23 | stride: 2 24 | weight_filler { 25 | type: "msra" 26 | } 27 | bias_filler { 28 | type: "constant" 29 | } 30 | } 31 | } 32 | layer { 33 | name: "relu1" 34 | type: "ReLU" 35 | bottom: "conv1" 36 | top: "conv1" 37 | } 38 | layer { 39 | name: "pool1" 40 | type: "Pooling" 41 | bottom: "conv1" 42 | top: "pool1" 43 | pooling_param { 44 | pool: MAX 45 | kernel_size: 3 46 | stride: 2 47 | } 48 | } 49 | 50 | layer 51 | { 52 | name:"bn1" 53 | type:"BatchNorm" 54 | bottom:"pool1" 55 | top:"bn1" 56 | batch_norm_param:{ 57 | use_global_stats:false 58 | } 59 | } 60 | 61 | layer { 62 | name: "conv2" 63 | type: "Convolution" 64 | bottom: "bn1" 65 | top: "conv2" 66 | param { 67 | lr_mult: 1 68 | decay_mult: 0 69 | } 70 | param { 71 | lr_mult: 2 72 | decay_mult: 0 73 | } 74 | convolution_param { 75 | num_output: 200 76 | kernel_size: 5 77 | stride: 1 78 | weight_filler { 79 | type: "msra" 80 | } 81 | bias_filler { 82 | type: "constant" 83 | } 84 | } 85 | } 86 | layer { 87 | name: "relu2" 88 | type: "ReLU" 89 | bottom: "conv2" 90 | top: "conv2" 91 | } 92 | layer { 93 | name: "pool2" 94 | type: "Pooling" 95 | bottom: "conv2" 96 | top: "pool2" 97 | pooling_param { 98 | pool: MAX 99 | kernel_size: 3 100 | stride: 2 101 | } 102 | } 103 | layer 104 | { 105 | name:"bn2" 106 | type:"BatchNorm" 107 | bottom:"pool2" 108 | top:"bn2" 109 | batch_norm_param:{ 110 | use_global_stats:false 111 | } 112 | } 113 | 114 | #for group1 115 | layer { 116 | name: "conv3_g1_gender" 117 | type: "Convolution" 118 | bottom: "bn2" 119 | top: "conv3_g1_gender" 120 | param { 121 | lr_mult: 1 122 | decay_mult: 0 123 | } 124 | param { 125 | lr_mult: 2 126 | decay_mult: 0 127 | } 128 | convolution_param { 129 | num_output: 300 130 | kernel_size: 3 131 | stride: 1 132 | weight_filler { 133 | type: "msra" 134 | } 135 | bias_filler { 136 | type: "constant" 137 | } 138 | } 139 | } 140 | layer { 141 | name: "relu3_g1_gender" 142 | type: "ReLU" 143 | bottom: "conv3_g1_gender" 144 | top: "conv3_g1_gender" 145 | } 146 | layer { 147 | name: "pool3_g1_gender" 148 | type: "Pooling" 149 | bottom: "conv3_g1_gender" 150 | top: "pool3_g1_gender" 151 | pooling_param { 152 | pool: MAX 153 | kernel_size: 5 154 | stride: 3 155 | } 156 | } 157 | layer 158 | { 159 | name:"bn3_g1_gender" 160 | type:"BatchNorm" 161 | bottom:"pool3_g1_gender" 162 | top:"bn3_g1_gender" 163 | batch_norm_param:{ 164 | use_global_stats:false 165 | } 166 | } 167 | layer { 168 | name: "FC1_g1_gender" 169 | type: "InnerProduct" 170 | bottom: "bn3_g1_gender" 171 | top: "FC1_g1_gender" 172 | param { 173 | lr_mult: 1 174 | 175 | } 176 | param { 177 | lr_mult: 2 178 | } 179 | inner_product_param { 180 | num_output: 512 181 | weight_filler { 182 | type: "msra" 183 | } 184 | bias_filler { 185 | type: "constant" 186 | } 187 | } 188 | } 189 | layer { 190 | name: "relu4_g1_gender" 191 | type: "ReLU" 192 | bottom: "FC1_g1_gender" 193 | top: "relu4_g1_gender" 194 | } 195 | layer 196 | { 197 | name:"drop1_g1" 198 | type:"Dropout" 199 | bottom:"relu4_g1_gender" 200 | top:"relu4_g1_gender" 201 | dropout_param 202 | { 203 | dropout_ratio:0.5 204 | } 205 | } 206 | layer { 207 | name: "FC2_g1_gender" 208 | type: "InnerProduct" 209 | bottom: "relu4_g1_gender" 210 | top: "FC2_g1_gender" 211 | param { 212 | lr_mult: 1 213 | 214 | } 215 | param { 216 | lr_mult: 2 217 | } 218 | inner_product_param { 219 | num_output: 512 220 | weight_filler { 221 | type: "msra" 222 | } 223 | bias_filler { 224 | type: "constant" 225 | } 226 | } 227 | } 228 | layer { 229 | name: "relu5_g1_gender" 230 | type: "ReLU" 231 | bottom: "FC2_g1_gender" 232 | top: "relu5_g1_gender" 233 | } 234 | layer 235 | { 236 | name:"drop2_g1" 237 | type:"Dropout" 238 | bottom:"relu5_g1_gender" 239 | top:"relu5_g1_gender" 240 | dropout_param 241 | { 242 | dropout_ratio:0.5 243 | } 244 | } 245 | layer { 246 | name: "FC3_g1_gender" 247 | type: "InnerProduct" 248 | bottom: "relu5_g1_gender" 249 | top: "FC3_g1_gender" 250 | param { 251 | lr_mult: 1 252 | 253 | } 254 | param { 255 | lr_mult: 2 256 | } 257 | inner_product_param { 258 | num_output: 2 259 | weight_filler { 260 | type: "msra" 261 | } 262 | bias_filler { 263 | type: "constant" 264 | } 265 | } 266 | } 267 | 268 | layer { 269 | name: "accuracy_Male" 270 | type: "Softmax" 271 | bottom: "FC3_g1_gender" 272 | top: "accuracy_Male" 273 | include { 274 | phase: TEST 275 | } 276 | } 277 | 278 | #for group6 279 | layer { 280 | name: "conv3_g6_Other" 281 | type: "Convolution" 282 | bottom: "bn2" 283 | top: "conv3_g6_Other" 284 | param { 285 | lr_mult: 1 286 | decay_mult: 0 287 | } 288 | param { 289 | lr_mult: 2 290 | decay_mult: 0 291 | } 292 | convolution_param { 293 | num_output: 300 294 | kernel_size: 3 295 | stride: 1 296 | weight_filler { 297 | type: "msra" 298 | } 299 | bias_filler { 300 | type: "constant" 301 | } 302 | } 303 | } 304 | layer { 305 | name: "relu3_g6_Other" 306 | type: "ReLU" 307 | bottom: "conv3_g6_Other" 308 | top: "conv3_g6_Other" 309 | } 310 | layer { 311 | name: "pool3_g6_Other" 312 | type: "Pooling" 313 | bottom: "conv3_g6_Other" 314 | top: "pool3_g6_Other" 315 | pooling_param { 316 | pool: MAX 317 | kernel_size: 5 318 | stride: 3 319 | } 320 | } 321 | layer 322 | { 323 | name:"bn3_g6_Other" 324 | type:"BatchNorm" 325 | bottom:"pool3_g6_Other" 326 | top:"bn3_g6_Other" 327 | batch_norm_param:{ 328 | use_global_stats:false 329 | } 330 | } 331 | layer { 332 | name: "FC1_g6_Other" 333 | type: "InnerProduct" 334 | bottom: "bn3_g6_Other" 335 | top: "FC1_g6_Other" 336 | param { 337 | lr_mult: 1 338 | } 339 | param { 340 | lr_mult: 2 341 | } 342 | inner_product_param { 343 | num_output: 512 344 | weight_filler { 345 | type: "msra" 346 | } 347 | bias_filler { 348 | type: "constant" 349 | } 350 | } 351 | } 352 | layer { 353 | name: "relu4_g6_Other" 354 | type: "ReLU" 355 | bottom: "FC1_g6_Other" 356 | top: "relu4_g6_Other" 357 | } 358 | layer 359 | { 360 | name:"drop1_g6" 361 | type:"Dropout" 362 | bottom:"relu4_g6_Other" 363 | top:"relu4_g6_Other" 364 | dropout_param 365 | { 366 | dropout_ratio:0.5 367 | } 368 | } 369 | layer { 370 | name: "FC2_g6_Other" 371 | type: "InnerProduct" 372 | bottom: "relu4_g6_Other" 373 | top: "FC2_g6_Other" 374 | param { 375 | lr_mult: 1 376 | } 377 | param { 378 | lr_mult: 2 379 | } 380 | inner_product_param { 381 | num_output: 512 382 | weight_filler { 383 | type: "msra" 384 | } 385 | bias_filler { 386 | type: "constant" 387 | } 388 | } 389 | } 390 | layer { 391 | name: "relu5_g6_Other" 392 | type: "ReLU" 393 | bottom: "FC2_g6_Other" 394 | top: "relu5_g6_Other" 395 | } 396 | layer 397 | { 398 | name:"drop2_g5" 399 | type:"Dropout" 400 | bottom:"relu5_g6_Other" 401 | top:"relu5_g6_Other" 402 | dropout_param 403 | { 404 | dropout_ratio:0.5 405 | } 406 | } 407 | #group6 Bangs 408 | layer { 409 | name: "FC3_g6_Bangs" 410 | type: "InnerProduct" 411 | bottom: "relu5_g6_Other" 412 | top: "FC3_g6_Bangs" 413 | param { 414 | lr_mult: 1 415 | } 416 | param { 417 | lr_mult: 2 418 | } 419 | inner_product_param { 420 | num_output: 2 421 | weight_filler { 422 | type: "msra" 423 | } 424 | bias_filler { 425 | type: "constant" 426 | } 427 | } 428 | } 429 | 430 | layer { 431 | name: "accuracy_Bangs" 432 | type: "Softmax" 433 | bottom: "FC3_g6_Bangs" 434 | top: "accuracy_Bangs" 435 | include { 436 | phase: TEST 437 | } 438 | } 439 | 440 | #group4 Eyeglasses 441 | layer { 442 | name: "FC3_g4_Eyeglasses" 443 | type: "InnerProduct" 444 | bottom: "relu5_g6_Other" 445 | top: "FC3_g4_Eyeglasses" 446 | param { 447 | lr_mult: 1 448 | } 449 | param { 450 | lr_mult: 2 451 | } 452 | inner_product_param { 453 | num_output: 2 454 | weight_filler { 455 | type: "msra" 456 | } 457 | bias_filler { 458 | type: "constant" 459 | } 460 | } 461 | } 462 | 463 | layer { 464 | name: "accuracy_Eyeglasses" 465 | type: "Softmax" 466 | bottom: "FC3_g4_Eyeglasses" 467 | top: "accuracy_Eyeglasses" 468 | include { 469 | phase: TEST 470 | } 471 | } -------------------------------------------------------------------------------- /mcnn_Attri.prototxt: -------------------------------------------------------------------------------- 1 | name: "MCNN_Attri" 2 | layer { 3 | name: "data" 4 | type: "Data" 5 | top: "data" 6 | transform_param { 7 | scale: 0.007843 8 | mean_value: 127.5 9 | mean_value: 127.5 10 | mean_value: 127.5 11 | crop_size: 227 12 | } 13 | include { 14 | phase: TRAIN 15 | } 16 | data_param { 17 | source: "/home/hans/data/face/CelebA/attri/doc/val_db" 18 | batch_size: 192 19 | backend: LMDB 20 | } 21 | } 22 | 23 | layer { 24 | name: "labels" 25 | type: "Data" 26 | top: "labels" 27 | include { 28 | phase: TRAIN 29 | } 30 | data_param { 31 | source: "/home/hans/data/face/CelebA/attri/doc/val_lb" 32 | batch_size: 192 33 | backend: LMDB 34 | } 35 | } 36 | 37 | layer { 38 | name: "data" 39 | type: "Data" 40 | top: "data" 41 | transform_param { 42 | scale: 0.007843 43 | mean_value: 127.5 44 | mean_value: 127.5 45 | mean_value: 127.5 46 | crop_size: 227 47 | } 48 | include { 49 | phase: TEST 50 | } 51 | data_param { 52 | source: "/home/hans/data/face/CelebA/attri/doc/val_db" 53 | batch_size: 128 54 | backend: LMDB 55 | } 56 | } 57 | 58 | layer { 59 | name: "labels" 60 | type: "Data" 61 | top: "labels" 62 | include { 63 | phase: TEST 64 | } 65 | data_param { 66 | source: "/home/hans/data/face/CelebA/attri/doc/val_lb" 67 | batch_size: 128 68 | backend: LMDB 69 | } 70 | } 71 | 72 | layer { 73 | name: "sliceL" 74 | type: "Slice" 75 | bottom: "labels" 76 | top: "label_attr6" 77 | top: "label_attr16" 78 | top: "label_attr21" 79 | slice_param { 80 | slice_dim: 1 81 | slice_point: 1 82 | slice_point: 2 83 | } 84 | } 85 | 86 | layer { 87 | name: "conv1" 88 | type: "Convolution" 89 | bottom: "data" 90 | top: "conv1" 91 | param { 92 | lr_mult: 1 93 | decay_mult: 0 94 | } 95 | param { 96 | lr_mult: 2 97 | decay_mult: 0 98 | } 99 | convolution_param { 100 | num_output: 75 101 | kernel_size: 7 102 | stride: 2 103 | weight_filler { 104 | type: "msra" 105 | } 106 | bias_filler { 107 | type: "constant" 108 | } 109 | } 110 | } 111 | layer { 112 | name: "relu1" 113 | type: "ReLU" 114 | bottom: "conv1" 115 | top: "conv1" 116 | } 117 | layer { 118 | name: "pool1" 119 | type: "Pooling" 120 | bottom: "conv1" 121 | top: "pool1" 122 | pooling_param { 123 | pool: MAX 124 | kernel_size: 3 125 | stride: 2 126 | } 127 | } 128 | 129 | layer 130 | { 131 | name:"bn1" 132 | type:"BatchNorm" 133 | bottom:"pool1" 134 | top:"bn1" 135 | batch_norm_param:{ 136 | use_global_stats:false 137 | } 138 | } 139 | 140 | layer { 141 | name: "conv2" 142 | type: "Convolution" 143 | bottom: "bn1" 144 | top: "conv2" 145 | param { 146 | lr_mult: 1 147 | decay_mult: 0 148 | } 149 | param { 150 | lr_mult: 2 151 | decay_mult: 0 152 | } 153 | convolution_param { 154 | num_output: 200 155 | kernel_size: 5 156 | stride: 1 157 | weight_filler { 158 | type: "msra" 159 | } 160 | bias_filler { 161 | type: "constant" 162 | } 163 | } 164 | } 165 | layer { 166 | name: "relu2" 167 | type: "ReLU" 168 | bottom: "conv2" 169 | top: "conv2" 170 | } 171 | layer { 172 | name: "pool2" 173 | type: "Pooling" 174 | bottom: "conv2" 175 | top: "pool2" 176 | pooling_param { 177 | pool: MAX 178 | kernel_size: 3 179 | stride: 2 180 | } 181 | } 182 | layer 183 | { 184 | name:"bn2" 185 | type:"BatchNorm" 186 | bottom:"pool2" 187 | top:"bn2" 188 | batch_norm_param:{ 189 | use_global_stats:false 190 | } 191 | } 192 | 193 | #for group1 194 | layer { 195 | name: "conv3_g1_gender" 196 | type: "Convolution" 197 | bottom: "bn2" 198 | top: "conv3_g1_gender" 199 | param { 200 | lr_mult: 1 201 | decay_mult: 0 202 | } 203 | param { 204 | lr_mult: 2 205 | decay_mult: 0 206 | } 207 | convolution_param { 208 | num_output: 300 209 | kernel_size: 3 210 | stride: 1 211 | weight_filler { 212 | type: "msra" 213 | } 214 | bias_filler { 215 | type: "constant" 216 | } 217 | } 218 | } 219 | layer { 220 | name: "relu3_g1_gender" 221 | type: "ReLU" 222 | bottom: "conv3_g1_gender" 223 | top: "conv3_g1_gender" 224 | } 225 | layer { 226 | name: "pool3_g1_gender" 227 | type: "Pooling" 228 | bottom: "conv3_g1_gender" 229 | top: "pool3_g1_gender" 230 | pooling_param { 231 | pool: MAX 232 | kernel_size: 5 233 | stride: 3 234 | } 235 | } 236 | layer 237 | { 238 | name:"bn3_g1_gender" 239 | type:"BatchNorm" 240 | bottom:"pool3_g1_gender" 241 | top:"bn3_g1_gender" 242 | batch_norm_param:{ 243 | use_global_stats:false 244 | } 245 | } 246 | layer { 247 | name: "FC1_g1_gender" 248 | type: "InnerProduct" 249 | bottom: "bn3_g1_gender" 250 | top: "FC1_g1_gender" 251 | param { 252 | lr_mult: 1 253 | 254 | } 255 | param { 256 | lr_mult: 2 257 | } 258 | inner_product_param { 259 | num_output: 512 260 | weight_filler { 261 | type: "msra" 262 | } 263 | bias_filler { 264 | type: "constant" 265 | } 266 | } 267 | } 268 | layer { 269 | name: "relu4_g1_gender" 270 | type: "ReLU" 271 | bottom: "FC1_g1_gender" 272 | top: "relu4_g1_gender" 273 | } 274 | layer 275 | { 276 | name:"drop1_g1" 277 | type:"Dropout" 278 | bottom:"relu4_g1_gender" 279 | top:"relu4_g1_gender" 280 | dropout_param 281 | { 282 | dropout_ratio:0.5 283 | } 284 | } 285 | layer { 286 | name: "FC2_g1_gender" 287 | type: "InnerProduct" 288 | bottom: "relu4_g1_gender" 289 | top: "FC2_g1_gender" 290 | param { 291 | lr_mult: 1 292 | 293 | } 294 | param { 295 | lr_mult: 2 296 | } 297 | inner_product_param { 298 | num_output: 512 299 | weight_filler { 300 | type: "msra" 301 | } 302 | bias_filler { 303 | type: "constant" 304 | } 305 | } 306 | } 307 | layer { 308 | name: "relu5_g1_gender" 309 | type: "ReLU" 310 | bottom: "FC2_g1_gender" 311 | top: "relu5_g1_gender" 312 | } 313 | layer 314 | { 315 | name:"drop2_g1" 316 | type:"Dropout" 317 | bottom:"relu5_g1_gender" 318 | top:"relu5_g1_gender" 319 | dropout_param 320 | { 321 | dropout_ratio:0.5 322 | } 323 | } 324 | layer { 325 | name: "FC3_g1_gender" 326 | type: "InnerProduct" 327 | bottom: "relu5_g1_gender" 328 | top: "FC3_g1_gender" 329 | param { 330 | lr_mult: 1 331 | 332 | } 333 | param { 334 | lr_mult: 2 335 | } 336 | inner_product_param { 337 | num_output: 2 338 | weight_filler { 339 | type: "msra" 340 | } 341 | bias_filler { 342 | type: "constant" 343 | } 344 | } 345 | } 346 | 347 | layer { 348 | name: "accuracy_Male" 349 | type: "Accuracy" 350 | bottom: "FC3_g1_gender" 351 | bottom: "label_attr21" 352 | top: "accuracy_Male" 353 | include { 354 | phase: TEST 355 | } 356 | } 357 | 358 | layer { 359 | name: "loss_Male" 360 | type: "SoftmaxWithLoss" 361 | bottom: "FC3_g1_gender" 362 | bottom: "label_attr21" 363 | top: "loss_Male" 364 | loss_weight:0.3333 365 | include { 366 | phase: TRAIN 367 | } 368 | } 369 | 370 | #for group6 371 | layer { 372 | name: "conv3_g6_Other" 373 | type: "Convolution" 374 | bottom: "bn2" 375 | top: "conv3_g6_Other" 376 | param { 377 | lr_mult: 1 378 | decay_mult: 0 379 | } 380 | param { 381 | lr_mult: 2 382 | decay_mult: 0 383 | } 384 | convolution_param { 385 | num_output: 300 386 | kernel_size: 3 387 | stride: 1 388 | weight_filler { 389 | type: "msra" 390 | } 391 | bias_filler { 392 | type: "constant" 393 | } 394 | } 395 | } 396 | layer { 397 | name: "relu3_g6_Other" 398 | type: "ReLU" 399 | bottom: "conv3_g6_Other" 400 | top: "conv3_g6_Other" 401 | } 402 | layer { 403 | name: "pool3_g6_Other" 404 | type: "Pooling" 405 | bottom: "conv3_g6_Other" 406 | top: "pool3_g6_Other" 407 | pooling_param { 408 | pool: MAX 409 | kernel_size: 5 410 | stride: 3 411 | } 412 | } 413 | layer 414 | { 415 | name:"bn3_g6_Other" 416 | type:"BatchNorm" 417 | bottom:"pool3_g6_Other" 418 | top:"bn3_g6_Other" 419 | batch_norm_param:{ 420 | use_global_stats:false 421 | } 422 | } 423 | layer { 424 | name: "FC1_g6_Other" 425 | type: "InnerProduct" 426 | bottom: "bn3_g6_Other" 427 | top: "FC1_g6_Other" 428 | param { 429 | lr_mult: 1 430 | } 431 | param { 432 | lr_mult: 2 433 | } 434 | inner_product_param { 435 | num_output: 512 436 | weight_filler { 437 | type: "msra" 438 | } 439 | bias_filler { 440 | type: "constant" 441 | } 442 | } 443 | } 444 | layer { 445 | name: "relu4_g6_Other" 446 | type: "ReLU" 447 | bottom: "FC1_g6_Other" 448 | top: "relu4_g6_Other" 449 | } 450 | layer 451 | { 452 | name:"drop1_g6" 453 | type:"Dropout" 454 | bottom:"relu4_g6_Other" 455 | top:"relu4_g6_Other" 456 | dropout_param 457 | { 458 | dropout_ratio:0.5 459 | } 460 | } 461 | layer { 462 | name: "FC2_g6_Other" 463 | type: "InnerProduct" 464 | bottom: "relu4_g6_Other" 465 | top: "FC2_g6_Other" 466 | param { 467 | lr_mult: 1 468 | } 469 | param { 470 | lr_mult: 2 471 | } 472 | inner_product_param { 473 | num_output: 512 474 | weight_filler { 475 | type: "msra" 476 | } 477 | bias_filler { 478 | type: "constant" 479 | } 480 | } 481 | } 482 | layer { 483 | name: "relu5_g6_Other" 484 | type: "ReLU" 485 | bottom: "FC2_g6_Other" 486 | top: "relu5_g6_Other" 487 | } 488 | layer 489 | { 490 | name:"drop2_g5" 491 | type:"Dropout" 492 | bottom:"relu5_g6_Other" 493 | top:"relu5_g6_Other" 494 | dropout_param 495 | { 496 | dropout_ratio:0.5 497 | } 498 | } 499 | #group6 Bangs 500 | layer { 501 | name: "FC3_g6_Bangs" 502 | type: "InnerProduct" 503 | bottom: "relu5_g6_Other" 504 | top: "FC3_g6_Bangs" 505 | param { 506 | lr_mult: 1 507 | } 508 | param { 509 | lr_mult: 2 510 | } 511 | inner_product_param { 512 | num_output: 2 513 | weight_filler { 514 | type: "msra" 515 | } 516 | bias_filler { 517 | type: "constant" 518 | } 519 | } 520 | } 521 | 522 | layer { 523 | name: "accuracy_Bangs" 524 | type: "Accuracy" 525 | bottom: "FC3_g6_Bangs" 526 | bottom: "label_attr6" 527 | top: "accuracy_Bangs" 528 | include { 529 | phase: TEST 530 | } 531 | } 532 | 533 | layer { 534 | name: "loss_Bangs" 535 | type: "SoftmaxWithLoss" 536 | bottom: "FC3_g6_Bangs" 537 | bottom: "label_attr6" 538 | top: "loss_Bangs" 539 | loss_weight:0.3333 540 | include { 541 | phase: TRAIN 542 | } 543 | } 544 | 545 | #group4 Eyeglasses 546 | layer { 547 | name: "FC3_g4_Eyeglasses" 548 | type: "InnerProduct" 549 | bottom: "relu5_g6_Other" 550 | top: "FC3_g4_Eyeglasses" 551 | param { 552 | lr_mult: 1 553 | } 554 | param { 555 | lr_mult: 2 556 | } 557 | inner_product_param { 558 | num_output: 2 559 | weight_filler { 560 | type: "msra" 561 | } 562 | bias_filler { 563 | type: "constant" 564 | } 565 | } 566 | } 567 | 568 | layer { 569 | name: "accuracy_Eyeglasses" 570 | type: "Accuracy" 571 | bottom: "FC3_g4_Eyeglasses" 572 | bottom: "label_attr16" 573 | top: "accuracy_Eyeglasses" 574 | include { 575 | phase: TEST 576 | } 577 | } 578 | 579 | layer { 580 | name: "loss_Eyeglasses" 581 | type: "SoftmaxWithLoss" 582 | bottom: "FC3_g4_Eyeglasses" 583 | bottom: "label_attr16" 584 | top: "loss_Eyeglasses" 585 | loss_weight:0.3333 586 | include { 587 | phase: TRAIN 588 | } 589 | } --------------------------------------------------------------------------------