caffe学习笔记13(补充)--关于ContrastiveLossLayer层

之前写了一系列caffe官网中关于caffe python使用例子的翻译。在最后一个例子:http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/siamese/mnist_siamese.ipynb中,将mnist降维到2维并将其可视化。我当时按例子跑了下代码并且大致翻译了下:http://blog.csdn.net/thystar/article/details/50715835 , 这几天看deepid忽然发现这个东西我没看到重点,在这个例子中,训练使用的prototxt和mnist是不一样的,其网络结构如下:(有些地方省略)

name: "mnist_siamese_train_test"
layer {
  name: "pair_data" # 图像是成对输入的
  type: "Data"
  top: "pair_data"
  top: "sim"  # 是一个二进制的标签,说明两幅图像是否属于同一类
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/siamese/mnist_siamese_train_leveldb"
    batch_size: 64
  }
}

layer {
  name: "slice_pair"
  type: "Slice"
  bottom: "pair_data"
  top: "data"
  top: "data_p"
  slice_param {
    slice_dim: 1
    slice_point: 1
  }
}
layer {
  ...... conv和pooling层
}
layer {
  ......全连接层
}
layer {
  name: "feat"
  type: "InnerProduct"
  bottom: "ip2"
  top: "feat"  #第一幅图提取的特征。
  param {
    name: "feat_w"
    lr_mult: 1
  }
  param {
    name: "feat_b"
    lr_mult: 2
  }
  inner_product_param {
    num_output: 2  #特征维度为2
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  ...data_p的卷积层和全连接层
}
layer {
  name: "feat_p"
  type: "InnerProduct"
  bottom: "ip2_p"
  top: "feat_p"
  param {
    name: "feat_w"
    lr_mult: 1
  }
  param {
    name: "feat_b"
    lr_mult: 2
  }
  inner_product_param {
    num_output: 2
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "loss"
  type: "ContrastiveLoss"
  bottom: "feat"
  bottom: "feat_p"
  bottom: "sim"
  top: "loss"
  contrastive_loss_param {
    margin: 1
  }
}

这里,手画了个渣图大概说明下这个网络结构:


这里网络的第二层:

    layer {
      name: "slice_pair"
      type: "Slice"
      bottom: "pair_data"
      top: "data"
      top: "data_p"
      slice_param {
        slice_dim: 1
        slice_point: 1
      }
    }
将两幅图分开,分别做卷积并提取特征。

在最后一层使用contrastiveloss损失函数:其输入是两个特征和标签。

    layer {
        name: "loss"
        type: "ContrastiveLoss"
        contrastive_loss_param {
            margin: 1.0
        }
        bottom: "feat"
        bottom: "feat_p"
        bottom: "sim"
        top: "loss"
    }


大致解释下这个损失函数cpp代码

#include <algorithm>
#include <vector>

#include "caffe/layers/contrastive_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void ContrastiveLossLayer<Dtype>::LayerSetUp(//装载该层数据
  const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());
  CHECK_EQ(bottom[0]->height(), 1);
  CHECK_EQ(bottom[0]->width(), 1); //bottom[0]为第一个特征
  CHECK_EQ(bottom[1]->height(), 1);
  CHECK_EQ(bottom[1]->width(), 1);//bottom[1]为第二个特征
  CHECK_EQ(bottom[2]->channels(), 1);
  CHECK_EQ(bottom[2]->height(), 1);
  CHECK_EQ(bottom[2]->width(), 1);//bottom[2]为标签
  diff_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);
  diff_sq_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);
  dist_sq_.Reshape(bottom[0]->num(), 1, 1, 1);
  // vector of ones used to sum along channels
  summer_vec_.Reshape(bottom[0]->channels(), 1, 1, 1);
  for (int i = 0; i < bottom[0]->channels(); ++i)
    summer_vec_.mutable_cpu_data()[i] = Dtype(1);
}

template <typename Dtype>
void ContrastiveLossLayer<Dtype>::Forward_cpu(//前向传播过程
    const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  int count = bottom[0]->count();
  caffe_sub(
      count,
      bottom[0]->cpu_data(),  // a 第一个特征
      bottom[1]->cpu_data(),  // b 第二个特征
      diff_.mutable_cpu_data());  // a_i-b_i 两个特征的对应元素相减
  const int channels = bottom[0]->channels();
  Dtype margin = this->layer_param_.contrastive_loss_param().margin(); //读取prototxt中设置好的margin, 一般为1
  bool legacy_version =
      this->layer_param_.contrastive_loss_param().legacy_version();
  Dtype loss(0.0);
  for (int i = 0; i < bottom[0]->num(); ++i) {
    dist_sq_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,
        diff_.cpu_data() + (i*channels), diff_.cpu_data() + (i*channels));
    if (static_cast<int>(bottom[2]->cpu_data()[i])) {  // 如果sim标签为1,说明为同类
      loss += dist_sq_.cpu_data()[i];//损失为特征的距离,这里表示为dist
    } else {  // sim标签为0
      if (legacy_version) {//legacy_version不知道是什么估计对于不同类的情况由不同的函数形式。
        loss += std::max(margin - dist_sq_.cpu_data()[i], Dtype(0.0));//这是,loss为0和m-dist的最大值,这个表示,如果dist大于1,则说明这个两个特征距离足够源,loss=0, 如果dist小于1,则说明两个特征距离太近,需要算入loss中
      } else {
        Dtype dist = std::max<Dtype>(margin - sqrt(dist_sq_.cpu_data()[i]),
          Dtype(0.0));
        loss += dist*dist;
      }
    }
  }
  loss = loss / static_cast<Dtype>(bottom[0]->num()) / Dtype(2);
  top[0]->mutable_cpu_data()[0] = loss;
}

//反向传播过程这里不解释了。


#ifdef CPU_ONLY
STUB_GPU(ContrastiveLossLayer);
#endif

INSTANTIATE_CLASS(ContrastiveLossLayer);
REGISTER_LAYER_CLASS(ContrastiveLoss);

}  // namespace caffe


如果文章中有问题希望阅读者帮忙纠正!


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值