caffe提取特征用svm进行分类

caffe c++批量抽取特征的方法在[1],但是该方法使用中有几个疑问:

1. 如何转换levelDB 格式为libsvm格式。

2.  ./build/tools/extract_features mini-batch 是代表什么意思,和imagenet_val.prototxt中的batch_size的关系是什么?

本文主要解决如上两个问题,具体extract_features源代码还需要进一步分析。

第一个问题,

[plain]  view plain  copy
 
  1. ./build/tools/extract_features models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel examples/_temp/imagenet_val.prototxt fc7 examples/_temp/features 10  
其中,10 是mini-batch, 假设imagenet_val.prototxt的batches size是128, 那么程序将抽取128 * 10个图片的特征。如果你有100张图片, 你可以设置mini-batch = 1, batches size = 100.
如果你的image个数是1283, 那么如上数值的设置会是的leveldb多出3个无用的feature,这个需要注意, 我测试过好像是会重复之前的图片,具体需要研究源代码。


第二个问题, 特征保存的格式为leveldb,如果需要用libsvm的格式访问特征,可以用python 进行转换, 程序如下, 这里感谢bean的程序[1]:

[python]  view plain  copy
 
  1. import numpy as np  
  2. import caffe  
  3. import sys  
  4. from caffe.proto import caffe_pb2  
  5.   
  6. #parse argument  
  7. dbName = sys.argv[1]  
  8. featureFile = sys.argv[2]  
  9. output = open(featureFile, 'w')  
[python]  view plain  copy
 
  1. # open leveldb files  
  2. db = leveldb.LevelDB(dbName)  
  3.   
  4. # get db iterator  
  5. it = db.RangeIter()  
  6. count = 0  
  7. for key,value in it:  
  8.     # convert string to datum  
  9.   
  10.     datum = caffe_pb2.Datum.FromString(db.Get(key))  
  11.   
  12.     # convert datum to numpy string  
  13.   
  14.     arr = caffe.io.datum_to_array(datum)[0]  
  15.   
  16.     i = 0  
  17.     tmpS = ''  
  18.   
  19.     # convert to svm format  
  20.   
  21.     for i in range(0, len(arr)):  
  22.         tmpS += str(i+1) + ':' + str(arr[i].tolist()[0]) + ' '  
  23.     #print tmpS  
  24.     output.write(tmpS.strip() + "\n")  
  25.     count+=1  
  26.     print count  
  27. output.close()  

但是这个程序有个巨大的bug,db.RangeIter()返回的key 顺序是按照 字母 进行排序的,和levelDB的排序方式是不一样的。具体参见[3]:

The problem is most likely caused by re-ordering of training/test examples since the db.RangeIter()iterates over keys in alphabetical order while extract_features creates keys from index values without leading zeros (unlike convert_imageset). Hence, you get an order like 0, 1, 10, 100, ...

Parse the key value in python and put the extracted feature vector at that position.

在这里,我们也只能说fuck了。修改后代码如下 :

[python]  view plain  copy
 
  1. # get db iterator  
  2. it = db.RangeIter()  
  3. features = {}  
  4. for key,value in it:  
  5.     # convert string to datum  
  6.     datum = caffe_pb2.Datum.FromString(value)  
  7.     # convert datum to numpy string   
  8.     arr = caffe.io.datum_to_array(datum)[0]  
  9.     features[int(key)] = arr  
  10.   
  11. #write to file, since the key in it is sorted by alpha_number default, while leveldb is sorted by number, we must sort the key again.  
  12. sort_features = collections.OrderedDict(sorted(features.items()))  
  13. for k, arr  in sort_features.iteritems():  
  14.     if(k > imageCount - 1):  
  15.         break  
  16.     line = ""  
  17.     for i in range(0, len(arr)):  
  18.         line += str(i+1) + ':' + str(arr[i].tolist()[0]) + ' '  
  19.     output.write(line.strip() + "\n")  
  20. output.close()  

通过对比c++和python提取的feature, 大部分是一致的,但是还是有会细微的差别,可能是浮点数的精度问题吧。


参考文章:

1. http://caffe.berkeleyvision.org/gathered/examples/feature_extraction.html

2. http://bean.logdown.com/posts/211192-caffe-use-caffe-to-extract-features-of-each-layer

3. https://github.com/BVLC/caffe/issues/1158

你可能感兴趣的:(caffe框架)