1. 程式人生 > >caffe 用訓練好的模型提取圖片特徵(使用自帶classify.py和classifier.py)

caffe 用訓練好的模型提取圖片特徵(使用自帶classify.py和classifier.py)

原材料:

1)訓練好的caffemodel

2)  定義網路結構的deploy.prototxt配置檔案

3) 訓練時使用的mean檔案,在/cafferoot/python/classify.py的demo中,要求使用的是.npy格式的meanfile,如果我們手上有的是mean.binaryproto檔案,則需要自己完成轉換:可以使用以下convert_mean.py來實現

#!/usr/bin/python

import numpy as np
import sys
sys.path.append('/home/caffe/python')			#caffe_root is your caffe root dir need change
import caffe

blob = caffe.proto.caffe_pb2.BlobProto()
data = open( 'places205CNN_mean.binaryproto', 'rb' ).read()
blob.ParseFromString(data)
arr = np.array( caffe.io.blobproto_to_array(blob) )
out = arr[0]
np.save( 'mean' , out )

places205CNN_mean.binaryproto是我存放在當前目錄下的mean檔案,執行上面的python程式將它轉換成存在當前目錄下的mean.npy檔案。

4)    圖片檔案list,其中存有圖片絕對路徑和圖片的標籤。

具體過程:

/cafferoot/python/classify.py是一個可以實現特徵提取/分類的demo,呼叫的是/cafferoot/python/caffe/classifier.py檔案裡實現的classifer和predict函式。

classify.py可以接受一系列命令列引數,可以接受的資料來源格式非常靈活,包括:圖片絕對路徑/儲存圖片的資料夾路徑/儲存圖片的.npy。檔案內容如下:

#!/usr/bin/env python
"""
classify.py is an out-of-the-box image classifer callable from the command line.

By default it configures and runs the Caffe reference ImageNet model.
"""
import numpy as np
import os
import sys
import argparse
import glob
import time

import caffe


def main(argv):
    pycaffe_dir = os.path.dirname(__file__)

    parser = argparse.ArgumentParser()
    # Required arguments: input and output files.
    parser.add_argument(
        "input_file",
        help="Input image, directory, or npy."
    )
    parser.add_argument(
        "output_file",
        help="Output npy filename."
    )
    # Optional arguments.
    parser.add_argument(
        "--model_def",
        default=os.path.join(pycaffe_dir,
                "../models/bvlc_reference_caffenet/deploy.prototxt"),
        help="Model definition file."
    )
    parser.add_argument(
        "--pretrained_model",
        default=os.path.join(pycaffe_dir,
                "../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel"),
        help="Trained model weights file."
    )
    parser.add_argument(
        "--gpu",
        action='store_true',
        help="Switch for gpu computation."
    )
    parser.add_argument(
        "--center_only",
        action='store_true',
        help="Switch for prediction from center crop alone instead of " +
             "averaging predictions across crops (default)."
    )
    parser.add_argument(
        "--images_dim",
        default='256,256',
        help="Canonical 'height,width' dimensions of input images."
    )
    parser.add_argument(
        "--mean_file",
        default=os.path.join(pycaffe_dir,
                             'caffe/imagenet/ilsvrc_2012_mean.npy'),
        help="Data set image mean of [Channels x Height x Width] dimensions " +
             "(numpy array). Set to '' for no mean subtraction."
    )
    parser.add_argument(
        "--input_scale",
        type=float,
        help="Multiply input features by this scale to finish preprocessing."
    )
    parser.add_argument(
        "--raw_scale",
        type=float,
        default=255.0,
        help="Multiply raw input by this scale before preprocessing."
    )
    parser.add_argument(
        "--channel_swap",
        default='2,1,0',
        help="Order to permute input channels. The default converts " +
             "RGB -> BGR since BGR is the Caffe default by way of OpenCV."
    )
    parser.add_argument(
        "--ext",
        default='jpg',
        help="Image file extension to take as input when a directory " +
             "is given as the input file."
    )
    args = parser.parse_args()

    image_dims = [int(s) for s in args.images_dim.split(',')]

    mean, channel_swap = None, None
    if args.mean_file:
        mean = np.load(args.mean_file)
    if args.channel_swap:
        channel_swap = [int(s) for s in args.channel_swap.split(',')]

    if args.gpu:
        caffe.set_mode_gpu()
        print("GPU mode")
    else:
        caffe.set_mode_cpu()
        print("CPU mode")

    # Make classifier.
    classifier = caffe.Classifier(args.model_def, args.pretrained_model,
            image_dims=image_dims, mean=mean,
            input_scale=args.input_scale, raw_scale=args.raw_scale,
            channel_swap=channel_swap)

    # Load numpy array (.npy), directory glob (*.jpg), or image file.
    args.input_file = os.path.expanduser(args.input_file)
    if args.input_file.endswith('npy'):
        print("Loading file: %s" % args.input_file)
        inputs = np.load(args.input_file)
    elif os.path.isdir(args.input_file):
        print("Loading folder: %s" % args.input_file)
        inputs =[caffe.io.load_image(im_f)
                 for im_f in glob.glob(args.input_file + '/*.' + args.ext)]
    else:
        print("Loading file: %s" % args.input_file)
        inputs = [caffe.io.load_image(args.input_file)]

    print("Classifying %d inputs." % len(inputs))

    # Classify.
    start = time.time()
    predictions = classifier.predict(inputs, not args.center_only)
    print("Done in %.2f s." % (time.time() - start))
    print(predictions)
    # Save
    print("Saving results into %s" % args.output_file)
    np.save(args.output_file, predictions)


