Je ne sais pas si vous avez déjà compris comment résoudre ce problème, mais voici comment je viens de le découvrir récemment. Je suis nouveau à Caffe et j'ai du mal à comprendre toute l'architecture de Caffe. Je voulais juste une méthode rapide pour extraire les fonctionnalités de CNN de Caffe et les manipuler plus tard. De plus, je travaille sur OSX et n'ai pas installé Caffe depuis la source. Je l'ai installé via 'port', et l'installation semble incomplète. J'ai donc lancé 'feature_extractor' de Caffe sur une autre machine où Caffe est correctement installé et copié le fichier de sortie sur ma machine pour le traitement ultérieur. Pour cela, vous devrez installer LMDB et Protobuf de Google sur votre machine. Pour cela, vous devez installer LMDB et Google Protobuf. Vous devrez lier le programme C/C++ avec liblmdb et libprotobuf.
J'ai suivi le tutoriel de Caffe pour enregistrer la sortie de la couche 'fc7' d'AlexNet dans un fichier au format LMDB. Puis j'ai écrit un simple programme C/C++ pour le lire. Cela peut être fait en utilisant le code suivant:
#include <fstream>
#include <iostream>
#include <lmdb.h>
using namespace std;
int main(int argc, char *argv[])
{
if(argc!=2)
{
cerr<< "Error"<< endl
<< "Usage : "<< argv[0]<< " mdb_dirname"<< endl;
return 0;
}
char *mdb_dirname = argv[1];
int rc;
MDB_env *env;
MDB_dbi dbi;
MDB_val key, data;
MDB_txn *txn;
MDB_cursor *cursor;
char sval[32];
rc = mdb_env_create(&env);
rc = mdb_env_open(env, mdb_dirname, 0, 0664);
rc = mdb_txn_begin(env, NULL, 0, &txn);
rc = mdb_open(txn, NULL, 0, &dbi);
rc = mdb_cursor_open(txn, dbi, &cursor);
key.mv_size = sizeof(int);
key.mv_data = sval;
data.mv_size = sizeof(sval);
data.mv_data = sval;
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0)
{
printf("key: %p %d %.*s, data: %p %d %.*s\n",
key.mv_data, (int) key.mv_size, (int) key.mv_size, (char *) key.mv_data,
data.mv_data, (int) data.mv_size, (int) data.mv_size, (char *) data.mv_data);
}
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
mdb_close(env, dbi);
mdb_env_close(env);
return 0;
}
« mdb_dirname » est le répertoire créé par « feature_extractor ». Il contient 'data.mdb' et 'lock.mdb'.
A noté que je suis aussi nouveau à LMDB. Je ne comprends pas vraiment toutes les lignes de code ci-dessus. Cependant, je ne fonctionne pas :)
Si vous traitez votre fichier LMDB, vous pouvez observer que 'key.mv_data' est bien l'index de votre exemple. La donnée 'data.mv_data' devrait donc contenir le vecteur de caractéristiques pour cet exemple. J'ai regardé dans le code source de feature_extractor de Caffe et j'ai trouvé que la chaîne 'data.mv_data' est obtenue à partir de la sérialisation d'un objet 'Datum'. Ce datum est en effet construit à l'aide de Protocol Buffer ou Protobuf de Google. Vous pouvez trouver 'caffe.proto' quelque part dans le répertoire Caffe. Ce fichier .proto est traité par le compilateur 'protoc' et produit 'caffe.pb.h' et 'caffe.pb.cc' qui doivent être inclus dans votre projet. Si vous ne pouvez pas le trouver, voici à quoi cela ressemble
syntax = "proto2";
package caffe;
message Datum {
optional int32 channels = 1;
optional int32 height = 2;
optional int32 width = 3;
// the actual image data, in bytes
optional bytes data = 4;
optional int32 label = 5;
// Optionally, the datum could also hold float data.
repeated float float_data = 6;
// If true data contains an encoded image that need to be decoded
optional bool encoded = 7 [default = false];
}
Ensuite, vous pouvez convertir des données.mv_data » dans les vecteurs de caractéristiques par
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0)
{
string str((char*)data.mv_data, (int)data.mv_size);
datum.ParseFromString(str);
if(datum.float_data_size()>0)
{
// datum.float_data_size() is the dimension of the feature vectors
for(int i = 0; i < datum.float_data_size(); i++)
{
float f = datum.float_data(i);
// do something
}
}
}
Lorsque je construis le code ci-dessus, il y a beaucoup d'erreurs êtes les reliant, comme les références non définies ... et autres étoffes liées à Protobuf. Si vous rencontrez le même problème, une solution que j'ai trouvée est de lier le programme contre libprotobuf.a au lieu de simplement -llmdb (lien statique au lieu de lien dynamique).
Un autre petit problème est que l'étiquette attribuée à chaque exemple dans le fichier traité par 'feature_extractor' est perdue. Je ne sais pas pourquoi. Je viens donc de mettre ces étiquettes dans un fichier séparé et de les traiter le long du fichier LMDB. Par exemple, si vous voulez sortir le fichier LIBSVM:
int c = 0;
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0)
{
string str((char*)data.mv_data, (int)data.mv_size);
datum.ParseFromString(str);
if(datum.float_data_size()>0)
{
cout<< label[c]<< " ";
for(int i = 0; i < datum.float_data_size(); i++)
{
float f = datum.float_data(i);
cout<< (i+1)<< ":"<< f<< " ";
}
cout<< endl;
c++;
}
}
Bonne chance.