Current section

Files

Jump to
tflite_beam c_src tflite tflitetensor.cpp
Raw

c_src/tflite/tflitetensor.cpp

#include <erl_nif.h>
#include "../nif_utils.hpp"
#include "../helper.h"
#include "tensorflow/lite/c/c_api.h"
#include "tensorflow/lite/c/common.h"
#include "tflitetensor.h"
int _tflitetensor_name(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
auto tensor_name_str = TfLiteTensorName(tensor);
ERL_NIF_TERM tensor_name;
unsigned char * ptr;
size_t len = strlen(tensor_name_str);
if (!(ptr = enif_make_new_binary(env, len, &tensor_name))) {
return false;
}
memcpy((char *)ptr, tensor_name_str, len);
out = tensor_name;
return true;
}
int _tflitetensor_shape(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
size_t num_dims = TfLiteTensorNumDims(tensor);
ERL_NIF_TERM * dims = nullptr;
if (num_dims == 0) {
out = enif_make_list_from_array(env, dims, (unsigned)num_dims);
return true;
}
dims = (ERL_NIF_TERM *)enif_alloc(sizeof(ERL_NIF_TERM) * num_dims);
if (dims == nullptr) {
return false;
}
for (size_t i = 0; i < num_dims; ++i) {
size_t dim = TfLiteTensorDim(tensor, i);
dims[i] = enif_make_uint64(env, dim);
}
out = enif_make_list_from_array(env, dims, (unsigned)num_dims);
enif_free(dims);
return true;
}
int _tflitetensor_shape_signature(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
if (tensor->dims_signature == nullptr || tensor->dims_signature->size == 0) {
return _tflitetensor_shape(env, tensor, out);
}
ERL_NIF_TERM shape_signature;
if (erlang::nif::make_i64_list_from_c_array(env, tensor->dims_signature->size, tensor->dims_signature->data, shape_signature)) {
return false;
}
out = shape_signature;
return true;
}
int _tflitetensor_type(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
ERL_NIF_TERM tensor_type;
if (tensor_type_to_erl_term(TfLiteTensorType(tensor), env, tensor_type)) {
out = tensor_type;
return true;
} else {
return false;
}
}
int _tflitetensor_quantization_params(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
const TfLiteQuantization quantization = tensor->quantization;
float* scales_data = nullptr;
int32_t* zero_points_data = nullptr;
int32_t scales_size = 0;
int32_t zero_points_size = 0;
int32_t quantized_dimension = 0;
if (quantization.type == kTfLiteAffineQuantization) {
const TfLiteAffineQuantization* q_params = reinterpret_cast<const TfLiteAffineQuantization*>(quantization.params);
if (q_params) {
if (q_params->scale) {
scales_data = q_params->scale->data;
scales_size = q_params->scale->size;
}
if (q_params->zero_point) {
zero_points_data = q_params->zero_point->data;
zero_points_size = q_params->zero_point->size;
}
quantized_dimension = q_params->quantized_dimension;
}
}
ERL_NIF_TERM scale;
if (erlang::nif::make_f64_list_from_c_array(env, scales_size, scales_data, scale)) {
return false;
}
ERL_NIF_TERM zero_point;
if (erlang::nif::make_i32_list_from_c_array(env, zero_points_size, zero_points_data, zero_point)) {
return false;
}
ERL_NIF_TERM quantized_dimension_term = enif_make_int(env, quantized_dimension);
out = enif_make_tuple3(env, scale, zero_point, quantized_dimension_term);
return true;
}
int _tflitetensor_sparsity_params(ErlNifEnv *env, TfLiteTensor * tensor, ERL_NIF_TERM &out) {
if (tensor->sparsity == nullptr) {
out = enif_make_new_map(env);
return true;
}
auto param = tensor->sparsity;
const size_t NUM_SPARITY_ITEMS = 3;
ERL_NIF_TERM sparsity_keys[NUM_SPARITY_ITEMS];
ERL_NIF_TERM sparsity_vals[NUM_SPARITY_ITEMS];
const size_t TRAVERSAL_ORDER_INDEX = 0;
const size_t BLOCK_MAP_INDEX = 1;
const size_t DIM_METADATA_INDEX = 2;
sparsity_keys[TRAVERSAL_ORDER_INDEX] = erlang::nif::atom(env, "traversal_order");
if (erlang::nif::make_i64_list_from_c_array(env, param->traversal_order->size, param->traversal_order->data, sparsity_vals[TRAVERSAL_ORDER_INDEX])) {
return false;
}
sparsity_keys[BLOCK_MAP_INDEX] = erlang::nif::atom(env, "block_map");
if (erlang::nif::make_i64_list_from_c_array(env, param->block_map->size, param->block_map->data, sparsity_vals[BLOCK_MAP_INDEX])) {
return false;
}
sparsity_keys[DIM_METADATA_INDEX] = erlang::nif::atom(env, "dim_metadata");
ERL_NIF_TERM * dim_metadata = (ERL_NIF_TERM *)enif_alloc(sizeof(ERL_NIF_TERM) * param->dim_metadata_size);
if (dim_metadata == nullptr) {
return false;
}
const size_t NUM_DIM_METADTA_ITEMS = 3;
for (int i = 0; i < param->dim_metadata_size; i++) {
ERL_NIF_TERM dim_metadata_i;
ERL_NIF_TERM dim_metadata_i_keys[NUM_DIM_METADTA_ITEMS];
ERL_NIF_TERM dim_metadata_i_vals[NUM_DIM_METADTA_ITEMS];
if (param->dim_metadata[i].format == kTfLiteDimDense) {
dim_metadata_i_keys[0] = erlang::nif::atom(env, "format");
dim_metadata_i_vals[0] = erlang::nif::make(env, (long)0);
dim_metadata_i_keys[1] = erlang::nif::atom(env, "dense_size");
dim_metadata_i_vals[1] = erlang::nif::make(env, (long)param->dim_metadata[i].dense_size);
enif_make_map_from_arrays(env, dim_metadata_i_keys, dim_metadata_i_vals, 2, &dim_metadata_i);
} else {
dim_metadata_i_keys[0] = erlang::nif::atom(env, "format");
dim_metadata_i_vals[0] = erlang::nif::make(env, (long)1);
const auto* array_segments = param->dim_metadata[i].array_segments;
const auto* array_indices = param->dim_metadata[i].array_indices;
dim_metadata_i_keys[1] = erlang::nif::atom(env, "array_segments");
if (erlang::nif::make_i64_list_from_c_array(env, array_segments->size, array_segments->data, dim_metadata_i_vals[1])) {
return false;
}
dim_metadata_i_keys[2] = erlang::nif::atom(env, "array_indices");
if (erlang::nif::make_i64_list_from_c_array(env, array_indices->size, array_indices->data, dim_metadata_i_vals[2])) {
return false;
}
enif_make_map_from_arrays(env, dim_metadata_i_keys, dim_metadata_i_vals, 3, &dim_metadata_i);
}
dim_metadata[i] = dim_metadata_i;
}
sparsity_vals[DIM_METADATA_INDEX] = enif_make_list_from_array(env, dim_metadata, (unsigned)param->dim_metadata_size);
enif_free(dim_metadata);
enif_make_map_from_arrays(env, sparsity_keys, sparsity_vals, NUM_SPARITY_ITEMS, &out);
return true;
}
ERL_NIF_TERM tflitetensor_type(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
ERL_NIF_TERM self_nif = argv[0];
NifResTfLiteTensor *self_res;
if (!enif_get_resource(env, self_nif, NifResTfLiteTensor::type, (void **)&self_res) || self_res->val == nullptr) {
return erlang::nif::error(env, "cannot access NifResTfLiteTensor resource");
}
ERL_NIF_TERM ret = erlang::nif::error(env, "invalid tensor");
_tflitetensor_type(env, self_res->val, ret);
return ret;
}
ERL_NIF_TERM tflitetensor_dims(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
ERL_NIF_TERM self_nif = argv[0];
NifResTfLiteTensor *self_res;
if (!enif_get_resource(env, self_nif, NifResTfLiteTensor::type, (void **)&self_res) || self_res->val == nullptr) {
return erlang::nif::error(env, "cannot access NifResTfLiteTensor resource");
}
ERL_NIF_TERM tensor_shape;
if (!_tflitetensor_shape(env, self_res->val, tensor_shape)) {
return erlang::nif::error(env, "cannot allocate memory for storing tensor shape");
}
return erlang::nif::ok(env, tensor_shape);
}
ERL_NIF_TERM tflitetensor_quantization_params(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
ERL_NIF_TERM self_nif = argv[0];
NifResTfLiteTensor *self_res;
if (!enif_get_resource(env, self_nif, NifResTfLiteTensor::type, (void **)&self_res) || self_res->val == nullptr) {
return erlang::nif::error(env, "cannot access NifResTfLiteTensor resource");
}
ERL_NIF_TERM tensor_quantization_params;
if (!_tflitetensor_quantization_params(env, self_res->val, tensor_quantization_params)) {
return erlang::nif::error(env, "cannot allocate memory for storing tensor quantization params");
}
return erlang::nif::ok(env, tensor_quantization_params);
}
ERL_NIF_TERM tflitetensor_to_binary(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
ERL_NIF_TERM self_nif = argv[0];
ERL_NIF_TERM limit = argv[1];
NifResTfLiteTensor *self_res;
ErlNifUInt64 limit_len;
if (!enif_get_resource(env, self_nif, NifResTfLiteTensor::type, (void **)&self_res) || self_res->val == nullptr) {
return erlang::nif::error(env, "cannot access NifResTfLiteTensor resource");
}
if (!enif_get_uint64(env, limit, (ErlNifUInt64 *)&limit_len)) {
return erlang::nif::error(env, "expecting limit to be an unsigned integer");
}
ErlNifBinary tensor_data;
size_t tensor_size = self_res->val->bytes;
size_t bytes_to_return = tensor_size;
if (limit_len != 0 && limit_len < tensor_size) {
bytes_to_return = limit_len;
}
if (!enif_alloc_binary(bytes_to_return, &tensor_data)) {
return erlang::nif::error(env, "cannot allocate enough memory for the tensor");
}
memcpy(tensor_data.data, self_res->val->data.data, bytes_to_return);
return erlang::nif::ok(env, enif_make_binary(env, &tensor_data));
}
ERL_NIF_TERM tflitetensor_set_data(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
ERL_NIF_TERM self_nif = argv[0];
ERL_NIF_TERM data_nif = argv[1];
ErlNifBinary data;
NifResTfLiteTensor *self_res;
if (!enif_get_resource(env, self_nif, NifResTfLiteTensor::type, (void **)&self_res) || self_res->val == nullptr) {
return erlang::nif::error(env, "cannot access NifResTfLiteTensor resource");
}
if (!enif_inspect_binary(env, data_nif, &data)) {
return erlang::nif::error(env, "cannot get input data");
}
if (self_res->val->data.data == nullptr) {
return erlang::nif::error(env, "tensor is not allocated yet? Please call TFLite.Interpreter.allocateTensors first");
}
size_t maximum_bytes = self_res->val->bytes;
if (data.size < maximum_bytes) {
maximum_bytes = data.size;
}
memcpy(self_res->val->data.data, data.data, maximum_bytes);
return erlang::nif::ok(env);
}