2015-03-18 9 views
10

Uso Caffe per classificare i dati non immagine utilizzando una struttura CNN piuttosto semplice. Non ho avuto problemi ad allenare la mia rete sui miei dati HDF5 con dimensioni n x 1 x 156 x 12. Tuttavia, ho difficoltà a classificare nuovi dati.Pronostico in Caffe - Eccezione: gli argomenti del blob di input non corrispondono agli input netti

Come si esegue un inoltro semplice senza alcun pre-elaborazione? I miei dati sono stati normalizzati e hanno dimensioni corrette per Caffe (è già stato utilizzato per addestrare la rete). Di seguito è riportato il mio codice e la struttura della CNN.

EDIT: Ho isolato il problema con la funzione '_Net_forward' in pycaffe.py e ho riscontrato che il problema si pone quando il dict self.input è vuoto. Qualcuno può spiegare perché è così? Il set dovrebbe essere uguale al set proveniente dalla nuova dati di test:

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

Il mio codice è cambiato un po 'come io uso i metodi IO per convertire i dati in riferimento (vedi sotto). In questo modo ho riempito la variabile kwargs con i dati corretti.

Anche piccoli accorgimenti sarebbero molto apprezzati!

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 prototesto

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

Visualizzazione del file di registro troppo ci aiuterebbe restringere ulteriormente la questione –

+0

Giusto per farvi sapere, mi è stato detto che non è un bug sul tracker. Ho chiesto come farlo sulla mailing list ma non ho ricevuto risposta fino ad ora https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/caffe-users/eEhSBlKcjpc/llQi9PTPAYsJ – Mark

+0

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

risposta

8

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

self._inputs è infatti per la guida o "distribuire" ingressi come definito dai campi di input in un prototxt. Per eseguire una rete con livelli di dati in tramite pycaffe, è sufficiente chiamare net.forward() senza argomenti. Non è necessario modificare la definizione del treno o delle reti di prova.

Vedere ad esempio la cella di codice [10] di Python LeNet example.

In realtà penso che sia più chiaro nel Instant Recognition with Caffe tutorial, 6 celle:

# 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())) 

In altre parole, per generare le uscite previste e le loro probabilità utilizzando pycaffe, una volta che avete preparato il vostro modello, devi prima alimentare il livello dati con il tuo input, quindi eseguire un passaggio in avanti con net.forward().


In alternativa, come sottolineato in altre risposte, è possibile utilizzare un prototxt deploy che è simile a quella che si usa per definire la rete addestrata, ma rimuovendo gli strati di input e output, e aggiungere il seguente all'inizio (ovviamente adattare secondo la vostra dimensione dell'input):

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

Questo è quello che uso nel CIFAR10 tutorial.

(pycaffe dovrebbe davvero essere meglio documentato ...)

2

Solo grazie alla mia esperienza sperimentale, non è una buona idea per specificare treno e al netto di prova in un file utilizzando {} FASE clausola. Ho avuto molti strani errori quando ho usato un file net come quello, ma quando ho usato una versione precedente di file net che contenevano due file separatamente, treno e test, ha funzionato. Comunque stavo usando la versione di caffe a novembre 2014, forse c'è qualche bug o problemi compatibili lì.

Bene, quando il modello viene utilizzato per la previsione, non dovrebbe esserci un file di distribuzione che specifica la struttura di rete? Se guardi ImageNet dovresti trovare imagenet_deploy.prototxt lì. Sebbene il file di distribuzione sia simile al file treno/test, ho sentito che è un po 'diverso a causa di alcuni filler. Non so se è il problema, ma ogni discussione è benvenuto, ho bisogno di imparare nuovo schema caffe se esistono anche

1
Even small hints would be greatly appreciated! 

Sono bloccato anche in modo non molto di aiuto, mi dispiace. Potrebbe voler saltare fino alla fine.

net.inputs è una funzione @property che presumibilmente genera i nomi dei layer di input.

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

Dove list(self.blobs.keys()) per voi sarebbe

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

Dal inputs deve corrispondere kwargs.keys() = ['data'] possiamo concludere che net._inputs avrebbe dovuto essere [0]. In qualche modo.

Dal _inputs non viene utilizzato da nessun'altra parte in pycaffe.py Dare un'occhiata a _caffe.cpp. Intorno alla linea 222 che dice

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

Così _inputs sono il input_blob_indices e ha senso che questi dovrebbero essere [0] per la rete.

input_blob_indices a sua volta, è semplicemente una funzione che restituisce net_input_blob_indices_ in include/caffe/net.hpp

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

... che viene utilizzato solo in src/caffe/net.cpp, ma io non riesco a trovarlo in fase di definizione o assegnato da nessuna parte.

Ho provato con type: Data e ma ciò non fa differenza. Che cosa funziona utilizzando

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

... anziché un livello. In tal caso net._inputs = [0] e net.inputs = ['data'] (in realtà net._inputs è un caffe._caffe.IntVec object ma list(net._inputs) = [0]).

TLDR: Si sta cominciando a guardare un po 'come un insetto così ho presentato: https://github.com/BVLC/caffe/issues/2246

P.S. sembra che tu stia convertendo ndarray in datum e poi di nuovo. Questo ha uno scopo?

1

Ho esattamente lo stesso problema. Questo è ciò che l'ha risolto.

Innanzitutto, prendere lo stesso file di prototesto utilizzato per addestrare, rimuovere i due livelli di dati.

quindi aggiungere il blocco come Marco sopra

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

dove il mio input_dim sono per mnist, cambiarli a vostro dim.

Tutto funziona.

+0

Sì, una buona risposta, probabilmente lo risolve per il 90% delle persone. Ma a volte hai davvero bisogno di livelli, ad es. per alimentare i dati in diverse parti della rete (come extra dopo la convoluzione), o forme di dati diverse. Ad ogni modo +1 – Mark