Прогнозирование в 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, измените их на ваш тусклый.

Все работает.