Прогнозирование в Caffe - Исключение: аргументы ввода blob не соответствуют чистым входам
Я использую Caffe для классификации данных без изображения, используя довольно простую структуру CNN. У меня не было проблем с обучением моей сети на моих HDF5-данных с размерами n x 1 x 156 x 12. Однако у меня возникают трудности с классификацией новых данных.
Как мне сделать простой проход без предварительной обработки? Мои данные были нормализованы и имеют правильные размеры для Caffe (он уже использовался для обучения сети). Ниже мой код и структура CNN.
EDIT: Я выделил проблему для функции _Net_forward в файле pycaffe.py и обнаружил, что проблема возникает, поскольку self.input dict пуст. Может ли кто-нибудь объяснить, почему это так? Предполагается, что набор будет равен множеству, исходящему из новых тестовых данных:
if set(kwargs.keys()) != set(self.inputs):
raise Exception('Input blob arguments do not match net inputs.')
Мой код немного изменился, поскольку теперь я использую методы ввода-вывода для преобразования данных в базу данных (см. ниже). Таким образом, я заполнил переменную 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"
}
Ответы
Ответ 1
Вот ответ от Эвана Шелхамера, я попал в группы Google Caffe:
self._inputs
действительно для ручных или "разворачиваемых" входов, как определено по полям ввода в проточнике. Для запуска сети с уровнями данных в через pycaffe, просто вызовите net.forward()
без аргументов. Не нужно изменить определение вашего поезда или тестовых сетей.
См., например, ячейку кода [10] примера Python LeNet.
На самом деле я думаю, что это яснее в Мгновенное распознавание с уроком 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()
.
В качестве альтернативы, как указано в других ответах, вы можете использовать прототип развертывания, который похож на тот, который вы используете для определения обученной сети, но удаляя входные и выходные слои и добавляя в начале (например, к вашему размеру ввода):
name: "your_net"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 1
input_dim: 250
Что они используют в учебнике CIFAR10.
(пикафф действительно должен быть лучше документирован...)
Ответ 2
Только из-за моего собственного экспериментального опыта, не очень хорошая идея указать поезд и тестовую сеть в одном файле с использованием предложения {PHASE}. У меня появилось много странных ошибок, когда я использовал такой сетевой файл, но когда я использовал более старую версию сетевых файлов, которые содержали два файла отдельно, тренировались и тестировались, это сработало. Однако я использовал версию caffe в ноябре 2014 года, возможно, там есть какая-то ошибка или совместимые проблемы.
Ну, когда модель используется для прогнозирования, не должен ли быть файл развертывания, определяющий структуру сети? Если вы посмотрите на ImageNet, вы должны найти файл imagenet_deploy.prototxt. Хотя файл развертывания похож на файл train/test, я слышал, что он немного отличается из-за некоторых наполнителей. Я не знаю, если это проблема, но любое обсуждение приветствуется, мне нужно изучить новую схему caffe, если есть слишком
Ответ 3
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: 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]
).
TL;DR: он начинает сильно напоминать ошибку, поэтому я отправил его: https://github.com/BVLC/caffe/issues/2246
P.s. похоже, что вы конвертируете ndarray в datum, а затем обратно. Имеет ли это цель?
Ответ 4
У меня точно такая же проблема. Это и зафиксировало это.
Сначала возьмите тот же файл prototext, который использовался для тренировки, удалите два слоя данных.
Затем добавьте блок как Mark выше
name: "Name_of_your_net"
input: "data"
input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28
где my input_dim для mnist, измените их на ваш тусклый.
Все работает.