如何在HDF5格式中提供多标签数据给Caffe?

10

我想使用caffe和一个向量标签,而不是整数。我查看了一些答案,似乎HDF5是更好的方式。但是,我遇到了以下错误:

accuracy_layer.cpp:34] Check failed: outer_num_ * inner_num_ == bottom[1]->count() (50 vs. 200) 标签数量必须与预测数量匹配;例如,如果标签轴==1且预测形状为(N,C,H,W),则标签计数(标签数量)必须为N*H*W,其中整数值在{0,1,…,C-1}中。

HDF5创建如下:

f = h5py.File('train.h5', 'w')
f.create_dataset('data', (1200, 128), dtype='f8')
f.create_dataset('label', (1200, 4), dtype='f4')

我的网络是由以下生成:

def net(hdf5, batch_size):
    n = caffe.NetSpec()
    n.data, n.label = L.HDF5Data(batch_size=batch_size, source=hdf5, ntop=2)
    n.ip1 = L.InnerProduct(n.data, num_output=50, weight_filler=dict(type='xavier'))
    n.relu1 = L.ReLU(n.ip1, in_place=True)
    n.ip2 = L.InnerProduct(n.relu1, num_output=50, weight_filler=dict(type='xavier'))
    n.relu2 = L.ReLU(n.ip2, in_place=True)
    n.ip3 = L.InnerProduct(n.relu1, num_output=4, weight_filler=dict(type='xavier'))
    n.accuracy = L.Accuracy(n.ip3, n.label)
    n.loss = L.SoftmaxWithLoss(n.ip3, n.label)
    return n.to_proto()

with open(PROJECT_HOME + 'auto_train.prototxt', 'w') as f:
f.write(str(net('/home/romulus/code/project/train.h5list', 50)))

with open(PROJECT_HOME + 'auto_test.prototxt', 'w') as f:
f.write(str(net('/home/romulus/code/project/test.h5list', 20)))

似乎我应该增加标签的数量并将它们放入整数中而不是数组,但如果我这样做,Caffe 就会抱怨数据和标签的数量不相等,然后程序就会出错。

那么,正确的多标签数据格式是什么呢?

另外,我很想知道为什么没有人简单地写出 HDF5 如何映射到 Caffe blobs 的数据格式呢?


“data” 应该也是 “f4” 类型的,对吗? - Shai
更改为f4不会改变错误。 - Romulus Urakagi Ts'ai
1
可能是一个有价值的资源:https://dev59.com/tlwY5IYBdhLWcg3wAj09 - Aidan Gomez
谢谢,那个损失层正是我需要的。 - Romulus Urakagi Ts'ai
2个回答

23

回答此问题的标题:

HDF5文件应在根目录中有两个数据集,分别命名为"data"和"label"。 形状为(数据量维度)。 我只使用一维数据,所以不确定通道宽度高度的顺序。也许这没有关系。dtype应为float或double。

使用h5py创建训练集的示例代码如下:

import h5py, os
import numpy as np

f = h5py.File('train.h5', 'w')
# 1200 data, each is a 128-dim vector
f.create_dataset('data', (1200, 128), dtype='f8')
# Data's labels, each is a 4-dim vector
f.create_dataset('label', (1200, 4), dtype='f4')
# Fill in something with fixed pattern # Regularize values to between 0 and 1, or SigmoidCrossEntropyLoss will not work for i in range(1200): a = np.empty(128) if i % 4 == 0: for j in range(128): a[j] = j / 128.0; l = [1,0,0,0] elif i % 4 == 1: for j in range(128): a[j] = (128 - j) / 128.0; l = [1,0,1,0] elif i % 4 == 2: for j in range(128): a[j] = (j % 6) / 128.0; l = [0,1,1,0] elif i % 4 == 3: for j in range(128): a[j] = (j % 4) * 4 / 128.0; l = [1,0,1,1] f['data'][i] = a f['label'][i] = l
f.close()

另外,精度层不需要,只需将其删除即可。下一个问题是损失层。由于SoftmaxWithLoss仅具有一个输出(最大值维度的索引),因此它不能用于多标签问题。感谢Adian和Shai,我发现在这种情况下使用SigmoidCrossEntropyLoss很好。

以下是完整代码,包括数据创建、训练网络和获取测试结果:

main.py(从caffe lanet示例修改)

