11

我正在使用 Caffe 使用非常简单的 CNN 结构对非图像数据进行分类。我在使用尺寸为 nx 1 x 156 x 12 的 HDF5 数据上训练我的网络时没有问题。但是,我在分类新数据时遇到了困难。

如何在没有任何预处理的情况下进行简单的前向传递?我的数据已经过标准化,并且对于 Caffe 具有正确的尺寸(它已被用于训练网络)。下面是我的代码和 CNN 结构。

编辑:我已将问题隔离到 pycaffe.py 中的函数“_Net_forward”,并发现问题出现在 self.input dict 为空时。谁能解释这是为什么?该集合应该等于来自新测试数据的集合:

if set(kwargs.keys()) != set(self.inputs):
            raise Exception('Input blob arguments do not match net inputs.')

我的代码发生了一些变化,因为我现在使用 IO 方法将数据转换为数据(见下文)。这样我就用正确的数据填充了 kwargs 变量。

即使是很小的提示也将不胜感激!

    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt

    # Make sure that caffe is on the python path:
    caffe_root = ''  # this file is expected to be run from {caffe_root}
    import sys
    sys.path.insert(0, caffe_root + 'python')

    import caffe

    import os
    import subprocess
    import h5py
    import shutil
    import tempfile

    import sklearn
    import sklearn.datasets
    import sklearn.linear_model
    import skimage.io



    def LoadFromHDF5(dataset='test_reduced.h5', path='Bjarke/hdf5_classification/data/'):

        f   = h5py.File(path + dataset, 'r')
        dat = f['data'][:]
        f.close()   

        return dat;

    def runModelPython():
        model_file = 'Bjarke/hdf5_classification/conv_v2_simple.prototxt'
        pretrained = 'Bjarke/hdf5_classification/data/train_iter_10000.caffemodel'
        test_data = LoadFromHDF5()

        net = caffe.Net(model_file, pretrained)
        caffe.set_mode_cpu()
        caffe.set_phase_test()  

        user = test_data[0,:,:,:] 
        datum = caffe.io.array_to_datum(user.astype(np.uint8))
        user_dat = caffe.io.datum_to_array(datum)
        user_dat = user_dat.astype(np.uint8)
        out = net.forward_all(data=np.asarray([user_dat]))

if __name__ == '__main__':
    runModelPython()

CNN 原型

name: "CDR-CNN"
layers {
  name: "data"
  type: HDF5_DATA
  top: "data"
  top: "label"
  hdf5_data_param {
    source: "Bjarke/hdf5_classification/data/train.txt"
    batch_size: 10
  }
  include: { phase: TRAIN }
}
layers {
  name: "data"
  type: HDF5_DATA
  top: "data"
  top: "label"
  hdf5_data_param {
    source: "Bjarke/hdf5_classification/data/test.txt"
    batch_size: 10
  }
  include: { phase: TEST }
}

