#include <string>
#include <vector>

#include "boost/scoped_ptr.hpp"
#include "google/protobuf/text_format.h"
#include "gtest/gtest.h"

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/layer.hpp"
#include "caffe/util/db.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/upgrade_proto.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

class PaddingLayerUpgradeTest : public ::testing::Test {
 protected:
  void RunPaddingUpgradeTest(
      const string& input_param_string, const string& output_param_string) {
    // Test that UpgradeV0PaddingLayers called on the proto specified by
    // input_param_string results in the proto specified by
    // output_param_string.
    NetParameter input_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        input_param_string, &input_param));
    NetParameter expected_output_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        output_param_string, &expected_output_param));
    NetParameter actual_output_param;
    UpgradeV0PaddingLayers(input_param, &actual_output_param);
    EXPECT_EQ(expected_output_param.DebugString(),
        actual_output_param.DebugString());
    // Also test idempotence.
    NetParameter double_pad_upgrade_param;
    UpgradeV0PaddingLayers(actual_output_param, &double_pad_upgrade_param);
    EXPECT_EQ(actual_output_param.DebugString(),
       double_pad_upgrade_param.DebugString());
  }
};

TEST_F(PaddingLayerUpgradeTest, TestSimple) {
  const string& input_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad1' "
      "    type: 'padding' "
      "    pad: 2 "
      "  } "
      "  bottom: 'data' "
      "  top: 'pad1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  const string& expected_output_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunPaddingUpgradeTest(input_proto, expected_output_proto);
}

TEST_F(PaddingLayerUpgradeTest, TestTwoTops) {
  const string& input_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad1' "
      "    type: 'padding' "
      "    pad: 2 "
      "  } "
      "  bottom: 'data' "
      "  top: 'pad1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv2' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad1' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  const string& expected_output_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv2' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunPaddingUpgradeTest(input_proto, expected_output_proto);
}

TEST_F(PaddingLayerUpgradeTest, TestImageNet) {
  const string& input_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu1' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool1' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm1' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad2' "
      "    type: 'padding' "
      "    pad: 2 "
      "  } "
      "  bottom: 'norm1' "
      "  top: 'pad2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv2' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 5 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu2' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool2' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'pool2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm2' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool2' "
      "  top: 'norm2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad3' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'norm2' "
      "  top: 'pad3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv3' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu3' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad4' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'pad4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv4' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu4' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad5' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'pad5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv5' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu5' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool5' "
      "    type: 'pool' "
      "    kernelsize: 3 "
      "    pool: MAX "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'pool5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc6' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pool5' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu6' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop6' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc7' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu7' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop7' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  const string& expected_output_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu1' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool1' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm1' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv2' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 5 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'norm1' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu2' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool2' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'pool2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm2' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool2' "
      "  top: 'norm2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv3' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    kernelsize: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'norm2' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu3' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv4' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu4' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv5' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu5' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool5' "
      "    type: 'pool' "
      "    kernelsize: 3 "
      "    pool: MAX "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'pool5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc6' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pool5' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu6' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop6' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc7' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu7' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop7' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunPaddingUpgradeTest(input_proto, expected_output_proto);
}

class NetUpgradeTest : public ::testing::Test {
 protected:
  void RunV0UpgradeTest(
      const string& input_param_string, const string& output_param_string) {
    // Test that UpgradeV0Net called on the NetParameter proto specified by
    // input_param_string results in the NetParameter proto specified by
    // output_param_string.
    NetParameter input_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        input_param_string, &input_param));
    NetParameter expected_output_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        output_param_string, &expected_output_param));
    NetParameter actual_output_param;
    UpgradeV0Net(input_param, &actual_output_param);
    EXPECT_EQ(expected_output_param.DebugString(),
        actual_output_param.DebugString());
  }

  void RunV1UpgradeTest(
      const string& input_param_string, const string& output_param_string) {
    // Test that UpgradeV0Net called on the NetParameter proto specified by
    // input_param_string results in the NetParameter proto specified by
    // output_param_string.
    NetParameter input_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        input_param_string, &input_param));
    NetParameter expected_output_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        output_param_string, &expected_output_param));
    NetParameter actual_output_param;
    UpgradeV1Net(input_param, &actual_output_param);
    EXPECT_EQ(expected_output_param.DebugString(),
        actual_output_param.DebugString());
  }
};

