CNTK从入门到深入研究10.docx

上传人:b****4 文档编号:3732786 上传时间:2022-11-25 格式:DOCX 页数:12 大小:21.76KB
下载 相关 举报
CNTK从入门到深入研究10.docx_第1页
第1页 / 共12页
CNTK从入门到深入研究10.docx_第2页
第2页 / 共12页
CNTK从入门到深入研究10.docx_第3页
第3页 / 共12页
CNTK从入门到深入研究10.docx_第4页
第4页 / 共12页
CNTK从入门到深入研究10.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

CNTK从入门到深入研究10.docx

《CNTK从入门到深入研究10.docx》由会员分享,可在线阅读,更多相关《CNTK从入门到深入研究10.docx(12页珍藏版)》请在冰豆网上搜索。

CNTK从入门到深入研究10.docx

CNTK从入门到深入研究10

CNTK从入门到深入研究(10)

前言

CNTK中网络模型的使用是通过EvalDLL进行的。

但EvalDLL目前为C++的实现,本文将仿照CNTK中EvalWrapper工程,将EvalDLL封装为Python可以调用的Python模块。

目标

根据EvalWrapper工程,具体需要封装的其实只有2个全局的方法(分别对应float和double)以及1个接口。

enumNodeGroup

{

nodeInput,//aninputnode

nodeOutput,//anoutputnode

nodeSpecified

};

//IEvaluateModel-interfaceusedbydecodersandothercomponentsthatneedjustevaluatorfunctionalityinDLLform

template

classIEvaluateModel//EvaluateModelInterface

{

public:

virtualvoidInit(conststd:

:

string&config)=0;

virtualvoidDestroy()=0;

virtualvoidCreateNetwork(conststd:

:

string&networkDescription)=0;

virtualvoidGetNodeDimensions(std:

:

map&dimensions,NodeGroupnodeGroup)=0;

virtualvoidStartEvaluateMinibatchLoop(conststd:

:

wstring&outputNodeName)=0;

virtualvoidEvaluate(std:

:

map*>&inputs,std:

:

map*>&outputs)=0;

virtualvoidEvaluate(std:

:

map*>&outputs)=0;

virtualvoidResetState()=0;

};

//GetEval-getaevaluatortypefromtheDLL

//sincewehave2evaluatortypesbasedontemplateparameters,exposes2exports

//couldbedonedirectlywiththetemplatedname,butthatrequiresmangledC++names

template

voidEVAL_APIGetEval(IEvaluateModel**peval);

extern"C"EVAL_APIvoidGetEvalF(IEvaluateModel**peval);

extern"C"EVAL_APIvoidGetEvalD(IEvaluateModel**peval);123456789101112131415161718192021222324252627282930123456789101112131415161718192021222324252627282930

上述声明中的GetEvalF以及GetEvalD方法分别对应获取float或者是double类型的IEvaluateModel。

之后通过IEvaluateModel即可调用已经训练完成的网络模型。

实现

封装的思路

通过Python调用C++的方法有很多,这里计划使用Boost.Python来封装,原因主要是因为CNTK工程中已经引入的Boost库,所以继续使用Boost.Python可以不增加负担,并且目前为Boost.Python的封装的软件也有好多,包括py++等。

使用Boost.Python对C++进行封装也是比较成熟的方法。

所以笔者目前决定使用Boost.Python来对EvalDLL进行针对Python调用的封装。

具体针对Boost.Python的介绍可以参考如下链接:

http:

//www.boost.org/doc/libs/1_60_0/libs/python/doc/html/index.html

另外介绍一点,其实Apache的thrift也是在备选范围内的一种,Thrift的本质目的就是提供一种异步架构的互操作机制。

但是如果要使用Thrift,则需要提供一个service的进程来提供服务。

相比于直接利用C++中本身Boost库提供的机制来讲,Boost.Python在封装上相比较thrift比较麻烦,但是提供给最终用户的调用很方便。

具体针对Thrift的介绍可以参考如下链接:

https:

//thrift.apache.org/

创建及配置工程

为保持CNTK的整体Project的结构风格,笔者将在CNTK工程中的Extensibility目录创建一个子工程,命名为CNTKPythonWrapper,目标目录选择CNTK\Source\Extensibility\。

之后就是配置工程,配置工程不建议用VisualStudio的界面去配置,因为目前已经存在EvalWrapper工程,并且我们的工程配置信息应该同这个类似,所以我建议复制EvalWrapper.vcxproj的内容,来修改我们的配置。

具体需要做的事情就是:

