개발자료·참조 구현
1c3e781 기준)Nemotron은 NVIDIA의 모델 계열 이름이면서, 이 저장소에서는 그 모델을 활용하는 개발 자산의 묶음을 뜻합니다. 이 저장소에서 배울 핵심은 모델 호출 한 번이 아니라, 데이터·설정·학습 결과를 연결하는 방법입니다.
처음에는 usage-cookbook/의 노트북으로 추론을 살펴볼 수 있습니다.
다음에는 use-case-examples/에서 검색·문서 처리·에이전트 구성 사례를 읽습니다.
더 깊이 들어가면 src/nemotron/recipes/가 데이터 준비와 학습 단계를, src/nemo_runspec/이 실행 설정과 결과물 추적을 담당합니다.
추론 노트북은 요리를 주문하는 방법, 데이터 준비는 재료 손질, SFT와 강화학습은 맛을 조절하는 과정입니다. 실행 설정은 사용할 조리 기구를 정하고, 아티팩트 기록은 어느 재료로 어느 요리를 만들었는지 남기는 장부입니다.
초보자는 모든 조리 기구를 살 필요가 없습니다. 먼저 입력과 출력을 이해한 뒤, 한 단계씩 내부 공정을 읽으면 됩니다.
| 하고 싶은 일 | 처음 읽을 위치 | 확인할 것 |
|---|---|---|
| 모델에 질문하기 | usage-cookbook/Nemotron-Nano-9B-v2/vllm_cookbook.ipynb | LLM, SamplingParams, 생성 결과 |
| 에이전트 만들기 | use-case-examples/Simple Nemotron-3-Nano Usage Example/simple_usage_notebook.ipynb | 모델 호출·검색 도구·대화 상태의 연결 |
| 학습 과정 이해하기 | src/nemotron/recipes/nano3/ | 사전학습 → SFT → RL의 입력과 출력 |
| 실험을 다시 추적하기 | src/nemo_runspec/ | 실행 명세·최종 설정·아티팩트 버전 |
입력 데이터는 무엇인가? 어떤 설정이 최종 적용되는가? 실제 계산은 어느 외부 엔진이 맡는가? 결과가 다음 단계에 어떻게 전달되는가? 이 네 가지를 설명할 수 있으면 모델 이름을 외우는 수준에서 시스템을 이해하는 수준으로 넘어갑니다.
2026-10-23 GitHub 기준 스타 2,201개, 포크 450개이며, GitHub Trending Jupyter Notebook Daily #11에 선정된 저장소입니다. 이 순위만으로 유입 원인이나 실사용 규모를 알 수는 없습니다. 다만 소스와 README에서 관심을 끌 만한 요소는 확인할 수 있습니다.
루트 README는 Nemotron 3.5 Super와 Lightning 공개를 전면에 소개합니다.
각각의 학습 경로도 src/nemotron/recipes/super35/와 src/nemotron/recipes/lightning35/에 있습니다.
모델 공개 소식에서 곧바로 사용 예제와 학습 구성으로 이동할 수 있다는 점이 이 허브의 장점입니다.
이것이 트렌딩에 기여했을 가능성은 있지만, 인과관계를 확인한 통계는 없습니다.
새 모델을 소개하는 문서와 그 모델로 실험을 구성하는 코드를 함께 읽을 수 있다는 점이 학습 가치를 만듭니다.
특히 src/nemotron/recipes/embed/와 src/nemotron/recipes/rerank/처럼 검색 모델을 다루는 경로까지 있어, 대화형 LLM 이외의 활용법도 배울 수 있습니다.
아래 표는 성능 순위가 아니라 무엇을 맡기는 도구인가를 비교합니다. vLLM·Transformers·LangChain은 이 저장소의 예제에서 실제로 사용되므로, Nemotron과 서로 대체만 하는 관계는 아닙니다.
| 선택지 | 주로 해결하는 일 | Nemotron 허브의 상대적 장점·제약 |
|---|---|---|
| 모델 배포 페이지 | 가중치와 모델 카드 확인 | 학습·데이터·활용 예제까지 연결해 읽기 좋음. 가중치는 별도 배포 경로가 필요 |
| Transformers | 모델 로딩과 토큰화·추론 | 특정 Nemotron 모델의 사용 절차를 제공. 범용 모델 라이브러리 구현은 외부에 의존 |
| vLLM | 추론 엔진과 API 서빙 | 모델별 실행·도구 호출 예제를 제공. 엔진 자체의 성능 최적화 코드는 vLLM에서 학습해야 함 |
| LangChain·LangGraph | 도구·상태·에이전트 조합 | Nemotron을 연결한 완성 사례를 제공. 에이전트 프레임워크를 새로 구현한 저장소는 아님 |
| Megatron-Bridge·NeMo-RL | 분산 학습과 강화학습 | 모델별 설정과 단계 연결을 제공. 실제 학습 루프 상당 부분은 이 외부 엔진들이 담당 |
src/nemotron/recipes/nano3/README.md는 추론 처리량 최대 3.3배, 최대 1M 토큰 문맥 길이를 소개합니다.
동시에 공개된 학습 데이터 부분집합만 사용하므로 기술 보고서와 결과가 달라진다고 명시합니다.
따라서 수치를 이 레시피의 실행 결과로 인용하거나, 모든 환경에서 같은 성능이 나온다고 해석하면 안 됩니다.
공식 경기 기록과 연습용 훈련 계획표의 관계입니다. 계획표로 훈련 방식을 배울 수 있지만, 같은 기록을 내려면 선수·훈련량·장비·조건까지 같아야 합니다. 레시피 공개와 결과 재현 보장은 별개의 주장입니다.
초보자가 먼저 얻을 성과는 벤치마크 1등이 아닙니다. 설정 파일 하나를 읽고 어떤 엔진과 데이터가 필요한지 설명하는 능력, 그리고 결과가 달라졌을 때 원인을 좁히는 능력입니다.
루트 pyproject.toml의 패키지 이름은 nemotron, 버전은 0.2.0입니다.
Python 허용 범위는 >=3.11,<3.14, .python-version은 3.12입니다.
README의 Python 3.10+ 배지보다 실제 설치 메타데이터가 엄격합니다.
| 영역 | 실제 의존성 지정 | 역할 |
|---|---|---|
| 명령행 | typer>=0.12.0, rich>=13.0.0, textual>=0.70.0 | CLI 명령, 도움말과 터미널 표현 |
| 설정·검증 | omegaconf>=2.3.0, pydantic>=2.0.0, pydantic-settings>=2.12.0 | YAML 병합, 구조 검증, 환경 기반 설정 |
| 분산 데이터 | ray[default,data]>=2.58.0, pyarrow>=14.0.0 | 분산 데이터 처리와 열 기반 데이터 형식 |
| 모델·데이터 | transformers>=5.17.0,<6.0, datasets>=2.14.0 | 토크나이저·모델 및 데이터셋 연동 |
| 저장·추적 | fsspec>=2024.0.0, wandb>=0.23.1 | 파일시스템 접근과 실험·아티팩트 추적 |
| 작업 제출 | nemo-run의 Git 리비전 a8425c9f11a45412e6d5338cecb1c014b0ecc0c4 | 외부 실행 환경과 학습 작업 연결 |
>=는 설치된 버전이 아니라 허용하는 하한입니다.
루트 uv.lock과 단계별 잠금 파일이 따로 있으므로 위 표를 하나의 검증된 실행 환경으로 합쳐 읽지 마세요.
루트 [tool.uv].override-dependencies에는 torch==2.10.0도 지정됩니다.
data-sdg는 합성 데이터 생성용입니다.
잠금 파일은 의존성 해결 결과를 기록합니다. 허용 범위가 넓은 선언만 복사하는 것보다 환경 재구성의 출발점으로 유용합니다.| 파일·영역 | 지정 내용 | 읽을 때 주의할 점 |
|---|---|---|
루트 data-sdg | data-designer>=0.5.9,<0.6, torch>=2.10,<2.11 | 기본 의존성 전체와 같은 의미가 아님 |
루트 curate | nemo-curator[text_cpu]==1.3.0 | GPU 중복 제거는 curate-gpu로 분리 |
루트 bfcl-mcp | mcp>=2.2,<3 | Data Designer의 MCP v1 의존성과 분리. tool.uv.conflicts에 충돌 선언 |
| 음성 RAG 예제 | Python >=3.10,<3.13, Transformers >=4.47.1,<5.0.0 | use-case-examples/nemotron-voice-rag-agent-example/pyproject.toml 기준 |
| 간단한 Nano3 예제 | Python >=3.13, langchain>=1.1.3, langgraph>=1.0.4 | use-case-examples/Simple Nemotron-3-Nano Usage Example/pyproject.toml 기준 |
특히 두 예제의 Python 범위는 서로 겹치지 않습니다. 폴더마다 의존성 파일이 있는 이유가 여기에 있습니다. 모든 예제를 한 가상환경에 설치하는 접근은 피하고, 학습할 예제의 환경부터 구분하세요.
저장소의 사용자 인터페이스는 주로 Jupyter 노트북입니다.
음성 RAG 예제에는 ipywidgets와 ipywebrtc>=0.6.0가 있으며, 시각 조사 에이전트의
usage-cookbook/Nemotron-3.5-Super-VL/visual-investigation-agent/requirements.txt에는 jupyterlab==4.6.4, ipykernel==7.4.0, matplotlib==3.11.2가 고정되어 있습니다.
브라우저 UI가 전혀 없는 것은 아닙니다.
usage-cookbook/Nemotron-3-Nano-Omni/computer-use-agent-with-omni/에는 usage-cookbook/Nemotron-3-Nano-Omni/computer-use-agent-with-omni/web/index.html과 usage-cookbook/Nemotron-3-Nano-Omni/computer-use-agent-with-omni/web/sidepanel.js가 있습니다.
usage-cookbook/Nemotron-3-Nano-Omni/computer-use-agent-with-omni/server/main.py는 FastAPI로 정적 파일을 제공하고, 프론트엔드는 fetch()와 EventSource로 상태와 이벤트를 받습니다.
| 웹 데모 구성 | 근거 | 배울 점 |
|---|---|---|
| Python API 서버 | usage-cookbook/Nemotron-3-Nano-Omni/computer-use-agent-with-omni/requirements.txt: fastapi==0.136.1, uvicorn==0.46.0 | 학습 엔진과 웹 API 서버의 역할 구분 |
| 입출력 검증 | pydantic==2.13.3, StartAgentRequest의 min_length=1 | 빈 지시문을 요청 경계에서 거부 |
| 이벤트 전달 | GET /agent/{job_id}/events와 StreamingResponse | 작업 제출과 진행 상황 수신 분리 |
추적 대상 파일에서 package.json·Cargo.toml·go.mod는 발견되지 않았습니다.
저장소 전체를 React·Node.js 기반의 단일 웹 앱으로 설명할 근거는 없습니다.
배포 패키지는 hatchling.build로 만들며, 휠에는 src/nemotron과 src/nemo_runspec이 포함됩니다.
문서는 Sphinx 계열이고, justfile의 docs-render는 sphinx-build를 호출합니다.
| 영역 | 실제 파일과 설정 | 학습 관점 |
|---|---|---|
| 컨테이너 | src/nemotron/recipes/omni3/stage0_sft/Dockerfile: nvcr.io/nvidian/nemo:26.04.rc7 | GPU 라이브러리가 있는 기반 이미지 활용 |
| 환경 분리 | 같은 Dockerfile의 UV_PROJECT_ENVIRONMENT, --system-site-packages | 기반 이미지의 CUDA용 torch를 상속하며 별도 환경에 의존성 구성 |
| CPU 계약 검사 | .github/workflows/retrieval-recipes.yml: Ubuntu 24.04, uv 0.12.12 | GPU 없이도 설정·경로·단계 연결 규칙 검증 |
| 문서 검사 | .github/workflows/build_docs.yml | 공유 CI 워크플로를 Git 리비전으로 고정 |
| 정적 검사 | 루트 설정의 Ruff py311, 줄 길이 119; mypy disallow_untyped_defs=true | 코드 스타일과 함수 타입 규칙 명시 |
재현성을 이해하려면 모델 설정뿐 아니라 Python 범위·잠금 파일·컨테이너·외부 코드 리비전을 함께 읽어야 합니다.
모든 외부 코드가 커밋으로 고정된 것은 아닙니다. 위 Dockerfile은 nemotron_3_omni 브랜치를 가져오므로, 같은 명령도 시점에 따라 다른 코드를 얻을 수 있습니다.
데이터 준비와 학습을 같은 단계로 묶지 않는 것이 중요합니다.
src/nemotron/recipes/nano3/stage0_pretrain/data_prep.py는 blend.json과 토큰 파일을 만들고,
src/nemotron/recipes/nano3/stage0_pretrain/train.py는 그 경로를 학습 엔진의 설정에 넣습니다.
준비가 끝난 데이터를 여러 학습 실험에서 다시 사용할 수 있는 구조입니다.
src/nemotron/recipes/nano3/stage0_pretrain/train.py의 맨 위에는 PEP 723 형식의 주석 블록이 있습니다.
TOML 문법으로 실행 이름·컨테이너·실행기·기본 GPU 자원을 선언합니다. 아래는 해당 명세의 일부입니다.
# /// script
# [tool.runspec]
# schema = "1"
# name = "nano3/pretrain"
# image = "nvcr.io/nvidia/nemo:25.11.nemotron_3_nano"
#
# [tool.runspec.run]
# launch = "torchrun"
#
# [tool.runspec.resources]
# nodes = 2
# gpus_per_node = 8
# ///
src/nemo_runspec/_parser.py의 extract_pep723_toml()은 파일을 텍스트로 읽어 이 블록을 찾고,
주석 접두사를 제거합니다. parse()는 tomllib.loads()로 해석하고 parse_runspec()으로 구조화합니다.
이 파서는 학습 스크립트를 실행하거나 import하지 않고 메타데이터를 읽습니다.
src/nemo_runspec/_models.py의 Runspec·RunspecRun·RunspecResources는
@dataclass(frozen=True)로 선언되어 있습니다. 읽어 들인 실행 명세를 이후 단계에서 함부로 바꾸지 않도록 의도를 표현합니다.
다만 내부에 담긴 딕셔너리까지 깊게 불변이 되는 것은 아닙니다.
일반화할 수 있는 교훈은 기계가 읽을 수 있는 설명을 코드 가까이에 둔다는 것입니다.
단, PEP 723이 tool.runspec의 모든 키를 표준으로 정한 것은 아닙니다. 이 스키마는 저장소가 정의한 규약입니다.
근거: 실행 명세 파서
src/nemotron/cli/commands/nano3/pretrain.py의 _execute_pretrain()은
parse_config()와 parse_env()를 호출하고 build_job_config()로 최종 작업 설정을 만듭니다.
cfg.dry_run이면 설정을 보여 준 뒤 반환하며, 설정 파일 저장과 실제 실행은 그 뒤에 있습니다.
# _execute_pretrain()의 주요 순서를 간추린 흐름
train_config = parse_config(cfg.ctx, SPEC.config_dir, SPEC.config.default)
env = parse_env(cfg.ctx)
job_config = build_job_config(...)
display_job_config(job_config, for_remote=for_remote)
if cfg.dry_run:
return
# 이후 job.yaml·train.yaml 저장, 실행기 선택, 작업 제출
설정 저장은 전체 실행 정보를 담는 job.yaml과 학습 스크립트에 전달할 train.yaml을 나눕니다.
제출 기록과 실제 학습 입력을 따로 살펴볼 수 있어, 원격 환경에서 경로가 달라졌을 때도 비교할 근거가 생깁니다.
로컬 모드에서는 execute_local(), 클라우드 실행기 이름이 dgxcloud 또는 lepton이면
execute_cloud(), 나머지 원격 경로에서는 _execute_remote()를 선택합니다.
후자는 SelfContainedPackager로 코드와 설정을 묶고 run.Experiment에 작업을 추가합니다.
반대로 src/nemotron/recipes/nano3/stage0_pretrain/train.py는 어디에 작업을 제출할지 결정하는 대신,
학습 설정을 조립하고 pretrain(config=cfg, forward_step_func=forward_step)를 호출합니다.
실행 환경을 바꾸는 수정과 학습 내용을 바꾸는 수정을 나눌 수 있습니다.
src/nemo_runspec/config/loader.py의 build_job_config()는 일반 환경 키에 프로필 값을 덮어쓰지만,
YAML에 있던 container_image·nodes·gpus_per_node·ntasks_per_node·nproc_per_node는 다시 적용합니다.
마지막에는 CLI의 dotlist 변경을 재적용합니다.
| 입력 | 예시 | 최종 동작 |
|---|---|---|
| 레시피 YAML | nodes: 8 | 레시피가 명시한 자원 조건을 보존 |
| 환경 프로필 | nodes: 1, partition: site-partition | 위 YAML이 있으면 노드는 8, 파티션은 프로필 값 |
| CLI 변경 | run.env.nodes=2 | 최종 적용 단계에서 노드 수를 2로 변경 |
tests/nemo_runspec/test_config_loader.py의
test_build_job_config_preserves_yaml_owned_image_and_resources()가 YAML 자원 보존과 환경변수 병합을 검증합니다.
함수 위 설명만 읽으면 프로필이 항상 우선한다고 오해할 수 있으므로, 병합 코드와 테스트까지 같이 읽어야 합니다.
실험의 실제 조건은 기본 YAML 하나가 아니라, 모든 병합을 마친 최종 설정에 있습니다. 근거: 설정 조립 코드
사전학습 YAML은 recipe._target_에
megatron.bridge.recipes.nemotronh.nemotron_3_nano.nemotron_3_nano_pretrain_config를 지정합니다.
src/nemotron/kit/recipe_loader.py의 extract_recipe_config()는 이 경로와 나머지 인자를 분리합니다.
# import_recipe_function()의 핵심 부분
module_path, function_name = target.rsplit(".", 1)
module = importlib.import_module(module_path)
return getattr(module, function_name)
# 학습 스크립트에서 구성 객체를 얻는 부분
recipe_func = import_recipe_function(recipe_target)
cfg = recipe_func(**recipe_kwargs)
이후 create_omegaconf_dict_config()로 구성 객체를 변환하고 YAML 및 CLI 변경을 병합한 다음,
apply_overrides()로 실제 학습 설정에 반영합니다.
같은 학습 진입점을 두고 어떤 구성 함수를 사용할지 교체할 수 있으므로 팩터리와 의존성 주입의 작은 사례로 볼 수 있습니다.
src/nemotron/recipes/nano3/stage0_pretrain/config/tiny.yaml은
megatron.bridge.recipes.qwen.qwen3.qwen3_8b_pretrain_config를 지정합니다.
반복 수도 1700, 전역 배치 크기도 32입니다.
이 파일명만 보고 매우 작은 Nano3가 잠깐 실행된다고 해석하면 안 됩니다.
또한 _target_은 실제 Python 모듈을 import하는 경로입니다.
데이터처럼 보이는 설정도 실행할 코드를 선택할 수 있다는 뜻입니다. 어떤 함수를 가리키는지 읽는 습관이 필요합니다.
근거: 레시피 로더
src/nemotron/kit/artifacts/base.py의 Artifact는 Pydantic 모델입니다.
path·type·metadata와 생성 시각·생산자 정보를 담고,
model_validator로 하위 클래스 필드와 메타데이터를 맞춥니다.
src/nemo_runspec/artifacts.py의 setup_artifact_tracking()은 설정을 읽어
manifest와 W&B 추적을 선택합니다. ManifestTracker.log_artifact()는
실제 대용량 데이터를 복사하는 대신 manifest.json에 경로와 입력 참조를 기록합니다.
_atomic_json_write()는 임시 파일에 JSON을 쓴 뒤 fsspec의 mv()를 호출합니다.
hf:// 저장소는 별도 경로에서 관련 파일을 한 커밋으로 묶습니다.
다만 모든 원격 파일시스템에서 같은 원자성이 보장된다고 확대 해석할 수는 없습니다.
수 톤짜리 재료를 매번 다른 창고로 옮기는 대신, 재료의 위치와 제조 번호를 장부에 적습니다. 기록 비용은 줄지만 원본이 삭제되거나 내용이 바뀌면 장부만으로 재료를 되살릴 수 없습니다.
따라서 :latest는 편리한 참조일 뿐 고정된 실험 조건이 아닙니다.
비교 실험에는 실제 버전과 데이터 내용, 설정, 외부 엔진 버전까지 기록해야 합니다.
공통 추적 계층이 manifest를 지원해도 Nano3 학습 스크립트에는 W&B 관련 패치가 남아 있으므로 모든 레시피가 동일하게 동작한다고 단정하면 안 됩니다.
근거: manifest 추적 구현
usage-cookbook/Nemotron-Nano-9B-v2/vllm_cookbook.ipynb에는 stream_like()가 있습니다.
이 함수는 먼저 llm.generate()의 전체 결과를 받은 뒤 문자열을 한 글자씩 출력합니다.
서버에서 생성 중인 토큰을 받는 진짜 스트리밍과는 대기 시간의 성격이 다릅니다.
# 노트북의 stream_like()에서 중요한 부분
outputs = llm.generate([prompt], sampling_params=sampling_params)
text = outputs[0].outputs[0].text
for ch in text:
print(ch, end="", flush=True)
# 별도의 API 예제는 stream=True로 청크를 받는다
for chunk in stream:
delta = chunk.choices[0].delta
if delta and delta.content:
print(delta.content, end="", flush=True)
같은 화면 효과라도 데이터가 도착하는 시점은 다를 수 있습니다. 첫 토큰 지연을 비교하려면 출력 애니메이션이 아니라 요청 시각과 첫 응답 청크 수신 시각을 관찰해야 합니다.
위 구조는 주요 경로만 남긴 요약입니다. src/는 Python 패키지의 소스 디렉토리입니다.
예제 디렉토리까지 패키지 내부 코드와 같은 방식으로 설치·관리되는 것은 아닙니다.
| 경로 | 주된 책임 | 직접 찾을 질문 |
|---|---|---|
src/nemotron/cli/commands/ | 옵션을 받아 실행 설정을 만들고 작업 제출 | 어디에서 어떻게 실행하는가? |
src/nemotron/recipes/ | 모델별 입력·출력과 학습 설정 | 무엇을 학습하는가? |
src/nemotron/data_prep/ | 원문을 학습 엔진이 읽는 형식으로 변환 | 데이터는 어떤 형태여야 하는가? |
src/nemo_runspec/ | 모델과 무관한 실행·설정·추적 지원 | 여러 레시피에서 공통으로 쓰는 규칙은 무엇인가? |
처음부터 모든 파일을 정독하지 마세요.
src/nemotron/cli/commands/nano3/pretrain.py → src/nemotron/recipes/nano3/stage0_pretrain/train.py →
src/nemotron/kit/recipe_loader.py 순서로 한 경로를 완주한 뒤, 데이터 준비 쪽으로 돌아오는 편이 좋습니다.
| 분류 | 파일 수 | 대략적인 물리 행 수 |
|---|---|---|
| Python 파일 | 1,304 | 347,695행 |
| 노트북 코드 셀 | 노트북 61본 / 코드 셀 674개 | 15,876행 |
| YAML·YML | 304 | 33,821행 |
| Shell | 17 | 1,068행 |
| JavaScript | 3 | 760행 |
| HTML·CSS | 6 | 3,983행 |
| Markdown 문서 | 671 | 106,355행 |
| TOML 설정 | 78 | 7,455행 |
커밋 1c3e781의 git ls-files에 있는 추적 파일 2,727개를 대상으로 셌습니다.
텍스트는 줄 단위로, 노트북은 JSON 전체가 아닌 코드 셀의 source만 셌습니다.
공백·주석을 포함하며, Python 파일에 포함된 테스트와 예제도 제외하지 않았습니다.
Python 중 src/nemotron/은 195,685행, src/nemo_runspec/은 10,432행,
tests/는 107,217행입니다. 이 세 수치는 전체 Python 행 수 안에 포함되는 부분집합입니다.
GitHub의 주 언어 표시는 이런 물리 행 수와 같은 계산이 아니므로 서로 모순이라고 볼 수 없습니다.
Runspec의 dataclass와 Artifact의 Pydantic 모델은 서로 다른 필요를 해결합니다.
전자는 읽은 실행 명세를 구조화하고, 후자는 저장·전달할 아티팩트의 필드를 검증합니다.
“모든 데이터를 dict로 넘길까?” 대신, 어느 지점에서 입력을 검증해야 하는지 생각해 보세요.
실습 아이디어: 실행 명세에서 nodes와 gpus_per_node를 표로 옮기고,
값이 누락됐을 때 parse_runspec()이 고르는 기본값을 찾아 적습니다.
타입 표기와 범위 검증은 같은 것이 아니라는 점도 확인합니다.
load_config()는 기본 설정을 병합하면서 순환 상속을 검사합니다.
apply_dotlist_overrides()는 OmegaConf.from_dotlist()로
train.train_iters=5 같은 문자열을 중첩 구조로 바꿉니다.
실습 아이디어: YAML의 train_iters: 1700에 CLI 변경 train.train_iters=5를 적용한다고 가정하고,
바뀌는 키와 유지되는 키를 손으로 계산합니다. 이어서 run.env.nodes는 왜 프로필과 다른 규칙을 따르는지 설명합니다.
src/nemotron/recipes/nano3/stage1_sft/data_prep.py의 run_data_prep_main()은
PlanStage·DownloadStage·PackedSftParquetStage를 연결합니다.
대화를 토큰으로 바꾸고, 역할별 loss mask를 만든 뒤 다음 토큰 예측에 맞게 샘플 안에서 한 칸 당겨 정렬합니다. 여러 시퀀스를 묶어 Parquet 샤드로 저장하며, 각 샘플의 마지막 loss mask는 0으로 둡니다.
Nano3 레시피 README의 흐름도와 명령 설명은 SFT 출력을 .npy로 설명하지만,
현재 데이터 준비 코드와 학습 스크립트는 packed Parquet 경로를 연결합니다. 데이터 형식은 오래된 요약 표보다 실제 생산자와 소비자 코드를 함께 확인해야 합니다.
실습 아이디어: 길이 6·4·3인 샘플을 용량 10인 상자에 넣어 보고,
경계 표시를 잃으면 어떤 오류가 생길지 적습니다. 이후 src/nemotron/recipes/nano3/stage1_sft/train.py의
_build_dataset_config()가 nano3_packed_sft_dir에서 학습 경로를 자동 구성할 때 Parquet 파일이 없으면 어떻게 실패하는지 읽습니다.
src/nemotron/kit/recipe_loader.py의 derive_pad_seq_to_mult()는
CP·TP·sequence parallel 조건으로 패딩 길이의 배수를 계산합니다.
명시된 배수와 학습·평가 병렬 구성의 요구값을 math.lcm()으로 합칩니다.
# 함수 규칙을 손으로 계산하는 예시
explicit = 3
CP = 2
TP = 4
sequence_parallel = True
# CP 제약: 2 * CP = 4
# sequence parallel 제약: CP * TP = 8
# 최종 배수: lcm(3, 4, 8) = 24
여기서 24는 토큰 길이 정렬의 배수입니다. GPU가 24개 필요하다는 뜻이 아닙니다. 실습 아이디어: sequence parallel을 끄거나 평가 CP를 추가했을 때 배수가 어떻게 바뀌는지 계산합니다.
vLLM 노트북의 가장 짧은 경로는 모델 로딩 → 생성 옵션 → 결과 추출입니다. 다음은 그 구조를 유지하고 질문만 한국어로 바꾼 예시입니다. 실제 실행에는 해당 모델을 수용할 GPU 환경이 필요합니다.
from vllm import LLM, SamplingParams
llm = LLM(
model="nvidia/NVIDIA-Nemotron-Nano-9B-v2",
trust_remote_code=True,
dtype="bfloat16",
)
params = SamplingParams(temperature=0.6, max_tokens=200)
outputs = llm.generate(["GPU가 하는 일을 쉽게 설명해 줘."], sampling_params=params)
print(outputs[0].outputs[0].text)
trust_remote_code=True는 모델 저장소의 사용자 정의 코드를 허용하는 선택입니다.
모델 식별자뿐 아니라 실제로 사용할 코드 리비전도 확인할 대상이 됩니다.
vLLM 노트북의 TOOLS는 calculate_tip 함수 이름과 JSON Schema를 모델에 제공합니다.
해당 셀은 응답의 message.content와 message.tool_calls를 출력하지만,
실제 calculate_tip() 함수를 정의해 호출하는 실행 루프까지 구현하지는 않습니다.
실습 아이디어: 청구액 50, 비율 15라는 인자를 받은 뒤 애플리케이션이 검증·계산·결과 전달을 수행하는 흐름을 그립니다. 모델이 함수 이름을 반환했다는 사실만으로 함수가 실행됐다고 판단하지 않는 연습입니다.
.github/workflows/retrieval-recipes.yml은 CUDA_VISIBLE_DEVICES를 비우고,
Hugging Face·Transformers의 오프라인 모드와 WANDB_MODE=disabled를 설정합니다.
tests/recipes/retrieval_ci/run.py의 RequireCoverage는 테스트가 건너뛰어져도 실패하도록 만듭니다.
비싼 GPU 계산을 돌리기 전에, 설정과 파일 경로와 단계 간 약속부터 검증할 수 있습니다. 이 CI는 그런 계약을 검사하는 사례이며, 모델 정확도나 전체 학습 성공을 증명하는 검사는 아닙니다.
tests/nemo_runspec/test_config_loader.py를 읽고, 기본 YAML 상속·자원 우선순위·환경변수 병합을 각각 어떤 assert가 확인하는지 적어 보세요.
테스트가 확인하지 않는 GPU 메모리와 모델 품질은 별도 항목으로 남깁니다.
이 허브 전체를 대표하는 최소 사양 하나는 없습니다. API를 호출하는 노트북과 모델을 직접 올리는 추론, 분산 학습 레시피가 함께 있기 때문입니다. 아래에서 “소스의 기본값”과 “설명상의 권장 조건”을 구분합니다.
| 작업 | 확인된 조건 | 현실적인 출발점 |
|---|---|---|
| 코드·노트북 읽기 | GPU 계산 불필요 | 텍스트 편집기와 노트북 내용을 읽을 수 있는 도구 |
| 호스팅 API 이용 | 간단한 Nano3 예제 README 기준 OpenRouter API 키 사용 | 로컬 GPU 대신 네트워크·계정·호출 한도 확인 |
| 9B 모델 로컬 추론 | vLLM 노트북 설명: BF16 가능 NVIDIA GPU, VRAM 24GB 이상 권장, CUDA 12.x | 이 권장치는 해당 모델·예제 기준. 최대 문맥과 큰 배치를 보장하지 않음 |
| Nano3 데이터 준비 | 실행 명세: 노드 1, GPU 0, Ray 기반 처리 | CPU·RAM·다운로드 공간·샤드 출력 공간 계획 |
| Nano3 사전학습 | 실행 명세 기본값: 노드 2 × 노드당 GPU 8 | 16 GPU는 명세 기본값. 측정된 최소 GPU 수로 해석하지 않음 |
| Nano3 SFT·RL | 각 실행 명세 기본값: 노드 1 × GPU 8 | 실제 모델·시퀀스·배치·병렬 설정을 함께 점검 |
Nano3 레시피 README는 총 31.6B, 활성 3.6B 파라미터를 구분합니다. MoE는 한 토큰 계산에 일부 전문가를 선택하지만, 선택되지 않은 전문가의 가중치가 모델에서 사라지는 것은 아닙니다.
# BF16 가중치만 놓고 계산한 단순 추정
가중치 바이트 수 ≈ 전체 파라미터 수 × 2
9B × 2바이트 ≈ 18.0GB ≈ 16.8GiB
31.6B × 2바이트 ≈ 63.2GB ≈ 58.9GiB
# 포함되지 않은 것
추론: KV 캐시 또는 모델별 상태, 작업 버퍼, 엔진 오버헤드
학습: 그래디언트, 옵티마이저 상태, 활성값 등
위 계산은 파라미터 수를 단순화한 가중치 용량 추정입니다. 실행 가능한 최소 VRAM을 보증하지 않습니다. 특히 Mamba와 attention이 섞인 모델은 모든 상태를 동일한 Transformer KV 캐시 공식으로 설명하기 어렵습니다.
MoE의 활성 파라미터 수가 작아도, 전체 모델의 저장·배치 비용까지 같은 비율로 줄어드는 것은 아닙니다.
소스 읽기와 API 클라이언트 학습에는 CUDA가 필요 없습니다.
반면 GPU 선택 의존성의 cupy-cuda12x·cudf-cu12 등에는
Linux·x86_64 조건이 붙어 있습니다. 이 레시피의 NVIDIA GPU 실행 경로를 macOS의 Metal 환경과 동일하게 가정할 수 없습니다.
루트 패키지는 Python 3.11~3.13 범위를 허용하지만, vLLM 9B 노트북은 Python 3.10 환경을 설명합니다. 이는 서로 다른 실행 경로의 안내입니다. 노트북의 설명을 루트 패키지 설치 조건으로 그대로 가져오지 마세요.
| 자원 | 왜 필요한가 | 소스에서 볼 지점 |
|---|---|---|
| 디스크 | 원문·토큰화 결과·샤드·체크포인트가 함께 남을 수 있음 | src/nemotron/recipes/nano3/stage0_pretrain/data_prep.py의 output_dir, 학습 YAML의 checkpoint.save |
| 네트워크·공유 경로 | 모델과 데이터 다운로드, 여러 노드의 동일 경로 접근 | env.toml의 마운트와 원격 작업 디렉토리 |
| CPU·RAM | 데이터 다운로드·토큰화·Parquet 처리 | plan·download·tokenization 설정 |
| 시간 | 여러 답안 생성·학습·평가·체크포인트 저장 | RL의 num_generations_per_prompt, max_total_sequence_length |
src/nemotron/recipes/nano3/stage2_rl/config/tiny.yaml조차 프롬프트당 생성 수 16, 최대 전체 시퀀스 길이 49152,
최대 스텝 수 1000000을 지정합니다. 최대 스텝이 실제 실행 횟수를 뜻하는 것은 아니지만, 파일명만으로 짧고 저렴한 실행을 기대할 근거도 없습니다.
docs/train-models/sizing-calculator.md는 SFT·LoRA·GRPO의 GPU 수·시간·비용 추정 방법을 설명합니다.
문서도 이를 방향을 잡는 추정이라고 명시하며, 대기열·데이터 준비·평가·배포 시간은 학습 시간 추정에 포함하지 않습니다.
다음 다섯 과제는 파일 읽기와 손계산만으로 수행할 수 있습니다. 난이도는 계산량보다 서로 다른 파일의 관계를 얼마나 연결해야 하는가를 기준으로 정했습니다.
대상: usage-cookbook/Nemotron-Nano-9B-v2/vllm_cookbook.ipynb
할 일: 모델 이름·dtype·temperature·max_tokens를 찾고,
stream_like()와 API 스트리밍 셀을 비교합니다. 노트북 셀은 실행하지 않습니다.
제출물: “입력 → 모델/엔진 → 출력” 흐름도와, 두 스트리밍 예제의 첫 응답 시점 차이를 설명한 세 문장.
완료 기준: llm.generate()가 끝난 뒤 출력하는 함수와, 응답 청크를 순회하는 코드를 구분할 수 있습니다.
노트북은 JSON 파일이므로 표준 라이브러리만으로 코드 셀을 읽을 수 있습니다. 아래 명령은 저장소 루트에서 내용을 출력할 뿐, 노트북 코드를 실행하지 않습니다.
python3 - <<'PY'
import json
from pathlib import Path
path = Path("usage-cookbook/Nemotron-Nano-9B-v2/vllm_cookbook.ipynb")
notebook = json.loads(path.read_text(encoding="utf-8"))
for index, cell in enumerate(notebook.get("cells", [])):
if cell.get("cell_type") == "code":
print(f"\n셀 {index}")
print("".join(cell.get("source", [])))
PY
대상: src/nemotron/recipes/nano3/stage0_pretrain/config/default.yaml과 src/nemotron/recipes/nano3/stage0_pretrain/config/tiny.yaml
할 일: recipe._target_·입력 아티팩트·컨테이너·반복 수·저장 간격을 두 열 표로 만듭니다.
파일에 없는 값은 “이 YAML에 명시되지 않음”이라고 적습니다.
제출물: 설정 비교표와 “tiny가 Nano3 축소 모델이라는 해석이 왜 틀릴 수 있는가”에 대한 설명.
완료 기준: 기본 파일에서 직접 찾지 못한 train_iters를 추정으로 채워 넣지 않고,
외부 레시피 함수의 기본값을 더 확인해야 한다고 말할 수 있습니다.
대상: src/nemo_runspec/config/loader.py의 build_job_config()
할 일: 아래 가상의 세 입력을 합친 결과를 먼저 적고,
test_build_job_config_preserves_yaml_owned_image_and_resources()의 assert와 비교합니다.
제출물: 최종 run.env 및 각 값의 출처를 기록한 표.
완료 기준: 노드 수는 2, 노드당 GPU 수는 8, 파티션은 batch가 되는 이유를 코드의 적용 순서로 설명합니다.
# 설명용 입력. 실제 클러스터 설정이 아니다.
레시피 YAML:
run.env.nodes = 8
run.env.gpus_per_node = 8
run.env.env_vars.FROM_CONFIG = "1"
환경 프로필:
nodes = 1
partition = "batch"
env_vars.FROM_PROFILE = "1"
CLI 변경:
run.env.nodes=2
정답에서는 두 환경변수도 모두 남습니다. 이 결과를 “프로필이 항상 우선” 또는 “YAML이 항상 우선”이라는 한 문장으로 줄일 수 없는 이유를 적어 보세요.
대상: src/nemotron/recipes/nano3/stage1_sft/data_prep.py, src/nemotron/recipes/nano3/stage1_sft/train.py, src/nemotron/kit/recipe_loader.py
할 일: 토큰 길이 6·4·3인 세 샘플을 패킹하고 경계를 표시합니다. 별도로 CP=2, TP=4, sequence parallel 활성, 명시 배수 3일 때 정렬 배수 24를 계산합니다.
제출물: 원본 메시지·토큰·loss mask·패킹 경계·Parquet·학습 입력을 잇는 도식.
완료 기준: 패킹 용량과 패딩 배수는 다른 설정임을 설명하고,
_build_dataset_config()에서 nano3_packed_sft_dir로 학습 경로를 자동 구성할 때의 Parquet 파일 존재 검사를 찾습니다.
대상: Nano3 학습 스크립트·YAML, src/nemo_runspec/manifest_tracker.py, src/nemotron/cli/commands/nano3/pipe.py
할 일: 코드 리비전·데이터 버전·가중치 버전·토크나이저·컨테이너·최종 설정·시드를 기록할 위치를 찾습니다.
:latest와 브랜치 참조, 원본 데이터 경로가 변했을 때의 영향을 적습니다.
제출물: 사전학습 → SFT → RL의 입력·출력 계약표와, 재현을 막을 수 있는 조건 세 가지.
완료 기준: nano3 pipe가 원격 모드에서 사전학습과 SFT를 묶고,
RL은 Ray를 사용해 별도 경로로 실행된다는 점을 소스로 확인합니다. 명령 하나가 모든 단계를 자동 보장한다고 쓰지 않습니다.
다섯 과제를 마치면 실제 실행 전에 확인할 파일과 필요한 환경을 스스로 고를 수 있습니다. GPU 실험으로 넘어갈 때도 “모델 하나 실행”보다 입력·배치·시퀀스 길이를 제한한 단일 단계부터 계획하세요.
주당 3~5시간 정도의 읽기 중심 학습 계획입니다. 시간을 채우는 것보다 매주 적힌 산출물을 남기는 것이 중요합니다. GPU 학습 실행은 이 로드맵의 필수 조건이 아닙니다.
| 주차 | 학습 주제와 읽을 위치 | 완성할 것 |
|---|---|---|
| 1주차 | Python·JSON·노트북 구조. vLLM 노트북의 모델 입력과 출력 | 추론과 학습의 차이, 동기 응답과 스트리밍 차이 설명 |
| 2주차 | TOML·YAML·dataclass·Pydantic. src/nemo_runspec/_parser.py, src/nemo_runspec/_models.py, src/nemotron/kit/artifacts/base.py | 실행 명세와 아티팩트의 필드 사전 |
| 3주차 | Typer·설정 병합·실행기. src/nemotron/cli/commands/nano3/pretrain.py, src/nemo_runspec/config/loader.py | CLI → 최종 설정 → 실행기 흐름도와 우선순위 표 |
| 4주차 | 토큰화·loss mask·Parquet·패킹. src/nemotron/data_prep/, Nano3 SFT 경로 | 텍스트가 학습 입력이 되는 변환 과정 |
| 5주차 | SFT·GRPO·분산 병렬화. Nano3 src/nemotron/recipes/nano3/stage1_sft/, src/nemotron/recipes/nano3/stage2_rl/ | 단계별 목적·엔진·체크포인트 형식 비교표 |
| 6주차 | 아티팩트 이력·오프라인 CI·재현성. src/nemo_runspec/manifest_tracker.py, retrieval CI | 하나의 실험에 필요한 증거 목록과 실패 원인 지도 |
Python이 낯설면 먼저 함수·클래스·모듈 import·타입 힌트·파일 읽기를 익힙니다. ML이 낯설면 토큰·가중치·loss·배치·추론과 학습 차이를 먼저 정리합니다. 분산 시스템은 프로세스와 노드, 작업 제출과 실제 계산의 차이부터 이해하면 됩니다.
지하철을 배우듯 한 노선을 끝까지 타 보세요. CLI에서 학습 엔진까지 한 경로를 설명할 수 있게 된 뒤 데이터 준비·추적·추론으로 환승하면, 전체 지도를 처음부터 외우는 것보다 각 구성 요소의 필요성이 선명해집니다.
| 관심 | 다음에 읽을 경로 | 새롭게 던질 질문 |
|---|---|---|
| RAG·검색 | src/nemotron/recipes/embed/, src/nemotron/recipes/rerank/ | 검색 후보를 만드는 모델과 순서를 재평가하는 모델은 어떻게 다른가? |
| 에이전트 | 간단한 Nano3 사용 예제와 Omni 컴퓨터 사용 데모 | 도구 호출의 검증·실행·중단·관측을 누가 책임지는가? |
| 학습·데이터 | src/nemotron/recipes/data/, docs/train-models/faq/ | 데이터 품질과 혼합 비율은 어떤 결과 변화를 만드는가? |
마지막에는 같은 입력·같은 평가 기준을 두고 무엇 하나만 바꾼 실험을 설계해 보세요. 측정 방법이 정해지지 않았다면, 구현을 늘리기 전에 무엇을 비교하려는지부터 다시 적는 편이 좋습니다.
| 용어 | 쉬운 설명 |
|---|---|
| Nemotron | NVIDIA 모델 계열 이름. 이 저장소는 모델 사용·학습·데이터 관련 개발 자산을 모은 허브 |
| 추론 | 준비된 가중치로 입력의 결과를 계산하는 일. 보통 그 과정에서 가중치를 학습으로 바꾸지는 않음 |
| 사전학습 | 많은 데이터로 기본 언어·지식 패턴을 학습하는 단계 |
| SFT | 질문과 바람직한 답변 같은 지도 데이터를 이용해 모델을 조정하는 학습 |
| LoRA | 모든 가중치 대신 작은 추가 행렬 등을 학습해 모델을 조정하는 방법 |
| 강화학습·GRPO | 보상으로 모델을 조정하는 학습. GRPO는 같은 질문에 대한 여러 생성 결과의 상대적 보상을 활용 |
| 토큰·토크나이저 | 모델이 처리하는 작은 입력 단위와, 텍스트를 그 단위의 숫자로 바꾸는 도구 |
| loss·loss mask | 예측 오차를 수치화한 값과, 어느 토큰의 오차를 반영할지 정하는 표시 |
| 배치·스텝 | 한 번에 처리하는 샘플 묶음과 학습 진행의 한 단계. 전역 배치와 장치별 배치는 다를 수 있음 |
| 체크포인트 | 학습 중간 또는 최종 상태를 저장한 결과물. 목적에 따라 가중치 외 상태도 포함 |
| 아티팩트·계보 | 데이터·모델 같은 버전 있는 결과물과, 어떤 입력에서 어떤 결과가 나왔는지의 연결 기록 |
| manifest | 실제 파일의 위치·버전·생산자·입력 참조 등을 기록한 장부 |
| MoE·활성 파라미터 | 여러 전문가 중 일부를 선택하는 구조와, 한 입력 계산에 실제 사용되는 파라미터 |
| Mamba·Transformer | 시퀀스를 처리하는 서로 다른 모델 구성 방식. Nemotron 문서는 두 방식을 섞은 모델을 설명 |
| BF16·VRAM | 16비트 숫자 표현 형식과 GPU의 메모리. 가중치 외에도 실행 중 상태가 VRAM을 사용 |
| 문맥 길이 | 모델이 처리하는 입력·출력 범위의 토큰 길이. 최대 길이 사용에는 별도 자원 조건이 필요 |
| TP·PP·CP·EP | 텐서·파이프라인·문맥·전문가를 기준으로 계산이나 데이터를 여러 장치에 나누는 병렬화 방식 |
| 패킹·패딩 | 샘플을 묶어 공간을 채우는 일과, 길이·정렬 조건을 맞추기 위해 빈 토큰 등을 덧붙이는 일 |
| Parquet·샤드 | 열 기반 데이터 파일 형식과, 큰 데이터셋을 나눈 조각 |
| PEP 723·Runspec | 스크립트에 메타데이터를 넣는 형식과, 그 형식 안에 이 저장소가 정의한 실행 명세 |
| OmegaConf·dotlist | 설정을 다루는 라이브러리와, a.b=value 형태로 중첩 설정을 바꾸는 표기 |
| Slurm·torchrun·Ray | 클러스터 작업 스케줄러, PyTorch 분산 프로세스 실행 도구, 분산 작업 실행 프레임워크 |
| vLLM·NIM | 모델 추론 엔진·서빙 도구와 NVIDIA의 모델 추론 마이크로서비스 제공 방식 |
| 도구 호출 | 모델이 함수 이름과 인자를 제안하는 응답. 실제 검증과 함수 실행은 애플리케이션의 역할 |
| SSE | 서버가 클라이언트로 이벤트를 이어 보내는 HTTP 통신 방식. 웹 데모의 진행 상황 표시에 사용 |
| RAG·임베딩·재정렬 | 검색 자료를 생성에 활용하는 방식, 내용을 벡터로 바꾸는 일, 검색 후보 순서를 다시 평가하는 일 |
| CI·계약 테스트 | 변경 시 자동 검사를 수행하는 체계와, 입력·출력·설정 사이의 약속을 확인하는 테스트 |
| 항목 | 확인 내용 |
|---|---|
| 선정 | GitHub Trending Jupyter Notebook Daily #11 · 2026-10-23 분석 |
| 스타 / 포크 | 2,201 / 450 · 2026-10-23 GitHub 기준 |
| 생성일 | 2025-10-03 |
| 주 언어 | GitHub 표기 Jupyter Notebook |
| 최신 릴리스 | v0.2.0 · 2026-10-15. 루트 패키지 버전도 0.2.0 |
| 최근 push | 2026-10-21 |
| 분석 기준 커밋 | 1c3e781 · 2026-10-21 · docs(pr-review): cover onboarding and reproducibility (#379) |
| 코드 규모 | 추적 파일 2,727개. Python 1,304개 / 347,695행. 노트북 61본 / 코드 셀 15,876행 |
| 테스트 규모 | tests/ 아래 Python 314개 / 107,217행. 실제 테스트 통과율·커버리지를 뜻하지 않음 |
| 루트 Python | >=3.11,<3.14. .python-version은 3.12. 예제별 범위는 다름 |
| 라이선스 | GitHub·루트 LICENSE·README는 Apache-2.0. 루트 pyproject와 일부 모듈의 MIT 표기와 불일치 |
| 안정성 표기 | 루트 패키지 분류에 Development Status :: 3 - Alpha가 남아 있음 |
설명 범위: 커밋 1c3e781의 파일·설정·테스트 정의를 기준으로 설명합니다.
이 정의만으로 모델 추론, 데이터 다운로드, GPU 학습, CI 테스트의 실행 성공을 보장할 수는 없습니다.
하드웨어 기본값은 실행 가능한 최소 사양으로 검증된 숫자가 아닙니다.
문서와 구현의 차이: README는 Python 3.10+를 표시하지만 루트 패키지는 3.11 이상을 요구합니다. Nano3 README의 Slurm 전용·W&B 필수 안내와 달리 현재 공통 계층에는 여러 실행기와 manifest 추적이 있습니다. 다만 Nano3 학습 스크립트의 W&B 경로가 남아 있으므로, 공통 기능의 존재를 모든 레시피의 지원 보장으로 확대할 수 없습니다.
재현성: 공개 데이터 부분집합으로는 기술 보고서와 결과가 달라질 수 있습니다.
:latest·브랜치 참조·서로 다른 이미지 태그도 고정된 조건이 아닙니다.
Nano3 사전학습 스크립트의 이미지 명세와 YAML의 이미지 태그도 다릅니다. 실행 계층은 run.env.container_image → 기존 키인 run.env.container → 스크립트의 SPEC.image 순으로 이미지를 선택합니다. YAML의 container는 병합 시 보존 대상인 container_image와 다른 키이므로 최종 실행 설정을 확인해야 합니다.
의존성과 권리 표기: 예제별 Python·Transformers 범위가 다르고, byob와 bfcl-mcp는 충돌이 선언되어 있습니다.
루트 LICENSE의 Apache-2.0과 패키지·일부 파일의 MIT 표기도 일치하지 않습니다.
모델 가중치와 데이터셋의 사용 조건은 각 배포 페이지에서 별도로 확인해야 합니다.
참고 자료의 시점: 특정 커밋의 파일 구성은 전체 커밋 수나 장기 기여 추이를 나타내지 않습니다.
Nano3 레시피 README의 논문 링크에는 2506.XXXXX 자리표시자가 남아 있고,
CHANGELOG에도 과거 계획과 현재 구현이 섞여 있어 전체 상태를 대표하지 않습니다.
위의 공식 기술 보고서 링크와 커밋이 고정된 소스 경로를 함께 확인하세요.