layers {
  name: "feature_conv"
  type: CONVOLUTION
  bottom: "data"
  top: "feature_conv"
  blobs_lr: 1
  blobs_lr: 2
  convolution_param {
    num_output: 10
    kernel_w: 12
    kernel_h: 1
    stride_w: 1
    stride_h: 1
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
    }
  }
}
layers {
  name: "conv1"
  type: CONVOLUTION
  bottom: "feature_conv"
  top: "conv1"
  blobs_lr: 1
  blobs_lr: 2
  convolution_param {
    num_output: 14
    kernel_w: 1
    kernel_h: 4
    stride_w: 1
    stride_h: 1
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
    }
  }
}
layers {
  name: "pool1"
  type: POOLING
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_w: 1
    kernel_h: 3
    stride_w: 1
    stride_h: 3
  }
}
layers {
  name: "conv2"
  type: CONVOLUTION
  bottom: "pool1"
  top: "conv2"
  blobs_lr: 1
  blobs_lr: 2
  convolution_param {
    num_output: 120
    kernel_w: 1
    kernel_h: 5
    stride_w: 1
    stride_h: 1
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
    }
  }
}
layers {
  name: "fc1"
  type: INNER_PRODUCT
  bottom: "conv2"
  top: "fc1"
  blobs_lr: 1
  blobs_lr: 2
  weight_decay: 1
  weight_decay: 0
  inner_product_param {
    num_output: 84
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layers {
  name: "accuracy"
  type: ACCURACY
  bottom: "fc1"
  bottom: "label"
  top: "accuracy"
  include: { phase: TEST }
}
layers {
  name: "loss"
  type: SOFTMAX_LOSS
  bottom: "fc1"
  bottom: "label"
  top: "loss"
}
4

4 回答 4

9

这是我在 Caffe Google Groups 上得到的 Evan Shelhamer 的回答

self._inputs确实适用于由 prototxt 中的输入字段定义的手动或“部署”输入。要通过 pycaffe 运行带有数据层的网络,只需net.forward()不带参数调用即可。无需更改训练或测试网络的定义。

例如,参见Python LeNet 示例的代码单元 [10] 。

事实上,我认为在Instant Recognition with Caffe 教程中更清楚,单元格 6:

# Feed in the image (with some preprocessing) and classify with a forward pass.
net.blobs['data'].data[...] = transformer.preprocess('data', caffe.io.load_image(caffe_root + 'examples/images/cat.jpg'))
out = net.forward()
print("Predicted class is #{}.".format(out['prob'].argmax()))

换句话说,要使用 pycaffe 生成预测输出及其概率,一旦你训练了模型,你必须首先向数据层提供输入,然后使用net.forward().


或者,正如在其他答案中指出的那样,您可以使用与用于定义训练网络但删除输入和输出层的部署 prototxt 类似,并在开头添加以下内容(显然根据您的输入进行调整方面):

name: "your_net"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 1
input_dim: 250

这就是他们在CIFAR10 教程中使用的内容。

(pycaffe 真的应该有更好的文档记录……)

于 2015-07-13T18:44:38.853 回答
2

仅由于我自己的实验经验,使用 {PHASE} 子句在一个文件中指定训练和测试网络并不是一个好主意。当我使用这样的网络文件时,我遇到了很多奇怪的错误,但是当我使用旧版本的网络文件时,它分别包含两个文件,训练和测试,它起作用了。但是我在 2014 年 11 月使用的是 caffe 版本,可能存在一些错误或兼容问题。

那么,当模型用于预测时,不应该有一个指定网络结构的部署文件吗?如果您查看 ImageNet,您应该在那里找到 imagenet_deploy.prototxt。虽然部署文件类似于训练/测试文件,但我听说由于一些填充物而有点不同。我不知道是不是问题,但是欢迎任何讨论,如果也存在的话,我需要学习新的 caffe 架构

于 2015-03-24T01:12:48.940 回答
1
Even small hints would be greatly appreciated!

我也被卡住了,所以没有多大帮助,对不起。可能想跳到最后。

net.inputs是一个@property 函数,它应该生成输入层的名称。

@property
def _Net_inputs(self):
    return [list(self.blobs.keys())[i] for i in self._inputs]

list(self.blobs.keys())你会在哪里

['data', 'feature_conv', 'conv1', 'pool1', 'conv2', 'fc1', 'accuracy', 'loss']

由于inputs必须匹配kwargs.keys() = ['data'],我们可以得出结论net._inputs应该是[0]。不知何故。

由于_inputs在其他任何地方都没有使用过,pycaffe.py所以我看看_caffe.cpp. 它说在第 222 行附近

.add_property("_inputs", p::make_function(&Net<Dtype>::input_blob_indices,
    bp::return_value_policy<bp::copy_const_reference>()))

_inputs这些也是有道理input_blob_indices的,这些应该[0]适用于您的网络。

input_blob_indices反过来只是一个返回的net_input_blob_indices_函数include/caffe/net.hpp

inline const vector<int>& input_blob_indices() const { return net_input_blob_indices_; }

...仅用于src/caffe/net.cpp,但我找不到它在任何地方定义或分配。

我已经尝试过type: Datatype: MemoryData但这并没有什么不同。工作正在使用什么

input: "data"
input_dim: 1
input_dim: 3
input_dim: 227
input_dim: 227

...而不是一层。在这种情况下net._inputs = [0]and net.inputs = ['data'](实际上net._inputs是 a caffe._caffe.IntVec objectbut list(net._inputs) = [0])。

TLDR:它开始看起来很像一个错误,所以我提交了它:https ://github.com/BVLC/caffe/issues/2246

Ps 似乎您正在将 ndarray 转换为 datum 然后再返回。这有目的吗?

于 2015-04-02T23:03:17.247 回答
1

我有完全一样的问题。这就是修复它的原因。

首先,使用与训练时相同的 prototext 文件,删除两个数据层。

然后将块添加为上面的标记

name: "Name_of_your_net"
input: "data"
input_dim: 64 
input_dim: 1
input_dim: 28
input_dim: 28

我的 input_dim 用于 mnist,将它们更改为您的昏暗。

一切正常。

于 2015-07-11T18:04:23.697 回答