1.将EvalWrapper.vcxproj拷贝至CNTKPythonWrapper工程目录,然后改名为CNTKPythonWrapper.vcxproj覆盖原油的.vcxproj文件。

(这步骤主要是方便直接创建了x64以及Debug和Debuy_CPUonly等编译相关的配置管理)

2.删除.vcxproj中对原有.cpp文件的引用,就是删掉下面的内容,

```

```

3.去掉clr编译选项

4.添加Boost相关的Header文件以及Lib文件引用

5.Post-build时的文件拷贝(主要是boost库的一些dll)

 

重要的一点是Python加载的模块的拓展名为.pyd,我们修改输出文件为.pyd文件

 

根据上述步骤,我们即完成了工程的创建以及配置工作。

由于是该工程是用于封装,所以不必复杂,我们简单的添加一个PythonWrapper.cpp文件在工程中,所有实现都写在这个文件里即可(不用使用头文件,python调用不需要关心这些的)。

Boost.Python简单的介绍

这里简单介绍下Boost.Python的使用,首先是Header文件的引用,

#include11

对于Boost.Python,是通过BOOST_PYTHON_MODULE来创建一个Python的模块,模块名字写在其后面的括号中,具体形式如下:

BOOST_PYTHON_MODULE(TestForPython)

{

usingnamespaceboost:

:

python;

class_("hello",init())

//Addaregularmemberfunction.

.def("greet",&hello:

:

greet)

//Addinvite()asamemberofhello!

.def("invite",invite);

//Alsoaddinvite()asaregularfunctiontothemodule.

def("invite",invite);

}123456789101112123456789101112

上述代码中则实现了一个TestForPython的Python模块的封装,其中,定义了一个hello的类型,hello类型中,包括了一个传入std:

:

string的构造函数,以及greet方法。

而invite方法,被定义了两次,第一次是定义于hello类型中,默认这种定义要求的是可以接受一个hello类型作为传入参数的方法。

而后面单独的def("invite",invite);则是定义invite为一个全局方法。

def函数后面可能根据需要还需要添加针对参数以及返回值的修饰说明,例如下面情况,

def("getHello",getHello,return_value_policy());11

这里定义的getHello方法将返回值作为引用类型返回,这种情况下getHello的原型可能为:

hello&getHello()11

还有就是一些传入的数组等,Boost.Python中,提供了boost:

:

python:

:

list类型供使用。

所以一般c++同Python交互的时候使用该类型,然后再在c++这端将其解开在赋值。

封装IEvaluateModel

笔者对Boost.Python并不是很熟悉,研究了一下午,简单的封装了下IEvalueteModel方法,重点其实涉及到的主要是加载DLL以及找到函数的入口并进行调用。

首先是定义一下GetEval方法的原型,也就是之前在EvalDLL中暴露出来的C方法。

//Usedforretrievingthemodelappropriatefortheelementtype(float/double)

template

usingGetEvalProc=void(*)(IEvaluateModel**);123123

可以根据下面的方法,首先先加载evaldll.dll,然后再该dll中找到具体的获取IEvaluateModel对象的方法(GetEvalF或者是GetEvalD)。

autohModule=LoadLibraryA("evaldll.dll");

if(hModule==nullptr)

{

throwstd:

:

runtime_error("Cannotfindlibrary:

evaldll.dll");

}

autoprocAddress=GetProcAddress(hModule,funcName.c_str());

autogetEvalProc=(GetEvalProc)procAddress;

getEvalProc(&m_eval);

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("CannotgetIEvaluateModel.");

}1234567891011121312345678910111213

最后就是针对于相关接口的封装,其中用到了Boost.Python的一些对象,包括boost:

:

python:

:

dict以及boost:

:

python:

:

list等。

笔者将最后的封装完成的代码粘贴如下:

//Usedforretrievingthemodelappropriatefortheelementtype(float/double)

template

usingGetEvalProc=void(*)(IEvaluateModel**);

///Managedwrapperforthenativeevaluationmodel

template

classIPythonEvaluateModel

{

typedefstd:

:

pair*>MapEntry;

public:

///Initializesanewinstanceoftheclass.

///Factoryfunctionnameforretrievingthenativemodelfromthedll.

IPythonEvaluateModel(conststd:

:

string&funcName)

{

autohModule=LoadLibraryA("evaldll.dll");

if(hModule==nullptr)

{

throwstd:

:

runtime_error("Cannotfindlibrary:

evaldll.dll");

}

autoprocAddress=GetProcAddress(hModule,funcName.c_str());

autogetEvalProc=(GetEvalProc)procAddress;

getEvalProc(&m_eval);

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("CannotgetIEvaluateModel.");

}

}

///InitializesthemodelevaluationlibrarywithaCNTKconfiguration

///Modelconfigurationentries

voidInit(conststd:

:

string&config)

{

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("Objecthasbeendisposed.");

}

m_eval->Init(config);

}

