2015-03-18 4 views
10

Ich benutze Caffe für die Klassifizierung von Nicht-Bilddaten mit einer recht einfachen CNN-Struktur. Ich hatte keine Probleme, mein Netzwerk auf meinen HDF5-Daten mit den Abmessungen n x 1 x 156 x 12 zu trainieren. Ich habe jedoch Schwierigkeiten, neue Daten zu klassifizieren.Vorhersage in Caffe - Ausnahme: Eingabe-Blob-Argumente stimmen nicht mit den Netto-Eingaben überein

Wie mache ich einen einfachen Weiterleitungsdurchlauf ohne Vorverarbeitung? Meine Daten wurden normalisiert und haben korrekte Maße für Caffe (es wurde bereits verwendet, um das Netz zu trainieren). Unten ist mein Code und die CNN-Struktur.

EDIT: Ich habe das Problem auf die Funktion '_Net_forward' in pycaffe.py isoliert und festgestellt, dass das Problem auftritt, da das self.input dict leer ist. Kann mir jemand erklären, warum das so ist? Der Satz soll den Satz aus den neuen Testdaten kommt gleich sein:

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

Mein Code ein wenig verändert hat, wie ich jetzt die IO-Methoden zur Umwandlung der Daten in Bezug verwenden (siehe unten). Auf diese Weise habe ich die Variable Kwargs mit den richtigen Daten gefüllt.

Selbst kleine Hinweise würden sehr geschätzt werden!

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 Proto

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" 
} 
+0

auch die Protokolldatei angezeigt würde uns helfen, das Problem einzugrenzen weiter –

+0

Nur damit Sie wissen, ich habe es nicht ein Fehler auf der gesagt Tracker. Ich habe gefragt, wie man es auf der Mailingliste macht, aber bis jetzt keine Antwort erhalten https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/caffe-users/eEhSBlKcjpc/llQi9PTPAYSJ – Mark

+0

Gleiches Problem: https : //groups.google.com/forum/#! topic/caffe-users/aojN_bmbg74 –

Antwort

8

Hier the answer from Evan Shelhamer I got on the Caffe Google Groups:

self._inputs ist in der Tat für die manuelle oder „bereitstellen“ -Eingänge als durch die Eingabefelder in einem prototxt definiert. Um ein Netzwerk mit Datenebenen in über pycaffe zu betreiben, rufen Sie einfach net.forward() ohne Argumente. Keine Notwendigkeit , um die Definition Ihrer Zug- oder Testnetze zu ändern.

Siehe z. B. Codezelle [10] der Python LeNet example.

In der Tat denke ich, es in den Instant Recognition with Caffe tutorial klarer ist, Zelle 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())) 

Mit anderen Worten, die vorhergesagten Ausgaben sowie die Wahrscheinlichkeiten zu erzeugen pycaffe verwenden, sobald Sie Ihr Modell trainiert haben, Sie müssen zuerst die Datenebene mit Ihrer Eingabe füttern und dann einen Vorwärtsdurchlauf mit net.forward() durchführen.


Alternativ kann, wie in anderen Antworten erwähnt, können Sie eine deploy prototxt verwenden, die dem von Ihnen das trainierte Netzwerk verwenden ähnlich ist zu definieren, aber die Eingangs- und Ausgangsschichten zu entfernen, und fügen Sie den folgenden am Anfang (offensichtlich Anpassung entsprechend Ihrer Eingabe Dimension):

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

das ist, was sie in der CIFAR10 tutorial verwenden.

(pycaffe sollte wirklich besser dokumentiert sein ...)

2

nur aufgrund meiner eigenen experimentellen Erfahrung, es ist nicht eine sehr gute Idee Zug und Testnetz in einer Datei angeben, mit {PHASE} Klausel. Ich habe viele seltsame Fehler, wenn ich Net-Datei wie diese verwendet, aber wenn ich ältere Version von net-Dateien verwendet, die zwei Dateien getrennt enthalten, trainieren und testen, hat es funktioniert. Allerdings habe ich im November 2014 Caffe-Version verwendet, vielleicht gibt es dort einen Bug oder kompatible Probleme.

Nun, wenn das Modell für die Vorhersage verwendet wird, sollte es nicht eine Deploy-Datei geben, die die Netzstruktur angibt? Wenn Sie sich ImageNet anschauen, sollten Sie dort image_deploy.prototxt finden. Obwohl die Deploy-Datei der Train/Test-Datei ähnelt, habe ich gehört, dass sie aufgrund einiger Füllstoffe etwas anders ist. Ich weiß nicht, ob es das Problem ist, aber jede Diskussion ist willkommen, ich brauche neue caffe Schema zu lernen, wenn es

1
Even small hints would be greatly appreciated! 

zu existieren Ich bin auch so nicht viel Hilfe stecken, sorry. Vielleicht wollen Sie bis zum Ende überspringen.

net.inputs ist eine @property-Funktion, die angeblich die Namen der Eingabeschicht (en) generiert hat.

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

Wo list(self.blobs.keys()) für Sie würden

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

sein Da inputskwargs.keys() = ['data'] übereinstimmen muss können wir schließen, dass net._inputs sollte [0] gewesen sein. Irgendwie.

Da _inputs nirgends sonst in pycaffe.py verwendet wird, sehe ich _caffe.cpp. Rund 222 Linie sagt, es

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

So _inputs die input_blob_indices sind und es macht Sinn, dass diese [0] für Ihr Netzwerk sein sollte.

input_blob_indices wiederum ist einfach eine Funktion, die net_input_blob_indices_ in include/caffe/net.hpp

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

zurück ..., die nur in src/caffe/net.cpp verwendet wird, aber ich kann es nicht überall definiert oder zugeordnet finden werden. Ich habe es mit type: Data und versucht, aber das macht keinen Unterschied. Was verwendet die Arbeit?

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

... statt einer Schicht. In diesem Fall net._inputs = [0] und net.inputs = ['data'] (tatsächlich net._inputs ist ein caffe._caffe.IntVec object aber list(net._inputs) = [0]).

TLDR: Es beginnt viel wie ein Fehler zu suchen, so legte ich es: https://github.com/BVLC/caffe/issues/2246

P. S. Es sieht so aus, als würden Sie ndarray in Datum und dann wieder zurück konvertieren. Hat das einen Sinn?

1

Ich habe genau das gleiche Problem. Das hat es behoben.

Nehmen Sie zuerst die gleiche Prototext-Datei wie beim Trainieren, entfernen Sie die beiden Datenebenen.

Dann fügen Sie den Block als Markierung oben

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

wo mein input_dim für mnist sind, ändern sie zu Ihren dimmen.

Alles funktioniert.

+0

Ja gute Antwort, löst es wahrscheinlich für 90% der Leute. Aber manchmal brauchen Sie wirklich Schichten, z.B. um Daten in verschiedene Teile des Netzwerks (wie zB nach der Faltung) oder verschiedene Formen von Daten zuzuführen. Jedenfalls +1 – Mark

Verwandte Themen