title: caffe forward net in a for loop not working
body: <p>I am currently trying to write a c++ wrapper for PSPNet's prediction (originally in Matlab). PSPNet runs on Caffe. </p>
  
  <p>Situation: I have a trained caffe model, and would like to implement this wrapper to run the segmentation result when given an input. In this case, my crop_size is smaller than it's original size. Thus, it is being <strong>cropped manually to multiple 425x425 "frames"</strong> and <strong>fed forward</strong> into caffe net after the pre-processes in a <strong>for-loop</strong>. </p>
  
  <p>Problem: However, net seems to <strong>only</strong> be <strong>running forward once</strong> despite being in a for loop. Supported by its processing time and output, refer below. </p>
  
  <p>This is the incomplete code I am currently trying to work on: </p>
  
  <pre><code>#define USE_OPENCV 1
  #define trimapSize 1
  #define Debug 0
  #include &lt;caffe/caffe.hpp&gt;
  
  #include "Header.h"
  #include "caffe/data_reader.hpp"
  #include "caffe/proto/caffe.pb.h"
  #include "caffe/blob.hpp"
  
  
  #ifdef USE_OPENCV
  #include &lt;opencv2/core/core.hpp&gt;
  #include &lt;opencv2/highgui/highgui.hpp&gt;
  #include &lt;opencv2/imgproc/imgproc.hpp&gt;
  #endif  // USE_OPENCV
  
  #include &lt;algorithm&gt;
  #include &lt;iosfwd&gt;
  #include &lt;memory&gt;
  #include &lt;string&gt;
  #include &lt;utility&gt;
  #include &lt;vector&gt;
  #include &lt;chrono&gt; //Just for time measurement
  #include &lt;cmath&gt;
  #include &lt;array&gt;
  
  #include &lt;iostream&gt;
  #include &lt;fstream&gt;
  
  #ifdef USE_OPENCV
  using namespace caffe;  // NOLINT(build/namespaces)
  using std::string;
  
  
  class Classifier {
   public:
    Classifier(const string&amp; model_file,
               const string&amp; trained_file);
  
    cv::Mat Predict(const cv::Mat&amp; img);
  
   private:
    void SetMean(int weight, int heigh);
  
    void WrapInputLayer(std::vector&lt;cv::Mat&gt;* input_channels);
  
    cv::Mat Visualization(Blob&lt;float&gt;* output_layer);
    cv::Mat Preprocess(const cv::Mat&amp; img_scale, int ori_rows, int ori_cols, std::vector&lt;cv::Mat&gt;* input_channels);
  
   private:
    shared_ptr&lt;Net&lt;float&gt; &gt; net_;
    cv::Size input_geometry_;
    int num_channels_;
    cv::Mat mean_;
  };
  
  Classifier::Classifier(const string&amp; model_file,
                         const string&amp; trained_file) {
  
  
    Caffe::set_mode(Caffe::GPU);
  
    /* Load the network. */
    net_.reset(new Net&lt;float&gt;(model_file, TEST));
    net_-&gt;CopyTrainedLayersFrom(trained_file);
  
    CHECK_EQ(net_-&gt;num_inputs(), 1) &lt;&lt; "Network should have exactly one input.";
    CHECK_EQ(net_-&gt;num_outputs(), 2) &lt;&lt; "Network should have exactly one output.";
  
    Blob&lt;float&gt;* input_layer = net_-&gt;input_blobs()[0];
    num_channels_ = input_layer-&gt;channels();
    CHECK(num_channels_ == 3 || num_channels_ == 1)
      &lt;&lt; "Input layer should have 1 or 3 channels.";
    input_geometry_ = cv::Size(input_layer-&gt;width(), input_layer-&gt;height());
  }
  
  /* Create the mean file in binaryproto format. */
  void Classifier::SetMean(int weight, int heigh) {
  
    mean_ = cv::Mat(heigh, weight, CV_32FC3);
  
    mean_ = cv::Scalar(94.6744, 88.8887, 100.5404);//RGB
  
  }
  
  cv::Mat Classifier::Predict(const cv::Mat&amp; img) {
  
    cv::Mat originalTmp = img.clone();
    Blob&lt;float&gt;* input_layer = net_-&gt;input_blobs()[0];
    input_layer-&gt;Reshape(1, num_channels_,
                         input_geometry_.height, input_geometry_.width);
  
    std::cout &lt;&lt; "input_geometry_.height = " &lt;&lt; input_geometry_.height &lt;&lt; "input_geometry_.width = "&lt;&lt; input_geometry_.width &lt;&lt; std::endl;
  
    /* Forward dimension change to all layers. */
    net_-&gt;Reshape();
  
    std::vector&lt;cv::Mat&gt; input_channels;
    WrapInputLayer(&amp;input_channels);
  
     /*-----------------------------FOR MULTI-SCALE PROCESSING--------------------------*/
    int base_size = 0;
    int ori_rows = img.rows;
    int ori_cols = img.cols;
    float scale_array [1] = {1};
    //  float scale_array = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75]
    std::cout &lt;&lt; "ori_rows = " &lt;&lt; ori_rows &lt;&lt; "\t ori_cols = " &lt;&lt; ori_cols &lt;&lt; std::endl;
    cv::Mat data_all = cv::Mat::zeros(cv::Size(425, 425), CV_32FC3);
  
    if (ori_rows &gt; ori_cols) {
         base_size = ori_rows;
    }
    else base_size =  ori_cols;
  
    std::cout &lt;&lt; "base_size = " &lt;&lt; base_size &lt;&lt; std::endl;
    std::cout &lt;&lt; "size of array = " &lt;&lt; (sizeof(scale_array)/sizeof(*scale_array)) &lt;&lt; std::endl;
  
    for (int i=0; i &lt; (sizeof(scale_array)/sizeof(*scale_array)); i++){
      int long_size = base_size * scale_array[i] + 1;
      int new_rows = long_size;
      int new_cols = long_size;
  
       std::cout &lt;&lt; "BEFORE new rows = " &lt;&lt; new_rows &lt;&lt; "\t new cols = " &lt;&lt; new_cols &lt;&lt; std::endl;
  
      if (ori_rows &gt; ori_cols){
        new_cols = round(long_size/ori_rows*ori_cols);
      }
      else {new_rows = round(long_size/ori_cols*ori_rows);}
  
      std::cout &lt;&lt; "AFTER new rows = " &lt;&lt; new_rows &lt;&lt; "\t new cols = " &lt;&lt; new_cols &lt;&lt; std::endl;
  
      cv::Mat img_scale;
      cv::resize(img, img_scale, cv::Size(new_cols, new_rows), 0, 0, CV_INTER_LINEAR);
  
      std::cout &lt;&lt; "img_scale height: " &lt;&lt; img_scale.rows &lt;&lt; "\t width = " &lt;&lt; img_scale.cols &lt;&lt; std::endl;
      cv::imshow("img_scale",img_scale);
      cv::waitKey(0);
  
      data_all = data_all + Preprocess(img_scale, ori_rows, ori_cols, &amp;input_channels);
      std::cout &lt;&lt; "ok! DONE PREPROCESS!" &lt;&lt; std::endl;
    }
  
    return data_all;
  }
  
  cv::Mat Classifier::Preprocess(const cv::Mat&amp; img_scale, int ori_rows, int ori_cols, std::vector&lt;cv::Mat&gt;* input_channels)
  {
    int crop_size = 425;
    int new_rows = img_scale.rows;
    int new_cols = img_scale.cols;
    cv::Mat data_output = cv::Mat::zeros(cv::Size(ori_cols, ori_rows), CV_32FC3);
    int long_size = new_rows;
    cv::Mat img_processed;
  
    if (new_cols &gt; new_rows){
      long_size = new_cols;
    }
  
    if (long_size &lt;= crop_size){
      // img_processed = Preprocess(img_scale, &amp;input_channels);
      //RUN CAFFE --- NOT YET DONE ---
      std::cout &lt;&lt; "OK!" &lt;&lt; std::endl;
    }
    else {
      float stride_rate = 2.0/3.0;
      std::cout &lt;&lt; "stride_rate = " &lt;&lt; stride_rate &lt;&lt; std::endl;
      int stride = ceil(crop_size*stride_rate);
      std::cout &lt;&lt; "stride = " &lt;&lt; stride &lt;&lt; std::endl;
  
      cv::Mat img_pad = img_scale;
  
      int pad_rows = img_pad.rows;
      int pad_cols = img_pad.cols;
      int h_grid = ceil((pad_rows - crop_size)/stride) + 1;
      int w_grid = ceil((pad_cols - crop_size)/stride) + 1;
      cv::Mat img_sub;
  
      cv::Mat data_scale = cv::Mat::zeros(cv::Size(pad_cols, pad_cols), CV_32FC3);
  
      for(int grid_yidx = 1; grid_yidx &lt;= h_grid; grid_yidx++){
        for (int grid_xidx = 1; grid_xidx &lt;= w_grid; grid_xidx++){
          int s_x = (grid_xidx-1)*stride+1;
          int s_y = (grid_yidx-1)*stride+1;
          int e_x = std::min(s_x + crop_size -1, pad_cols);
          int e_y = std::min(s_y + crop_size -1, pad_rows);
          s_x = e_x - crop_size + 1;
          s_y = e_y - crop_size + 1;
  
      /* Cropping image */
          img_pad(cv::Rect(s_x,s_y,crop_size,crop_size)).copyTo(img_sub);
  
          cv::Mat sample;
         if (img_sub.channels() == 3 &amp;&amp; num_channels_ == 1)
            cv::cvtColor(img_sub, sample, cv::COLOR_BGR2GRAY);
          else if (img_sub.channels() == 4 &amp;&amp; num_channels_ == 1)
            cv::cvtColor(img_sub, sample, cv::COLOR_BGRA2GRAY);
          else if (img_sub.channels() == 4 &amp;&amp; num_channels_ == 3)
            cv::cvtColor(img_sub, sample, cv::COLOR_BGRA2BGR);
          else if (img_sub.channels() == 1 &amp;&amp; num_channels_ == 3)
            cv::cvtColor(img_sub, sample, cv::COLOR_GRAY2BGR);
          else
            sample = img_sub;
  
          cv::Mat sample_float;
  
          if (num_channels_ == 3)
            sample.convertTo(sample_float, CV_32FC3);
          else
            sample.convertTo(sample_float, CV_32FC1);
  
          SetMean(sample.rows, sample.cols);
  
          cv::imshow("sample_float", sample_float);
  
          cv::cvtColor(sample_float, sample_float, cv::COLOR_BGRA2RGB);
          sample_float =  sample_float.t();
  
  
          cv::Mat sample_normalized(sample_float.size(),sample_float.type());
  
          cv::subtract(sample_float.clone(), mean_, sample_normalized); 
  
    cv::Mat sample_temp;
    sample_normalized.convertTo(sample_temp, CV_32FC3, 255);
    cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/sample_normalized.png", sample_temp);
    cv::imshow("sample_normalized", sample_normalized);
    cv::waitKey(0);
  
  
          /* This operation will write the separate BGR planes directly to the
           * input layer of the network because it is wrapped by the cv::Mat
           * objects in input_channels. */
          img_processed = sample_normalized.t();
  
          cv::split(img_processed, *input_channels);
  
          CHECK(reinterpret_cast&lt;float*&gt;(input_channels-&gt;at(0).data)
                == net_-&gt;input_blobs()[0]-&gt;cpu_data())
            &lt;&lt; "Input channels are not wrapping the input layer of the network.";
  
          img_processed.convertTo(sample_temp, CV_32FC3, 255);
          cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/img_processed.png", sample_temp);
          cv::imshow("img_normalised",img_processed);
          cv::waitKey();
  
          std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); //Just for time measurement
  
          // float loss = 0.0;
          // net_-&gt;Forward(&amp;loss);
          net_-&gt;Forward();
  
          std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
          std::cout &lt;&lt; "Processing time = " &lt;&lt; (std::chrono::duration_cast&lt;std::chrono::microseconds&gt;(end - begin).count())/1000000.0 &lt;&lt; " sec" &lt;&lt;std::endl; //Just for time measurement
  
          /* Copy the output layer to a std::vector */
          Blob&lt;float&gt;* output_layer = net_-&gt;output_blobs()[0];
  
          cv::Mat segment = Visualization(output_layer);
          cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/segment.png", segment);
        }
      }
    }
    return (img_processed);
  }
  
  struct RGB {
    int R;
    int G;
    int B;
  };
  
  vector&lt;RGB&gt; get_palette(int nClass)
  {
    vector&lt;RGB&gt; listPlalette;
    RGB rgb0;
    rgb0.R = 0;
    rgb0.G = 0;
    rgb0.B = 0;
    listPlalette.push_back(rgb0);
    for (int i = 1; i &lt; nClass; i++)
    {
      RGB rgb;
  
      rgb.R = i*50;
      rgb.G = i*50 + i;
      rgb.B = 255-i*20;
  
      listPlalette.push_back(rgb); 
    }
    return listPlalette;
  }
  
  cv::Mat Classifier::Visualization(Blob&lt;float&gt;* output_layer) {
  
    std::vector&lt;cv::Mat&gt; input_channels;
  
    int H = output_layer-&gt;height();
    int W = output_layer-&gt;width();
    // int N = output_layer-&gt;num();      //Batch Size 
    int C = output_layer-&gt;channels(); //Number of classes
  
    int index = 0;
  
  #ifdef CPU_ONLY
    const float* output_data = output_layer-&gt;cpu_data();
  #else
    const float* output_data = output_layer-&gt;cpu_data();
  #endif // !CPU_ONLY
  
  
    cv::Mat class_each_row(C, W*H, CV_32F);
    for (int i = 0; i &lt; C; i++) {
      for (int j = 0; j &lt; (W*H); j++) {
        class_each_row.at&lt;float&gt;(i, j) = output_data[index];
        index = index + 1;
      }
    }
  
    class_each_row = class_each_row.t();
  
  //==================================CONVERT INTO LABELS==================================//
    float maxValue = 0;
  
    int* labelIndex = (int*)malloc(W*H * sizeof(int));
    int indexX = 0;
    for (int i = 0; i &lt; class_each_row.rows; i++) {
  
      maxValue = -999999999999;
      indexX = 0;
      for (int k = 0; k &lt; C; k++)
      {
        float dataM = class_each_row.at&lt;float&gt;(i, k);
        if (dataM &gt; maxValue) {
          maxValue = dataM;
          indexX = k;
        }
      }
  
      labelIndex[i] = indexX;
    }
  
    cv::Mat labelTmp(W, H, CV_8UC3);
    uchar* dataLabelTmp = labelTmp.data;
    vector&lt;RGB&gt; listPalette = get_palette(21);
  
    for (int i = 0; i &lt; H; i++)
    {
      for (int j = 0; j &lt; W; j++)
      {
        RGB rgb = listPalette[labelIndex[(i*W + j)]];
        dataLabelTmp[3 * (i*W + j)] = rgb.B;
        dataLabelTmp[3 * (i*W + j) + 1] = rgb.G;
        dataLabelTmp[3 * (i*W + j) + 2] = rgb.R;
      }
  
    }
  
     cv::imshow( "Display window", labelTmp);
     cv::waitKey(0);
  
    free(labelIndex);
    labelIndex = NULL;
  
    return labelTmp;
  }
  
  
  /* Wrap the input layer of the network in separate cv::Mat objects
   * (one per channel). This way we save one memcpy operation and we
   * don't need to rely on cudaMemcpy2D. The last preprocessing
   * operation will write the separate channels directly to the input
   * layer. */
  void Classifier::WrapInputLayer(std::vector&lt;cv::Mat&gt;* input_channels) {
    Blob&lt;float&gt;* input_layer = net_-&gt;input_blobs()[0];
  
    int width = input_layer-&gt;width();
    int height = input_layer-&gt;height();
    float* input_data = input_layer-&gt;mutable_cpu_data();
    for (int i = 0; i &lt; input_layer-&gt;channels(); ++i) {
      cv::Mat channel(height, width, CV_32FC1, input_data);
      input_channels-&gt;push_back(channel);
      input_data += width * height;
    }
  }
  
  
  int main(int argc, char** argv) {
    if (argc != 4) {
      std::cerr &lt;&lt; "Usage: " &lt;&lt; argv[0]
                &lt;&lt; " \ndeploy.prototxt \nnetwork.caffemodel"
                &lt;&lt; " \nimg.jpg" &lt;&lt; " \ncamvid12.png (for example: /SegNet-Tutorial/Scripts/camvid12.png)" &lt;&lt; std::endl;
      return 1;
    }
  
    ::google::InitGoogleLogging(argv[0]);
  
    string model_file   = argv[1];
    string trained_file = argv[2]; //for visualization
  
  
    Classifier classifier(model_file, trained_file);
  
    string file = argv[3];
  
    std::cout &lt;&lt; "---------- Semantic Segmentation for "
              &lt;&lt; file &lt;&lt; " ----------" &lt;&lt; std::endl;
  
    cv::Mat img = cv::imread(file, 1);
    CHECK(!img.empty()) &lt;&lt; "Unable to decode image " &lt;&lt; file;
    cv::Mat prediction;
  
    classifier.Predict(img);
  }
  #else
  int main(int argc, char** argv) {
    LOG(FATAL) &lt;&lt; "This example requires OpenCV; compile with USE_OPENCV.";
  }
  #endif //USE_OPENCV
  </code></pre>
  
  <p>To clarify: The <strong>for-loop</strong> refers to the one in pre-process: specifically this portion:</p>
  
  <pre><code> for(int grid_yidx = 1; grid_yidx &lt;= h_grid; grid_yidx++){
    for (int grid_xidx = 1; grid_xidx &lt;= w_grid; grid_xidx++){
      int s_x = (grid_xidx-1)*stride+1;
      int s_y = (grid_yidx-1)*stride+1;
      int e_x = std::min(s_x + crop_size -1, pad_cols);
      int e_y = std::min(s_y + crop_size -1, pad_rows);
      s_x = e_x - crop_size + 1;
      s_y = e_y - crop_size + 1;
  
  /* Cropping image */
      img_pad(cv::Rect(s_x,s_y,crop_size,crop_size)).copyTo(img_sub);
  
      cv::Mat sample;
     if (img_sub.channels() == 3 &amp;&amp; num_channels_ == 1)
        cv::cvtColor(img_sub, sample, cv::COLOR_BGR2GRAY);
      else if (img_sub.channels() == 4 &amp;&amp; num_channels_ == 1)
        cv::cvtColor(img_sub, sample, cv::COLOR_BGRA2GRAY);
      else if (img_sub.channels() == 4 &amp;&amp; num_channels_ == 3)
        cv::cvtColor(img_sub, sample, cv::COLOR_BGRA2BGR);
      else if (img_sub.channels() == 1 &amp;&amp; num_channels_ == 3)
        cv::cvtColor(img_sub, sample, cv::COLOR_GRAY2BGR);
      else
        sample = img_sub;
  
      cv::Mat sample_float;
  
      if (num_channels_ == 3)
        sample.convertTo(sample_float, CV_32FC3);
      else
        sample.convertTo(sample_float, CV_32FC1);
  
      SetMean(sample.rows, sample.cols);
  
      cv::imshow("sample_float", sample_float);
  
      cv::cvtColor(sample_float, sample_float, cv::COLOR_BGRA2RGB);
      sample_float =  sample_float.t();
  
  
      cv::Mat sample_normalized(sample_float.size(),sample_float.type());
  
      cv::subtract(sample_float.clone(), mean_, sample_normalized); 
  
    cv::Mat sample_temp;
    sample_normalized.convertTo(sample_temp, CV_32FC3, 255);
    cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/sample_normalized.png", sample_temp);
    cv::imshow("sample_normalized", sample_normalized);
    cv::waitKey(0);
  
  
      /* This operation will write the separate BGR planes directly to the
       * input layer of the network because it is wrapped by the cv::Mat
       * objects in input_channels. */
      img_processed = sample_normalized.t();
  
      cv::split(img_processed, *input_channels);
  
      CHECK(reinterpret_cast&lt;float*&gt;(input_channels-&gt;at(0).data)
            == net_-&gt;input_blobs()[0]-&gt;cpu_data())
        &lt;&lt; "Input channels are not wrapping the input layer of the network.";
  
      img_processed.convertTo(sample_temp, CV_32FC3, 255);
      cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/img_processed.png", sample_temp);
      cv::imshow("img_normalised",img_processed);
      cv::waitKey();
  
      std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); //Just for time measurement
  
      // float loss = 0.0;
      // net_-&gt;Forward(&amp;loss);
      net_-&gt;Forward();
  
      std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
      std::cout &lt;&lt; "Processing time = " &lt;&lt; (std::chrono::duration_cast&lt;std::chrono::microseconds&gt;(end - begin).count())/1000000.0 &lt;&lt; " sec" &lt;&lt;std::endl; //Just for time measurement
  
      /* Copy the output layer to a std::vector */
      Blob&lt;float&gt;* output_layer = net_-&gt;output_blobs()[0];
  
      cv::Mat segment = Visualization(output_layer);
      cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/segment.png", segment);
    }
  }
  </code></pre>
  
  <p>Original Image:<a href="https://i.stack.imgur.com/KUmqI.png" rel="nofollow noreferrer">Original Image (Without pre-processing)</a></p>
  
  <p>Input: <a href="https://i.stack.imgur.com/843gc.png" rel="nofollow noreferrer">Input (first cropped frame)</a></p>
  
  <p>Output: <a href="https://i.stack.imgur.com/26bZj.png" rel="nofollow noreferrer">Output of the first cropped frame</a></p>
  
  <p>Time taken for forwarding: <a href="https://i.stack.imgur.com/cMvIN.png" rel="nofollow noreferrer">Time taken</a></p>
  
  <p>Following cropped frame gives the same output through out. </p>
  
  <p>P/s: If i shift the code below to the end of <em>predict</em> function and <em>return segment instead</em>, it will work well. But only the last cropped frame will be segmented. </p>
  
  <pre><code> std::chrono::steady_clock::time_point begin = 
   std::chrono::steady_clock::now(); //Just for time measurement
  
   // float loss = 0.0;
   // net_-&gt;Forward(&amp;loss);
   net_-&gt;Forward();
  
   std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
   std::cout &lt;&lt; "Processing time = " &lt;&lt; (std::chrono::duration_cast&lt;std::chrono::microseconds&gt;(end - begin).count())/1000000.0 &lt;&lt; " sec" &lt;&lt;std::endl; //Just for time measurement
  
   /* Copy the output layer to a std::vector */
   Blob&lt;float&gt;* output_layer = net_-&gt;output_blobs()[0];
  
   cv::Mat segment = Visualization(output_layer);
   cv::imwrite("/home/sgp1053c/Desktop/PSPNET-cudnn5_wrapper/wrapper/segment.png", segment);`
  </code></pre>
  
  <p>input: <a href="https://i.stack.imgur.com/e9l9C.png" rel="nofollow noreferrer">Input (Last cropped frame of pre-processed image)</a></p>
  
  <p>output: <a href="https://i.stack.imgur.com/YX3Rp.png" rel="nofollow noreferrer">Output of the last cropped frame</a></p>
  
  <p>Any help will be appreciated, thank youuuuu!!!</p>