Текущие фреймворки глубокого обучения обычно реализуются на основе Python, а построение, обучение, сохранение и вызов моделей можно легко выполнить с помощью Python. Но иногда, когда мы действительно применяем эти модели, нам может потребоваться сделать это на других языках программирования.В этой статье предварительно обученная модель TensorFlow будет вызываться в программе C/C++ путем косвенного вызова Python из C/C++.
1. Конфигурация среды
-
Чтобы вызвать Python в C/C++, нам нужно настроить путь к заголовочным файлам и библиотекам.В этой статье в качестве примера используется Code::Blocks.
-
Добавить библиотеку ссылок в Build -> Project optionslibpython3.5m.soА путь, где находится заголовочный файл Python.h, разные версии Python можно корректировать по ситуации.
2. Инициализировать и импортировать модули Python и связанные с ними функции
void Initialize()
{
Py_Initialize();
if ( !Py_IsInitialized() )
{
printf("Initialize failed!");
}
// Path of the python file. 需要更改为 python 文件所在路径
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('/home/senius/python/c_python/test/')");
const char* modulName = "forward"; // Module name of python file.
pMod = PyImport_ImportModule(modulName);
if(!pMod)
{
printf("Import Module failed!\n");
}
const char* funcName = "load_model"; // Function name in the python file.
load_model = PyObject_GetAttrString(pMod, funcName);
if(!load_model)
{
printf("Import load_model Function failed!\n");
}
funcName = "predict"; // Function name in the python file.
predict = PyObject_GetAttrString(pMod, funcName);
if(!predict)
{
printf("Import predict Function failed!\n");
}
PyEval_CallObject(load_model, NULL); // 导入预训练的模型
pParm = PyTuple_New(1); // 新建一个元组,参数只能通过元组传入 Python 程序
}
- Через PyImport_ImportModule мы можем импортировать файл Python, который нужно вызвать, затем получить функции в модуле через PyObject_GetAttrString и, наконец, импортировать предварительно обученную модель и создать новый кортеж в качестве параметра.
3. Создание аргументов, передаваемых в Python из C
void Read_data()
{
const char* txtdata_path = "/home/senius/python/c_python/test/04t30t00.npy";
//Path of the TXT file. 需要更改为txt文件所在路径
FILE *fp;
fp = fopen(txtdata_path, "rb");
if(fp == NULL)
{
printf("Unable to open the file!");
}
fread(data, num*SIZE, sizeof(float), fp);
fclose(fp);
// copying the data to the list
int j = 0;
pArgs = PyList_New(num * SIZE); // 新建一个列表,并填入数据
while(j < num * SIZE)
{
PyList_SET_ITEM(pArgs, j, Py_BuildValue("f", data[j]));
j++;
}
}
- Считайте тестовые данные и заполните список данными.
4. Передайте список в кортеж, затем передайте его в Python в качестве параметра и проанализируйте возвращаемое значение.
void Test()
{
PyTuple_SetItem(pParm, 0, pArgs);
pRetVal = PyEval_CallObject(predict, pParm);
int list_len = PyList_Size(pRetVal);
PyObject *list_item = NULL;
PyObject *tuple_item = NULL;
for (int i = 0; i < list_len; i++)
{
list_item = PyList_GetItem(pRetVal, i);
tuple_item = PyList_AsTuple(list_item);
PyArg_ParseTuple(tuple_item, "f", &iRetVal[i]);
}
}
- Передайте кортеж в программу Python, вызовите функцию прогнозирования, чтобы получить возвращаемое значение, а затем проанализируйте его.
5. Некоторые параметры и основная функция
#include <Python.h>
#include <stdio.h>
#define SIZE 41*41*41*3
#define NUM 100
PyObject* pMod = NULL;
PyObject* load_model = NULL;
PyObject* predict = NULL;
PyObject* pParm = NULL;
PyObject* pArgs = NULL;
PyObject* pRetVal = NULL;
float iRetVal[NUM*3] = {0};
float data[NUM * SIZE] = {0};
int num = 1; //实际的样本数100
void Initialize();
void Read_data();
void Test();
int main(int argc, char **argv)
{
Initialize(); // 初始化
Read_data(); // 读入数据
Test(); // 调用预测函数并解析返回值
int j = 0;
while(j < num*3)
{
printf("%f\n", iRetVal[j]);
j++;
}
printf("Done!\n");
Py_Finalize();
return 0;
}
Для более захватывающих, пожалуйста, обратите внимание на "seniusen"!