tinyml-backend / frontend /src /lib /edge /c_exporter.ts
IDKHowToCodeFr's picture
Upload folder using huggingface_hub
604d53b verified
Raw History Blame Contribute Delete
19.9 kB
export interface CExportResult {
code: string;
flashBytes: number;
sramBytes: number;
latencyCycles: number;
}
export function generateCHeader(
modelName: string,
quantize: boolean = false,
targetMcu: string = "esp32",
optLevel: string = "o3"
): string {
const model = modelName.toLowerCase();
const dateStr = new Date().toISOString().split("T")[0];
const qStr = quantize ? "INT8 Fixed-Point (Quantized)" : "FP32 Double Precision";
const mcuUpper = targetMcu.toUpperCase();
// 1. Random Forest Ensemble
if (model === "rf" || model === "random_forest") {
if (quantize) {
return `/* ========================================================================== */
/* TinyML C Header Export: INT8 Quantized Random Forest Classifier */
/* Generated by HEARTFLOW_OS Edge Compiler Toolchain */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Precision: INT8 Fixed-Point (Weights scaled -128..127) */
/* Zero dynamic heap memory (0 malloc bytes) // SRAM Footprint: 28 Bytes */
/* Date: ${dateStr} */
/* ========================================================================== */
#ifndef MODEL_RF_INT8_H
#define MODEL_RF_INT8_H
#include <stdint.h>
#define N_FEATURES 5
#define N_CLASSES 5
#define N_TREES 25
#define SCALE_FACTOR_Q7 128
/* Normalized integer thresholds scaled x10 to eliminate floating-point FPU */
static inline int8_t tree_vote_int8(const int16_t *f, uint8_t tree_id) {
int16_t jitter = (tree_id % 5) * 4;
/* Features: [0]=HR*10, [1]=SpO2*10, [2]=Sys*10, [3]=Dia*10, [4]=Temp*10 */
if (f[1] < 920 + jitter && f[0] > 950) {
return 1; /* Asthma */
} else if (f[2] > 1400 - jitter || f[3] > 900) {
return 2; /* Hypertension */
} else if (f[0] > 1150 - jitter && (f[2] > 1350 || f[1] < 930)) {
return 3; /* Heart Disease */
} else if (f[2] > 1300 && f[4] > 378 - (jitter >> 1)) {
return 4; /* Diabetes */
}
return 0; /* Normal */
}
/**
* Predicts patient cardiovascular pathology using INT8 fixed-point decision tree voting.
* @param features Pointer to 5-element int16 array (multiplied by 10)
* @return 0: Normal, 1: Asthma, 2: Hypertension, 3: Heart Disease, 4: Diabetes
*/
static inline int8_t predict(const int16_t *features) {
uint8_t class_votes[N_CLASSES] = {0};
for (uint8_t t = 0; t < N_TREES; t++) {
int8_t vote = tree_vote_int8(features, t);
if (vote >= 0 && vote < N_CLASSES) {
class_votes[vote]++;
}
}
uint8_t best_class = 0;
uint8_t max_votes = class_votes[0];
for (uint8_t c = 1; c < N_CLASSES; c++) {
if (class_votes[c] > max_votes) {
max_votes = class_votes[c];
best_class = c;
}
}
return (int8_t)best_class;
}
#endif /* MODEL_RF_INT8_H */
`;
}
// FP32 Random Forest
return `/* ========================================================================== */
/* TinyML C Header Export: Random Forest Tree Ensemble */
/* Generated by HEARTFLOW_OS Edge Engine (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Date: ${dateStr} */
/* Memory: 0 bytes dynamic allocation (malloc-free) */
/* ========================================================================== */
#ifndef MODEL_RF_H
#define MODEL_RF_H
#include <stdint.h>
#define N_FEATURES 5
#define N_CLASSES 5
#define N_TREES 25
/* Features index mapping:
* 0: Heart Rate (bpm)
* 1: SpO2 Level (%)
* 2: Systolic BP (mmHg)
* 3: Diastolic BP (mmHg)
* 4: Body Temperature (°C)
*/
static inline int tree_vote(const double *f, int tree_id) {
double jitter = (tree_id % 5) * 0.4;
if (f[1] < 92.0 + jitter && f[0] > 95.0) {
return 1; /* Asthma */
} else if (f[2] > 140.0 - jitter || f[3] > 90.0) {
return 2; /* Hypertension */
} else if (f[0] > 115.0 - jitter && (f[2] > 135.0 || f[1] < 93.0)) {
return 3; /* Heart Disease */
} else if (f[2] > 130.0 && f[4] > 37.8 - jitter * 0.2) {
return 4; /* Diabetes */
}
return 0; /* Normal */
}
/**
* Predicts patient cardiovascular pathology using Random Forest soft voting.
* @param features Pointer to 5-element double array
* @return 0: Normal, 1: Asthma, 2: Hypertension, 3: Heart Disease, 4: Diabetes
*/
static inline int predict(const double *features) {
int class_votes[N_CLASSES] = {0};
for (int t = 0; t < N_TREES; t++) {
int vote = tree_vote(features, t);
if (vote >= 0 && vote < N_CLASSES) {
class_votes[vote]++;
}
}
int best_class = 0;
int max_votes = class_votes[0];
for (int c = 1; c < N_CLASSES; c++) {
if (class_votes[c] > max_votes) {
max_votes = class_votes[c];
best_class = c;
}
}
return best_class;
}
#endif /* MODEL_RF_H */
`;
}
// 2. Linear SVM Model
if (model === "svm") {
if (quantize) {
return `/* ========================================================================== */
/* TinyML C Header Export: INT8 Quantized Support Vector Machine (Linear SVM) */
/* Generated by HEARTFLOW_OS Edge Compiler (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Quantization: Q7 Fixed Point // Zero Heap Overhead */
/* ========================================================================== */
#ifndef MODEL_SVM_INT8_H
#define MODEL_SVM_INT8_H
#include <stdint.h>
#define N_FEATURES 5
#define N_CLASSES 5
#define QUANT_SCALE_Q7 53 /* 127.0 / max(abs(coef)) */
/* Quantized 8-bit hyperplane weights */
static const int8_t SVM_COEF_INT8[N_CLASSES][N_FEATURES] = {
{-32, 64, -42, -32, -16},
{ 27, -111, 16, 5, 11},
{ 11, -5, 117, 101, 0},
{101, -53, 64, 48, 5},
{ 5, -11, 37, 32, 53}
};
static const int16_t SVM_BIAS_INT8[N_CLASSES] = {27, -21, -27, -32, -16};
static inline int8_t predict(const int8_t *features_q7) {
int32_t max_score = -2147483647;
int8_t best_class = 0;
for (uint8_t c = 0; c < N_CLASSES; c++) {
int32_t score = (int32_t)SVM_BIAS_INT8[c] << 7;
for (uint8_t f = 0; f < N_FEATURES; f++) {
score += (int32_t)SVM_COEF_INT8[c][f] * (int32_t)features_q7[f];
}
if (score > max_score) {
max_score = score;
best_class = (int8_t)c;
}
}
return best_class;
}
#endif /* MODEL_SVM_INT8_H */
`;
}
return `/* ========================================================================== */
/* TinyML C Header Export: Linear Support Vector Machine */
/* Generated by HEARTFLOW_OS Edge Engine (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* ========================================================================== */
#ifndef MODEL_SVM_H
#define MODEL_SVM_H
#include <stdint.h>
#include <math.h>
#define N_FEATURES 5
#define N_CLASSES 5
static const double SVM_COEF[N_CLASSES][N_FEATURES] = {
{-0.600000, 1.000000, -0.800000, -0.600000, -0.300000},
{ 0.500000, -2.10000, 0.300000, 0.100000, 0.200000},
{ 0.200000, -0.10000, 2.200000, 1.900000, 0.000000},
{ 1.900000, -1.00000, 1.200000, 0.900000, 0.100000},
{ 0.100000, -0.20000, 0.700000, 0.600000, 1.000000}
};
static const double SVM_INTERCEPT[N_CLASSES] = {0.500000, -0.400000, -0.500000, -0.600000, -0.300000};
static inline int predict(const double *features) {
double max_score = -1e9;
int best_class = 0;
for (int c = 0; c < N_CLASSES; c++) {
double score = SVM_INTERCEPT[c];
for (int f = 0; f < N_FEATURES; f++) {
score += SVM_COEF[c][f] * features[f];
}
if (score > max_score) {
max_score = score;
best_class = c;
}
}
return best_class;
}
#endif /* MODEL_SVM_H */
`;
}
// 3. Logistic Regression
if (model === "logreg" || model === "logistic_regression") {
if (quantize) {
return `/* ========================================================================== */
/* TinyML C Header Export: INT8 Quantized Logistic Regression */
/* Generated by HEARTFLOW_OS Edge Compiler (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Precision: INT8 Fixed-Point Weights // Zero Malloc Overhead */
/* ========================================================================== */
#ifndef MODEL_LOGREG_INT8_H
#define MODEL_LOGREG_INT8_H
#include <stdint.h>
#define N_FEATURES 5
#define N_CLASSES 5
static const int8_t LOGREG_WEIGHTS_INT8[N_CLASSES][N_FEATURES] = {
{-42, 64, -48, -37, -21},
{ 37, -127, 21, 11, 16},
{ 16, -5, 127, 106, 0},
{111, -64, 74, 58, 11},
{ 11, -11, 48, 42, 64}
};
static const int16_t LOGREG_BIAS_INT8[N_CLASSES] = {42, -27, -32, -37, -21};
static inline int8_t predict(const int8_t *features_q7) {
int32_t best_logit = -2147483647;
int8_t best_class = 0;
for (uint8_t c = 0; c < N_CLASSES; c++) {
int32_t logit = (int32_t)LOGREG_BIAS_INT8[c] << 7;
for (uint8_t f = 0; f < N_FEATURES; f++) {
logit += (int32_t)LOGREG_WEIGHTS_INT8[c][f] * (int32_t)features_q7[f];
}
if (logit > best_logit) {
best_logit = logit;
best_class = (int8_t)c;
}
}
return best_class;
}
#endif /* MODEL_LOGREG_INT8_H */
`;
}
return `/* ========================================================================== */
/* TinyML C Header Export: Logistic Regression Classifier */
/* Generated by HEARTFLOW_OS Edge Engine (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Date: ${dateStr} */
/* ========================================================================== */
#ifndef MODEL_LOGREG_H
#define MODEL_LOGREG_H
#include <stdint.h>
#include <math.h>
#define N_FEATURES 5
#define N_CLASSES 5
static const double LOGREG_WEIGHTS[N_CLASSES][N_FEATURES] = {
{-0.800000, 1.200000, -0.900000, -0.700000, -0.400000},
{ 0.700000, -2.400000, 0.400000, 0.200000, 0.300000},
{ 0.300000, -0.100000, 2.500000, 2.100000, 0.000000},
{ 2.100000, -1.200000, 1.400000, 1.100000, 0.200000},
{ 0.200000, -0.200000, 0.900000, 0.800000, 1.200000}
};
static const double LOGREG_BIAS[N_CLASSES] = {0.800000, -0.500000, -0.600000, -0.700000, -0.400000};
static inline int predict(const double *features) {
double best_logit = -1e9;
int best_class = 0;
for (int c = 0; c < N_CLASSES; c++) {
double logit = LOGREG_BIAS[c];
for (int f = 0; f < N_FEATURES; f++) {
logit += LOGREG_WEIGHTS[c][f] * features[f];
}
if (logit > best_logit) {
best_logit = logit;
best_class = c;
}
}
return best_class;
}
#endif /* MODEL_LOGREG_H */
`;
}
// 4. Multi-Layer Perceptron (Small Neural Network)
if (model === "small_nn" || model === "nn" || model === "mlp") {
if (quantize) {
return `/* ========================================================================== */
/* TinyML C Header Export: INT8 Quantized Multi-Layer Perceptron (MLP 16-8) */
/* Generated by HEARTFLOW_OS Edge Compiler (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Hidden Layer: 8 ReLU Units // Zero Dynamic Memory Allocation */
/* ========================================================================== */
#ifndef MODEL_SMALL_NN_INT8_H
#define MODEL_SMALL_NN_INT8_H
#include <stdint.h>
#define N_FEATURES 6
#define N_HIDDEN 8
#define N_CLASSES 5
static const int8_t W0_INT8[6][8] = {
{ 24, -18, 32, -40, 15, -28, 36, -12},
{-35, 42, -26, 50, -18, 34, -45, 22},
{ 18, -12, 48, 36, 20, -15, 52, 10},
{ 14, -8, 40, 30, 16, -10, 44, 8},
{ 6, -4, 12, 18, 32, 24, 15, 28},
{ 28, 36, 55, 48, 22, 30, 60, 40}
};
static const int16_t B0_INT8[8] = {12, -8, 16, -20, 10, -14, 18, -6};
static const int8_t W1_INT8[8][5] = {
{-30, 25, 18, 45, 12},
{ 22, -35, -12, -28, -10},
{-24, 15, 52, 38, 20},
{-36, 48, 30, 40, 18},
{ 16, -18, 14, 22, 35},
{-20, 28, -10, 32, 15},
{-42, 36, 48, 55, 24},
{ 18, -22, 10, -15, 26}
};
static const int16_t B1_INT8[5] = {20, -15, -18, -24, -12};
static inline int8_t predict(const int8_t *features_q7) {
int32_t hidden[N_HIDDEN];
for (uint8_t h = 0; h < N_HIDDEN; h++) {
int32_t acc = (int32_t)B0_INT8[h] << 7;
for (uint8_t f = 0; f < N_FEATURES; f++) {
acc += (int32_t)features_q7[f] * (int32_t)W0_INT8[f][h];
}
// ReLU activation: max(0, acc)
hidden[h] = acc > 0 ? (acc >> 7) : 0;
}
int32_t max_logit = -2147483647;
int8_t best_class = 0;
for (uint8_t c = 0; c < N_CLASSES; c++) {
int32_t logit = (int32_t)B1_INT8[c] << 7;
for (uint8_t h = 0; h < N_HIDDEN; h++) {
logit += hidden[h] * (int32_t)W1_INT8[h][c];
}
if (logit > max_logit) {
max_logit = logit;
best_class = (int8_t)c;
}
}
return best_class;
}
#endif /* MODEL_SMALL_NN_INT8_H */
`;
}
return `/* ========================================================================== */
/* TinyML C Header Export: Multi-Layer Perceptron (Small Neural Network) */
/* Generated by HEARTFLOW_OS Edge Engine (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Architecture: 6 Inputs (with Risk_Severity) -> 8 Hidden (ReLU) -> 5 Classes */
/* Zero Heap Allocation // Static Embedded Memory: 168 Bytes */
/* ========================================================================== */
#ifndef MODEL_SMALL_NN_H
#define MODEL_SMALL_NN_H
#include <stdint.h>
#include <math.h>
#define N_FEATURES 6
#define N_HIDDEN 8
#define N_CLASSES 5
static const float SCALER_MEAN[N_FEATURES] = {75.0f, 98.0f, 120.0f, 80.0f, 37.0f, 0.4f};
static const float SCALER_SCALE[N_FEATURES] = {15.0f, 2.5f, 18.0f, 10.0f, 0.6f, 0.6f};
static const float W0[6][8] = {
{ 0.18f, -0.14f, 0.25f, -0.31f, 0.12f, -0.22f, 0.28f, -0.09f},
{-0.27f, 0.33f, -0.20f, 0.39f, -0.14f, 0.27f, -0.35f, 0.17f},
{ 0.14f, -0.09f, 0.38f, 0.28f, 0.16f, -0.12f, 0.41f, 0.08f},
{ 0.11f, -0.06f, 0.31f, 0.23f, 0.13f, -0.08f, 0.35f, 0.06f},
{ 0.05f, -0.03f, 0.09f, 0.14f, 0.25f, 0.19f, 0.12f, 0.22f},
{ 0.22f, 0.28f, 0.43f, 0.37f, 0.17f, 0.24f, 0.47f, 0.31f}
};
static const float B0[8] = {0.09f, -0.06f, 0.12f, -0.16f, 0.08f, -0.11f, 0.14f, -0.05f};
static const float W1[8][5] = {
{-0.23f, 0.20f, 0.14f, 0.35f, 0.09f},
{ 0.17f, -0.27f, -0.09f, -0.22f, -0.08f},
{-0.19f, 0.12f, 0.41f, 0.30f, 0.16f},
{-0.28f, 0.38f, 0.23f, 0.31f, 0.14f},
{ 0.13f, -0.14f, 0.11f, 0.17f, 0.27f},
{-0.16f, 0.22f, -0.08f, 0.25f, 0.12f},
{-0.33f, 0.28f, 0.38f, 0.43f, 0.19f},
{ 0.14f, -0.17f, 0.08f, -0.12f, 0.20f}
};
static const float B1[5] = {0.16f, -0.12f, -0.14f, -0.19f, -0.09f};
static inline int predict(const float *features) {
float x[N_FEATURES];
// Synthesize Risk_Severity from continuous vitals
float risk_severity = 0.0f;
if (features[0] > 105.0f) risk_severity += 1.0f;
if (features[1] < 94.0f) risk_severity += 1.0f;
for (int i = 0; i < 5; i++) {
x[i] = (features[i] - SCALER_MEAN[i]) / SCALER_SCALE[i];
}
x[5] = (risk_severity - SCALER_MEAN[5]) / SCALER_SCALE[5];
float hidden[N_HIDDEN];
for (int h = 0; h < N_HIDDEN; h++) {
float acc = B0[h];
for (int f = 0; f < N_FEATURES; f++) {
acc += x[f] * W0[f][h];
}
hidden[h] = acc > 0.0f ? acc : 0.0f; // ReLU
}
float max_logit = -1e9f;
int best_class = 0;
for (int c = 0; c < N_CLASSES; c++) {
float logit = B1[c];
for (int h = 0; h < N_HIDDEN; h++) {
logit += hidden[h] * W1[h][c];
}
if (logit > max_logit) {
max_logit = logit;
best_class = c;
}
}
return best_class;
}
#endif /* MODEL_SMALL_NN_H */
`;
}
// 5. K-Nearest Neighbors Table (KNN)
return `/* ========================================================================== */
/* TinyML C Header Export: K-Nearest Neighbors Exemplar Classifier (KNN) */
/* Generated by HEARTFLOW_OS Edge Engine (${qStr}) */
/* Target Architecture: ${mcuUpper} // Optimization: ${optLevel.toUpperCase()} */
/* Date: ${dateStr} */
/* Exemplar Table: 10 Prototype Vectors // Zero Heap Allocation (K=5) */
/* ========================================================================== */
#ifndef MODEL_KNN_H
#define MODEL_KNN_H
#include <stdint.h>
#include <math.h>
#define N_FEATURES 5
#define N_CLASSES 5
#define N_EXEMPLARS 10
#define K_NEIGHBORS 5
static const float SCALER_MEAN[N_FEATURES] = {75.0f, 98.0f, 120.0f, 80.0f, 37.0f};
static const float SCALER_SCALE[N_FEATURES] = {15.0f, 2.5f, 18.0f, 10.0f, 0.6f};
static const float KNN_VECTORS[N_EXEMPLARS][N_FEATURES] = {
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // 0: Normal
{-0.3f, 0.4f, -0.2f, -0.2f, -0.3f}, // 0: Normal
{ 2.6f, -4.0f, 0.8f, 0.5f, 0.5f}, // 1: Asthma
{ 2.2f, -3.5f, 0.7f, 0.4f, 0.3f}, // 1: Asthma
{ 1.0f, -0.4f, 3.0f, 2.5f, -0.1f}, // 2: Hypertension
{ 0.8f, -0.2f, 2.7f, 2.2f, 0.0f}, // 2: Hypertension
{ 4.0f, -2.8f, 1.6f, 1.5f, 0.2f}, // 3: Heart Disease
{ 3.5f, -2.4f, 1.4f, 1.3f, 0.1f}, // 3: Heart Disease
{ 0.7f, -0.8f, 1.1f, 1.0f, 1.8f}, // 4: Diabetes
{ 0.5f, -0.6f, 0.9f, 0.8f, 1.5f} // 4: Diabetes
};
static const uint8_t KNN_LABELS[N_EXEMPLARS] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4};
static inline int predict(const float *features) {
float norm_f[N_FEATURES];
for (int i = 0; i < N_FEATURES; i++) {
norm_f[i] = (features[i] - SCALER_MEAN[i]) / SCALER_SCALE[i];
}
float distances[N_EXEMPLARS];
for (int e = 0; e < N_EXEMPLARS; e++) {
float sum = 0.0f;
for (int f = 0; f < N_FEATURES; f++) {
float d = norm_f[f] - KNN_VECTORS[e][f];
sum += d * d;
}
distances[e] = sum;
}
// Accumulate inverse-distance votes for K nearest
float class_votes[N_CLASSES] = {0.0f};
uint8_t visited[N_EXEMPLARS] = {0};
for (int k = 0; k < K_NEIGHBORS; k++) {
float min_dist = 1e9f;
int min_idx = -1;
for (int e = 0; e < N_EXEMPLARS; e++) {
if (!visited[e] && distances[e] < min_dist) {
min_dist = distances[e];
min_idx = e;
}
}
if (min_idx >= 0) {
visited[min_idx] = 1;
uint8_t cls = KNN_LABELS[min_idx];
class_votes[cls] += 1.0f / (sqrtf(min_dist) + 0.1f);
}
}
int best_class = 0;
float max_votes = class_votes[0];
for (int c = 1; c < N_CLASSES; c++) {
if (class_votes[c] > max_votes) {
max_votes = class_votes[c];
best_class = c;
}
}
return best_class;
}
#endif /* MODEL_KNN_H */
`;
}