2016-05-17 22 views
4

Ich bin neu in Caffe Framework und ich würde gerne Caffe verwenden, um das Training mit Multi-Label zu implementieren. Ich benutze zwei LMDB um Daten und Labels zu speichern. Die Daten LMDB haben die Dimension Nx1xHxW, während das Label LMDB die Dimension Nx1x1x3 hat. Labels sind Float-Daten.Multi-Etiketten mit zwei verschiedenen LMDB

Die Textdatei ist wie folgt:

5911 3 
train/train_data/4224.bmp  13   0  12 
train/train_data/3625.bmp  11   3   7 
...        ... 

I C++ verwenden LMDB zu erstellen. Mein main.cpp:

#include <algorithm> 
#include <fstream> // NOLINT(readability/streams) 
#include <string> 
#include <utility> 
#include <vector> 
#include <QImage> 

#include "boost/scoped_ptr.hpp" 
#include "gflags/gflags.h" 
#include "glog/logging.h" 

#include "caffe/proto/caffe.pb.h" 
#include "caffe/util/db.hpp" 
#include "caffe/util/format.hpp" 
#include "caffe/util/rng.hpp" 

#include <boost/filesystem.hpp> 
#include <iomanip> 
#include <iostream> // NOLINT(readability/streams) 
#include <string> 

#include "google/protobuf/message.h" 

#include "caffe/common.hpp" 
#include "caffe/proto/caffe.pb.h" 
#include "caffe/util/format.hpp" 

#ifndef CAFFE_TMP_DIR_RETRIES 
#define CAFFE_TMP_DIR_RETRIES 100 
#endif 

using namespace caffe; // NOLINT(build/namespaces) 
using std::pair; 
using boost::scoped_ptr; 

const char *dat_lab="/home/mul/caffe-master/examples/2D_3D/new/info/train.data"; 
string data_db="/home/mul/caffe-master/examples/2D_3D/new/2D_3D_data_leveldb"; 
string label_db="/home/mul/caffe-master/examples/2D_3D/new/2D_3D_label_leveldb"; 
string root="/home/mul/caffe-master/examples/2D_3D/new/"; 
string path; 

int main() 
{ 

    //Create data DB 
    scoped_ptr<db::DB> dat_db(db::GetDB("leveldb")); 
    dat_db->Open(data_db, db::NEW); 
    scoped_ptr<db::Transaction> dat_txn(dat_db->NewTransaction()); 

    //Create label DB 
    scoped_ptr<db::DB> lab_db(db::GetDB("leveldb")); 
    lab_db->Open(label_db, db::NEW); 
    scoped_ptr<db::Transaction> lab_txn(lab_db->NewTransaction()); 

    //Storing to db 
    Datum dat_datum,lab_datum; 
    int count=0; 

    std::ifstream infile(dat_lab); 
    std::string filename; 
    const char *dataname; 
    int dataNum; 
    int labelcount; 
    QImage img; 
    infile>>dataNum>>labelcount; 
    LOG(INFO) << "A total of " << dataNum<< " images."; 

    for (int line_id = 0; line_id < dataNum; ++line_id) 
    { 
     infile>>filename; 
     path=root+filename; 
     dataname=path.c_str(); 
     img.load(dataname); 

     dat_datum.set_channels(1); 
     dat_datum.set_height(img.height()); 
     dat_datum.set_width(img.width()); 
     dat_datum.clear_data(); 
     dat_datum.clear_float_data(); 

     int datum_channels = dat_datum.channels(); 
     int datum_height = dat_datum.height(); 
     int datum_width = dat_datum.width(); 
     int datum_size = datum_channels * datum_height * datum_width; 
     std::string buffer(datum_size, ' '); 
     const uchar* ptr = img.bits(); 
     int img_index = 0; 
     for (int h = 0; h < datum_height; ++h) 
     { 

      for (int w = 0; w < datum_width; ++w) 
      { 
       for (int c = 0; c < datum_channels; ++c) 
       { 
        int datum_index = (c * datum_height + h) * datum_width + w; 
        buffer[datum_index] = static_cast<char>(ptr[img_index++]); 
       } 
      } 
     } 
     dat_datum.set_data(buffer); 


     lab_datum.set_channels(labelcount); 
     lab_datum.set_height(1); 
     lab_datum.set_width(1); 
     lab_datum.clear_data(); 
     lab_datum.clear_float_data(); 
     for(int i=0;i<labelcount;++i) 
     { 
      float mid; 
      infile>>mid; 
      lab_datum.add_float_data(mid); 
     } 

     // sequential 
     string key_str = caffe::format_int(line_id, 8); 

     // Put in db 
     string out; 
     CHECK(dat_datum.SerializeToString(&out)); 
     dat_txn->Put(key_str, out); 
     CHECK(lab_datum.SerializeToString(&out)); 
     lab_txn->Put(key_str, out); 

     if (++count % 1000 == 0) 
     { 
      // Commit db 
      dat_txn->Commit(); 
      dat_txn.reset(dat_db->NewTransaction()); 
      lab_txn->Commit(); 
      lab_txn.reset(lab_db->NewTransaction()); 
      LOG(INFO) << "Processed " << count << " files."; 
     } 
    } 
    // write the last batch 
    if (count % 1000 != 0) 
    { 
     dat_txn->Commit(); 
     lab_txn->Commit(); 
     LOG(INFO) << "Processed " << count << " files."; 
    } 
    return 0; 
} 

