2015-10-15 7 views
8

Voglio usare caffe con un'etichetta vettoriale, non intero. Ho controllato alcune risposte e sembra che HDF5 sia un modo migliore. Ma poi mi sono stucked con l'errore del tipo:Come alimentare i dati multi etichetta con etichetta in formato HDF5?

accuracy_layer.cpp:34] Check failed: outer_num_ * inner_num_ == bottom[1]->count() (50 vs. 200) Number of labels must match number of predictions; e.g., if label axis == 1 and prediction shape is (N, C, H, W), label count (number of labels) must be N*H*W , with integer values in {0, 1, ..., C-1}.

con HDF5 creato come:

f = h5py.File('train.h5', 'w') 
f.create_dataset('data', (1200, 128), dtype='f8') 
f.create_dataset('label', (1200, 4), dtype='f4') 

La mia rete è generato da:

def net(hdf5, batch_size): 
    n = caffe.NetSpec() 
    n.data, n.label = L.HDF5Data(batch_size=batch_size, source=hdf5, ntop=2) 
    n.ip1 = L.InnerProduct(n.data, num_output=50, weight_filler=dict(type='xavier')) 
    n.relu1 = L.ReLU(n.ip1, in_place=True) 
    n.ip2 = L.InnerProduct(n.relu1, num_output=50, weight_filler=dict(type='xavier')) 
    n.relu2 = L.ReLU(n.ip2, in_place=True) 
    n.ip3 = L.InnerProduct(n.relu1, num_output=4, weight_filler=dict(type='xavier')) 
    n.accuracy = L.Accuracy(n.ip3, n.label) 
    n.loss = L.SoftmaxWithLoss(n.ip3, n.label) 
    return n.to_proto() 

with open(PROJECT_HOME + 'auto_train.prototxt', 'w') as f: 
f.write(str(net('/home/romulus/code/project/train.h5list', 50))) 

with open(PROJECT_HOME + 'auto_test.prototxt', 'w') as f: 
f.write(str(net('/home/romulus/code/project/test.h5list', 20))) 

Sembra che dovrebbe aumentare il numero di etichette e metti le cose in un intero piuttosto che in un array, ma se faccio questo, caffe lamenta il numero di dati e l'etichetta non è uguale, quindi esiste.

Quindi, qual è il formato corretto per alimentare i dati con più etichette?

Inoltre, mi sto chiedendo il motivo per cui nessuno semplicemente scrive il formato dei dati su come l'HDF5 si associa ai blob di caffe?

+0

non dovrebbe 'data' di tipo' f4' pure? – Shai

+0

Cambiare in f4 non modifica l'errore. –

+1

Probabilmente una risorsa preziosa: http://stackoverflow.com/questions/33112941/multiple-category-classification-in-caffe –

risposta

21

Risposta a titolo di questa domanda:

Il file HDF5 dovrebbe avere due set di dati in radice il nome di "dati" e "etichetta", rispettivamente. La forma è (data amount, dimension). Sto utilizzando solo dati a una dimensione, quindi non sono sicuro di quale sia l'ordine di channel, width e height. Forse non importa. dtype dovrebbe essere mobile o doppio.

Un codice di esempio creando convoglio con h5py è:

 
import h5py, os 
import numpy as np 

f = h5py.File('train.h5', 'w') 
# 1200 data, each is a 128-dim vector 
f.create_dataset('data', (1200, 128), dtype='f8') 
# Data's labels, each is a 4-dim vector 
f.create_dataset('label', (1200, 4), dtype='f4') 

# Fill in something with fixed pattern 
# Regularize values to between 0 and 1, or SigmoidCrossEntropyLoss will not work 
for i in range(1200): 
    a = np.empty(128) 
    if i % 4 == 0: 
     for j in range(128): 
      a[j] = j/128.0; 
     l = [1,0,0,0] 
    elif i % 4 == 1: 
     for j in range(128): 
      a[j] = (128 - j)/128.0; 
     l = [1,0,1,0] 
    elif i % 4 == 2: 
     for j in range(128): 
      a[j] = (j % 6)/128.0; 
     l = [0,1,1,0] 
    elif i % 4 == 3: 
     for j in range(128): 
      a[j] = (j % 4) * 4/128.0; 
     l = [1,0,1,1] 
    f['data'][i] = a 
    f['label'][i] = l 

