【问题标题】:How to feed caffe multi label data in HDF5 format?如何以 HDF5 格式输入 caffe 多标签数据?
【发布时间】:2016-07-31 17:32:04
【问题描述】:

我想使用带有矢量标签的 caffe,而不是整数。我检查了一些答案,似乎 HDF5 是一种更好的方法。但是后来我遇到了这样的错误:

accuracy_layer.cpp:34] 检查失败: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 blob 的数据格式?

【问题讨论】:

  • 不应该是data 类型为f4 吗?
  • 改成 f4 不会改变错误。
  • 可能是宝贵的资源:@​​987654321@
  • 谢谢,那个损失层正是我需要的。

标签: python neural-network deep-learning caffe


【解决方案1】:

回答这个问题的标题:

HDF5 文件的根目录应该有两个数据集,分别命名为“data”和“label”。形状是 (data amount, dimension)。我只使用一维数据,所以我不确定channelwidthheight 的顺序是什么。也许没关系。 dtype 应该是浮点数或双精度数。

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

导入 h5py,操作系统 将 numpy 导入为 np f = h5py.File('train.h5', 'w') # 1200个数据,每个都是一个128维向量 f.create_dataset('data', (1200, 128), dtype='f8') # 数据的标签,每个都是一个 4-dim 向量 f.create_dataset('label', (1200, 4), dtype='f4') # 用固定模式填充一些东西 # 将值正则化到 0 到 1 之间,否则 SigmoidCrossEntropyLoss 将不起作用 对于我在范围内(1200): a = np.empty(128) 如果我 % 4 == 0: 对于范围内的 j (128): a[j] = j / 128.0; l = [1,0,0,0] elif 我 % 4 == 1: 对于范围内的 j (128): a[j] = (128 - j) / 128.0; l = [1,0,1,0] elif 我 % 4 == 2: 对于范围内的 j (128): a[j] = (j % 6) / 128.0; l = [0,1,1,0] elif 我 % 4 == 3: 对于范围内的 j (128): a[j] = (j % 4) * 4 / 128.0; l = [1,0,1,1] f['数据'][i] = a f['标签'][i] = l f.close()

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

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

main.py(根据 caffe lanet 示例修改)

导入操作系统、系统 PROJECT_HOME = '.../项目/' CAFFE_HOME = '.../caffe/' os.chdir(PROJECT_HOME) sys.path.insert(0, CAFFE_HOME + 'caffe/python') 导入咖啡,h5py 从 pylab 导入 * 从 caffe 导入图层为 L 定义网(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) 返回 n.to_proto() 使用 open(PROJECT_HOME + 'auto_train.prototxt', 'w') 作为 f: f.write(str(net(PROJECT_HOME + 'train.h5list', 50))) 使用 open(PROJECT_HOME + 'auto_test.prototxt', 'w') 作为 f: f.write(str(net(PROJECT_HOME + 'test.h5list', 20))) caffe.set_device(0) caffe.set_mode_gpu() 求解器 = caffe.SGDSolver(PROJECT_HOME + 'auto_solver.prototxt') 求解器.net.forward() 求解器.test_nets[0].forward() 求解器.step(1) 尼特 = 200 测试间隔 = 10 train_loss = zeros(niter) test_acc = zeros(int(np.ceil(niter * 1.0 / test_interval))) 打印长度(test_acc) 输出 = zeros((niter, 8, 4)) # 主求解器循环 在范围内(niter): solver.step(1) # Caffe 的 SGD train_loss[it] = solver.net.blobs['loss'].data solver.test_nets[0].forward(start='data') output[it] = solver.test_nets[0].blobs['ip3'].data[:8] 如果它 % test_interval == 0: 打印'迭代',它,'测试......' 正确 = 0 数据 = solver.test_nets[0].blobs['ip3'].data 标签 = solver.test_nets[0].blobs['label'].data 对于范围内的 test_it(100): 求解器.test_nets[0].forward() # 正值映射到标签1,负值映射到标签0 对于我在范围内(len(数据)): 对于范围内的 j (len(data[i])): 如果数据[i][j] > 0 并且标签[i][j] == 1: 正确 += 1 elif 数据[i][j] %lt;= 0 和标签[i][j] == 0: 正确 += 1 test_acc[int(it/test_interval)] = 正确 * 1.0 / (len(data) * len(data[0]) * 100) # 训练和测试完成,输出收敛图 _, ax1 = subplots() ax2 = ax1.twinx() ax1.plot(arange(niter), train_loss) ax2.plot(test_interval * arange(len(test_acc)), test_acc, 'r') ax1.set_xlabel('迭代') ax1.set_ylabel('训练损失') ax2.set_ylabel('测试精度') _.savefig('converge.png') # 查看最后一批的结果 打印solver.test_nets[0].blobs['ip3'].data 打印solver.test_nets[0].blobs['label'].data

h5list 文件每行只包含 h5 文件的路径:

train.h5list

/home/foo/bar/project/train.h5

test.h5list

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

和求解器:

auto_solver.prototxt

train_net: "auto_train.prototxt"
test_net:“auto_test.prototxt”
测试者:10
测试间隔:20
base_lr:0.01
动量:0.9
重量衰减:0.0005
lr_policy:“inv”
伽玛:0.0001
功率:0.75
显示:100
最大迭代器:10000
快照:5000
快照前缀:“sed”
求解器模式:GPU

收敛图:

最后一批结果:

[[ 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.]]

我认为这段代码还有很多需要改进的地方。任何建议表示赞赏。

【讨论】:

  • 你能解释一下标签是如何定义的,是二进制系统吗?
  • 是的,我只试过二进制系统。 ON 为 1,OFF 为 0。
  • 你的caffe版本是什么?我有一个错误ImportError: cannot import name layers
  • 我目前没有这台机器,这应该是2015年10月的最新版本。
  • 为什么在计算准确率的时候需要运行test_net 100次?为什么这 100 次运行的结果不同?
【解决方案2】:

您的准确性层毫无意义。

准确率层的工作方式 准确率层需要两个输入
(i) 一个预测概率向量
(ii) ground-truth 对应的标量整数标签。
准确性层然后检查预测标签的概率是否确实是最大的(或在top_k 内)。
因此,如果您必须对 C 不同的类别进行分类,您的输入将是 N-by-C(其中 N 是批量大小)输入预测概率 N 属于每个 @ 的样本的概率987654328@ 类和N 标签。

它在你的网络中定义的方式:你输入准确层 N-by-4 预测和 N-by-4 标签——这对 caffe 没有意义。

【讨论】:

  • 看来我误解了准确性层。但是如果我删除它,损失层会返回同样的错误给我。也许我需要另一个损失层作为矢量标签?我找不到可用的损失层列表。
  • 我尝试了 EuclideanLoss(没有准确层),但它返回了大量的 nan。
  • @RomulusUrakagiTs'ai 一开始是NaN 吗?可能是损失太高导致你的梯度“爆炸”而放弃你的训练。尝试显着减少损失层的loss_weight
  • 是的,它是NaN。我试试看,非常感谢!
  • 完全不同,我会用完整的代码发布答案。
猜你喜欢
  • 2017-05-26
  • 2017-03-07
  • 2017-02-15
  • 2017-04-20
  • 2017-04-22
  • 2017-01-21
  • 2016-10-28
  • 2016-09-23
相关资源
最近更新 更多