使用Caffe基于cifar10进行物体识别

使用Caffe基于cifar10进行物体识别

原创 2017年06月10日 18:31:30

http://blog.****.net/fengbingchun/article/details/72953284中对cifar10进行train,这里通过train得到的model,对图像进行识别。cifar10数据集共包括10类,按照0到9的顺序依次为airplane(飞机)、automobile(轿车)、bird(鸟)、cat(猫)、deer(鹿)、dog(狗)、frog(青蛙)、horse(房子)、ship(船)、truck(卡车)。

在识别前需要对原有的cifar10_quick_train_test.prototxt文件进行调整,调整后的内容如下:

[plain] view plain copy
  1. name: "CIFAR10_quick"  
  2. layer {  
  3.   name: "data"  
  4.   type: "MemoryData"  
  5.   top: "data"  
  6.   top: "label"  
  7.   memory_data_param {  
  8.     batch_size: 1  
  9.     channels: 3  
  10.     height: 32  
  11.     width: 32  
  12.   }  
  13. }  
  14. layer {  
  15.   name: "conv1"  
  16.   type: "Convolution"  
  17.   bottom: "data"  
  18.   top: "conv1"  
  19.   param {  
  20.     lr_mult: 1  
  21.   }  
  22.   param {  
  23.     lr_mult: 2  
  24.   }  
  25.   convolution_param {  
  26.     num_output: 32  
  27.     pad: 2  
  28.     kernel_size: 5  
  29.     stride: 1  
  30.     weight_filler {  
  31.       type: "gaussian"  
  32.       std: 0.0001  
  33.     }  
  34.     bias_filler {  
  35.       type: "constant"  
  36.     }  
  37.   }  
  38. }  
  39. layer {  
  40.   name: "pool1"  
  41.   type: "Pooling"  
  42.   bottom: "conv1"  
  43.   top: "pool1"  
  44.   pooling_param {  
  45.     pool: MAX  
  46.     kernel_size: 3  
  47.     stride: 2  
  48.   }  
  49. }  
  50. layer {  
  51.   name: "relu1"  
  52.   type: "ReLU"  
  53.   bottom: "pool1"  
  54.   top: "pool1"  
  55. }  
  56. layer {  
  57.   name: "conv2"  
  58.   type: "Convolution"  
  59.   bottom: "pool1"  
  60.   top: "conv2"  
  61.   param {  
  62.     lr_mult: 1  
  63.   }  
  64.   param {  
  65.     lr_mult: 2  
  66.   }  
  67.   convolution_param {  
  68.     num_output: 32  
  69.     pad: 2  
  70.     kernel_size: 5  
  71.     stride: 1  
  72.     weight_filler {  
  73.       type: "gaussian"  
  74.       std: 0.01  
  75.     }  
  76.     bias_filler {  
  77.       type: "constant"  
  78.     }  
  79.   }  
  80. }  
  81. layer {  
  82.   name: "relu2"  
  83.   type: "ReLU"  
  84.   bottom: "conv2"  
  85.   top: "conv2"  
  86. }  
  87. layer {  
  88.   name: "pool2"  
  89.   type: "Pooling"  
  90.   bottom: "conv2"  
  91.   top: "pool2"  
  92.   pooling_param {  
  93.     pool: AVE  
  94.     kernel_size: 3  
  95.     stride: 2  
  96.   }  
  97. }  
  98. layer {  
  99.   name: "conv3"  
  100.   type: "Convolution"  
  101.   bottom: "pool2"  
  102.   top: "conv3"  
  103.   param {  
  104.     lr_mult: 1  
  105.   }  
  106.   param {  
  107.     lr_mult: 2  
  108.   }  
  109.   convolution_param {  
  110.     num_output: 64  
  111.     pad: 2  
  112.     kernel_size: 5  
  113.     stride: 1  
  114.     weight_filler {  
  115.       type: "gaussian"  
  116.       std: 0.01  
  117.     }  
  118.     bias_filler {  
  119.       type: "constant"  
  120.     }  
  121.   }  
  122. }  
  123. layer {  
  124.   name: "relu3"  
  125.   type: "ReLU"  
  126.   bottom: "conv3"  
  127.   top: "conv3"  
  128. }  
  129. layer {  
  130.   name: "pool3"  
  131.   type: "Pooling"  
  132.   bottom: "conv3"  
  133.   top: "pool3"  
  134.   pooling_param {  
  135.     pool: AVE  
  136.     kernel_size: 3  
  137.     stride: 2  
  138.   }  
  139. }  
  140. layer {  
  141.   name: "ip1"  
  142.   type: "InnerProduct"  
  143.   bottom: "pool3"  
  144.   top: "ip1"  
  145.   param {  
  146.     lr_mult: 1  
  147.   }  
  148.   param {  
  149.     lr_mult: 2  
  150.   }  
  151.   inner_product_param {  
  152.     num_output: 64  
  153.     weight_filler {  
  154.       type: "gaussian"  
  155.       std: 0.1  
  156.     }  
  157.     bias_filler {  
  158.       type: "constant"  
  159.     }  
  160.   }  
  161. }  
  162. layer {  
  163.   name: "ip2"  
  164.   type: "InnerProduct"  
  165.   bottom: "ip1"  
  166.   top: "ip2"  
  167.   param {  
  168.     lr_mult: 1  
  169.   }  
  170.   param {  
  171.     lr_mult: 2  
  172.   }  
  173.   inner_product_param {  
  174.     num_output: 10  
  175.     weight_filler {  
  176.       type: "gaussian"  
  177.       std: 0.1  
  178.     }  
  179.     bias_filler {  
  180.       type: "constant"  
  181.     }  
  182.   }  
  183. }  
  184. layer {  
  185.   name: "prob"  
  186.   type: "Softmax"  
  187.   bottom: "ip2"  
  188.   top: "prob"  
  189. }  