///Createsanetworkbasedfromthenetworkdescriptionintheconfiguration

///Theconfigurationfilecontainingthenetworkdescription

voidCreateNetwork(conststd:

:

string&networkDescription)

{

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("Objecthasbeendisposed.");

}

m_eval->CreateNetwork(networkDescription);

}

///Evaluatesthemodelusingasingleforwardfeedpassandretrievestheoutputlayerdata

///

///

///Resultsforspecifiedlayer

boost:

:

python:

:

listEvaluate(conststd:

:

wstring&outputKey,intoutputSize)

{

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("Objecthasbeendisposed.");

}

std:

:

map*>stdOutputs;

std:

:

shared_ptr>pOutputVector(newstd:

:

vector());

pOutputVector->resize(outputSize);

stdOutputs[outputKey]=pOutputVector.get();

m_eval->Evaluate(stdOutputs);

boost:

:

python:

:

listret;

for(std:

:

vector:

:

iteratoritr=pOutputVector->begin();itr!

=pOutputVector->end();++itr)

{

ret.append(*itr);

}

returnret;

}///Evaluatesthemodelagainstinputdataandretrievestheoutputlayerdata

///

///

///

///Resultsforspecifiedlayer

boost:

:

python:

:

listEvaluate2(constboost:

:

python:

:

dict&inputs,conststd:

:

wstring&outputKey,intoutputSize)

{

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("Objecthasbeendisposed.");

}

std:

:

map*>stdInputs;

std:

:

vector>>resourceManagement;

for(inti=0;ipInputVector(newstd:

:

vector());

resourceManagement.push_back(pInputVector);

boost:

:

python:

:

listtheValues=boost:

:

python:

:

extract(inputs.values()[i]);

for(intj=0;jpush_back(boost:

:

python:

:

extract(theValues[j]));

}

std:

:

wstringkey=boost:

:

python:

:

extract(inputs.keys()[i]);

stdInputs[key]=pInputVector.get();

}

 

std:

:

map*>stdOutputs;

std:

:

shared_ptr>pOutputVector(newstd:

:

vector());

pOutputVector->resize(outputSize);

stdOutputs[outputKey]=pOutputVector.get();

m_eval->Evaluate(stdInputs,stdOutputs);

boost:

:

python:

:

listret;

for(std:

:

vector:

:

iteratoritr=pOutputVector->begin();itr!

=pOutputVector->end();++itr)

{

ret.append(*itr);

}

returnret;

}

std:

:

stringTEST()

{

return"TEST";

}

#if0//NotIMPLEMENT

///Evaluatesthemodelagainstinputdataandretrievestheoutputlayerdata

///

///

voidEvaluate3(constboost:

:

python:

:

dict&inputs,boost:

:

python:

:

dict&outputs)

{

if(m_eval==nullptr)

{

throwstd:

:

runtime_error("Objecthasbeendisposed.");

}

throwstd:

:

runtime_error("Notimplemented.");

}

#endif

~IPythonEvaluateModel()

{

if(m_eval!

=nullptr)

{

m_eval->Destroy();

m_eval=nullptr;

}

}

private:

//Nativemodelevaluationinstance

IEvaluateModel*m_eval;

};

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174

上述封装的内容为base类,根据不同的类型(float或者是double),派生出来2个其他类型,IPythonEvaluateModelF以及IPythonEvaluateModelD,这两个类型将在python中直接使用。

classIPythonEvaluateModelF:

publicIPythonEvaluateModel

{

public:

IPythonEvaluateModelF()

:

IPythonEvaluateModel("GetEvalF")

{

}

};

classIPythonEvaluateModelD:

publicIPythonEvaluateModel

{

public:

IPythonEvaluateModelD()

:

IPythonEvaluateModel("GetEvalD")

{

}

};12345678910111213141516171234567891011121314151617

封装Python模块

上述内容只是将IEvaluateModel给暴露出来,但是并没有暴露到具体的Python模块。

下面的代码将根据Boost.Python将其封装成模块。

BOOST_PYTHON_MODULE(CNTKPythonWrapper)

{

usingnamespace

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 中考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1