TEST_F(NetUpgradeTest, TestSimple) {
  const string& v0_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad1' "
      "    type: 'padding' "
      "    pad: 2 "
      "  } "
      "  bottom: 'data' "
      "  top: 'pad1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  const string& expected_v1_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  name: 'data' "
      "  type: DATA "
      "  data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "  } "
      "  transform_param { "
      "    crop_size: 227 "
      "    mirror: true "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  name: 'conv1' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 96 "
      "    kernel_size: 11 "
      "    stride: 4 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  name: 'fc8' "
      "  type: INNER_PRODUCT "
      "  inner_product_param { "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  name: 'loss' "
      "  type: SOFTMAX_LOSS "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunV0UpgradeTest(v0_proto, expected_v1_proto);

  const string& expected_v2_proto =
      "name: 'CaffeNet' "
      "layer { "
      "  name: 'data' "
      "  type: 'Data' "
      "  data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "  } "
      "  transform_param { "
      "    crop_size: 227 "
      "    mirror: true "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layer { "
      "  name: 'conv1' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 96 "
      "    kernel_size: 11 "
      "    stride: 4 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layer { "
      "  name: 'fc8' "
      "  type: 'InnerProduct' "
      "  inner_product_param { "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'fc8' "
      "} "
      "layer { "
      "  name: 'loss' "
      "  type: 'SoftmaxWithLoss' "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunV1UpgradeTest(expected_v1_proto, expected_v2_proto);
}

