我正在尝试在Caffe中创建一个单一的多类别和多标签网络配置。
例如,对狗进行分类:狗是小型还是大型?(类别)狗是什么颜色?(类别)狗是否带有项圈?(标签)
使用Caffe实现这种分类是否可行?正确的做法是什么?
我只是想了解实际操作的方法。在创建了两个包含所有图像标签的文本文件(一个用于训练,一个用于验证)之后,例如:
/train/img/1.png 0 4 18/train/img/2.png 1 7 17 33/train/img/3.png 0 4 17
运行Python脚本:
import h5py, osimport caffeimport numpy as npSIZE = 227 # 所有图像的固定大小with open( 'train.txt', 'r' ) as T : lines = T.readlines()# 如果内存不足,可以将数据分成多个批次并生成多个独立的h5文件X = np.zeros( (len(lines), 3, SIZE, SIZE), dtype='f4' ) y = np.zeros( (len(lines),1), dtype='f4' )for i,l in enumerate(lines): sp = l.split(' ') img = caffe.io.load_image( sp[0] ) img = caffe.io.resize( img, (SIZE, SIZE, 3) ) # 调整到固定大小 # 你可以在这里应用其他输入转换... # 请注意,转换应将图像从size-by-size-by-3转换为3-by-size-by-size # 例如 transposed_img = img.transpose((2,0,1))[::-1,:,:] # RGB->BGR X[i] = transposed_img y[i] = float(sp[1])with h5py.File('train.h5','w') as H: H.create_dataset( 'X', data=X ) # 注意数据集命名为X! H.create_dataset( 'y', data=y ) # 注意数据集命名为y!with open('train_h5_list.txt','w') as L: L.write( 'train.h5' ) # 列出你将要使用的所有h5文件
并创建train.h5和val.h5(X数据集包含图像,而Y包含标签吗?)。
将我的网络输入层从以下内容替换:
layers { name: "data" type: DATA top: "data" top: "label" data_param { source: "/home/gal/digits/digits/jobs/20181010-191058-21ab/train_db" backend: LMDB batch_size: 64 } transform_param { crop_size: 227 mean_file: "/home/gal/digits/digits/jobs/20181010-191058-21ab/mean.binaryproto" mirror: true } include: { phase: TRAIN } } layers { name: "data" type: DATA top: "data" top: "label" data_param { source: "/home/gal/digits/digits/jobs/20181010-191058-21ab/val_db" backend: LMDB batch_size: 64 } transform_param { crop_size: 227 mean_file: "/home/gal/digits/digits/jobs/20181010-191058-21ab/mean.binaryproto" mirror: true } include: { phase: TEST } }
替换为
layer { type: "HDF5Data" top: "X" # 与create_dataset中的名称相同! top: "y" hdf5_data_param { source: "train_h5_list.txt" # 不要直接给出h5文件,而是给出列表。 batch_size: 32 } include { phase:TRAIN }}layer { type: "HDF5Data" top: "X" # 与create_dataset中的名称相同! top: "y" hdf5_data_param { source: "val_h5_list.txt" # 不要直接给出h5文件,而是给出列表。 batch_size: 32 } include { phase:TEST }}
我猜HDF5不需要mean.binaryproto文件?
接下来,输出层应该如何更改以输出多个标签的概率?我猜我需要使用交叉熵层而不是softmax层?这是当前的输出层:
layers { bottom: "prob" bottom: "label" top: "loss" name: "loss" type: SOFTMAX_LOSS loss_weight: 1}layers { name: "accuracy" type: ACCURACY bottom: "prob" bottom: "label" top: "accuracy" include: { phase: TEST }}
回答:
均值减法
虽然lmdb输入数据层能够为你处理各种输入转换,但"HDF5Data"
层不支持此功能。
因此,你必须在创建hdf5文件时处理所有输入转换(特别是均值减法)。
查看你的代码中标有
# you may apply other input transformations here...
多个标签
尽管你的.txt文件为每张图像列出了多个标签,但你只将第一个标签保存到hdf5文件中。如果你想使用这些标签,你必须将它们输入到网络中。
你的示例中立即出现的问题是你没有为每个训练图像固定数量的标签——为什么?这意味着什么?
假设你为每张图像有三个标签(在.txt文件中):
< filename > < dog size > < dog color > < has collar >
那么你可以在你的hdf5中使用y_size
,y_color
和y_collar
(而不是单一的y
)。
y_size[i] = float(spl[1])y_color[i] = float(spl[2])y_collar[i] = float(spl[3])
你的输入数据层将相应地有更多的"top"
:
layer { type: "HDF5Data" top: "X" # 与create_dataset中的名称相同! top: "y_size" top: "y_color" top: "y_collar" hdf5_data_param { source: "train_h5_list.txt" # 不要直接给出h5文件,而是给出列表。 batch_size: 32 } include { phase:TRAIN }}
预测
目前你的网络只能预测一个标签(带有top: "prob"
的层)。你需要你的网络预测所有三个标签,因此你需要添加计算top: "prob_size"
,top: "prob_color"
和top: "prob_collar"
的层(每个"prob_*"
使用不同的层)。
一旦你为每个标签有了预测,你就需要一个损失(同样,每个标签一个损失)。