import os, sys
PROJECT_HOME = '.../project/' CAFFE_HOME = '.../caffe/' os.chdir(PROJECT_HOME)
sys.path.insert(0, CAFFE_HOME + 'caffe/python') import caffe, h5py
from pylab import * from caffe import layers as L
def net(hdf5, batch_size): n = caffe.NetSpec() n.data, n.label = L.HDF5Data(batch_size=batch_size, source=hdf5, ntop=2) n.ip1 = L.InnerProduct(n.data, num_output=50, weight_filler=dict(type='xavier')) n.relu1 = L.ReLU(n.ip1, in_place=True) n.ip2 = L.InnerProduct(n.relu1, num_output=50, weight_filler=dict(type='xavier')) n.relu2 = L.ReLU(n.ip2, in_place=True) n.ip3 = L.InnerProduct(n.relu2, num_output=4, weight_filler=dict(type='xavier')) n.loss = L.SigmoidCrossEntropyLoss(n.ip3, n.label) return n.to_proto()
with open(PROJECT_HOME + 'auto_train.prototxt', 'w') as f: f.write(str(net(PROJECT_HOME + 'train.h5list', 50))) with open(PROJECT_HOME + 'auto_test.prototxt', 'w') as f: f.write(str(net(PROJECT_HOME + 'test.h5list', 20)))
caffe.set_device(0) caffe.set_mode_gpu() solver = caffe.SGDSolver(PROJECT_HOME +
/home/foo/bar/project/train.h5

测试.h5列表

/home/foo/bar/project/test.h5

和求解器:

auto_solver.prototxt

train_net: "auto_train.prototxt"
test_net: "auto_test.prototxt"
test_iter: 10
test_interval: 20
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
lr_policy: "inv"
gamma: 0.0001
power: 0.75
display: 100
max_iter: 10000
snapshot: 5000
snapshot_prefix: "sed"
solver_mode: GPU

收敛图: Converge graph

最后一批结果:

[[ 35.91593933 -37.46276474 -6.2579031 -6.30313492]
[ 42.69248581 -43.00864792 13.19664764 -3.35134125]
[ -1.36403108 1.38531208 2.77786589 -0.34310576]
[ 2.91686511 -2.88944006 4.34043217 0.32656598]
...
[ 35.91593933 -37.46276474 -6.2579031 -6.30313492]
[ 42.69248581 -43.00864792 13.19664764 -3.35134125]
[ -1.36403108 1.38531208 2.77786589 -0.34310576]
[ 2.91686511 -2.88944006 4.34043217 0.32656598]]
[[ 1. 0. 0. 0.] [ 1. 0. 1. 0.] [ 0. 1. 1. 0.] [ 1. 0. 1. 1.] ... [ 1. 0. 0. 0.] [ 1. 0. 1. 0.] [ 0. 1. 1. 0.] [ 1. 0. 1. 1.]]

我认为这段代码仍有很多需要改进的地方,欢迎提出建议。


你能解释一下标签是如何定义的吗?它是一个二进制系统吗? - R.Falque
是的,我只尝试过二进制系统。ON表示1,OFF表示0。 - Romulus Urakagi Ts'ai
你的caffe版本是什么?我遇到了一个错误:“ImportError: cannot import name layers”。 - tidy
我目前没有这台机器,这应该是2015年10月的最新版本。 - Romulus Urakagi Ts'ai
为什么在计算准确度时需要运行test_net 100次?这100次运行的结果为什么会不同? - Hui Liu

1
你的准确度层没有意义。
准确度层的工作方式:在 中,准确度层需要两个输入: (i) 预测的概率向量和 (ii) 对应的标签。
然后,准确度层会检查预测标签的概率是否确实是最大的(或者在 top_k 范围内)。因此,如果你要分类 C 个不同的类,则你的输入将是 N×C 的预测概率输入(其中 N 是批处理大小),针对每个类别中属于 N 个样本的 N 个标签。
在你的网络中定义的方式:你的准确度层输入 N×4 的预测和 N×4 的标签-这在 caffe 中没有意义。

看起来我误解了准确度层。但是如果我删除它,损失层会向我返回相同的错误。也许我需要另一个针对向量标签的损失层?我找不到可用的损失层列表。 - Romulus Urakagi Ts'ai
我尝试使用EuclideanLoss(没有accuracy层),但它返回了大量的nan。 - Romulus Urakagi Ts'ai
1
@RomulusUrakagiTs'ai,一开始就是NaN吗?可能是损失过高导致梯度“爆炸”,使您的训练失败。尝试显著降低损失层的loss_weight - Shai
我认为我已经让事情正常运转了,我应该写一个完整的“回答你的问题”,还是只在这里留下评论并将其作为被接受的答案? - Romulus Urakagi Ts'ai
1
有些细节不同,我会发布一个带有完整代码的答案。 - Romulus Urakagi Ts'ai
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接