// Test any layer or parameter upgrades not covered by other tests.
TEST_F(NetUpgradeTest, TestAllParams) {
  const string& input_proto =
      "name: 'CaffeNet' "
      "input: 'input_data' "
      "input_dim: 64 "
      "input_dim: 3 "
      "input_dim: 32 "
      "input_dim: 32 "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "    scale: 0.25 "
      "    rand_skip: 73 "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'images' "
      "    type: 'images' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-images' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "    scale: 0.25 "
      "    rand_skip: 73 "
      "    shuffle_images: true "
      "    new_height: 40 "
      "    new_width: 30 "
      "  } "
      "  top: 'images_data' "
      "  top: 'images_label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'window_data' "
      "    type: 'window_data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "    det_fg_threshold: 0.25 "
      "    det_bg_threshold: 0.75 "
      "    det_fg_fraction: 0.5 "
      "    det_context_pad: 16 "
      "    det_crop_mode: 'square' "
      "  } "
      "  top: 'window_data' "
      "  top: 'window_label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'hdf5data' "
      "    type: 'hdf5_data' "
      "    source: '/my/hdf5/data' "
      "    batchsize: 256 "
      "  } "
      "  top: 'hdf5data' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    biasterm: false "
      "    pad: 4 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 3. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool1ave' "
      "    type: 'pool' "
      "    pool: AVE "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1ave' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool1stoch' "
      "    type: 'pool' "
      "    pool: STOCHASTIC "
      "    kernelsize: 4 "
      "    stride: 5 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1stoch' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'concat' "
      "    type: 'concat' "
      "    concat_dim: 2 "
      "  } "
      "  bottom: 'pool1ave' "
      "  bottom: 'pool1stoch' "
      "  top: 'pool1concat' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm1' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1concat' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc6' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    biasterm: false "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'norm1' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu6' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop6' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.2 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'infogain_loss' "
      "    source: '/my/infogain/matrix' "
      "  } "
      "  bottom: 'fc6' "
      "  bottom: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'accuracy' "
      "    type: 'accuracy' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'bnll' "
      "    type: 'bnll' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'euclidean_loss' "
      "    type: 'euclidean_loss' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'flatten' "
      "    type: 'flatten' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'hdf5_output' "
      "    type: 'hdf5_output' "
      "    hdf5_output_param { "
      "      file_name: '/my/hdf5/output/file' "
      "    } "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'im2col' "
      "    type: 'im2col' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'images' "
      "    type: 'images' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'multinomial_logistic_loss' "
      "    type: 'multinomial_logistic_loss' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'sigmoid' "
      "    type: 'sigmoid' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'softmax' "
      "    type: 'softmax' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'split' "
      "    type: 'split' "
      "  } "
      "} "
      "layers { "
      "  layer { "
      "    name: 'tanh' "
      "    type: 'tanh' "
      "  } "
      "} ";
  const string& expected_output_proto =
      "name: 'CaffeNet' "
      "input: 'input_data' "
      "input_dim: 64 "
      "input_dim: 3 "
      "input_dim: 32 "
      "input_dim: 32 "
      "layers { "
      "  name: 'data' "
      "  type: DATA "
      "  data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "    rand_skip: 73 "
      "  } "
      "  transform_param { "
      "    crop_size: 227 "
      "    mirror: true "
      "    scale: 0.25 "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  name: 'images' "
      "  type: IMAGE_DATA "
      "  image_data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-images' "
      "    batch_size: 256 "
      "    rand_skip: 73 "
      "    shuffle: true "
      "    new_height: 40 "
      "    new_width: 30 "
      "  } "
      "  transform_param {"
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    crop_size: 227 "
      "    mirror: true "
      "    scale: 0.25 "
      "  } "
      "  top: 'images_data' "
      "  top: 'images_label' "
      "} "
      "layers { "
      "  name: 'window_data' "
      "  type: WINDOW_DATA "
      "  window_data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "    fg_threshold: 0.25 "
      "    bg_threshold: 0.75 "
      "    fg_fraction: 0.5 "
      "    context_pad: 16 "
      "    crop_mode: 'square' "
      "  } "
      "  transform_param { "
      "    mirror: true "
      "    crop_size: 227 "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  }"
      "  top: 'window_data' "
      "  top: 'window_label' "
      "} "
      "layers { "
      "  name: 'hdf5data' "
      "  type: HDF5_DATA "
      "  hdf5_data_param { "
      "    source: '/my/hdf5/data' "
      "    batch_size: 256 "
      "  } "
      "  top: 'hdf5data' "
      "} "
      "layers { "
      "  name: 'conv1' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 96 "
      "    bias_term: false "
      "    pad: 4 "
      "    kernel_size: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 3. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  name: 'pool1ave' "
      "  type: POOLING "
      "  pooling_param { "
      "    pool: AVE "
      "    kernel_size: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1ave' "
      "} "
      "layers { "
      "  name: 'pool1stoch' "
      "  type: POOLING "
      "  pooling_param { "
      "    pool: STOCHASTIC "
      "    kernel_size: 4 "
      "    stride: 5 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1stoch' "
      "} "
      "layers { "
      "  name: 'concat' "
      "  type: CONCAT "
      "  concat_param { "
      "    concat_dim: 2 "
      "  } "
      "  bottom: 'pool1ave' "
      "  bottom: 'pool1stoch' "
      "  top: 'pool1concat' "
      "} "
      "layers { "
      "  name: 'norm1' "
      "  type: LRN "
      "  lrn_param { "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1concat' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  name: 'fc6' "
      "  type: INNER_PRODUCT "
      "  inner_product_param { "
      "    num_output: 4096 "
      "    bias_term: false "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'norm1' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'relu6' "
      "  type: RELU "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'drop6' "
      "  type: DROPOUT "
      "  dropout_param { "
      "    dropout_ratio: 0.2 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'loss' "
      "  type: INFOGAIN_LOSS "
      "  infogain_loss_param { "
      "    source: '/my/infogain/matrix' "
      "  } "
      "  bottom: 'fc6' "
      "  bottom: 'label' "
      "} "
      "layers { "
      "  name: 'accuracy' "
      "  type: ACCURACY "
      "} "
      "layers { "
      "  name: 'bnll' "
      "  type: BNLL "
      "} "
      "layers { "
      "  name: 'euclidean_loss' "
      "  type: EUCLIDEAN_LOSS "
      "} "
      "layers { "
      "  name: 'flatten' "
      "  type: FLATTEN "
      "} "
      "layers { "
      "  name: 'hdf5_output' "
      "  type: HDF5_OUTPUT "
      "  hdf5_output_param { "
      "    file_name: '/my/hdf5/output/file' "
      "  } "
      "} "
      "layers { "
      "  name: 'im2col' "
      "  type: IM2COL "
      "} "
      "layers { "
      "  name: 'images' "
      "  type: IMAGE_DATA "
      "} "
      "layers { "
      "  name: 'multinomial_logistic_loss' "
      "  type: MULTINOMIAL_LOGISTIC_LOSS "
      "} "
      "layers { "
      "  name: 'sigmoid' "
      "  type: SIGMOID "
      "} "
      "layers { "
      "  name: 'softmax' "
      "  type: SOFTMAX "
      "} "
      "layers { "
      "  name: 'split' "
      "  type: SPLIT "
      "} "
      "layers { "
      "  name: 'tanh' "
      "  type: TANH "
      "} ";
  this->RunV0UpgradeTest(input_proto, expected_output_proto);
}

