{"id":30898162,"url":"https://github.com/auralius/noodle","last_synced_at":"2025-09-09T01:07:13.988Z","repository":{"id":304651853,"uuid":"1018835835","full_name":"auralius/noodle","owner":"auralius","description":"noodle is an implementation of the forward pass of CNN layers for Arduino. noodle relies on SD Card and memory-reuse for efficient implementation.","archived":false,"fork":false,"pushed_at":"2025-09-05T20:44:24.000Z","size":953,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-05T22:25:17.787Z","etag":null,"topics":["arduino","cnn","edge-computing","embedded-systems","lenet"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/auralius.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-13T06:34:20.000Z","updated_at":"2025-09-05T20:44:29.000Z","dependencies_parsed_at":"2025-07-14T14:52:00.989Z","dependency_job_id":"cf90b238-3644-4992-93e6-7b18769cc72d","html_url":"https://github.com/auralius/noodle","commit_stats":null,"previous_names":["auralius/noodle"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/auralius/noodle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/auralius%2Fnoodle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/auralius%2Fnoodle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/auralius%2Fnoodle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/auralius%2Fnoodle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/auralius","download_url":"https://codeload.github.com/auralius/noodle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/auralius%2Fnoodle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274231936,"owners_count":25245855,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","cnn","edge-computing","embedded-systems","lenet"],"created_at":"2025-09-09T01:07:11.515Z","updated_at":"2025-09-09T01:07:13.972Z","avatar_url":"https://github.com/auralius.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\r\n  \u003cimg src=\"./noodle.png\" alt=\"Description\" width=\"100\"\u003e \r\n\u003c/p\u003e\r\n\r\n\u003ch1 align=\"center\"\u003eNoodle 🍜≈🧠\r\n  \r\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.16239228.svg)](https://doi.org/10.5281/zenodo.16239228)\r\n  \r\n\u003c/h1\u003e\r\n\r\n\r\n**Noodle** is a lightweight convolutional neural network inference library designed for MCUs with **very small RAM**.  \r\nIt streams activations and weights from **SD/FFat/SD_MMC** filesystems to overcome RAM limitations, while providing modular primitives for **convolution, pooling, FCN, and activations**. During the development, we typically test Noodle with Arduino UNO R3, UNO R4, and some ESP32 variants.\r\n\r\n---\r\n\r\n## Configuration\r\n\r\nConfiguration is controlled in [`noodle_config.h`](./noodle_config.h):\r\n\r\n- **Filesystem Backend** (select exactly one):\r\n  - `NOODLE_USE_SDFAT`\r\n  - `NOODLE_USE_SD_MMC`\r\n  - `NOODLE_USE_FFAT`\r\n\r\n- **Pooling Mode**:\r\n  ```c\r\n  #define NOODLE_POOL_MAX   1\r\n  #define NOODLE_POOL_MEAN  2\r\n  #define NOODLE_POOL_MODE NOODLE_POOL_MEAN  // or NOODLE_POOL_MAX\r\n  ```\r\n\r\nSee [`noodle_fs.h`](./noodle_fs.h) for backend definitions.\r\n\r\n---\r\n\r\n## Data Structures\r\n\r\n### `enum Activation`\r\n- `ACT_NONE` — no activation  \r\n- `ACT_RELU` — ReLU clamp  \r\n- `ACT_SOFTMAX` — softmax (applied at vector level)\r\n\r\n### `struct Conv`\r\nParameters for convolution:\r\n- `K` — kernel size  \r\n- `P` — padding  \r\n- `S` — stride  \r\n- `weight_fn` — filename template for weights (per input/output channel)  \r\n- `bias_fn` — filename of biases (one per output channel)  \r\n- `act` — activation (see `Activation`)\r\n\r\n### `struct Pool`\r\nParameters for pooling:\r\n- `M` — kernel size  \r\n- `T` — stride\r\n\r\n### `struct FCNFile`\r\n- `weight_fn` — filename of weights  \r\n- `bias_fn` — filename of biases  \r\n- `act` — activation\r\n\r\n### `struct FCNMem`\r\nIn-memory FCN layer parameters:\r\n- `weight` — pointer to row-major weights `[n_outputs, n_inputs]`  \r\n- `bias` — pointer to bias array  \r\n- `act` — activation\r\n\r\n---\r\n\r\n## Utilities\r\n\r\n### Memory\r\n- `float* noodle_slice(float* flat, size_t W, size_t z)`  \r\n  Returns pointer to the `z`-th slice of a stacked `[Z, W, W]` tensor.  \r\n\r\n- `void noodle_setup_temp_buffers(void *b1, void *b2)`  \r\n  Registers two scratch buffers (input + accumulator) for streamed ops.  \r\n\r\n- `float* noodle_create_buffer(uint16_t size)` / `void noodle_delete_buffer(float* buffer)`  \r\n  Allocate/free float buffers.  \r\n\r\n- `void noodle_reset_buffer(float* buffer, uint16_t n)`  \r\n  Zero-fill a float buffer.  \r\n\r\n### File/FS Helpers\r\n- `NDL_File noodle_open_file_for_write(const char* fn)`  \r\n- `size_t noodle_read_bytes_until(NDL_File\u0026, char terminator, char* buf, size_t len)`  \r\n- `bool noodle_sd_init()` / `bool noodle_sd_init(int clk, int cmd, int d0)`  \r\n- `void noodle_n2ll(uint16_t number, char* out)` — encodes int → 2-letter code (aa..zz)  \r\n- `void noodle_delete_file(const char* fn)`  \r\n\r\n### Scalar I/O\r\n- `void noodle_write_float(NDL_File\u0026, float d)` / `float noodle_read_float(NDL_File\u0026)`  \r\n- `void noodle_write_byte(NDL_File\u0026, byte d)` / `byte noodle_read_byte(NDL_File\u0026)`  \r\n\r\n### Array/Grid I/O\r\n- `void noodle_array_to_file(float* arr, const char* fn, uint16_t n)`  \r\n- `void noodle_grid_to_file(byte*/float* grid, const char* fn, uint16_t n)`  \r\n- `void noodle_array_from_file(const char* fn, float* buf, uint16_t K)`  \r\n- `void noodle_grid_from_file(const char* fn, byte*/int8_t*/float* buf, uint16_t K)`  \r\n\r\n---\r\n\r\n## Core Ops\r\n\r\n### Convolution (2D)\r\n\r\n#### Primitives\r\n- `uint16_t noodle_do_conv(byte* grid, float* kernel, K, W, float* output, P, S)`  \r\n- `uint16_t noodle_do_conv(float* grid, float* kernel, K, W, float* output, P, S)`  \r\n\r\nOutput size: `V = (W - K + 2P)/S + 1`.\r\n\r\n#### File/Memory Variants\r\n- `noodle_conv_byte` — File→File, byte inputs  \r\n- `noodle_conv_float` — Overloaded for:\r\n  - File→File\r\n  - File→Memory\r\n  - Memory→File\r\n  - Memory→Memory\r\n\r\nEach variant:\r\n- Iterates input channels **I**, output channels **O**  \r\n- Loads weights/bias  \r\n- Applies conv + bias + activation  \r\n- Writes pooled feature maps to file or memory  \r\n\r\n### Pooling\r\n- `noodle_do_pooling(float* in, W, K, S, const char* fn)` → File output  \r\n- `noodle_do_pooling(const float* in, W, K, S, float* out)` → Memory output  \r\n- `noodle_do_pooling1d(float* in, W, K, S, const char* fn)` → 1D MAX pooling  \r\n\r\nOutput size: `Wo = (W - K)/S + 1`.\r\n\r\n---\r\n\r\n## Fully Connected Layers (FCN)\r\n\r\n- `uint16_t noodle_fcn(const int8_t* in, n_inputs, n_outputs, const char* out_fn, const FCNFile\u0026, CBFPtr cb)`  \r\n- `uint16_t noodle_fcn(const float* in, n_inputs, n_outputs, const char* out_fn, const FCNFile\u0026, CBFPtr cb)`  \r\n- `uint16_t noodle_fcn(const byte* in, n_inputs, n_outputs, const char* out_fn, const FCNFile\u0026, CBFPtr cb)`  \r\n- `uint16_t noodle_fcn(const char* in_fn, n_inputs, n_outputs, const char* out_fn, const FCNFile\u0026, CBFPtr cb)`  \r\n- `uint16_t noodle_fcn(const float* in, n_inputs, n_outputs, float* out, const FCNMem\u0026, CBFPtr cb)`  \r\n\r\nGeneral behavior:\r\n- Computes `y = W·x + b`  \r\n- Optional activation: ReLU, Softmax  \r\n- Supports **File→File**, **File→Memory**, **Memory→File**, **Memory→Memory**  \r\n\r\n---\r\n\r\n## Flattening\r\n- `uint16_t noodle_flat(const char* in_fn, float* out, uint16_t V, uint16_t n_filters)` — File→Memory  \r\n- `uint16_t noodle_flat(float* in, float* out, uint16_t V, uint16_t n_filters)` — Memory→Memory  \r\n\r\nOutput: `V * V * n_filters` vector.\r\n\r\n---\r\n\r\n## Activations\r\n- `uint16_t noodle_do_bias(float* out, float bias, uint16_t n)` — bias + ReLU  \r\n- `uint16_t noodle_do_bias_act(float* out, float bias, uint16_t n, Activation act)` — bias + activation  \r\n- `uint16_t noodle_soft_max(float* vec, uint16_t n)` — in-place softmax  \r\n- `uint16_t noodle_sigmoid(float* vec, uint16_t n)` — in-place sigmoid  \r\n\r\n---\r\n\r\n## 📏 1D Convolution\r\n- `uint16_t noodle_do_conv1d(float* in, float* kernel, W, K, float* out, P, S)`  \r\n- `uint16_t noodle_conv1d(float* in, float* out, n_inputs, n_outputs, const char* in_fn, const char* out_fn, W, const Conv\u0026, const Pool\u0026, CBFPtr cb)` — with pooling  \r\n- `uint16_t noodle_conv1d(float* in, float* out, n_inputs, n_outputs, const char* in_fn, const char* out_fn, W, const Conv\u0026, CBFPtr cb)` — no pooling  \r\n\r\n---\r\n\r\n## Example Usage\r\n\r\n```cpp\r\n#include \"noodle.h\"\r\n\r\nConv conv = {3, 1, 1, \"w____\", \"b.txt\", ACT_RELU};\r\nPool pool = {2, 2};\r\n\r\nvoid setup() {\r\n  static byte buffer1[784];    // temp input\r\n  static float buffer2[784];   // temp accumulator\r\n\r\n  noodle_setup_temp_buffers(buffer1, buffer2);\r\n\r\n  noodle_sd_init();  // init filesystem\r\n\r\n  // Run conv layer\r\n  noodle_conv_byte(\"in____\", 1, 6, \"out__\", 28, conv, pool);\r\n}\r\n```\r\n\r\n---\r\n\r\n## References\r\n\r\n- [Noodle source code](./noodle.cpp)  \r\n- [Noodle headers](./noodle.h)  \r\n- [Noodle config](./noodle_config.h)  \r\n- [Filesystem backend](./noodle_fs.h)  \r\n\r\n\r\n## Authors\r\n\r\n- Auralius Manurung — Universitas Telkom, Bandung  \r\n- Lisa Kristiana — ITENAS, Bandung\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fauralius%2Fnoodle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fauralius%2Fnoodle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fauralius%2Fnoodle/lists"}