将功能提取到文本文件

时间:2015-10-01 05:10:44

标签: neural-network caffe lmdb

按照步骤进行操作 http://caffe.berkeleyvision.org/gathered/examples/feature_extraction.html 在训练后从新图像中提取特征,

你最终获得了一个data.mdb文件。

我更喜欢将功能写入txt文件,以便我可以轻松操作它。

我做了一些谷歌搜索,发现了一些代码,但没有奏效。此外,生成的data.mdb文件,当使用mac上的mdb opener apps打开时,根本不显示任何表。

是否有一种简单的方法可以将提取的特征写入文本文件,或者,可以轻松地操作mdb文件,以便我们可以检查每个图像的实际值?

2 个答案:

答案 0 :(得分:0)

Caffe的c ++接口提供了一些lmdb功能来读取数据,然后将其写回。

您可以使用look yourself来了解LMDBDataLayer如何执行它的读取,然后将其用作编写程序来编写程序来操作/写入来自LMDB数据库的数据文本。

答案 1 :(得分:0)

我不知道你是否已经知道如何解决这个问题,但这是我最近刚刚发现的。

我是Caffe的新手,我发现很难理解整个Caffe的架构。我只想要一个快速的方法从Caffe的CNN中提取特征并在以后操作它们。此外,我在OSX上工作,并没有从源代码安装Caffe。我通过'port'安装它,安装似乎不完整。所以我在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'对象的序列化中获得的。这个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相关的其他内容。如果你遇到同样的问题,我发现的解决方案是将程序与libprotobuf.a链接,而不是简单的-llmdb(静态链接而不是动态链接)。

另一个小问题是我分配给'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++;
        }
    }
祝你好运。