Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[circle-interpreter] Introduce a library for C-Python interaction #14369

Merged
merged 3 commits into from
Nov 28, 2024

Conversation

mhs4670go
Copy link
Contributor

This commit introduces a library for C-Python interaction.

Related: #14352
ONE-DCO-1.0-Signed-off-by: seongwoo [email protected]

This commit introduces a library for C-Python interaction.

ONE-DCO-1.0-Signed-off-by: seongwoo <[email protected]>
@mhs4670go mhs4670go added the PR/ready for review It is ready to review. Please review it. label Nov 26, 2024
@mhs4670go mhs4670go requested a review from a team November 26, 2024 08:28
@mhs4670go
Copy link
Contributor Author

mhs4670go commented Nov 26, 2024

This is Python side codes.

from cffi import FFI

ffi = FFI()
ffi.cdef("""
  typedef struct InterpreterWrapper InterpreterWrapper;

  InterpreterWrapper *Interpreter_new(const uint8_t *data, const size_t data_size);
  void Interpreter_delete(InterpreterWrapper *intp);
  void Interpreter_interpret(InterpreterWrapper *intp);
  void Interpreter_writeInputTensor(InterpreterWrapper *intp, const int input_idx, const void *data);
  void Interpreter_readOutputTensor(InterpreterWrapper *intp, const int output_idx, void *output, size_t output_size);
""")
C = ffi.dlopen('./libcircle_interpreter_cffi.so')

import torch
class add(torch.nn.Module):
  def __init__(self):
    super().__init__()

  def forward(self, x, y):
    return x + y

  def get_inputs(self):
    return (torch.randn(3), torch.randn(3))

m = add()

import circle_exir
cm = circle_exir.convert(m, m.get_inputs())
model_data = ffi.from_buffer(cm.circle_binary)

import numpy as np

intp = C.Interpreter_new(model_data, len(cm.circle_binary))

inputs = m.get_inputs()
arr1 = inputs[0].numpy()
arr2 = inputs[1].numpy()
c_arr1 = ffi.from_buffer(arr1)
c_arr2 = ffi.from_buffer(arr2)
print (f'Input1: {arr1}')
print (f'Input2: {arr2}')

# Set input
C.Interpreter_writeInputTensor(intp, 0, c_arr1)
C.Interpreter_writeInputTensor(intp, 1, c_arr2)

# Interpret
C.Interpreter_interpret(intp)

# Retrieve output tensor info
from circle_schema import circle
model = circle.Model.Model.GetRootAsModel(cm.circle_binary, 0)
graph = model.Subgraphs(0)
out_tensors = [graph.Tensors(graph.Outputs(o)) for o in range(graph.OutputsLength())]
out_shapes = [t.ShapeAsNumpy() for t in out_tensors]
out_types = [t.Type() for t in out_tensors]

# Get output
result = np.empty(out_shapes[0], dtype=np.float32)
c_result = ffi.from_buffer(result)
C.Interpreter_readOutputTensor(intp, 0, c_result, 12)
print (f'Output: {result}')

# Free memory
C.Interpreter_delete(intp)
python eval.py
Input1: [ 1.5746298  2.3252928 -1.2210928]
Input2: [0.46135813 0.6819443  0.09515246]
Output: [ 2.0359879  3.0072372 -1.1259403]

@seanshpark
Copy link
Contributor

Q) any plans for unit tests ?

@mhs4670go
Copy link
Contributor Author

mhs4670go commented Nov 27, 2024

Q) any plans for unit tests ?

Please refer to #14376.

{
const auto output_nodes = loco::output_nodes(_module->graph());
const auto output_node =
loco::must_cast<const luci::CircleOutput *>(output_nodes.at(output_idx));
Copy link
Contributor

@jinevening jinevening Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about throwing an exception if output_size != getTensorSize(output_node) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding an exception if output_size != getTensorSize(output_node) ?
Why doesn't writeInputTensor have data_size argument? readOutputTensor has output_size argument.

I'll add input data size argument and add an exception to both sides.

@mhs4670go
Copy link
Contributor Author

With patched codes, the error message prints like this.

$ python eval.py
C++ Exception: Invalid input size: 12 != 2

Comment on lines +43 to +47
// Function to retrieve the last error message.
extern "C" const char *get_last_error(void) { return last_error_message.c_str(); }

// Clear the last error message
extern "C" void clear_last_error(void) { last_error_message.clear(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these functions for? Is it used in Python-side? If so, could you show the Python codes too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the python codes.

def check_for_errors():
  error_message = ffi.string(C.get_last_error()).decode('utf-8')
  if error_message:
    C.clear_last_error()
    raise RuntimeError(f'C++ Exception: {error_message}')

# ..

try:
  C.Interpreter_writeInputTensor(intp, 0, c_arr1, 123456)
  check_for_errors()
except RuntimeError as e:
  print(e)

jinevening
jinevening previously approved these changes Nov 27, 2024
Copy link
Contributor

@jinevening jinevening left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The interface seems a bit tricky to use, but I guess it may be wrapped by other functions in python.

Copy link
Contributor

@seanshpark seanshpark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@seanshpark seanshpark merged commit 8c6cde6 into Samsung:master Nov 28, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR/ready for review It is ready to review. Please review it.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants