Skip to content

Commit

Permalink
input/output buffer support
Browse files Browse the repository at this point in the history
  • Loading branch information
chaoqing committed Apr 16, 2024
1 parent db4bee0 commit 6721fec
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 85 deletions.
42 changes: 42 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/example/example.out",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/example",
"environment": [{
"name": "PATH",
"value": "/opt/conda/envs/py38/bin"
}],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
},
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
2 changes: 1 addition & 1 deletion example/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
CC = c++

# Compiler flags
CFLAGS = -O3 -Wall -std=c++17 -fPIC
CFLAGS = -g -Wall -std=c++17 -fPIC
CFLAGS = -I../src/cpp
CFLAGS += $(shell python3-config --cflags --ldflags --embed)
CFLAGS += $(shell python3 -m pybind11 --includes)
Expand Down
28 changes: 15 additions & 13 deletions example/main.cpp
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
#include <algorithm>
#include <iostream>
#include <iterator>
#define PYBIND11_DETAILED_ERROR_MESSAGES

#include "PyCXpress.hpp"
#include "Utils.hpp"

namespace pcx = PyCXpress;

void show_test(pcx::PythonInterpreter &python) {
std::vector<float> data(6);
for (size_t i = 0; i < 6; i++) {
std::vector<double> data(12);
for (size_t i = 0; i < 12; i++) {
data[i] = i;
}

memcpy(python.set_buffer("input_a", {3, 2}), data.data(),
data.size() * sizeof(float));
memcpy(python.set_buffer("input_b", {3, 2}), data.data(),
data.size() * sizeof(float));
std::vector<uint8_t> shape = {3, 4};
memcpy(python.set_buffer("data_to_be_reshaped", {12}), data.data(),
data.size() * sizeof(double));
memcpy(python.set_buffer("new_2d_shape", {2}), shape.data(),
shape.size() * sizeof(uint8_t));

python.run();

void *p = nullptr;
std::vector<size_t> shape;
std::tie(p, shape) = python.get_buffer("output_a");
std::vector<size_t> new_shape;
std::tie(p, new_shape) = python.get_buffer("output_a");

std::cout << "output shape: ";
std::copy(shape.begin(), shape.end(),
std::ostream_iterator<double>(std::cout, ", "));
std::copy(new_shape.begin(), new_shape.end(),
std::ostream_iterator<size_t>(std::cout, ", "));
std::cout << std::endl;

size_t size =
std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<int>());
size_t size = std::accumulate(new_shape.begin(), new_shape.end(), 1,
std::multiplies<int>());
std::cout << "output data: ";
std::copy((float *)p, (float *)p + size,
std::copy((double *)p, (double *)p + size,
std::ostream_iterator<double>(std::cout, ", "));
std::cout << std::endl;
}
Expand Down
61 changes: 55 additions & 6 deletions example/model.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,69 @@
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import logging
logging.basicConfig(level=logging.DEBUG)

from pathlib import Path
import sys
import numpy as np
sys.path.append(str(Path(__file__).parent/".."/"src"/"python"))

from PyCXpress import debug_array
from PyCXpress import InputDataSet, OutputDataSet
from PyCXpress import TensorMeta, ModelAnnotationCreator, ModelAnnotationType, ModelRuntimeType
from PyCXpress import convert_to_spec_tuple
from contextlib import nullcontext

def show(a):
debug_array(a)
def show(a: np.array):
logging.info(f"array data type: {a.dtype}")
logging.info(f"array data shape: {a.shape}")
logging.info(f"array data: ")
logging.info(a)

InputFields = dict(
data_to_be_reshaped=TensorMeta(dtype=np.float_,
shape=(100,),
),
new_2d_shape=TensorMeta(dtype=np.uint8,
shape=-2,)
)


class InputDataSet(metaclass=ModelAnnotationCreator, fields=InputFields, type=ModelAnnotationType.Input, mode=ModelRuntimeType.EagerExecution):
pass


OutputFields = dict(
output_a=TensorMeta(dtype=np.float_,
shape=(10, 10),),
)


class OutputDataSet(metaclass=ModelAnnotationCreator, fields=OutputFields, type=ModelAnnotationType.Output, mode=ModelRuntimeType.EagerExecution):
pass


def init():
return InputDataSet(), OutputDataSet()
return InputDataSet(), OutputDataSet(), tuple((*convert_to_spec_tuple(InputFields.values()), *convert_to_spec_tuple(OutputFields.values()))), tuple(OutputFields.keys())

def model(input: InputDataSet, output: OutputDataSet):
with nullcontext():
output.output_a = input.input_a + input.input_b
# print(input.data_to_be_reshaped)
# print(input.new_2d_shape)
output.output_a = input.data_to_be_reshaped.reshape(input.new_2d_shape)
# print(output.output_a)

def main():
input_data, output_data, spec = init()
print(spec)

input_data.set_buffer_value("data_to_be_reshaped", np.arange(12, dtype=np.float_))
print(input_data.data_to_be_reshaped)
input_data.set_buffer_value("new_2d_shape", np.array([3, 4]).astype(np.uint8))
print(input_data.new_2d_shape)
output_data.set_buffer_value("output_a", np.arange(12)*0)

model(input_data, output_data)
print(output_data.output_a)
print(output_data.get_buffer_shape("output_a"))

if __name__ == "__main__":
main()
92 changes: 66 additions & 26 deletions src/cpp/PyCXpress.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,39 @@ class Buffer {
m_data = new Bytes[m_size];
m_length = size;

if (data_type == "bool_") {
if (data_type == "bool") {
m_converter = __to_array<bool>;
m_length /= sizeof(bool);
} else if (data_type == "float_") {
} else if (data_type == "int8_t") {
m_converter = __to_array<int8_t>;
m_length /= sizeof(int8_t);
} else if (data_type == "int16_t") {
m_converter = __to_array<int16_t>;
m_length /= sizeof(int16_t);
} else if (data_type == "int32_t") {
m_converter = __to_array<int32_t>;
m_length /= sizeof(int32_t);
} else if (data_type == "int64_t") {
m_converter = __to_array<int64_t>;
m_length /= sizeof(int64_t);
} else if (data_type == "uint8_t") {
m_converter = __to_array<uint8_t>;
m_length /= sizeof(uint8_t);
} else if (data_type == "uint16_t") {
m_converter = __to_array<uint16_t>;
m_length /= sizeof(uint16_t);
} else if (data_type == "uint32_t") {
m_converter = __to_array<uint32_t>;
m_length /= sizeof(uint32_t);
} else if (data_type == "uint64_t") {
m_converter = __to_array<uint64_t>;
m_length /= sizeof(uint64_t);
} else if (data_type == "float") {
m_converter = __to_array<float>;
m_length /= sizeof(float);
} else if (data_type == "double") {
m_converter = __to_array<double>;
m_length /= sizeof(double);
} else {
throw NotImplementedError(data_type);
}
Expand Down Expand Up @@ -98,31 +125,34 @@ class PythonInterpreter {
const std::vector<size_t> &shape) {
auto &buf = m_buffers[name];
void *p = buf.set(shape);
m_py_input.attr("set")(name, buf.get());
m_py_input.attr("set_buffer_value")(name, buf.get());
return p;
}

std::pair<void *, std::vector<size_t>> get_buffer(const std::string &name) {
auto &array = m_buffers[name].get();
return std::make_pair(
array.request().ptr,
std::vector<size_t>(array.shape(), array.shape() + array.ndim()));
auto &array = m_buffers[name].get();
auto pShape = m_output_buffer_sizes.find(name);
if (pShape == m_output_buffer_sizes.end()) {
return std::make_pair(
array.request().ptr,
std::vector<size_t>(array.shape(),
array.shape() + array.ndim()));
} else {
return std::make_pair(array.request().ptr, pShape->second);
}
}

void run() {
auto &buf = m_buffers["output_a"];
buf.reset();
m_py_output.attr("set_buffer")("output_a", buf.get());

p_pkg->attr("model")(m_py_input, m_py_output);

py::tuple py_shape = m_py_output.attr("get_shape")("output_a");
auto &shape = m_output_buffer_sizes["output_a"];
shape.clear();
for (auto d = py_shape.begin(); d != py_shape.end(); d++) {
shape.push_back(d->cast<int>());
for (auto &kv : m_output_buffer_sizes) {
kv.second.clear();
py::tuple shape = m_py_output.attr("get_buffer_shape")(kv.first);

for (auto &d : shape) {
kv.second.push_back(d.cast<size_t>());
}
}
set_buffer("output_a", shape);
}

void show_buffer(const std::string &name) {
Expand All @@ -135,19 +165,29 @@ class PythonInterpreter {
const char *const *argv, bool add_program_dir_to_path) {
py::initialize_interpreter(true, 0, nullptr, true);

m_buffers.insert(std::make_pair("input_a", Buffer{1000, "float_"}));
m_buffers.insert(std::make_pair("input_b", Buffer{1000, "float_"}));
m_buffers.insert(std::make_pair("output_a", Buffer{1000, "float_"}));


p_pkg = std::make_unique<py::module_>(py::module_::import("model"));

py::print(p_pkg->attr("__file__"));

m_py_input = p_pkg->attr("InputDataSet")();
m_py_output = p_pkg->attr("OutputDataSet")();
py::tuple spec, output_fields;
std::tie(m_py_input, m_py_output, spec, output_fields) =
p_pkg->attr("init")()
.cast<
std::tuple<py::object, py::object, py::tuple, py::tuple>>();

for (auto d = spec.begin(); d != spec.end(); d++) {
auto meta = d->cast<py::tuple>();
m_buffers.insert(std::make_pair(
meta[0].cast<std::string>(),
Buffer{meta[2].cast<int>(), meta[1].cast<std::string>()}));
}

m_py_output.attr("set_buffer")("output_a", m_buffers["output_a"].get());
for (auto d = output_fields.begin(); d != output_fields.end(); d++) {
const auto name = d->cast<std::string>();
m_output_buffer_sizes[name] = {};
auto &buf = m_buffers[name];
buf.reset();
m_py_output.attr("set_buffer_value")(name, buf.get());
}
}

void finalize() {
Expand Down
Loading

0 comments on commit 6721fec

Please sign in to comment.