可视化结果如下图(https://ethereon.github.io/netscope/quickstart.html):

使用Caffe基于cifar10进行物体识别

从网上找了10幅较标准的图像,如下:
使用Caffe基于cifar10进行物体识别

测试代码如下:

  1. #include "funset.hpp"  
  2. #include "common.hpp"  
  3.   
  4. int cifar10_predict()  
  5. {  
  6. #ifdef CPU_ONLY  
  7.     caffe::Caffe::set_mode(caffe::Caffe::CPU);  
  8. #else  
  9.     caffe::Caffe::set_mode(caffe::Caffe::GPU);  
  10. #endif  
  11.   
  12.     const std::string param_file{ "E:/GitCode/Caffe_Test/test_data/model/cifar10/cifar10_quick_train_test_.prototxt" };  
  13.     const std::string trained_filename{ "E:/GitCode/Caffe_Test/test_data/model/cifar10/cifar10_quick_iter_4000.caffemodel.h5" };  
  14.     const std::string image_path{ "E:/GitCode/Caffe_Test/test_data/images/object_recognition/" };  
  15.     const std::string mean_file{"E:/GitCode/Caffe_Test/test_data/model/cifar10/mean.binaryproto"};  
  16.   
  17.     caffe::Net<float> caffe_net(param_file, caffe::TEST);  
  18.     caffe_net.CopyTrainedLayersFromHDF5(trained_filename);  
  19.   
  20.     const boost::shared_ptr<caffe::Blob<float> > blob_by_name = caffe_net.blob_by_name("data");  
  21.     int image_channel = blob_by_name->channels();  
  22.     int image_height = blob_by_name->height();  
  23.     int image_width = blob_by_name->width();  
  24.   
  25.     int num_outputs = caffe_net.num_outputs();  
  26.     const std::vector<caffe::Blob<float>*>& output_blobs = caffe_net.output_blobs();  
  27.     int require_blob_index{ -1 };  
  28.     const int digit_category_num{ 10 };  
  29.     for (int i = 0; i < output_blobs.size(); ++i) {  
  30.         if (output_blobs[i]->count() == digit_category_num)  
  31.             require_blob_index = i;  
  32.     }  
  33.     if (require_blob_index == -1) {  
  34.         fprintf(stderr, "ouput blob don't match\n");  
  35.         return -1;  
  36.     }  
  37.   
  38.     std::vector<int> target{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
  39.     std::vector<int> result;  
  40.   
  41.     // read mean data  
  42.     caffe::BlobProto image_mean; // storage order: rr..rrgg..ggbb..bb  
  43.     if (!caffe::ReadProtoFromBinaryFile(mean_file, &image_mean)) {  
  44.         fprintf(stderr, "parse mean file fail\n");  
  45.         return -1;  
  46.     }  
  47.   
  48.     if (image_channel != image_mean.channels() || image_height != image_mean.height() || image_width != image_mean.width() ||  
  49.         image_channel != 3) {  
  50.         fprintf(stderr, "their dimension dismatch\n");  
  51.         return -1;  
  52.     }  
  53.   
  54.     cv::Mat mat_mean(image_height, image_width, CV_32FC3, const_cast<float*>(image_mean.data().data()));  
  55.   
  56.     for (auto num : target) {  
  57.         std::string str = std::to_string(num);  
  58.         str += ".jpg";  
  59.         str = image_path + str;  
  60.   
  61.         cv::Mat mat = cv::imread(str.c_str(), 1);  
  62.         if (!mat.data) {  
  63.             fprintf(stderr, "load image error: %s\n", str.c_str());  
  64.             return -1;  
  65.         }  
  66.   
  67.         if (image_channel == 1)  
  68.             cv::cvtColor(mat, mat, CV_BGR2GRAY);  
  69.         else if (image_channel == 4)  
  70.             cv::cvtColor(mat, mat, CV_BGR2BGRA);  
  71.   
  72.         cv::resize(mat, mat, cv::Size(image_width, image_height));  
  73.         mat.convertTo(mat, CV_32FC3);  
  74.   
  75.         // Note: need to subtract mean  
  76.         std::vector<cv::Mat> mat_tmp2; //b,g,r  
  77.         cv::split(mat, mat_tmp2);  
  78.         cv::Mat mat_tmp3(image_height, image_width, CV_32FC3);  
  79.         float* p = (float*)mat_tmp3.data;  
  80.         memcpy(p, mat_tmp2[2].data, image_height * image_width * sizeof(float));  
  81.         memcpy(p + image_height * image_width, mat_tmp2[1].data, image_height * image_width * sizeof(float));  
  82.         memcpy(p + image_height * image_width * 2, mat_tmp2[0].data, image_height * image_width * sizeof(float));  
  83.         cv::subtract(mat_tmp3, mat_mean, mat_tmp3);  
  84.   
  85.         boost::shared_ptr<caffe::MemoryDataLayer<float> > memory_data_layer =  
  86.             boost::static_pointer_cast<caffe::MemoryDataLayer<float>>(caffe_net.layer_by_name("data"));  
  87.         float dummy_label[1] {0};  
  88.         memory_data_layer->Reset((float*)(mat_tmp3.data), dummy_label, 1); // rr..rrgg..ggbb..bb  
  89.   
  90.         float loss{ 0.0 };  
  91.         const std::vector<caffe::Blob<float>*>& results = caffe_net.ForwardPrefilled(&loss); // Net forward  
  92.         const float* output = results[require_blob_index]->cpu_data();  
  93.   
  94.         float tmp{ -1 };  
  95.         int pos{ -1 };  
  96.   
  97.         fprintf(stderr, "actual digit is: %d\n", target[num]);  
  98.         for (int j = 0; j < 10; j++) {  
  99.             printf("Probability to be Number %d is: %.3f\n", j, output[j]);  
  100.             if (tmp < output[j]) {  
  101.                 pos = j;  
  102.                 tmp = output[j];  
  103.             }  
  104.         }  
  105.   
  106.         result.push_back(pos);  
  107.     }  
  108.   
  109.     for (auto i = 0; i < 10; i++)  
  110.         fprintf(stderr, "actual digit is: %d, result digit is: %d\n", target[i], result[i]);  
  111.   
  112.     fprintf(stderr, "predict finish\n");  
  113.   
  114.     return 0;  
  115. }  
测试结果如下:

使用Caffe基于cifar10进行物体识别

其中鹿和青蛙识别错误。

GitHubhttps://github.com/fengbingchun/Caffe_Test