忍者ブログ

揺動経路の記録

   

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

Visual Studioを用いたPython拡張モジュール作成

pythonからC++で作成したものを使用したい場合の設定メモ。

C++で作成したオンライン線形分類器であるSCW(Soft Confidence-Weighted Learning)
のpython Wrapperを作成しPythonからの使用テストを行った。

【環境】
◆pyd(dll)作成環境
 Visual Studio 2012 for Windows Desktop
◆実行環境
python 2.7.9

1.pyd作成
①[構成プロパティ]-[C/C++]-[全般]の追加のインストールディレクトリ「C:\Python27\include」



②[構成プロパティ]-[リンカー]-[全般]の出力ファイルを.pyd形式に変更する




③[構成プロパティ]-[リンカー]-[入力]の追加の依存ファイルには「C:\Python27\libs\python27.lib」
モジュール定義ファイル名を追加(ここでは便宜上SCW.def)




④モジュールの定義ファイルの作成(SCW.def) 
プロジェクトディレクトリに定義ファイルを作成
------------------------------------ SCW.def ------------------------------------
EXPORTS
initSCW
------------------------------------ SCW.def ------------------------------------

⑤ラッパー作成(実体は未実装)
------------------------------------ scw_wrapper.c ------------------------------------
#include "Python.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <vector>

#include "SCW.h"/* 自作ヘッダー */

using namespace std;

SCW scw;

/* 初期化 */
static PyObject* init(PyObject* self, PyObject* args){
    float eta, C;
    PyObject* x;

    if(!PyArg_ParseTuple(args, "ffO", &eta, &C, &x)) {
        return NULL;
    }
    int len = PyList_Size(x);
    scw(len, eta, C);
    return Py_BuildValue("ff", eta, C);
}


/* 学習 */
static PyObject* train(PyObject* self, PyObject* args){
   
    int y;// 教師(+1, -1)
    PyObject* x;// 特徴ベクトル(Python Object)
    vector<double> x_vec;// 特徴ベクトル(C++)
    PyObject* WObj;// モデル(重みベクトル)
    PyObject* list_item;

    if(!PyArg_ParseTuple(args, "iO", &y, &x)) {
        return NULL;
    }

    /* create array from list */
    for(Py_ssize_t i = 0; i < PyList_Size(x); ++i)
    {
        list_item = PyList_GetItem(x, i);
        x_vec.push_back(PyFloat_AS_DOUBLE(list_item));
    }
    /* SCW学習 */
    scw.train(y, x_vec);

    /* 学習モデル取得 */
    vector<double> Mu = scw.getMu();
    /* create list from array */
    WObj = PyList_New(PyList_Size(x));
    for (Py_ssize_t i = 0; i < PyList_Size(x); ++i)
    {
        PyList_SetItem(WObj, i, PyFloat_FromDouble(Mu[i]));
    }
    return Py_BuildValue("O", WObj);
}

/* 予測 */
static PyObject* predict(PyObject* self, PyObject* args){

    PyObject* x;// 特徴ベクトル(Python Object)
    vector<double> x_vec;// 特徴ベクトル(C++)

    PyObject* list_item;
    if(!PyArg_ParseTuple(args, "O", &x)) {
        return NULL;
    }
    /* create array from list */
    for(Py_ssize_t i = 0; i < PyList_Size(x); ++i)
    {
        list_item = PyList_GetItem(x, i);
        x_vec.push_back(PyFloat_AS_DOUBLE(list_item));
    }

    return Py_BuildValue("i", scw.predict(x_vec));
}

/* Python関数と実態関数を結びつける */
static PyMethodDef defs[] = {
                            {"init", init, METH_VARARGS},
                            {"train", train, METH_VARARGS},
                            {"predict", predict, METH_VARARGS},
                            {NULL, NULL}
};

