Spaces:
Runtime error
Runtime error
Download frontend/src/lib/edge/c_exporter.ts from IDKHowToCodeFr/tinyml-backend: direct link, hf CLI and curl.
- Browser
- Download file 19.9 kB
-
https://huggingface.co/spaces/IDKHowToCodeFr/tinyml-backend/resolve/main/frontend/src/lib/edge/c_exporter.ts
- Command line
-
hf download hf://spaces/IDKHowToCodeFr/tinyml-backend/frontend/src/lib/edge/c_exporter.ts
-
curl -L -o c_exporter.ts https://huggingface.co/spaces/IDKHowToCodeFr/tinyml-backend/resolve/main/frontend/src/lib/edge/c_exporter.ts
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 */ | |
| `; | |
| } | |