Nerve: 순수 C로 읽을 수 있는 현대 AI 스택
요약
Nerve는 순수 C 언어로 작성된 현대적인 AI 스택 라이브러리입니다. Transformer, 온디바이스 학습, 문장 임베딩 등 거대 프레임워크가 제공하는 기능을 의존성 없이 구현했습니다. 헤더 파일 하나로 마이크로컨트롤러부터 브라우저 탭까지 이식성이 뛰어납니다.
핵심 포인트
- 순수 C 언어로 작성되어 높은 이식성을 자랑합니다.
- 의존성(dependency)이 전혀 없어 임베디드 환경에 적합합니다.
- Transformer, 온디바이스 학습 등 핵심 AI 기능을 지원합니다.
Nerve
<img src="https://raw.githubusercontent.com/fkkarakurt/Nerve/HEAD/assets/nerve-flappy.gif" width="720" alt="Flappy Bird AI learning in real-time via neuroevolution" />순수 C로 읽을 수 있는 현대 AI 스택.
실제 Transformer, 온디바이스 학습(on-device learning), 그리고 문장 임베딩(sentence embeddings).
의존성 제로. 헤더 파일 하나. 마이크로컨트롤러부터 브라우저 탭까지 실행 가능.
</div>
Nerve를 사용해야 하는 이유?
대부분의 신경망 라이브러리는 거대한 프레임워크이거나 장난감 수준의 구현체입니다.
Nerve는 그 중간에 위치합니다: 오후 안에 읽을 만큼 작고, 실제 작업에 충분히 정확하며,
C가 컴파일되는 어디서든 — 베어메탈(bare-metal)을 포함하여 — 실행할 수 있을 만큼 이식성이 뛰어납니다.
| Nerve | TensorFlow Lite | tinyML | plain C | |
|---|---|---|---|---|
| 의존성 제로 | ✅ | ❌ | ❌ | ✅ |
| ... |
라이브러리를 넘어 — 순수 C로 읽을 수 있는 현대 AI 스택
Nerve는 다층 퍼셉트론(multilayer perceptron)으로 시작했습니다. 이제 의존성 없이, 처음부터 거인들이 사용하는 구성 요소들을 구현합니다 — 읽기에 충분히 작고,
2017년 노트북이나 브라우저 탭에서 실행할 만큼 이식성이 뛰어납니다. GPU도 없고, 런타임에 Python도 없으며, 클라우드 연결도 없고, 토큰당 비용 청구도 없습니다.
숫자를 입력하면, 방정식을 얻습니다.
이 저장소의 다른 모든 모델들은 매개변수(parameters)로 질문에 답합니다. nerve_discover.h는 **공식(formula)**으로 답하는데요 — 이 공식은 읽을 수 있고, 이론과 비교할 수 있으며, 손으로 미분할 수 있고, 논문에 넣을 수 있으며, 나아가 나노초 단위로 영원히, 그리고 무료로 평가할 수 있습니다.
#define NERVE_DISCOVER_IMPLEMENTATION
#include "nerve_discover.h"
...
힘에 대한 200개의 노이즈 샘플, 두 개의 질량(masses)과 하나의 거리(distance)를 입력하면, 중력이나 제곱, 나눗셈 등이 관련되어 있다는 사실을 전혀 듣지 못했음에도 불구하고 다음과 같은 결과가 나옵니다:
y = 0.996748*(m2*m1)/r^2 + 0.00943491
실제 측정된 아홉 개의 행성을 입력하면, 반 초 만에 케플러의 제3법칙(Kepler's third law)을 반환합니다. 가우시안 분포를 입력하면 0.398942*exp(-0.5*theta^2)를 반환하며, 여기서 선행 상수(leading constant)는 1/√(2π)의 여섯 자리까지입니다.
얼마나 좋은가요? 주장하는 것이 아니라 측정했습니다. 이 분야의 표준 자(yardstick)는 파인만 강의에 나오는 100개 방정식 — SRBench의 정확도 트랙입니다. Nerve는 보유 데이터에 대해 R² ≥ 0.999를 달성한 100개 중 82개를, 각각 한 번씩, 동일한 예산으로, 문제별 조정 없이 복구합니다. 이 벤치마크는 저장소에서 실행되며, make 단 한 번의 실행으로 다운로드할 것이 없고, 모든 실패와 함께 모든 성공을 출력합니다.
결과는 하나의 방정식이 아니라 **파레토 프론트(Pareto front)**입니다. 즉, 모든 복잡도 수준에서 가장 좋은 공식을 보여주므로, 각 추가 항이 정확히 무엇을 가져왔는지, 그리고 어느 지점부터는 더 이상 아무것도 가져오지 못했는지 명확하게 확인할 수 있습니다:
1 nodes R2 0.977612 y = 6.10996*a - 12.5517
2 nodes R2 0.987879 y = 0.161655*a^2 + 7.13717
4 nodes R2 0.99999951 y = 0.999498*a*sqrt(a) - 0.0274583 <- the knee
...
▶ 브라우저에서 사용해 보기
CSV를 붙여넣고, 방정식이 진화하는 것을 지켜보고, 공식을 얻으세요. 이 전체 엔진은 데이터 파일이 전혀 없는 70 KB의 WebAssembly 모듈입니다. 왜냐하면 방정식 발견기는 다운로드할 가중치(weights)가 없기 때문에, 페이지는 로드되는 즉시 사용 가능하고, 오프라인에서 작동하며, 데이터가 절대 탭을 벗어나지 않습니다.
심볼릭 회귀(Symbolic regression)는 보통 무거운 과학용 Python 환경에서 다뤄집니다. PySR은 Julia 백엔드를 사용하는 Python 패키지이며, AI Feynman은 신경망(neural network)이 필요합니다. 이들은 모두 훌륭한 연구 도구이지만, 어느 것도 임베드할 수 없습니다. 하지만 이것은 libm 외에는 의존성이 없는 단일 C99 헤더 파일입니다. 따라서 측정 장비(instrument), 마이크로컨트롤러, 데스크톱 바이너리 또는 브라우저 탭에 들어갈 수 있으며, 이는 인터프리터가 따라잡을 수 없는 바로 그 지점입니다.
JavaScript / TypeScript에서 사용하기
동일한 엔진이 WebAssembly로 컴파일되어 npm을 통해 배포되며, 브라우저나 Node용으로 사용할 수 있습니다. 서버도, GPU도, API 키도 필요 없습니다. 사용자 장치에서 실행됩니다.
npm install @fkkarakurt/nerve
import Nerve from "@fkkarakurt/nerve";
const nerve = await Nerve.load();
...
방정식 발견은 별도의 진입점(entry point)을 가집니다. 왜냐하면 모델이 전혀 필요하지 않기 때문입니다. 즉시 시작하는 약 62 KB 모듈입니다:
import { load, Ops } from "@fkkarakurt/nerve/discover";
const d = await load();
...
▶ 브라우저에서 실시간으로 사용해 보기
텍스트 생성(Text generation), 온디바이스 학습(on-device learning), 시맨틱 검색(semantic search) 및 필기체 숫자 인식(handwritten-digit recognition) — 모두 클라이언트 측, 즉 여러분의 탭에서 실행됩니다. 서버도 없고, GPU도 없고, API 키도 필요 없으며, 아무것도 업로드되지 않습니다. 문서화.
빠른 시작 (Quick Start)
3줄 API
#define NERVE_IMPLEMENTATION
#include "nerve.h"
...
gcc -O2 main.c -o main -lm
CMake도, vcpkg도, apt install도 필요 없습니다. 그저 gcc와 nerve.h만 있으면 됩니다.
전체 제어 API (Full-control API)
#define NERVE_IMPLEMENTATION
#include "nerve.h"
...
구성에 의해 재현 가능함 (Reproducible by construction)
Nerve는 절대 rand()를 호출하지 않습니다. 대신 자체 생성기인 xoshiro128**(Blackman & Vigna, 2021)**을 사용하며, 이는 SplitMix32를 통해 시드(seed)가 주어지기 때문입니다. 왜냐하면 rand()는 플랫폼 간에 동일한 답을 보장할 수 없기 때문입니다. 즉, 구현 정의적(implementation-defined)이며, Microsoft C 런타임의 경우 RAND_MAX가 32 767인 반면 glibc에서는 2 147 483 647입니다. 따라서 동일한 시드라도 Windows와 Linux에서 다른 정밀도(granularity)로 다른 가중치(weights)를 생성합니다.
erve_seed(42); /* 모든 libc, 컴파일러, 타겟에서 동일한 스트림 */
net_initialize_xavier(net); /* -> 어디서든 비트 단위로 동일한 가중치 */
이 생성기는 전체적으로 32비트를 유지하므로 ANSI C89 내에 머무르며 마이크로컨트롤러, 노트북, 브라우저 탭에서 동일하게 작동합니다. Nerve는 기본적으로 결정론적(deterministic)입니다. 상태가 고정되어 시작하며, nerve_seed(time(NULL))을 사용해야만 변화를 선택할 수 있습니다. nerve_rand_below(n)은 낮은 값에 은근히 편향되는 모듈로 연산이 아닌, 기각법(rejection)을 통해 $[0, n)$ 범위의 편향되지 않은 정수(unbiased integer)를 추출합니다.
테스트 스위트에서는 Nerve의 C89 생성기를 12만 번의 추출에 걸쳐 정확한 폭의 참조 구현체와 비교하고, 스트림이 조용히 벗어나는 것을 막기 위해 골든 벡터(golden vector)를 고정합니다.
부동소수점 결과는 여전히 플랫폼의 libm에 의존합니다: exp()와 tanh()는 어떤 표준으로도 올바르게 반올림되지 않기 때문에, 학습 출력은 기계마다 마지막 자릿수에서 다를 수 있습니다. Nerve가 보장하는 것은 랜덤 스트림이 두 실행 결과가 불일치하는 이유가 아니라는 것입니다.
벤치마크 — SGD 대 Adam
부울 함수에 대한 결과 (각 7회 독립 실행):
XOR (2-4-1 네트워크)
| 설정 | 수렴 여부 | 평균 반복 횟수 | 속도 향상 |
|---|---|---|---|
| SGD / Uniform / Sigmoid | 7 / 7 | 22,285 | 1× |
| ... | |||
| 4-Class Identity (4-6-4 네트워크) |
| 설정 | 수렴 여부 | 평균 반복 횟수 | 속도 향상 |
|---|---|---|---|
| SGD / Uniform / Sigmoid | 7 / 7 | 22,689 | 1× |
| Adam / He / ReLU | 7 / 7 | 1,214 | 18.7× |
알고리즘 참고 자료
| 구성 요소 | 옵션 | 참고 문헌 |
|---|---|---|
| 최적화기 (Optimizer) | SGD + 모멘텀 (momentum) | Rumelhart et al., 1986 |
| ... | ||
| ★ 은닉층에 권장되는 조합 |
예시
단독으로 실행 가능한 11개의 .c 파일 — 각 파일은 단일 gcc 명령어로 컴파일됩니다.
핵심 예제 (Core examples)
| # | 파일 | 결과 |
|---|---|---|
| 01 | 01_xor.c | Adam을 사용한 XOR, 2,000회 미만 반복으로 달성 |
| ... | ||
| 터미널 AI 게임 (Terminal AI games) — 플레이하는 방법을 학습하는 신경망이 터미널에 거주합니다. |
| # | 파일 | 아키텍처 | 알고리즘 |
|---|---|---|---|
| 10 | 10_snake_ai.c | 11 → 16 → 3 | 신경진화 (Neuroevolution), pop 100 |
| ... |
<details> <summary><b>예시 출력</b></summary>
XOR
$ gcc -O2 examples/01_xor.c -o xor -lm && ./xor
Nerve 2.0.0 — XOR 예제
...
Iris 분류 (Iris Classification)
$ gcc -O2 examples/03_iris.c -o iris -lm && ./iris
최종 테스트 정확도: 96.7%
...
3-Class Spiral
$ gcc -O2 examples/07_spiral.c -o spiral -lm && ./spiral
최종 테스트 정확도: 98.3% (59 / 60)
...
예측 유지보수 (Predictive Maintenance)
Reading 1 → [ OK ] 정상 (NORMAL) 99.9%
Reading 5 → [ WARN ] 경고 (WARNING) 98.8%
Reading 8 → [ CRIT ] 심각 (CRITICAL) 97.3%
...
API 레퍼런스 (API Reference)
<details> <summary><b>쉬운 API (Easy API)</b></summary>/* 생성 (Create) */
nerve_t *net = nerve_new("2->8->1"); /* Adam + Tanh + Xavier */
...
/* 결정론성 (Determinism) */
erve_seed(42); /* 내장 생성기 시드 설정 */
float u = nerve_rand_float(); /* 균일 분포 [0,1) */
...
</details>로딩 후에는
net_set_activation()및net_set_optimizer()를 다시 적용해야 합니다.
빌드 (Building)
# 모든 예제 (Linux / macOS)
make -C examples
...
테스트 (Tests)
gcc -O2 -std=c99 -Wall -Wextra tests/test_nerve.c -o test_nerve -lm && ./test_nerve
gcc -O2 -std=c99 -Wall -Wextra tests/test_discover.c -o test_discover -lm && ./test_discover
프레임워크나 의존성 없이, 파일 하나만으로 모든 것이 가능합니다 — 여기에 있는 다른 모든 것들과 마찬가지로 단일 라인 빌드입니다. 핵심 테스트 스위트는 생성기를 참조 구현과 비교하고, 역전파(backprop) 기울기를 중심 유한 차분(central finite differences)과 검증하며, 모든 영속성 형식(persistence format)을 순환 처리합니다. 디스커버리(discovery) 스위트는 파레토 전선(Pareto front)의 구조적 불변량, 고정된 시드 하에서의 결정론성, 포매터(formatter)의 버퍼 안전성, 그리고 퇴화 입력(degenerate input)에 대한 동작을 검증합니다. CI는 Linux (GCC 및 Clang), macOS 및 Windows에서 ASan + UBSan으로 모두 실행하며, 핵심 코어가 여전히 엄격한 ANSI C89로 컴파일되는 것을 별도로 강제합니다 — 위의 주장들은 마케팅 문구가 아니라, 만약 사실이 아니게 된다면 빌드 실패를 의미하는 것입니다.
벤치마크 (Benchmarks)
make -C bench/feynman full # 방정식 100개, 다운로드 불필요
이 README에 숫자가 포함된 클레임들은 리포지토리 내에서 재실행할 수 있는 무언가에 의해 생성됩니다. 방정식 발견(equation-discovery) 이미지는 bench/feynman/에서 가져온 것으로, 이 프로토콜 — 예산, 연산자 세트, 학습/테스트 분할, 그리고 무엇이 해결된 것으로 간주되는지 — 은 암시되기보다는 명확하게 작성되어 있습니다.
학문적 기반 (Academic foundations)
Nerve는 읽기 쉽도록 작성된, 확립된 결과들의 제로베이스 구현체입니다. 어텐션(attention), RoPE, RMSNorm, SwiGLU, GELU, BERT 스타일 인코더, Adam, 드롭아웃(dropout), 자동 미분(autodiff), int8 양자화(quantization), 그리고 발견 엔진 뒤에 있는 유전 프로그래밍(genetic programming), 선형 스케일링(linear scaling), 파레토 선택(Pareto selection) 등 모든 구성 요소는 docs/REFERENCES.md의 원본 논문에 근거하고 있습니다. 기여하는 바는 새로운 과학이 아니라, 가독성(readability), 이식성(portability), 그리고 재현성(reproducibility)입니다.
인용 (Citation)
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub AI Research의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기