/* 初期化時pythonから呼ばれる関数 */
/* 定義ファイル(SCW.def)で公開設定されている */
__declspec(dllexport) void APIENTRY initSCW(void){
    Py_InitModule("SCW", defs);
}

------------------------------------ scw_wrapper.c ------------------------------------


⑤ビルド後イベント追加
作成したSCW.pydファイルをpythonのDLLへコピーさせるようにした。
[構成プロパティ]-[ビルドイベント]-[ビルド後イベント]のコマンドラインに以下を追加する。

copy /Y "$(OutDir)SCW.pyd" "C:\Python27\DLLs\SCW.pyd"

2.pythonで使用
いつも通りの方法でモジュールを使用できるはず。

------------------------------------ TestSCW.py ------------------------------------
import numpy as np

import random

import SCW

def load_train_svmguide3():
    train_name = r"./data/svmguide3"
    fp = open(train_name, 'r')
    y = []
    x = []
    line = fp.readline()
    while line:
        xtmp = []
        for d in line.split(' '):
            if ':' in d:
                val = d[d.find(':', 0) + 1:]
                xtmp.append(float(val))
            else:
                y.append(int(d))
            if len(xtmp) == 21: break
        x.append(xtmp)
        line = fp.readline()
    fp.close()
    return y, x

# 共著者のmatlabコード結果との比較
def Debug_Evidence_SCW():
    # データ読み込み
    y, x = load_train_svmguide3()
    # パラメータ設定
    eta = 0.75
    C = 0.0625
    SCW.init(eta, C, x[1011])
    W = SCW.train(y[1011], x[1011])
    Wcheck = [0.01178605000, -0.0009365075000, 0.0001888526875, -0.01455644375, 0.00104711750, \
              -1.96136562500000e-05, 0.00154455250000000, -3.94857937500000e-05, 1.91726312500000e-06, 0.0625, \
              0.04889844375, 0.0502117187500000, 0.0224358625000000, 0.00625, 0.00625, \
              0.04888393125, 0.00596817562500000, 0.0113636375000000, 0.0153821000000000, 0.000229309875000000, 0]
    Wnp = np.array(W)
    Wchecknp = np.array(W)
    print 'Diff:', Wnp - Wcheck

if __name__ == '__main__':

    #Debug_Evidence_SCW()
    y, x = load_train_svmguide3()
    ytest, xtest = load_test_svmguide3()
    # パラメータ設定
    eta = 0.75
    C = 0.0625

    # 学習用順番インデックスリスト作成(ランダムシャッフリング)
    index_list = range(len(y))
    random.shuffle(index_list)
    # 初期化
    SCW.init(eta, C, x[0])
    for idx in index_list:
        W = SCW.train(y[idx], x[idx])

    index_list = range(len(y))
    random.shuffle(index_list)
    tp = 0.0
    for idx in index_list:
        if y[idx] == SCW.predict(x[idx]):
            tp = tp + 1.0


    print 100 * (tp / len(y)), "% (", int(tp), "/", len(y), ")"

------------------------------------ TestSCW.py ------------------------------------

とりあえず、SCWアルゴが共著者のmatlabコードと同じことを確認しつつ
同程度の精度を確認した。


何故か、matlabコードでは未知データに対して精度確認しておらず
自分で確認すると精度が途轍もなく悪かった。。。仕様だろうか?

データが線形分離不可能の可能性もあるが未確認

自分用のソース(Pass付)
PyModule_SCW
PyModule_SCW

PR

COMMENT

NAME
TITLE
MAIL(非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS(コメント編集に必須です)
SECRET
管理人のみ閲覧できます

プロフィール

HN:
stochaotic
性別:
非公開

最新記事

(06/17)
(05/31)
(11/09)
(03/23)
(02/11)

P R

Copyright ©  -- 揺動経路の記録 --  All Rights Reserved
Design by CriCri / Photo by Geralt / powered by NINJA TOOLS / 忍者ブログ / [PR]