TEST_F(NetUpgradeTest, TestImageNet) {
  const string& v0_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  layer { "
      "    name: 'data' "
      "    type: 'data' "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    meanfile: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "    batchsize: 256 "
      "    cropsize: 227 "
      "    mirror: true "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv1' "
      "    type: 'conv' "
      "    num_output: 96 "
      "    kernelsize: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu1' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool1' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm1' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad2' "
      "    type: 'padding' "
      "    pad: 2 "
      "  } "
      "  bottom: 'norm1' "
      "  top: 'pad2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv2' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 5 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu2' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool2' "
      "    type: 'pool' "
      "    pool: MAX "
      "    kernelsize: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'pool2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'norm2' "
      "    type: 'lrn' "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool2' "
      "  top: 'norm2' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad3' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'norm2' "
      "  top: 'pad3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv3' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu3' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad4' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'pad4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv4' "
      "    type: 'conv' "
      "    num_output: 384 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu4' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pad5' "
      "    type: 'padding' "
      "    pad: 1 "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'pad5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'conv5' "
      "    type: 'conv' "
      "    num_output: 256 "
      "    group: 2 "
      "    kernelsize: 3 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pad5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu5' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'pool5' "
      "    type: 'pool' "
      "    kernelsize: 3 "
      "    pool: MAX "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'pool5' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc6' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'pool5' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu6' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop6' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc7' "
      "    type: 'innerproduct' "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'relu7' "
      "    type: 'relu' "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'drop7' "
      "    type: 'dropout' "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'fc8' "
      "    type: 'innerproduct' "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "    blobs_lr: 1. "
      "    blobs_lr: 2. "
      "    weight_decay: 1. "
      "    weight_decay: 0. "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  layer { "
      "    name: 'loss' "
      "    type: 'softmax_loss' "
      "  } "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  const string& expected_v1_proto =
      "name: 'CaffeNet' "
      "layers { "
      "  name: 'data' "
      "  type: DATA "
      "  data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "  } "
      "  transform_param { "
      "    crop_size: 227 "
      "    mirror: true "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layers { "
      "  name: 'conv1' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 96 "
      "    kernel_size: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  name: 'relu1' "
      "  type: RELU "
      "  bottom: 'conv1' "
      "  top: 'conv1' "
      "} "
      "layers { "
      "  name: 'pool1' "
      "  type: POOLING "
      "  pooling_param { "
      "    pool: MAX "
      "    kernel_size: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1' "
      "} "
      "layers { "
      "  name: 'norm1' "
      "  type: LRN "
      "  lrn_param { "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1' "
      "  top: 'norm1' "
      "} "
      "layers { "
      "  name: 'conv2' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 256 "
      "    group: 2 "
      "    kernel_size: 5 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'norm1' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  name: 'relu2' "
      "  type: RELU "
      "  bottom: 'conv2' "
      "  top: 'conv2' "
      "} "
      "layers { "
      "  name: 'pool2' "
      "  type: POOLING "
      "  pooling_param { "
      "    pool: MAX "
      "    kernel_size: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'pool2' "
      "} "
      "layers { "
      "  name: 'norm2' "
      "  type: LRN "
      "  lrn_param { "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool2' "
      "  top: 'norm2' "
      "} "
      "layers { "
      "  name: 'conv3' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 384 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'norm2' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  name: 'relu3' "
      "  type: RELU "
      "  bottom: 'conv3' "
      "  top: 'conv3' "
      "} "
      "layers { "
      "  name: 'conv4' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 384 "
      "    group: 2 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'conv3' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  name: 'relu4' "
      "  type: RELU "
      "  bottom: 'conv4' "
      "  top: 'conv4' "
      "} "
      "layers { "
      "  name: 'conv5' "
      "  type: CONVOLUTION "
      "  convolution_param { "
      "    num_output: 256 "
      "    group: 2 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'conv4' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  name: 'relu5' "
      "  type: RELU "
      "  bottom: 'conv5' "
      "  top: 'conv5' "
      "} "
      "layers { "
      "  name: 'pool5' "
      "  type: POOLING "
      "  pooling_param { "
      "    kernel_size: 3 "
      "    pool: MAX "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'pool5' "
      "} "
      "layers { "
      "  name: 'fc6' "
      "  type: INNER_PRODUCT "
      "  inner_product_param { "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'pool5' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'relu6' "
      "  type: RELU "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'drop6' "
      "  type: DROPOUT "
      "  dropout_param { "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layers { "
      "  name: 'fc7' "
      "  type: INNER_PRODUCT "
      "  inner_product_param { "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'fc6' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  name: 'relu7' "
      "  type: RELU "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  name: 'drop7' "
      "  type: DROPOUT "
      "  dropout_param { "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layers { "
      "  name: 'fc8' "
      "  type: INNER_PRODUCT "
      "  inner_product_param { "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "  } "
      "  blobs_lr: 1. "
      "  blobs_lr: 2. "
      "  weight_decay: 1. "
      "  weight_decay: 0. "
      "  bottom: 'fc7' "
      "  top: 'fc8' "
      "} "
      "layers { "
      "  name: 'loss' "
      "  type: SOFTMAX_LOSS "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunV0UpgradeTest(v0_proto, expected_v1_proto);

  const string& expected_v2_proto =
      "name: 'CaffeNet' "
      "layer { "
      "  name: 'data' "
      "  type: 'Data' "
      "  data_param { "
      "    source: '/home/jiayq/Data/ILSVRC12/train-leveldb' "
      "    batch_size: 256 "
      "  } "
      "  transform_param { "
      "    crop_size: 227 "
      "    mirror: true "
      "    mean_file: '/home/jiayq/Data/ILSVRC12/image_mean.binaryproto' "
      "  } "
      "  top: 'data' "
      "  top: 'label' "
      "} "
      "layer { "
      "  name: 'conv1' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 96 "
      "    kernel_size: 11 "
      "    stride: 4 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'data' "
      "  top: 'conv1' "
      "} "
      "layer { "
      "  name: 'relu1' "
      "  type: 'ReLU' "
      "  bottom: 'conv1' "
      "  top: 'conv1' "
      "} "
      "layer { "
      "  name: 'pool1' "
      "  type: 'Pooling' "
      "  pooling_param { "
      "    pool: MAX "
      "    kernel_size: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv1' "
      "  top: 'pool1' "
      "} "
      "layer { "
      "  name: 'norm1' "
      "  type: 'LRN' "
      "  lrn_param { "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool1' "
      "  top: 'norm1' "
      "} "
      "layer { "
      "  name: 'conv2' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 256 "
      "    group: 2 "
      "    kernel_size: 5 "
      "    pad: 2 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'norm1' "
      "  top: 'conv2' "
      "} "
      "layer { "
      "  name: 'relu2' "
      "  type: 'ReLU' "
      "  bottom: 'conv2' "
      "  top: 'conv2' "
      "} "
      "layer { "
      "  name: 'pool2' "
      "  type: 'Pooling' "
      "  pooling_param { "
      "    pool: MAX "
      "    kernel_size: 3 "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv2' "
      "  top: 'pool2' "
      "} "
      "layer { "
      "  name: 'norm2' "
      "  type: 'LRN' "
      "  lrn_param { "
      "    local_size: 5 "
      "    alpha: 0.0001 "
      "    beta: 0.75 "
      "  } "
      "  bottom: 'pool2' "
      "  top: 'norm2' "
      "} "
      "layer { "
      "  name: 'conv3' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 384 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'norm2' "
      "  top: 'conv3' "
      "} "
      "layer { "
      "  name: 'relu3' "
      "  type: 'ReLU' "
      "  bottom: 'conv3' "
      "  top: 'conv3' "
      "} "
      "layer { "
      "  name: 'conv4' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 384 "
      "    group: 2 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'conv3' "
      "  top: 'conv4' "
      "} "
      "layer { "
      "  name: 'relu4' "
      "  type: 'ReLU' "
      "  bottom: 'conv4' "
      "  top: 'conv4' "
      "} "
      "layer { "
      "  name: 'conv5' "
      "  type: 'Convolution' "
      "  convolution_param { "
      "    num_output: 256 "
      "    group: 2 "
      "    kernel_size: 3 "
      "    pad: 1 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'conv4' "
      "  top: 'conv5' "
      "} "
      "layer { "
      "  name: 'relu5' "
      "  type: 'ReLU' "
      "  bottom: 'conv5' "
      "  top: 'conv5' "
      "} "
      "layer { "
      "  name: 'pool5' "
      "  type: 'Pooling' "
      "  pooling_param { "
      "    kernel_size: 3 "
      "    pool: MAX "
      "    stride: 2 "
      "  } "
      "  bottom: 'conv5' "
      "  top: 'pool5' "
      "} "
      "layer { "
      "  name: 'fc6' "
      "  type: 'InnerProduct' "
      "  inner_product_param { "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'pool5' "
      "  top: 'fc6' "
      "} "
      "layer { "
      "  name: 'relu6' "
      "  type: 'ReLU' "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layer { "
      "  name: 'drop6' "
      "  type: 'Dropout' "
      "  dropout_param { "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc6' "
      "} "
      "layer { "
      "  name: 'fc7' "
      "  type: 'InnerProduct' "
      "  inner_product_param { "
      "    num_output: 4096 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.005 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 1. "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'fc6' "
      "  top: 'fc7' "
      "} "
      "layer { "
      "  name: 'relu7' "
      "  type: 'ReLU' "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layer { "
      "  name: 'drop7' "
      "  type: 'Dropout' "
      "  dropout_param { "
      "    dropout_ratio: 0.5 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc7' "
      "} "
      "layer { "
      "  name: 'fc8' "
      "  type: 'InnerProduct' "
      "  inner_product_param { "
      "    num_output: 1000 "
      "    weight_filler { "
      "      type: 'gaussian' "
      "      std: 0.01 "
      "    } "
      "    bias_filler { "
      "      type: 'constant' "
      "      value: 0 "
      "    } "
      "  } "
      "  param { "
      "    lr_mult: 1 "
      "    decay_mult: 1 "
      "  } "
      "  param { "
      "    lr_mult: 2 "
      "    decay_mult: 0 "
      "  } "
      "  bottom: 'fc7' "
      "  top: 'fc8' "
      "} "
      "layer { "
      "  name: 'loss' "
      "  type: 'SoftmaxWithLoss' "
      "  bottom: 'fc8' "
      "  bottom: 'label' "
      "} ";
  this->RunV1UpgradeTest(expected_v1_proto, expected_v2_proto);
}  // NOLINT(readability/fn_size)

TEST_F(NetUpgradeTest, TestUpgradeV1LayerType) {
  LayerParameter layer_param;
  shared_ptr<Layer<float> > layer;
  for (int i = 0; i < V1LayerParameter_LayerType_LayerType_ARRAYSIZE; ++i) {
    ASSERT_TRUE(V1LayerParameter_LayerType_IsValid(i));
    V1LayerParameter_LayerType v1_type = V1LayerParameter_LayerType(i);
    string v2_layer_type(UpgradeV1LayerType(v1_type));
    if (v2_layer_type == "") {
      EXPECT_EQ(V1LayerParameter_LayerType_NONE, v1_type);
      continue;  // Empty string isn't actually a valid layer type.
    }
    layer_param.set_type(v2_layer_type);
    // Data layers expect a DB
    if (v2_layer_type == "Data") {
      #ifdef USE_LEVELDB
      string tmp;
      MakeTempDir(&tmp);
      boost::scoped_ptr<db::DB> db(db::GetDB(DataParameter_DB_LEVELDB));
      db->Open(tmp, db::NEW);
      db->Close();
      layer_param.mutable_data_param()->set_source(tmp);
      #else
      continue;
      #endif  // USE_LEVELDB
    }
    #ifndef USE_OPENCV
    if (v2_layer_type == "ImageData" || v2_layer_type == "WindowData") {
     continue;
    }
    #endif  // !USE_OPENCV
    layer = LayerRegistry<float>::CreateLayer(layer_param);
    EXPECT_EQ(v2_layer_type, layer->type());
  }
}

class SolverTypeUpgradeTest : public ::testing::Test {
 protected:
  void RunSolverTypeUpgradeTest(
      const string& input_param_string, const string& output_param_string) {
    // Test upgrading old solver_type field (enum) to new type field (string)
    SolverParameter input_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        input_param_string, &input_param));
    SolverParameter expected_output_param;
    CHECK(google::protobuf::TextFormat::ParseFromString(
        output_param_string, &expected_output_param));
    SolverParameter actual_output_param = input_param;
    UpgradeSolverType(&actual_output_param);
    EXPECT_EQ(expected_output_param.DebugString(),
        actual_output_param.DebugString());
  }
};

TEST_F(SolverTypeUpgradeTest, TestSimple) {
  const char* old_type_vec[6] = { "SGD", "ADAGRAD", "NESTEROV", "RMSPROP",
      "ADADELTA", "ADAM" };
  const char* new_type_vec[6] = { "SGD", "AdaGrad", "Nesterov", "RMSProp",
      "AdaDelta", "Adam" };
  for (int i = 0; i < 6; ++i) {
    const string& input_proto =
        "net: 'examples/mnist/lenet_train_test.prototxt' "
        "weights: 'examples/mnist/lenet_train_test1.caffemodel' "
        "weights: 'examples/mnist/lenet_train_test2.caffemodel' "
        "test_iter: 100 "
        "test_interval: 500 "
        "base_lr: 0.01 "
        "momentum: 0.0 "
        "weight_decay: 0.0005 "
        "lr_policy: 'inv' "
        "gamma: 0.0001 "
        "power: 0.75 "
        "display: 100 "
        "max_iter: 10000 "
        "snapshot: 5000 "
        "snapshot_prefix: 'examples/mnist/lenet_rmsprop' "
        "solver_mode: GPU "
        "solver_type: " + std::string(old_type_vec[i]) + " ";
    const string& expected_output_proto =
        "net: 'examples/mnist/lenet_train_test.prototxt' "
        "weights: 'examples/mnist/lenet_train_test1.caffemodel' "
        "weights: 'examples/mnist/lenet_train_test2.caffemodel' "
        "test_iter: 100 "
        "test_interval: 500 "
        "base_lr: 0.01 "
        "momentum: 0.0 "
        "weight_decay: 0.0005 "
        "lr_policy: 'inv' "
        "gamma: 0.0001 "
        "power: 0.75 "
        "display: 100 "
        "max_iter: 10000 "
        "snapshot: 5000 "
        "snapshot_prefix: 'examples/mnist/lenet_rmsprop' "
        "solver_mode: GPU "
        "type: '" + std::string(new_type_vec[i]) + "' ";
    this->RunSolverTypeUpgradeTest(input_proto, expected_output_proto);
  }
}

}  // NOLINT(readability/fn_size)  // namespace caffe