f.close() 

Inoltre, non è necessario lo strato di precisione, rimuovendo semplicemente va bene. Il prossimo problema è il livello di perdita. Poiché SoftmaxWithLoss ha una sola uscita (indice della dimensione con valore massimo), non può essere utilizzato per problemi con più etichette. Grazie ad Adian e Shai, trovo che SigmoidCrossEntropyLoss sia buono in questo caso.

Di seguito si riporta il codice completo, dalla creazione dei dati, rete di formazione, e ottenere risultato del test: file

main.py (modified from caffe lanet example)

 
import os, sys 

PROJECT_HOME = '.../project/' 
CAFFE_HOME = '.../caffe/' 
os.chdir(PROJECT_HOME) 

sys.path.insert(0, CAFFE_HOME + 'caffe/python') 
import caffe, h5py 

from pylab import * 
from caffe import layers as L 

def net(hdf5, batch_size): 
    n = caffe.NetSpec() 
    n.data, n.label = L.HDF5Data(batch_size=batch_size, source=hdf5, ntop=2) 
    n.ip1 = L.InnerProduct(n.data, num_output=50, weight_filler=dict(type='xavier')) 
    n.relu1 = L.ReLU(n.ip1, in_place=True) 
    n.ip2 = L.InnerProduct(n.relu1, num_output=50, weight_filler=dict(type='xavier')) 
    n.relu2 = L.ReLU(n.ip2, in_place=True) 
    n.ip3 = L.InnerProduct(n.relu2, num_output=4, weight_filler=dict(type='xavier')) 
    n.loss = L.SigmoidCrossEntropyLoss(n.ip3, n.label) 
    return n.to_proto() 

with open(PROJECT_HOME + 'auto_train.prototxt', 'w') as f: 
    f.write(str(net(PROJECT_HOME + 'train.h5list', 50))) 
with open(PROJECT_HOME + 'auto_test.prototxt', 'w') as f: 
    f.write(str(net(PROJECT_HOME + 'test.h5list', 20))) 

caffe.set_device(0) 
caffe.set_mode_gpu() 
solver = caffe.SGDSolver(PROJECT_HOME + 'auto_solver.prototxt') 

solver.net.forward() 
solver.test_nets[0].forward() 
solver.step(1) 

niter = 200 
test_interval = 10 
train_loss = zeros(niter) 
test_acc = zeros(int(np.ceil(niter * 1.0/test_interval))) 
print len(test_acc) 
output = zeros((niter, 8, 4)) 

# The main solver loop 
for it in range(niter): 
    solver.step(1) # SGD by Caffe 
    train_loss[it] = solver.net.blobs['loss'].data 
    solver.test_nets[0].forward(start='data') 
    output[it] = solver.test_nets[0].blobs['ip3'].data[:8] 

    if it % test_interval == 0: 
     print 'Iteration', it, 'testing...' 
     correct = 0 
     data = solver.test_nets[0].blobs['ip3'].data 
     label = solver.test_nets[0].blobs['label'].data 
     for test_it in range(100): 
      solver.test_nets[0].forward() 
      # Positive values map to label 1, while negative values map to label 0 
      for i in range(len(data)): 
       for j in range(len(data[i])): 
        if data[i][j] > 0 and label[i][j] == 1: 
         correct += 1 
        elif data[i][j] %lt;= 0 and label[i][j] == 0: 
         correct += 1 
     test_acc[int(it/test_interval)] = correct * 1.0/(len(data) * len(data[0]) * 100) 