if __name__ == '__main__':
    main(sys.argv)

錯誤一:我先將引數預設改為我自己的引數,第一次嘗試執行python classify.py,程式報錯http://blog.csdn.net/woshilimengxi/article/details/62886603 

錯誤二:修改後再次執行classify.py,這裡不再報錯,但程式卡在了loading folder那一步,判斷原因是視訊記憶體不足,電腦卡死。由於原先在資料來源是資料夾路徑的時候,classify是將整個資料夾下符合要求的全部圖片檔案讀入input中,一次性輸入到classifier中。為了解決這一問題,我修改了classify.py檔案,改為一次處理一張圖片。

最終我將/cafferoot/python/classify.py複製到當前專案目錄下,並修改為自己的介面:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
classify.py is an out-of-the-box image classifer callable from the command line.

By default it configures and runs the Caffe reference ImageNet model.
"""
import numpy as np
import os
import sys
import glob
import csv

import caffe
input_list= "/home/mokii/RGB-D/SUNRGBD/trainrgblist.csv"
model_def = "/home/caffe/placesCNN/places205CNN_deploy.prototxt"
pretrained_model = "/home/caffe/placesCNN/places205CNN_iter_300000.caffemodel"
mean_file = '/home/caffe/placesCNN/mean.npy'
center_only =  True
image_dims = [227,227]
mean_file  = '/home/caffe/placesCNN/mean.npy'
input_scale = None
raw_scale=None
channel_swap=[2,1,0]
ext = 'jpg'
feature_path = 'feature.txt'
label_path = 'label.txt'

def main():
    feature_list = []
    label_list = []
    cnt = 0
    mean = np.load(mean_file)
    caffe.set_mode_gpu()
    # Make classifier.
    classifier = caffe.Classifier(model_def, pretrained_model,
            image_dims=image_dims, mean=mean,
            input_scale=input_scale, raw_scale=raw_scale,
            channel_swap=channel_swap)
    # fe = open(feature_path,'w')
    # la = open(label_path,'w')

    fin = open(input_list,'r')
    reader = csv.reader(fin)
    for lines in reader:
        cnt = cnt+1
        inputs = [caffe.io.load_image(lines[0])]
        out = classifier.predict(inputs, -1)
        feature_list.append(out[0])
        label_list.append(lines[1])
        # fe.writelines(out)
        # la.write(str(lines[1]))
        # print len(out[0])
        # print label_list
        # print ('len(label_list): ',len(label_list) )
        # print ("len(feature_list):  ",len(feature_list))
        # print ("len(feature_list[-1]):  ", len(feature_list[-1]))

    feature = np.array(feature_list)
    label = np.array(label_list)
    print(feature.shape,label.shape)
    np.save('feature',feature)
    np.save('label',label)
    fin.close()
    # fe.close()
    # la.close()

if __name__ == '__main__':
    main()


現在只要在專案目錄直接執行extract_feature.py就可以儲存下特徵和標籤ndarray了。