在 Caffe 中训练孪生网络
Training Siamese Network in Caffe
我正在尝试建立一个孪生网络来比较两个图像样本。我遵循了 caffe.
中的 MNIST 示例
我想做的不是使用全连接层,而是全卷积连体网络。我这样做只是为了学习和理解深度学习。
我创建了自己的自定义网络,它采用 32 x 32
大小的 RGB 图像补丁并运行在附加的 Prototxt 文件中定义的网络的多个层。请注意,为简短起见,我删除了网络的另一半,它只是一个镜像。此外,我正在尝试学习如何在卷积层中使用填充,因此我也在此处的示例中进行了尝试。你会看到我在 conv3
层上填充了 1。
label1
和 label2
相同所以我使用静默层来屏蔽 label2
layer {
name: "data1"
type: "Data"
top: "data1"
top: "label"
include {
phase: TRAIN
}
data_param {
source: "Desktop/training/lmdb/train_1"
batch_size: 512
backend: LMDB
}
}
layer {
name: "data2"
type: "Data"
top: "data2"
top: "label2"
include {
phase: TRAIN
}
data_param {
source: "/Desktop/training/lmdb/train_2"
batch_size: 512
backend: LMDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data1"
top: "conv1"
param {
name: "conv1_w"
lr_mult: 1
}
param {
name: "conv1_b"
lr_mult: 2
}
convolution_param {
num_output: 32
pad: 0
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "conv1"
top: "conv1"
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "norm1"
type: "LRN"
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "norm1"
top: "conv2"
param {
name: "conv2_w"
lr_mult: 1
}
param {
name: "conv2_b"
lr_mult: 2
}
convolution_param {
num_output: 64
pad: 0
kernel_size: 1
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu2"
type: "ReLU"
bottom: "conv2"
top: "conv2"
}
layer {
name: "conv3"
type: "Convolution"
bottom: "conv2"
top: "conv3"
param {
name: "conv3_w"
lr_mult: 1
}
param {
name: "conv3_b"
lr_mult: 2
}
convolution_param {
num_output: 128
pad: 1
kernel_size: 3
stride: 2
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu3"
type: "ReLU"
bottom: "conv3"
top: "conv3"
}
# layer {
# name: "dropout"
# type: "Dropout"
# bottom: "conv3"
# top: "dropout"
# dropout_param {
# dropout_ratio: 0.5
# }
# }
layer {
name: "conv4"
type: "Convolution"
bottom: "conv3"
top: "conv4"
param {
name: "conv4_w"
lr_mult: 1
}
param {
name: "conv4_b"
lr_mult: 2
}
convolution_param {
num_output: 1
pad: 0
kernel_size: 1
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv4"
top: "pool2"
pooling_param {
pool: AVE
kernel_size: 7
stride: 1
}
}
#################
layer {
name: "loss"
type: "ContrastiveLoss"
bottom: "pool2"
bottom: "pool2_p"
bottom: "label"
top: "loss"
contrastive_loss_param {
margin: 1
}
include {
phase: TRAIN
}
}
有几件事让我感到困惑:
- 在卷积层上加padding是安全的还是会产生破坏性的影响?
- 我在siamaese network上读到的一些论文中,他们在全连接层之后使用了L2-Normalization。我没有在 caffe 上找到任何 L2-Normalization 层,但我支持 LRN 可以通过设置
alpha = 1
和 beta = 0.5
来做同样的事情。
- 在我的网络中,我只是平均汇集了
conv4
层,并使用它来计算使用 ContrastiveLoss 的损失。那行得通吗,或者我需要规范化 conv4
的输出,或者我在这里做错了什么。
- 卷积层的输出可以直接输入损失函数吗?
非常感谢您帮助我指明正确的方向。此外,我正在使用一些我无法发布的单元格的大约 50K 补丁的样本图像,因为它是分类的。补丁大小约为 25x25
,所以我将大小调整为 32x32
是的,向转换层添加填充是安全的。我认为您可以按照文档中描述的方式使用 LRN 层进行 L2 规范化。是的,CNN 层的输出可以直接用于损失函数,这没什么问题,它只是一个 blob。在全卷积网络中,情况总是如此。至少在理论上,你的输出不需要限制对比损失的工作,因为它是基于保证金的损失。通常,将对比损失更改为具有 softmax 损失的二元分类问题通常可行,并且没有归一化问题。
我正在尝试建立一个孪生网络来比较两个图像样本。我遵循了 caffe.
中的 MNIST 示例我想做的不是使用全连接层,而是全卷积连体网络。我这样做只是为了学习和理解深度学习。
我创建了自己的自定义网络,它采用 32 x 32
大小的 RGB 图像补丁并运行在附加的 Prototxt 文件中定义的网络的多个层。请注意,为简短起见,我删除了网络的另一半,它只是一个镜像。此外,我正在尝试学习如何在卷积层中使用填充,因此我也在此处的示例中进行了尝试。你会看到我在 conv3
层上填充了 1。
label1
和 label2
相同所以我使用静默层来屏蔽 label2
layer {
name: "data1"
type: "Data"
top: "data1"
top: "label"
include {
phase: TRAIN
}
data_param {
source: "Desktop/training/lmdb/train_1"
batch_size: 512
backend: LMDB
}
}
layer {
name: "data2"
type: "Data"
top: "data2"
top: "label2"
include {
phase: TRAIN
}
data_param {
source: "/Desktop/training/lmdb/train_2"
batch_size: 512
backend: LMDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data1"
top: "conv1"
param {
name: "conv1_w"
lr_mult: 1
}
param {
name: "conv1_b"
lr_mult: 2
}
convolution_param {
num_output: 32
pad: 0
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "conv1"
top: "conv1"
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "norm1"
type: "LRN"
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "norm1"
top: "conv2"
param {
name: "conv2_w"
lr_mult: 1
}
param {
name: "conv2_b"
lr_mult: 2
}
convolution_param {
num_output: 64
pad: 0
kernel_size: 1
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu2"
type: "ReLU"
bottom: "conv2"
top: "conv2"
}
layer {
name: "conv3"
type: "Convolution"
bottom: "conv2"
top: "conv3"
param {
name: "conv3_w"
lr_mult: 1
}
param {
name: "conv3_b"
lr_mult: 2
}
convolution_param {
num_output: 128
pad: 1
kernel_size: 3
stride: 2
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "relu3"
type: "ReLU"
bottom: "conv3"
top: "conv3"
}
# layer {
# name: "dropout"
# type: "Dropout"
# bottom: "conv3"
# top: "dropout"
# dropout_param {
# dropout_ratio: 0.5
# }
# }
layer {
name: "conv4"
type: "Convolution"
bottom: "conv3"
top: "conv4"
param {
name: "conv4_w"
lr_mult: 1
}
param {
name: "conv4_b"
lr_mult: 2
}
convolution_param {
num_output: 1
pad: 0
kernel_size: 1
stride: 1
weight_filler {
type: "xavier"
std: 0.03
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv4"
top: "pool2"
pooling_param {
pool: AVE
kernel_size: 7
stride: 1
}
}
#################
layer {
name: "loss"
type: "ContrastiveLoss"
bottom: "pool2"
bottom: "pool2_p"
bottom: "label"
top: "loss"
contrastive_loss_param {
margin: 1
}
include {
phase: TRAIN
}
}
有几件事让我感到困惑:
- 在卷积层上加padding是安全的还是会产生破坏性的影响?
- 我在siamaese network上读到的一些论文中,他们在全连接层之后使用了L2-Normalization。我没有在 caffe 上找到任何 L2-Normalization 层,但我支持 LRN 可以通过设置
alpha = 1
和beta = 0.5
来做同样的事情。 - 在我的网络中,我只是平均汇集了
conv4
层,并使用它来计算使用 ContrastiveLoss 的损失。那行得通吗,或者我需要规范化conv4
的输出,或者我在这里做错了什么。 - 卷积层的输出可以直接输入损失函数吗?
非常感谢您帮助我指明正确的方向。此外,我正在使用一些我无法发布的单元格的大约 50K 补丁的样本图像,因为它是分类的。补丁大小约为 25x25
,所以我将大小调整为 32x32
是的,向转换层添加填充是安全的。我认为您可以按照文档中描述的方式使用 LRN 层进行 L2 规范化。是的,CNN 层的输出可以直接用于损失函数,这没什么问题,它只是一个 blob。在全卷积网络中,情况总是如此。至少在理论上,你的输出不需要限制对比损失的工作,因为它是基于保证金的损失。通常,将对比损失更改为具有 softmax 损失的二元分类问题通常可行,并且没有归一化问题。