Zwei LMDB können erfolgreich erstellt werden. Aber wenn ich Caffe verwende, um das Training mit zwei LMDB zu implementieren, ist das Ergebnis immer falsch. Die Verlustschicht ist EUCLIDEAN_LOSS und der Verlust kann nicht abfallen. Ich weiß nicht, ob der Code, der zwei LMDB erzeugen kann, falsch ist. Wer kann mir helfen ? Danke, was auch immer.

+0

Warum verwenden Sie 'dat_datum.set_data (buffer)', um die Bilddaten zu setzen, während 'lab_datum.add_float_data (mid)' für die Etiketten verwendet wird? Ich habe keine Erfahrung mit 'Datum' C++ - Schnittstelle, aber ist es möglich, dass Einstellung' lab_datum.set_channels (labelcount) 'und dann' add_float_data' Methode die Größe der Daten ändern und legt schließlich die Label-Werte an Orten '3, 4, 5 'statt '0, 1, 2'? – Shai

+0

anstelle von levelfb für die etiketten, warum erwägen sie nicht mit hdf5 eingang? Für ein Beispiel siehe [diese Antwort] (http://stackoverflow.com/a/31808324/1714410). – Shai

+0

Diese Methode hat genügend Trainingsdaten, so dass der Speicher des Computers nicht alle Daten laden kann. Deshalb akzeptiere ich hdf5 nicht. Ich habe gerade dieses Problem gelöst und danke für Ihre Antwort. –

Antwort

2

Als Ganzes Code oben ist Ok, aber Sie sollten feststellen, dass:

  1. Ihre CPP ist LevelDB statt LMDB zu schaffen, das ist natürlich nicht der Grund, dass Ihr Problem verursacht, entweder Typ ist in Ordnung.
  2. Die "labelLMDB" von Ihrem Code erzeugt wird, von DimensionNx3x1x1 statt Nx1x1x3 (NumberxChannelxWidthxHeight).
  3. In einer Lernaufgabe mit Minibatch SGD, so weit ich weiß, ist es sehr nützlich, Ihre Daten für das Training zu mischen, um ein optimiertes Modell zu erhalten. Ich bin mir nicht sicher, ob Sie das bemerkt haben. Aber zumindest hat deine cpp deine "train.data" nicht gemischt.
  4. Am wichtigsten von allen, der Grund, dass Ihr Problem hier am wahrscheinlichsten in der Datenschicht in Ihrem Netzwerk gelogen hat, die Ihre Daten lesen und lmdb/leveldb-Dateien labeln, weil Sie den Floatdaten des Datums und der Etiketten zugewiesen haben Der DataLayer in Caffe liest tatsächlich die Float-Daten nicht (Nur wenn Sie Ihre selbstdefinierte Datenschicht verwendet haben). Bitte laden Sie auch Ihre Prototxt-Datei hoch, die Ihr Netzwerk definiert. So können wir herausfinden, was das Problem wirklich war.

Endlich Ich habe eine „MultiTaskData“ Schicht MultiTaskDataLayer Multi-Etikett von Datum für Multi-Task-Training zu lesen und können Sie einfache Änderungen vornehmen, um es zu Ihrem caffe hinzufügen und wie diese verwenden:

name: "AgeNet" 
    layer { 
     name: "Age" 
     type: "MultiTaskData" 
     top: "data" 
     top: "age_label" 
     top: "gender_label" 
     data_param { 
      source: "age_gender_classification_0_60p_train_leveldb" 
      batch_size: 60 
      task_num: 2 
      label_dimension: 1 
      label_dimension: 1 
     } 
     transform_param { 
      scale: 0.00390625 
      crop_size: 60 
      mirror: true 
     } 
     include:{ phase: TRAIN } 
    } 
    layer { 
     name: "cls_age" 
     type: "InnerProduct" 
     bottom: "data" 
     top: "cls_age" 
     param { 
      lr_mult: 1 
      decay_mult: 1 
     } 
     param { 
      lr_mult: 2 
      decay_mult: 0 
     } 
     inner_product_param { 
      num_output: 7 
      weight_filler { 
      type: "xavier" 
      }  
     bias_filler {  
      type: "constant" 
      } 
     } 
    } 
    layer { 
     name: "age_loss" 
     type: "SoftmaxWithLoss" 
     bottom: "cls_age" 
     bottom: "age_label" 
     top: "age_loss" 
     include:{ phase: TRAIN } 
    } 
    layer { 
     name: "cls_gender" 
     type: "InnerProduct" 
     bottom: "data" 
     top: "cls_gender" 
     param { 
      lr_mult: 1 
      decay_mult: 1 
     } 
     param { 
      lr_mult: 2 
      decay_mult: 0 
     } 
     inner_product_param { 
      num_output: 2 
      weight_filler { 
       type: "xavier" 
      }  
      bias_filler {  
       type: "constant" 
      } 
     } 
    } 
    layer { 
     name: "gender_loss" 
     type: "SoftmaxWithLoss" 
     bottom: "cls_gender" 
     bottom: "gender_label" 
     top: "gender_loss" 
     include:{ phase: TRAIN } 
    } 
+0

Danke für deine Antwort und ich habe mein Problem gelöst. –