# Train and test done, outputing convege graph 
_, ax1 = subplots() 
ax2 = ax1.twinx() 
ax1.plot(arange(niter), train_loss) 
ax2.plot(test_interval * arange(len(test_acc)), test_acc, 'r') 
ax1.set_xlabel('iteration') 
ax1.set_ylabel('train loss') 
ax2.set_ylabel('test accuracy') 
_.savefig('converge.png') 

# Check the result of last batch 
print solver.test_nets[0].blobs['ip3'].data 
print solver.test_nets[0].blobs['label'].data 

h5list semplicemente contengono percorsi dei file h5 in ogni riga:

train.h5list

/home/foo/bar/project/train.h5 

test.h5list

/home/foo/bar/project/test.h5 

e il risolutore:

auto_solver.prototxt

train_net: "auto_train.prototxt" 
test_net: "auto_test.prototxt" 
test_iter: 10 
test_interval: 20 
base_lr: 0.01 
momentum: 0.9 
weight_decay: 0.0005 
lr_policy: "inv" 
gamma: 0.0001 
power: 0.75 
display: 100 
max_iter: 10000 
snapshot: 5000 
snapshot_prefix: "sed" 
solver_mode: GPU 

Converge grafico: Converge graph

Ultimo risultato lotto:

 
[[ 35.91593933 -37.46276474 -6.2579031 -6.30313492] 
[ 42.69248581 -43.00864792 13.19664764 -3.35134125] 
[ -1.36403108 1.38531208 2.77786589 -0.34310576] 
[ 2.91686511 -2.88944006 4.34043217 0.32656598] 
... 
[ 35.91593933 -37.46276474 -6.2579031 -6.30313492] 
[ 42.69248581 -43.00864792 13.19664764 -3.35134125] 
[ -1.36403108 1.38531208 2.77786589 -0.34310576] 
[ 2.91686511 -2.88944006 4.34043217 0.32656598]] 

[[ 1. 0. 0. 0.] 
[ 1. 0. 1. 0.] 
[ 0. 1. 1. 0.] 
[ 1. 0. 1. 1.] 
... 
[ 1. 0. 0. 0.] 
[ 1. 0. 1. 0.] 
[ 0. 1. 1. 0.] 
[ 1. 0. 1. 1.]] 

penso che questo codice ha ancora molte cose da migliorare. Qualsiasi suggerimento è apprezzato.

+0

Puoi spiegare come è definita l'etichetta, è un sistema binario? –

+0

Sì, ho provato solo il sistema binario. ON è 1 e OFF è 0. –

+0

Qual è la tua versione di caffe? C'è un errore per me ImportError: impossibile importare i layer dei nomi – tidy

1

Il livello di precisione non ha senso.

Il modo strato precisione funziona: in strato accuratezza prevede due ingressi
(i) una probabilità predetta vettore e
(ii) terra-verità corrispondente scalare etichetta intero.
Il livello di precisione di verifica se la probabilità dell'etichetta prevista è effettivamente la massima (o entro top_k).
Pertanto se si deve classificare C classi diverse, gli ingressi stanno per essere N -by- C (dove è N dimensione del lotto) ingresso probabilità previste per N campioni appartenenti a ciascuno dei C classi e N etichette.

Il modo in cui è definito nella vostra rete: Voi strato accuratezza di input N -da-4 predizioni e N -da-4 etichette - questo non ha senso per caffe.

+0

Sembra che abbia frainteso il livello di accuratezza. Ma se lo elimino, lo strato di perdita restituisce lo stesso errore. Forse ho bisogno di un altro livello di perdita per l'etichetta vettoriale? Non riesco a trovare un elenco di livelli di perdita disponibili. –

+0

Ho provato EuclideanLoss (senza livello di precisione), ma restituisce nan enormi. –

+1

@ RomulusUrakagiTs'ai è "NaN" per l'inizio? potrebbe essere che la perdita sia troppo alta causando il "gradiente" dei gradienti che scaricano l'allenamento. Prova * significativamente * riducendo il 'loss_weight' del livello di perdita. – Shai