使用C++在CAFFE中设置输入层

3
我正在使用CAFFE编写C++代码来预测单个(目前只有一个)图像。该图像已经被预处理并以.png格式存在。我创建了一个Net对象并读取了训练好的模型。现在,我需要将.png图像用作输入层并调用net.Forward() - 但是有人能帮我弄清楚如何设置输入层吗?
我在网上找到了一些示例,但它们都不起作用,几乎所有示例都使用已弃用的功能。根据伯克利的Net API,使用"ForwardPrefilled"已被弃用,并且使用"Forward(vector, float*)"也已被弃用。API表明应该“设置输入blob,然后使用Forward()”。这很有道理,但是“设置输入blob”部分没有详细说明,我找不到一个好的C++示例来说明如何做到这一点。
我不确定是否使用caffe::Datum是正确的方法,但我一直在尝试:
float lossVal = 0.0;
caffe::Datum datum;
caffe::ReadImageToDatum("myImg.png", 1, imgDims[0], imgDims[1], &datum);
caffe::Blob< float > *imgBlob = new caffe::Blob< float >(1, datum.channels(), datum.height(), datum.width());
//How to get the image data into the blob, and the blob into the net as input layer???
const vector< caffe::Blob< float >* > &result = caffeNet.Forward(&lossVal);

再次强调,我希望遵循API的指导,设置输入blobs,然后使用(非废弃的)caffeNet.Forward(&lossVal)来获取结果,而不是使用已弃用的内容。

编辑:

根据下面的答案,我进行了更新,包括以下内容:

caffe::MemoryDataLayer<unsigned char> *memory_data_layer = (caffe::MemoryDataLayer<unsigned char> *)caffeNet.layer_by_name("input").get();
vector< caffe::Datum > datumVec;
datumVec.push_back(datum);
memory_data_layer->AddDatumVector(datumVec);

但现在调用AddDatumVector会导致段错误。我想知道这是否与我的prototxt格式有关?这是我的prototxt开头:

name: "deploy"  

input: "data"
input_shape {
dim: 1
dim: 3
dim: 100
dim: 100
}

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"

我根据这个讨论中关于prototxt中“source”字段的重要性,提出了这个问题...

你可以在你的net.prototxt中使用ImageData层。这个层可以读取你的图像列表并进行一些转换,就像Data层一样。 - Dale
3个回答

1
caffe::Datum datum;
caffe::ReadImageToDatum("myImg.png", 1, imgDims[0], imgDims[1], &datum);
MemoryDataLayer<float> *memory_data_layer = (MemoryDataLayer<float> *)caffeNet->layer_by_name("data").get();
memory_data_layer->AddDatumVector(datum);
const vector< caffe::Blob< float >* > &result = caffeNet.Forward(&lossVal);

这样做可能会很有用。在这里,您将需要使用MemoryData层作为输入层。我期望该层的名称命名为data

使用datum变量的方式可能不正确。如果我记得正确,我猜想,您必须使用一个datum数据向量。

我认为这应该能让您开始工作。

祝您愉快。 :D


因为某些原因,尽管我的prototxt中该层正确命名为data,但我的memory_data_layer被设置为null指针。我仍在努力解决这个问题,因为这似乎是正确的方向。 - daroo
在调试器中,看起来层的名称是“input”,而不是数据 - 它在prototxt中没有指定为层,它以'input:“data”'开头,所以我认为“data”是名称..更改后,memory_data_layer成为有效指针。无论如何,我将datum放入向量中,并将向量传递给AddDatumVector,但现在由于我找不到原因而导致seg faulting - gdb在这里没有帮助,因为似乎下面没有调试符号... - daroo
我在内存数据层方面遇到了问题,是否有其他选项可以避免使用这个层? - Atena Nguyen
有ImageData层、InputData层等可用于替代内存数据层。 - Anoop K. Prabhu

1

这是我代码的一部分,位于此处,其中我在C++代码中使用了Caffe。希望这可以帮到你。

Net<float> caffe_test_net("models/sudoku/deploy.prototxt", caffe::TEST);

caffe_test_net.CopyTrainedLayersFrom("models/sudoku/sudoku_iter_10000.caffemodel");

// Get datum
Datum datum;
if (!ReadImageToDatum("examples/sudoku/cell.jpg", 1, 28, 28, false, &datum)) {
     LOG(ERROR) << "Error during file reading";
}


// Get the blob
Blob<float>* blob = new Blob<float>(1, datum.channels(), datum.height(), datum.width());

// Get the blobproto
BlobProto blob_proto;
blob_proto.set_num(1);
blob_proto.set_channels(datum.channels());
blob_proto.set_height(datum.height());
blob_proto.set_width(datum.width());
int size_in_datum = std::max<int>(datum.data().size(),
                                          datum.float_data_size());

for (int ii = 0; ii < size_in_datum; ++ii) {
     blob_proto.add_data(0.);
}
const string& data = datum.data();
if (data.size() != 0) {
     for (int ii = 0; ii < size_in_datum; ++ii) {
         blob_proto.set_data(ii, blob_proto.data(ii) + (uint8_t)data[ii]);
     }
}

// Set data into blob
blob->FromProto(blob_proto);

// Fill the vector
vector<Blob<float>*> bottom;
bottom.push_back(blob);
float type = 0.0;

const vector<Blob<float>*>& result =  caffe_test_net.Forward(bottom, &type);

谢谢 - 我已经找到了那个例子,但是它使用了一个被弃用的Forward()版本,根据我上面链接的API。我试图避免使用它...我之前尝试过,但仍然没有成功,但承认在看到调用被弃用后没有太多地去尝试。 - daroo

0

这个怎么样:

Caffe::set_mode(Caffe::CPU);
caffe_net.reset(new caffe::Net<float>("your_arch.prototxt", caffe::TEST));
caffe_net->CopyTrainedLayersFrom("your_model.caffemodel");

Blob<float> *your_blob = caffe_net->input_blobs()[0];
your_blob->set_cpu_data(your_image_data_as_pointer_to_float);

caffe_net->Forward();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接