Caffe 中的预测 - 异常:输入 blob 参数与净输入不匹配
Prediction in Caffe - Exception: Input blob arguments do not match net inputs
我使用 Caffe 通过非常简单的 CNN 结构对非图像数据进行分类。我在尺寸为 n x 1 x 156 x 12 的 HDF5 数据上训练我的网络没有遇到任何问题。但是,我在对新数据进行分类时遇到了困难。
如何在不进行任何预处理的情况下进行简单的前向传播?我的数据已经过规范化并且具有适合 Caffe 的正确尺寸(它已经用于训练网络)。下面是我的代码和 CNN 结构。
编辑: 我已将问题隔离到 pycaffe.py 中的函数“_Net_forward”,发现问题出现在 self.input 字典是空的。谁能解释这是为什么?该集合应该等于来自新测试数据的集合:
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 Prototext
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"
}
仅根据我自己的实验经验,使用 {PHASE} 子句在一个文件中指定训练和测试网络并不是一个好主意。当我使用这样的网络文件时,我遇到了很多奇怪的错误,但是当我使用旧版本的网络文件时,它分别包含两个文件,训练和测试,它起作用了。但是我在 2014 年 11 月使用的是 caffe 版本,可能那里有一些错误或兼容问题。
嗯,用模型做预测的时候,不应该有一个deploy文件指定网络结构吗?如果您查看 ImageNet,您应该会在那里找到 imagenet_deploy.prototxt。虽然部署文件类似于 train/test 文件,但我听说由于一些填充物,它有点不同。不知道是不是这个问题,欢迎讨论,如果有新的caffe schema,我需要学习一下
Even small hints would be greatly appreciated!
我也卡住了,所以帮不上什么忙,抱歉。可能想跳到最后。
net.inputs
是一个@属性 函数,它应该生成输入层的名称。
@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
反过来只是 returns 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: Data
和 type: MemoryData
但这没有什么区别。什么工作正在使用
input: "data"
input_dim: 1
input_dim: 3
input_dim: 227
input_dim: 227
...而不是图层。在那种情况下 net._inputs = [0]
和 net.inputs = ['data']
(实际上 net._inputs
是 caffe._caffe.IntVec object
但 list(net._inputs) = [0]
)。
TLDR:它开始看起来很像一个错误所以我提交了它:https://github.com/BVLC/caffe/issues/2246
P.s。看起来你正在将 ndarray 转换为数据然后再返回。这是有目的的吗?
我也有同样的问题。这就是修复它的原因。
首先,使用与训练时相同的原始文本文件,删除两个数据层。
然后像上面马克的那样添加方块
name: "Name_of_your_net"
input: "data"
input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28
我的 input_dim 用于 mnist,将它们更改为您的 dim。
一切正常。
这里是the answer from Evan Shelhamer I got on the Caffe Google Groups:
self._inputs
is indeed for the manual or "deploy" inputs as defined
by the input fields in a prototxt. To run a net with data layers in
through pycaffe, just call net.forward()
without arguments. No need
to change the definition of your train or test nets.
See for instance code cell [10] of the Python LeNet example.
事实上,我认为在 Instant Recognition with Caffe tutorial 单元格 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()
.
或者,正如其他答案中所指出的,您可以使用类似于您用来定义训练网络但删除输入和输出层的 deploy prototxt,并在开头添加以下内容(显然根据您的输入维度进行调整):
name: "your_net"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 1
input_dim: 250
这就是他们在 CIFAR10 tutorial 中使用的内容。
(pycaffe 确实应该有更好的文档记录……)
我使用 Caffe 通过非常简单的 CNN 结构对非图像数据进行分类。我在尺寸为 n x 1 x 156 x 12 的 HDF5 数据上训练我的网络没有遇到任何问题。但是,我在对新数据进行分类时遇到了困难。
如何在不进行任何预处理的情况下进行简单的前向传播?我的数据已经过规范化并且具有适合 Caffe 的正确尺寸(它已经用于训练网络)。下面是我的代码和 CNN 结构。
编辑: 我已将问题隔离到 pycaffe.py 中的函数“_Net_forward”,发现问题出现在 self.input 字典是空的。谁能解释这是为什么?该集合应该等于来自新测试数据的集合:
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 Prototext
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"
}
仅根据我自己的实验经验,使用 {PHASE} 子句在一个文件中指定训练和测试网络并不是一个好主意。当我使用这样的网络文件时,我遇到了很多奇怪的错误,但是当我使用旧版本的网络文件时,它分别包含两个文件,训练和测试,它起作用了。但是我在 2014 年 11 月使用的是 caffe 版本,可能那里有一些错误或兼容问题。
嗯,用模型做预测的时候,不应该有一个deploy文件指定网络结构吗?如果您查看 ImageNet,您应该会在那里找到 imagenet_deploy.prototxt。虽然部署文件类似于 train/test 文件,但我听说由于一些填充物,它有点不同。不知道是不是这个问题,欢迎讨论,如果有新的caffe schema,我需要学习一下
Even small hints would be greatly appreciated!
我也卡住了,所以帮不上什么忙,抱歉。可能想跳到最后。
net.inputs
是一个@属性 函数,它应该生成输入层的名称。
@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
反过来只是 returns 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: Data
和 type: MemoryData
但这没有什么区别。什么工作正在使用
input: "data"
input_dim: 1
input_dim: 3
input_dim: 227
input_dim: 227
...而不是图层。在那种情况下 net._inputs = [0]
和 net.inputs = ['data']
(实际上 net._inputs
是 caffe._caffe.IntVec object
但 list(net._inputs) = [0]
)。
TLDR:它开始看起来很像一个错误所以我提交了它:https://github.com/BVLC/caffe/issues/2246
P.s。看起来你正在将 ndarray 转换为数据然后再返回。这是有目的的吗?
我也有同样的问题。这就是修复它的原因。
首先,使用与训练时相同的原始文本文件,删除两个数据层。
然后像上面马克的那样添加方块
name: "Name_of_your_net"
input: "data"
input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28
我的 input_dim 用于 mnist,将它们更改为您的 dim。
一切正常。
这里是the answer from Evan Shelhamer I got on the Caffe Google Groups:
self._inputs
is indeed for the manual or "deploy" inputs as defined by the input fields in a prototxt. To run a net with data layers in through pycaffe, just callnet.forward()
without arguments. No need to change the definition of your train or test nets.See for instance code cell [10] of the Python LeNet example.
事实上,我认为在 Instant Recognition with Caffe tutorial 单元格 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()
.
或者,正如其他答案中所指出的,您可以使用类似于您用来定义训练网络但删除输入和输出层的 deploy prototxt,并在开头添加以下内容(显然根据您的输入维度进行调整):
name: "your_net"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 1
input_dim: 250
这就是他们在 CIFAR10 tutorial 中使用的内容。
(pycaffe 确实应该有更好的文档记录……)