-1

http://caffe.berkeleyvision.org/gathered/examples/feature_extraction.htmlの手順に従って、 トレーニング後に新しい画像から特徴を抽出します。

最終的に data.mdb ファイルを取得します。

簡単に操作できるように、フィーチャを txt ファイルに書き込むことをお勧めします。

私はグーグルでいくつかのコードを見つけましたが、うまくいきませんでした。さらに、生成された data.mdb ファイルは、Mac で mdb オープナー アプリを使用して開くと、テーブルがまったく表示されません。

抽出した特徴をテキスト ファイルに書き込む簡単な方法、または画像ごとの実際の値を確認できるように mdb ファイルを操作する簡単な方法はありますか?

4

2 に答える 2

0

この問題を解決する方法を既に理解しているかどうかはわかりませんが、最近見つけた方法を次に示します。

私は Caffe を初めて使用し、Caffe のアーキテクチャ全体を理解するのが難しいと感じています。Caffe の CNN から特徴を抽出し、後で操作する簡単な方法が欲しかっただけです。さらに、私は OSX で作業しており、ソースから Caffe をインストールしていませんでした。「ポート」からインストールしましたが、インストールが不完全なようです。そこで、Caffe が適切にインストールされている別のマシンで Caffe の「feature_extractor」を実行し、出力ファイルを自分のマシンにコピーしてさらに処理しました。

そのためには、LMDB と Google の Protobuf をマシンにインストールする必要があります。C/C++ プログラムを liblmdb および libprotobuf とリンクする必要があります。

Caffe のチュートリアルに従って、AlexNet のレイヤー「fc7」からの出力を LMDB 形式のファイルに保存しました。次に、それを読み取るための簡単な C/C++ プログラムを作成しました。これは、次のコードを使用して実行できます。

#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」は、「feature_extractor」によって作成されたディレクトリです。「data.mdb」と「lock.mdb」が含まれています。

私もLMDBが初めてであることに注意してください。上記のコードのすべての行がよくわかりません。しかし、私は働きます:)

LMDB ファイルを処理すると、「key.mv_data」が実際にサンプルのインデックスであることがわかります。したがって、「data.mv_data」には、この例の特徴ベクトルが含まれている必要があります。Caffe の feature_extractor のソース コードを調べたところ、文字列「data.mv_data」が「Datum」オブジェクトのシリアル化から取得されていることがわかりました。このデータムは、実際には Google の Protocol Buffer または Protobuf を使用して構築されています。Caffe ディレクトリのどこかに「caffe.proto」があるかもしれません。この .proto ファイルは、コンパイラ「protoc」によって処理され、プロジェクトに含める必要がある「caffe.pb.h」と「caffe.pb.cc」を生成します。見つからない場合はこんな感じ

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];
}

次に、「data.mv_data」を特徴ベクトルに変換できます

    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
            }
        }
    }

上記のコードをビルドすると、未定義の参照など、多くのリンク エラーが発生し、Protobuf に関連するその他のエラーが発生します。同じ問題が発生した場合、私が見つけた解決策は、単純に -llmdb (動的リンケージではなく静的リンケージ) ではなく、libprotobuf.a に対してプログラムをリンクすることです。

もう 1 つの小さな問題は、'feature_extractor' によって処理されたファイル内の各サンプルに割り当てたラベルが失われていることです。どうしてか分かりません。そのため、これらのラベルを別のファイルに入れ、LMDB ファイルに沿って処理しました。たとえば、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++;
        }
    }

幸運を。

于 2016-05-16T15:06:27.693 に答える