Espruino/libs/tensorflow/jswrap_tensorflow.c

178 lines
5.5 KiB
C

/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains JavaScript interface for Neopixel/WS281x/APA10x devices
* ----------------------------------------------------------------------------
*/
#include <jswrap_tensorflow.h>
#include "jsvariterator.h"
#include "jsparse.h"
#include "jsinteractive.h"
#include "jswrap_arraybuffer.h"
#include "tensorflow.h"
/*JSON{
"type" : "library",
"class" : "tensorflow"
}
*/
void *jswrap_tfmicrointerpreter_getTFMI(JsVar *parent) {
JsVar *mi = jsvObjectGetChildIfExists(parent, "mi");
size_t tfSize;
char *tfPtr = jsvGetDataPointer(mi, &tfSize);
jsvUnLock(mi);
if (!tfPtr)
jsExceptionHere(JSET_ERROR, "TFMicroInterpreter structure corrupted");
//char *otf = tfPtr;
tfPtr = (char*)((((size_t)tfPtr)+15) & ~15);
//jsiConsolePrintf("TFMI 0x%08x -> 0x%08x\n", (int)otf, (int)tfPtr);;
return tfPtr;
}
/*JSON{
"type" : "staticmethod",
"class" : "tensorflow",
"name" : "create",
"generate" : "jswrap_tensorflow_create",
"params" : [
["arenaSize","int","The TensorFlow Arena size"],
["model","JsVar","The model to use - this should be a flat array/string"]
],
"return" : ["JsVar","A tensorflow instance"],
"return_object" : "TFMicroInterpreter"
}
*/
JsVar *jswrap_tensorflow_create(int arena_size, JsVar *model) {
if (arena_size<512) {
jsExceptionHere(JSET_ERROR, "Invalid Arena Size");
return 0;
}
size_t modelSize = 0;
char *modelPtr = jsvGetDataPointer(model, &modelSize);
if (!modelPtr) {
jsExceptionHere(JSET_TYPEERROR, "Model is not a Flat String/ArrayBuffer");
return 0;
}
JsVar *tfmi = jspNewObject(NULL,"TFMicroInterpreter");
if (!tfmi) return 0;
size_t tfSize = tf_get_size((size_t)arena_size, modelPtr);
JsVar *mi = jsvNewFlatStringOfLength(tfSize+15); // need +15 in case the flast string isn't 16 bytes aligned
if (!mi) {
jsExceptionHere(JSET_ERROR, "Unable to allocate enough RAM for TensorFlow");
jsvUnLock(tfmi);
return 0;
}
if (!jsvGetDataPointer(mi, &tfSize)) {
assert(0);
return 0; // should never get here
}
// Now set up values and ensure we get the correct reference
jsvObjectSetChild(tfmi, "model", model); // so we keep a reference
jsvObjectSetChildAndUnLock(tfmi, "mi", mi); // so we keep a reference
char *tfPtr = jswrap_tfmicrointerpreter_getTFMI(tfmi);
// allocate tensorflow
if (!tf_create(tfPtr, (size_t)arena_size, modelPtr)) {
jsExceptionHere(JSET_ERROR, "MicroInterpreter creation failed");
jsvUnLock(tfmi);
return 0;
}
return tfmi;
}
/*JSON{
"type" : "class",
"library" : "tensorflow",
"class" : "TFMicroInterpreter",
"ifdef" : "USE_TENSORFLOW"
}
Class containing an instance of TFMicroInterpreter
*/
JsVar *jswrap_tfmicrointerpreter_tensorToArrayBuffer(JsVar *parent, bool isInput) {
void *tfmi = jswrap_tfmicrointerpreter_getTFMI(parent);
JsVar *mi = jsvObjectGetChildIfExists(parent, "mi");
tf_tensorfinfo tensor = tf_get(tfmi, isInput);
if (!tensor.data || !mi) {
jsExceptionHere(JSET_ERROR, "Unable to get tensor");
return 0;
}
JsVarDataArrayBufferViewType abType = ARRAYBUFFERVIEW_UNDEFINED;
switch (tensor.type) {
case kTfLiteFloat32 :
abType = ARRAYBUFFERVIEW_FLOAT32; break;
case kTfLiteInt32 :
abType = ARRAYBUFFERVIEW_INT32; break;
case kTfLiteUInt8 :
abType = ARRAYBUFFERVIEW_UINT8; break;
case kTfLiteInt16 :
abType = ARRAYBUFFERVIEW_INT16; break;
case kTfLiteInt8 :
abType = ARRAYBUFFERVIEW_INT8; break;
default:
jsExceptionHere(JSET_TYPEERROR, "Unsupported Tensor format TfLiteType:%d", tensor.type);
return 0;
}
size_t tfSize;
char *tfPtr = jsvGetDataPointer(mi, &tfSize);
/* We can't just use 'tfmi' here because that's the 16 byte aligned address.
We need this relative to the unaligned address (tfPtr) */
JsVar *ab = jsvNewArrayBufferFromString(mi,0);
JsVar *b = jswrap_typedarray_constructor(abType, ab, ((size_t)tensor.data)-(size_t)tfPtr, tensor.bytes / JSV_ARRAYBUFFER_GET_SIZE(abType));
jsvUnLock2(ab,mi);
return b;
}
/*JSON{
"type" : "method",
"class" : "TFMicroInterpreter",
"name" : "getInput",
"generate" : "jswrap_tfmicrointerpreter_getInput",
"return" : ["JsVar","An arraybuffer referencing the input data"],
"return_object" : "ArrayBufferView"
}
*/
JsVar *jswrap_tfmicrointerpreter_getInput(JsVar *parent) {
return jswrap_tfmicrointerpreter_tensorToArrayBuffer(parent, true);
}
/*JSON{
"type" : "method",
"class" : "TFMicroInterpreter",
"name" : "getOutput",
"generate" : "jswrap_tfmicrointerpreter_getOutput",
"return" : ["JsVar","An arraybuffer referencing the output data"],
"return_object" : "ArrayBufferView"
}
*/
JsVar *jswrap_tfmicrointerpreter_getOutput(JsVar *parent) {
return jswrap_tfmicrointerpreter_tensorToArrayBuffer(parent, false);
}
/*JSON{
"type" : "method",
"class" : "TFMicroInterpreter",
"name" : "invoke",
"generate" : "jswrap_tfmicrointerpreter_invoke"
}
*/
void jswrap_tfmicrointerpreter_invoke(JsVar *parent) {
void *tfmi = jswrap_tfmicrointerpreter_getTFMI(parent);
if (!tfmi) return;
if (!tf_invoke(tfmi)) {
jsExceptionHere(JSET_TYPEERROR, "TFMicroInterpreter invoke failed");
}
}
// FIXME: what about tf_destroy?