# DINOv3: 이미지가 의미가 되는 순간

> 픽셀에서 표현으로, 표현에서 관계로 — 신경망 원리와 설명 가능한 데이터 선택을 연결하는 연구 리포트

작성·검토일: 2026-09-25 · 언어: 한국어 · 버전: 1.5 (핵심 요약·데이터셋 배경·질병·Greenhouse 기록 검토)

## Executive summary — 핵심 요약

이 연구 워크벤치는 우간다에서 촬영한 강낭콩 잎 사진을 이용해 **같은 이미지가 렌즈와 신경망 층에 따라 어떻게 다른 표현이 되는지**, 그리고 **그 표현 위에서 데이터 선택이 어떻게 달라지는지** 살펴본다. 아래 배경 설명을 읽은 뒤 실제 사진, 고차원 이웃, 패치 지도와 층별 값을 오가며 가설을 점검할 수 있다.

- 대상은 공개 beans 전체가 아니라 클래스별 100장씩 선택된 학습 부분집합 300장이다. 네 가지 최종 임베딩, 6장 실제 패치, 3장 실제 중간 텐서를 제공한다.
- 기존 DINOv3-L 자체 공간의 300→120장 선택 실험에서 H는 클래스 수를 맞춘 무작위 선택보다 균형 정확도가 +3.35%p 높았다. 렌즈·평가 조건을 고정한 결과이며, 데이터 전체의 품질 점수나 일반적인 성능 우위를 뜻하지 않는다. 반복·불확실성은 기존 실험 절을 참조한다.
- 전문가 주석과 클래스 균형은 강점이다. 그러나 Greenhouse의 GOOD·분별성만으로 무오류 라벨, 무중복, 누수 부재를 보증하지 않는다. 서로 다른 역사적 진단과 권고는 별도 근거로 보존한다.
- 실제 이미지·임베딩·층별 텐서와 합성 Gram·EMA 실험을 구별한다. 패치 유사도는 attention이나 인과적 설명이 아니며, 이 웹은 현장 병해 진단 서비스가 아니다.

DINOv3를 이해하는 핵심은 **신경망의 구조**, **그 구조를 학습시키는 목표**, **학습 후 벡터를 사용하는 방법**을 구분하는 것이다. ViT는 패치 사이의 정보를 교환하는 구조이고, DINO·iBOT·KoLeo·Gram anchoring은 표현에 서로 다른 제약을 주는 학습 요소다. 학습된 모델은 새 이미지를 벡터로 변환한다. FAISS 검색이나 Data Diet H의 표본 선택은 그 벡터를 사용하는 별도의 단계다.

이 보고서는 공식 논문과 고정된 코드 버전을 대조했다. 동반 웹에는 실제 beans 300장에 대한 네 가지 렌즈의 임베딩, 토큰 수 계산, EMA 모형, Gram 행렬 모형, 기존 H 실험의 효과와 불확실성을 담았다. 합성 예제를 실제 신경망의 관측 결과처럼 제시하지 않는다.

## 탐색 전에 — beans 데이터셋과 질병의 맥락

### 출처와 수집 목적

Makerere AI Lab과 우간다 국립작물자원연구소(NaCRRI)는 우간다 여러 지역의 밭에서 일반 스마트폰으로 잎을 촬영했다. NaCRRI 전문가가 수집 현장에서 주석을 달았다. 2020년 공개된 iBean 프로젝트는 농민이 현장에서 사용할 수 있는 강건한 모바일 병해 분류 모델을 목표로 한다. 원 저장소는 MIT 라이선스를 명시한다. 같은 기관의 다른 버전 데이터셋의 규모·라이선스를 이 자료에 혼용하지 않는다. [원저자의 iBean 설명](https://github.com/AI-Lab-Makerere/ibean)

여기서 beans는 대두가 아니라 common bean, 강낭콩류(*Phaseolus vulgaris*)다. 분류 대상은 모무늬병(Angular Leaf Spot), 녹병(Bean Rust), 건강(Healthy)의 세 라벨이며, 밭에서 발생 가능한 모든 병해를 포함하는 진단 체계는 아니다. [작물·모무늬병 설명](https://apps.lucidcentral.org/pppw_v10/text/web_full/entities/bean_angular_leaf_spot_216.htm)

### 공개 전체와 현재 부분집합의 차이

| 범위 | 규모와 의미 |
|---|---|
| 공식 배포 카탈로그 | 학습 1,034장 + 검증 133장 + 시험 128장 = 1,295장; 500×500 RGB |
| 이 웹의 탐색 대상 | 학습 부분집합 300장, 클래스별 100장; 원본 JPEG 및 기존 명세 재사용 |
| 기존 H 평가 프로토콜 | 별도 held-out 128장을 검증 65장 / 최종 평가 63장으로 분할; 공개 validation 133장과 혼동하지 않음 |
| 내부 표현 관찰 | 패치 6장, 층별 3장(#094·#183·#256); 현재 변경에서 새 추론 없음 |

출처: [TensorFlow Datasets beans 카탈로그](https://www.tensorflow.org/datasets/catalog/beans), 동반 웹의 `data/images.json`과 기존 실험 프로토콜. 원저자 README는 건강 428·모무늬병 432·녹병 436으로 합계 1,296장을 적고 있어 카탈로그와 1장 차이가 난다. 이번 검토에서 원인을 확인하지 못했으며, 원저자 숫자를 배포본 개수로 조용히 대체하지 않는다.

### 연구 활용과 이번 연구의 위치

실제 활용 예로 2025년 Frontiers in Plant Science 논문 「A novel transformer using dynamic range-enhanced discrete cosine transform for detecting bean leaf diseases」는 iBean 1,295장으로 주파수 기반 전처리와 Transformer 분류를 평가했다. [원 연구 논문](https://www.frontiersin.org/journals/plant-science/articles/10.3389/fpls.2025.1624373/full)

이번 워크벤치는 그 논문의 분류 정확도와 경쟁하거나 재현하는 작업이 아니다. 고정된 DataLens의 공간 구조와 층별 표현, 표본 선택을 비교한다. 외부 연구와 현재 실험의 분할·학습·평가 조건이 다르므로 정확도를 직접 비교하지 않는다.

### 잎의 질병이 무엇을 의미하는가

**모무늬병 — #094.** 곰팡이 *Pseudocercospora griseola*에 의한 병이다. 잎맥에 의해 경계가 제한되는 각진 회갈색 병반이 나타날 수 있다. 심한 발병은 조기 낙엽과 생산 저하로 이어진다. 이름이 같은 오이의 세균성 모무늬병과 구분한다. 탐색 질문은 ‘이웃 이미지도 병반의 모양을 공유하는가, 아니면 잎이나 배경의 색이 비슷한가’이다. [Pacific Pests, Pathogens & Weeds · Bean angular leaf spot 216](https://apps.lucidcentral.org/pppw_v10/text/web_full/entities/bean_angular_leaf_spot_216.htm)

**녹병 — #183.** 곰팡이 *Uromyces appendiculatus*가 일으킨다. 잎에 작게 솟은 적갈색 포자 덩어리와 노란 테두리가 나타날 수 있다. 심하면 잎이 마르고 일찍 떨어지며 꼬투리·종실 발달이 저하될 수 있다. 작은 점의 질감이 어느 패치·층에서 어떻게 표현되는지 관찰할 수 있지만, 높은 cosine 유사도만으로 그 질감이 모델 판단의 원인이라고 확정할 수는 없다. [Nebraska Extension · Rust of Dry Bean, 2013 개정](https://extensionpubs.unl.edu/publication/g1766/2013/pdf/view/g1766-2013.pdf)

**건강 — #256.** 수집·주석 과정에서 건강으로 분류된 잎이라는 뜻이다. 잠복 감염이나 사진 밖의 문제까지 배제한 실험실 검사 결과가 아니다. 건강한 잎 사이에도 모양·잎맥·조명·배경 차이가 있을 수 있다. 이 점은 원저자의 라벨 정의를 해석할 때의 한계이며, 추가 진단 결과를 주장하는 것이 아니다. [원저자의 클래스와 주석 설명](https://github.com/AI-Lab-Makerere/ibean)

세 장은 기존 최종 임베딩 공간에서 선정한 설명용 중심 사례이며 클래스 전체를 대표하는 통계적 증거가 아니다. 질병 카드의 탐색 버튼은 기존 3D 선택·이웃 8장·이미지 확대·6장 패치·3장 층별 흐름에 연결한다. 질병의 일반적인 설명을 해당 사진의 병원체 확진으로 취급하지 않는다.

### Data Greenhouse 품질 기록의 대조

2026-09-25에 운영 원천을 읽기 전용으로 검토했다. 아래는 **기존 기록의 값**이며 새 진단 결과가 아니다. 공개 근거 원장 `data/beans-context-audit.json`에 파일별 SHA-256, 값의 위치, 기록 간 차이와 미확인 사항을 남겼다.

| 근거 | 기록된 값 | 해석 범위 |
|---|---|---|
| 현재 이미지 명세 / 과거 `numByClass.json` | 각각 100·100·100장 | 클래스 수의 균형. 파일 단위로 두 집합이 동일하다는 증거는 별도 필요 |
| `data_quality_beans.html` | 분별성 92.19%, 정규밀도 0.393±0.122, GOOD, 감량 여력 85.7% 주장 | 과거 요약 보고서. 정확한 실행·밀도 정규화 계약을 이번에 복원하지 못함. 무오라벨·무중복 결론은 채택하지 않음 |
| `gate_report_beans.html` | DINOv2-base 93.75%; 셔플 30회 평균 35.89%, p=0.0323; 5-fold CV 89.72±2.25%, PASS | 해당 검사에서의 분별 신호. 모든 종류의 누수 부재를 입증하지 않음. 앞의 92.19%와 합치지 않음 |
| 현재 보관된 `beans_crosseval.json` | DINOv2-base 자체 공간: 300장 93.75%; 253장 92.19% 대 random 95.31%, 차이 −3.12%p | 로지스틱 회귀·accuracy·단일 random 조건이라는 기존 소스 감사에 기반. 현재 MLP·BA·반복 H 실험과 별개 |
| `diet_advisory_v3.json`, 2026-08-15 | 유지 비율 0.843, BAD/caution | 과거 저장 권고. 이전 GOOD/85.7% 감량 주장과 하나의 권고로 합치지 않음. 당시 입력 파일과 현재 파일의 동일성도 미확인 |

진단 원장 90건을 확인했고 beans 관련 correction/supersedes 항목은 없었다. 별도 bulkup 원장 237건에는 `lens_diet_mode_CORRECTION_2026-07-10`이 있었다. 특정 beans 오케스트레이션 및 `beans_pd79`·`beans_dt45` 파생셋의 ‘lens_diet’ 표기가 정밀 keep-list가 아니라 실제 R2 층화 무작위 절삭이었다는 정정이다. 명시된 과거 사례의 의미를 정정하는 것이며, 현재 모든 beans/H 실험이 잘못되었다고 확대 해석하지 않는다. 해당 사례는 정밀 H 선택의 증거로 인용하지 않는다.

**현재 판단:** 전문가 주석, 균형과 분별 신호는 유용한 출발점이다. 그러나 고유 파일·해시도 유사 촬영본의 부재를 보증하지 않는다. 식물 개체·농가 단위 독립성, near-duplicate 분할 누수, 전문가 간 주석 일치도, 배경 편향, 다른 지역·장비로의 일반화는 이번 작업에서 새로 검증하지 않았다. 과거 Greenhouse 300장과 현재 300장의 이미지 단위 동일성도 미확인이다. 품질 점수를 새로 만들어 제시하지 않는다.

로컬 원천 위치: `greenhouse/reports/`의 두 HTML 및 `mcp_assets/harvest/beans/` 자료, `aads/experiments/2026-06-10_ham10000-diet-greenhouse/`의 진단·정정 원장. cross-eval 방법은 기존 `data-lens-algorithm-lab/outputs/aads-diet-reuse-2026-09-18/REPORT.ko.md` 소스 감사 기록을 참조했다. 밀도 및 HTML의 반복 실험은 재실행하지 않았다.

## 1. 무엇을 ‘DINOv3 신경망’이라고 부르는가

DINOv3는 하나의 고정된 크기나 단일 네트워크가 아니라 학습 방법과 모델 계열을 가리킨다. 공식 배포에는 ViT와 ConvNeXt가 있다. 여기서는 기존 실험에 사용한 **DINOv3 ViT-L/16**을 중심으로 설명한다.

| ViT 계열 | 파라미터 수 | 출력 벡터 차원 |
|---|---:|---:|
| S | 21M | 384 |
| S+ | 29M | 384 |
| B | 86M | 768 |
| L | 300M | 1,024 |
| H+ | 840M | 1,280 |
| 7B | 6,716M | 4,096 |

M은 백만이며 수치는 공식 모델 카드의 표기를 따른다. ‘1,024차원’은 이미지 표현의 길이이고 ‘300M’은 모델의 학습 가능한 계수 규모다. 둘은 다른 개념이다. ViT-L은 24개 블록, 16개 attention head를 사용한다. [모델 카드][card] · [ViT 구현][vit]

기본 시각 사전학습의 손실은 이미지에 붙인 클래스 정답이나 문장과의 일치도를 직접 요구하지 않는다. 그렇다고 데이터 수집·정제 과정까지 인간의 선택에서 독립적이라는 뜻은 아니다. 또한 frozen backbone을 사용한다는 말은 모든 작업을 추가 학습 없이 수행한다는 뜻이 아니다. 분류기나 분할용 head를 별도로 학습할 수 있다. [모델 카드][card]

## 2. 픽셀에서 벡터로: 네트워크 안의 정보 흐름

### 2.1 패치와 세 종류의 토큰

ViT 입력의 개념적 흐름은 다음과 같다.

```text
이미지 → 16×16 패치 분할 → 패치별 선형 투영
       → [CLS] [REG×4] [PATCH×P]
       → 위치를 반영한 self-attention + MLP 블록 반복
       → 전역 CLS / 보조 register / 문맥화된 patch 표현
```

CLS는 이미지 전체를 요약하는 학습된 토큰이다. Register는 계산을 위한 보조 저장 공간이며 특정 픽셀에 대응하지 않는다. Patch 출력은 특정 위치에서 시작하지만 attention을 통해 다른 영역의 정보도 반영한다. 따라서 패치 벡터를 ‘그 조각만 본 결과’로 해석해서는 안 된다. [ViT 구현][vit]

정사각 입력의 한 변을 R, 패치 크기를 16이라고 놓으면:

\[
P=(R/16)^2,\qquad N=P+1+4.
\]

| 입력 크기 | 패치 P | 전체 토큰 N | N² 관계 수 | 224px 대비 |
|---|---:|---:|---:|---:|
| 224×224 | 196 | 201 | 40,401 | 1.00배 |
| 256×256 | 256 | 261 | 68,121 | 1.69배 |
| 512×512 | 1,024 | 1,029 | 1,058,841 | 26.21배 |
| 768×768 | 2,304 | 2,309 | 5,331,481 | 131.96배 |

이 표는 토큰 간 관계 수를 직접 계산한 것이지 실제 실행시간이나 GPU 메모리 측정이 아니다. 256→512처럼 한 변을 두 배로 하면 패치 수는 네 배, N² 항은 약 열여섯 배가 된다. 메모리 효율적인 attention은 N×N 행렬 전체를 저장하지 않을 수 있다. 위 해상도는 설명용 입력 조건이며 기존 네 렌즈의 전처리가 모두 같다는 뜻이 아니다.

### 2.2 Self-attention: 중요한 내용을 서로 참조하기

토큰 행렬 X에서 학습된 선형 변환으로 Q, K, V를 만든다. 한 head의 기본식은:

\[
Q=XW_Q,\quad K=XW_K,\quad V=XW_V,
\qquad A=\operatorname{softmax}(QK^\top/\sqrt{d_k}),
\qquad Y=AV.
\]

Q는 어떤 정보를 찾는지, K는 어떤 토큰과 맞는지, V는 전달할 내용을 결정한다고 생각하면 직관적이다. 여러 head는 서로 다른 관계를 병렬로 계산한다. MLP는 각 토큰의 특징을 비선형적으로 변환하고 잔차 연결은 갱신 전 정보를 유지한다. DINOv3의 RoPE는 위치에 따라 Q·K를 회전시켜 상대적 위치 관계가 attention에 반영되게 한다. [Attention 구현][attention]

이것은 계산 원리의 설명이지 attention map이 곧 ‘정답의 원인’이라는 주장이 아니다. 어떤 영역이 예측에 실제로 필요했는지는 가림·제거·교체 같은 추가 실험으로 따져야 한다.

## 3. 라벨 없이 배우는 방법: 교사와 학생

### 3.1 DINO: 벡터 자체가 아니라 목표 분포 맞추기

같은 이미지에서 서로 다른 crop을 만든다. 학생과 교사의 backbone 출력은 각각 학습용 projection head를 거친다. 학생의 logits에 softmax를 적용한 분포를 p_s, 교사가 만든 목표 분포를 p_t라 하면, 기본적인 비교는 교차엔트로피다.

\[
L_{DINO}=-\sum_k p_t(k)\log p_s(k).
\]

k는 학습용 prototype 인덱스이며 ‘콩잎’, ‘녹병’처럼 사람이 붙인 클래스 이름이 아니다. 따라서 ‘동일 클래스 이미지를 직접 가까이 붙이는 학습’이나 ‘교사의 1,024개 좌표를 그대로 복사’라는 설명은 부정확하다. 서로 다른 시야에도 일관된 표현을 만드는 압력이 유용한 특징을 형성한다. [DINO loss 구현][dino]

### 3.2 EMA 교사와 붕괴 방지

자기증류 사전학습에서는 학생을 역전파로 학습하고 교사 파라미터는 지수이동평균으로 갱신한다.

\[
\theta_t\leftarrow m\theta_t+(1-m)\theta_s.
\]

예를 들어 m=0.9라면 이번 학생 가중치가 10%, 이전 교사가 90% 반영된다. m이 클수록 목표가 천천히 변하지만 최근 변화에 늦게 반응한다. 웹의 160단계 곡선은 이 식을 합성된 1차원 입력에 적용한 수학 예제다. 실제 가중치나 학습 로그가 아니다.

모든 이미지에 같은 출력만 내어도 일관성은 높을 수 있다. 그래서 EMA만으로 충분하다고 설명하면 안 된다. DINOv3는 Sinkhorn–Knopp 기반 목표 분포 균형화, 온도 조절, KoLeo 등의 요소를 함께 사용한다. Sinkhorn–Knopp은 한 prototype에만 할당이 몰리는 것을 억제하도록 배치와 prototype 축을 반복 정규화한다. [DINO loss 구현][dino]

### 3.3 iBOT와 KoLeo는 서로 다른 문제를 보완한다

**iBOT**에서는 학생의 일부 패치 입력을 가리고 교사가 가리지 않은 입력에서 만든 해당 위치의 목표 분포를 맞춘다. RGB 픽셀을 복원하는 문제가 아니라 잠재 표현을 예측하는 문제다. 마스킹된 위치의 확률분포 손실을 모아 학습한다. [iBOT 구현][ibot]

**KoLeo**는 정규화된 CLS 특징의 최근접 이웃 거리가 지나치게 작아지는 것을 억제한다. 가장 단순한 형태는 다음과 같다.

\[
L_{KoLeo}\approx-\frac1B\sum_i\log(\lVert z_i-z_{NN(i)}\rVert_2+\epsilon).
\]

가까운 두 점이 거의 포개지면 손실이 커진다. 공간을 고르게 쓰도록 돕지만 클래스별 분리나 밀도 추정의 정답을 보장하지는 않는다. ‘다른 모든 이미지 쌍을 무조건 멀어지게 하는 손실’과도 다르다. [KoLeo 구현][koleo]

## 4. DINOv3의 핵심: Gram anchoring

### 4.1 전체 의미와 국소 구조는 같은 능력이 아니다

DINOv3 논문은 장기 대규모 학습에서 전역 분류 표현이 좋아지는 동안 patch 수준의 일관성과 dense task 성능이 저하될 수 있음을 관찰한다. Gram anchoring은 좋은 국소 관계를 가진 별도 참조 교사를 사용해 이를 보완한다. 참조는 초기 교사 체크포인트에서 시작하며 갱신 정책을 갖는다. 일반 EMA 교사와 역할을 구분해야 한다. [논문 §4][paper]

### 4.2 좌표가 아닌 관계 행렬

한 이미지의 P개 패치 특징을 행으로 쌓고 각 행을 L2 정규화한 행렬을 F∈R^(P×d)라고 하자.

\[
G=FF^\top,\qquad G_{ij}=f_i^\top f_j=\cos(f_i,f_j).
\]

G는 P×P 행렬로 ‘패치 i와 패치 j가 얼마나 유사한가’를 담는다. 논문 개념식은:

\[
L_{Gram}=\lVert G_s-G_g\rVert_F^2.
\]

공식 `GramLoss` 구현은 정규화 옵션, 이미지/배치 단위 계산, 음수 유사도 제거 옵션을 제공하며 최종 비교에 MSE를 쓴다. 생성자 기본값만 보고 특정 훈련 run의 설정이라고 단정하면 안 된다. 웹은 설명을 위해 **한 이미지, 행 정규화, 음수 유지, P²로 평균낸 MSE**를 사용한다. [GramLoss 구현][gram]

### 4.3 왜 벡터를 직접 고정하지 않는가

직교행렬 Q에 대해 QQᵀ=I이므로:

\[
(FQ)(FQ)^\top=FQQ^\top F^\top=FF^\top.
\]

즉 모든 벡터를 같은 방식으로 회전하면 좌표는 변하지만 관계 행렬은 유지된다. 웹의 ‘직교 회전’ 체크박스는 이 항등식을 시연한다. 좌표 하나하나를 고정하는 것보다 표현에 자유를 남기는 이유를 보여 주는, 본 보고서의 수학적 설명 예제다.

웹은 12개 패치와 6차원 합성 벡터를 사용한다. 교란 벡터를 더한 뒤 참조 쪽으로 선형 보간하고 행 정규화한다. α는 실제 DINOv3의 손실 가중치나 학습 진척도가 아니다. 오차가 감소하더라도 실제 분할 성능 향상률로 해석할 수 없다.

중요한 구분: Gram의 점은 **한 이미지 안의 패치**다. 데이터셋 탐색기의 점은 **각 이미지의 전역 임베딩**이다. 같은 ‘기하학’이라는 단어를 쓰더라도 분석 단위가 다르다.

## 5. 대규모 교사와 실용적인 ViT-L 사이

논문의 훈련 흐름은 대규모 자기지도 사전학습, Gram을 통한 관계 정제, 해상도 적응, 작은 모델로의 증류로 구분할 수 있다. 작은 모델의 증류에서는 EMA 교사가 아니라 **고정된 학습 완료 ViT-7B**를 사용한다. 논문은 이 작은 모델 증류에서 Gram anchoring을 적용하지 않았다고 명시한다. 따라서 ViT-L이 7B와 동일한 Gram 학습 과정을 독립적으로 반복했다고 설명하면 안 된다. [논문 §5][paper]

배포된 backbone으로 추론할 때는 교사와 학생 두 모델을 동시에 실행할 필요가 없다. 선택한 backbone에 이미지를 넣고 필요한 출력을 사용한다. 임베딩을 검색에 사용할 때는 마지막 LayerNorm과 L2 정규화를 구분해야 한다. LayerNorm을 거쳤다는 사실만으로 벡터의 유클리드 길이가 1이라는 결론은 나오지 않는다. [ViT 구현][vit]

## 6. 실제 네 렌즈를 비교하면 무엇이 달라지는가

### 6.1 시각화 데이터와 계산

기존 `diet-h-four-lens-beans-r40-2026-09-04` 실험의 학습 300장(모무늬병·녹병·건강 각 100장)을 사용했다. 네 렌즈 모두 표본 순서가 같은지 검증했다. 3D와 이미지 이웃은 모델을 다시 실행하지 않고 저장된 little-endian float64 벡터를 읽었다. §6.3의 6장 패치 특징은 버전 1.1에서 소규모 추론으로 추가했다. 버전 1.2와 1.3은 이 결과와 300장 원본만 재사용하며, 추가 추론이나 새 학습은 수행하지 않았다.

| 렌즈 | 원래 차원 | 상위 PCA 3축 설명 분산 |
|---|---:|---:|
| DINOv2-L (register) | 1,024 | 42.15% |
| DINOv3-L | 1,024 | 35.35% |
| SigLIP2 SO400M / 512 | 1,152 | 50.81% |
| C-RADIOv4-H | 2,560 | 56.84% |

PCA 전처리는 행별 L2 정규화 → 열별 평균 중심화 → SVD이며, 고유축 부호를 결정론적으로 고정했다. 렌즈 사이의 축을 Procrustes 등으로 정렬하지 않았다. 회전 가능한 3D 장면은 원근 투영으로 렌더링한다.

이웃은 **정규화된 원차원 벡터의 내적을 전수 계산하여 상위 8개**를 구했다. 자기 자신은 제외했다. 이 계산은 FAISS 근사 결과도, H의 복합 커널 재정렬 결과도 아니다. 3D 좌표에서 다시 계산한 이웃도 아니다. 3차원 그림의 거리를 알고리즘의 거리로 오인하지 않게 하기 위한 선택이다.

표본 선택을 고정한 채 렌즈를 바꾸면 고차원 이웃 목록과 DINOv2 기준 공통 이웃 수가 바뀐다. 이는 실제 저장된 표현으로 확인할 수 있는 현상이다. 그러나 이 변화만으로 특정 모델이 ‘진짜 의미’를 더 정확히 알았다고 말할 수는 없다.

### 6.2 H의 작은 탐색 실험: 평균과 한계를 함께 보기

유지율은 40%(120/300)이며 선택 방법은 `H_RBT_OOF`다. 대조군은 H와 클래스별 유지 수를 맞춘 무작위 표본이다. 균등 무작위 추출과 혼동하면 안 된다.

원래 평가 프로토콜은 raw 특징을 입력으로 하는 `F-512-tanh-256-tanh-C` MLP다. 기존 held-out 128장을 검증 65장과 최종 평가 63장으로 나누었다. 최종 평가에는 클래스별 21장이 있다. 모델의 backbone은 고정되어 있다. 학습 seed는 684162, 88304, 20260902이고 선택 seed는 0, 1, 2다.

| 선택·평가 렌즈 (self-space) | H − random BA | 95% 교차 부트스트랩 구간 |
|---|---:|---:|
| DINOv2-L | −4.76%p | [−8.11, −1.06]%p |
| DINOv3-L | +3.35%p | [+1.59, +5.29]%p |
| SigLIP2 | +1.41%p | [−0.53, +3.70]%p |
| C-RADIOv4-H | −1.59%p | [−4.23, +1.06]%p |

BA(Balanced Accuracy)는 클래스별 재현율의 평균이다. 구간은 기존 결과의 3×3 paired-effect 행렬에서 행과 열을 각각 복원추출하는 10,000회 교차 부트스트랩 값이다. seed 반복을 모두 독립 표본으로 취급한 구간이 아니다. 같은 선택 집합이 재사용될 수 있으며 실제 코드도 동일 fit을 중복 실행하지 않는다.

이 구간은 새 데이터셋으로의 일반화 불확실성이나 최종 63개 표본의 표본추출 오차를 모두 포함하지 않는다. DINOv3 선택을 다른 렌즈에서 평가한 off-diagonal 평균 효과는 약 +1.12%p, 가장 낮은 비교는 −2.29%p였다. 단일 최대값으로 렌즈를 순위 매기거나 Gram anchoring과 H 개선의 인과관계를 주장할 근거는 없다.

출처: 기존 로컬 `results/summary_beans.json`, `results/self_eval_beans.json`, `results/selections_beans.json` 및 해당 평가 코드. 웹에 결과 해시와 모델 revision을 표시하며 파생 JSON을 제공한다.

### 6.3 실제 패치 탐색: 점에서 원본 이미지로 돌아가기

기존 학습 300장 중 각 클래스의 중심부·주변부 사례를 한 장씩 선정했다. 기준은 **기존 DINOv3 CLS를 L2 정규화한 뒤, 같은 클래스 평균 벡터와의 내적(자기 자신 포함)**이 최대/최소인 표본이다. 평균 벡터는 다시 단위화하지 않는다. 아래 점수는 따라서 단위 평균 벡터와의 cosine이 아니라 클래스 내 평균 cosine이다. 전체 모집단의 통계적 대표 표본, 오라벨 판정, 경계 보호 판정이라는 뜻은 아니다.

| 3D 표본 ID | 클래스 | 선정 역할 | 클래스 중심 점수 |
|---|---|---|---:|
| 094 | 모무늬병 | 중심부 | 0.857049 |
| 099 | 모무늬병 | 주변부 | 0.593771 |
| 183 | 녹병 | 중심부 | 0.882295 |
| 123 | 녹병 | 주변부 | 0.627371 |
| 256 | 건강 | 중심부 | 0.897126 |
| 209 | 건강 | 주변부 | 0.703853 |

**추론과 전처리.** 기존 계산 서버의 캐시와 환경을 재사용했다. 모델은 `facebook/dinov3-vitl16-pretrain-lvd1689m`, Hugging Face revision `ea8dc2863c51be0a264bab82070e3e8836b02d51`, 가중치 SHA-256은 `dcb2e45127cccbf1601e5f42fef165eea275c8e5213197e8dcf3f48822718179`이다. PyTorch `2.7.0+cu126`, Transformers `4.57.6`, `DINOv3ViTImageProcessorFast`를 사용했다. `eval()`과 `inference_mode()`에서 float32로 6장 + 첫 이미지 반복 확인 1회, 총 7회 forward만 수행했다. 학습·가중치 변경·모델 다운로드는 없다. 기록된 forward 총시간 약 1.04초는 모델 로딩과 해시 검증을 제외하므로 서비스 지연 벤치마크가 아니다.

원본 JPEG(모두 500×500)를 RGB로 읽고 **1/255 스케일링 → bilinear antialias 224×224 리사이즈 → 채널별 평균 [0.485, 0.456, 0.406]·표준편차 [0.229, 0.224, 0.225] 정규화**를 수행했다. Center crop은 없다. 입력 표시 PNG는 실제 모델 입력 텐서의 채널 정규화를 되돌리고 8비트로 반올림한 미리보기다. 입력 패치의 좌표는 224×224 기준이며 원본 전체에 비례 대응한다. 이것은 원본을 임의로 합성하거나 모형으로 대체한 이미지가 아니다.

**어떤 벡터의 어떤 유사도인가.** 최종 LayerNorm 뒤 `last_hidden_state`의 형태는 `[1, 201, 1024]`다. CLS 1개와 register 4개를 제외하는 `[:, 5:, :]`로 **196×1024** 패치 특징을 얻는다. 격자는 14×14, 순서는 행 우선이며 `patch_id = row × 14 + column` (0부터 시작)이다. 각 특징을 float64로 별도 L2 정규화하고 같은 이미지 내 모든 쌍의 내적을 계산한다.

\[
S_{pq}=\frac{f_p^\top f_q}{\lVert f_p\rVert_2\lVert f_q\rVert_2}
\]

196×196 행렬은 little-endian float32로 저장했다. 반올림 최대 오차는 모든 이미지에서 3×10⁻⁸ 미만이다. 행렬의 대칭성·유한성·단위 대각선을 검사했고, 동일 입력 반복 추론의 최대 절대 특징 차이는 0이었다. 새 CLS와 기존 CLS의 cosine은 6장 모두 0.999999 이상이다. 이는 같은 표본·모델·전처리가 기존 3D 자료와 일치함을 점검하는 근거이지 모든 환경에서 비트 단위 재현을 보장하는 주장은 아니다.

**화면에서 검증하는 방법.** 3D 표본 선택과 6개 썸네일은 같은 표본 ID를 공유한다. 원본·실제 전처리 입력·패치 cosine 지도를 나란히 표시하고, 입력이나 지도에서 패치를 클릭하면 해당 행의 196개 cosine이 갱신된다. 방향키·행/열 입력도 지원한다. −1~+1 색 눈금은 고정이며, 자신과의 유사도 1은 가까운 패치 목록에서 제외한다. 수치 표와 출처 JSON을 통해 색 이외의 값도 확인할 수 있다. 다른 렌즈를 선택해도 패치 결과는 DINOv3 고정임을 표시하며, 준비되지 않은 294개 표본에는 다른 이미지의 지도를 대신 표시하지 않는다.

**읽으면 안 되는 의미.** 패치 특징은 전체 이미지 문맥을 포함한다. 높은 cosine은 해당 패치들이 비슷한 학습 표현을 가진다는 관찰이지 attention 가중치, 질병 확률, 픽셀별 기여도, 인과적 설명이 아니다. 별도 crop을 각각 독립 추론한 결과도 아니다. 실제 특징의 유사도 행렬과 §4의 합성 Gram 실험은 같은 내적 구조를 사용할 수 있지만, 이 6장은 Gram anchoring의 학습 전후 비교나 제거 실험(ablation)이 아니다. H의 보존·제거 원인을 패치 지도만으로 역추정하지 않는다.

## 7. 설명 가능한 임베딩과 설명 가능한 데이터 다이어트

**설명 가능한 임베딩**은 같은 이미지가 다른 DataLens에서 어떤 이웃·밀도·경계·구조를 갖는지 원본 이미지와 원공간 계산을 왕복하며 검증하는 것이다. 낮은 차원의 예쁜 군집만으로 설명이 완성되지 않는다. 전처리, 출력 토큰, 정규화, 거리 정책도 표현의 의미를 바꾼다.

**설명 가능한 Data Diet**는 왜 특정 표본이 보존·제거·경계보호되었는지 추적하는 것이다. 권장 증거 사슬은 다음과 같다.

```text
이미지 ID + 전처리 + 모델 revision
  → FAISS 후보와 후보 누락 검증
  → 정식 H 거리/커널 재정렬
  → OOF hardness + density / boundary / redundancy 근거
  → 선택 상태와 규칙별 기여
  → 무작위 대조 / 교차 렌즈 / 다운스트림 검증
```

기존 H 선택기에서 확인한 복합 유사도는 Gaussian RBF에 (cosine+1)/2를 곱한 형태다. raw 거리와 cosine 후보를 결합하는 후보 생성 단계와 최종 복합 유사도 재정렬은 구분해야 한다. 웹 맨 위의 일반 cosine 선은 이 H 근거 사슬을 대신하지 않는다.

OOF hardness는 해당 표본을 훈련에서 제외한 fold 모델이 정답 클래스에 부여한 확률을 이용해 정의할 수 있다. 기존 실험은 `1 − p(true class)` 정책을 사용한다. 높은 hardness가 자동으로 오라벨이나 중요한 경계를 뜻하지는 않는다. 희귀성, 난도, 노이즈, 모델 편향 등을 함께 확인해야 한다.

이번 산출물은 이러한 개념을 설명하는 **교육·연구 리포트**다. 이번 실험의 300장 원본 전수 탐색은 제공하지만, H 재실행이나 개별 결정의 완전한 provenance API를 갖춘 운영 워크벤치의 구현 완료를 주장하지 않는다. 기존 Data Clinic / Data Greenhouse 소스와 작업 중인 파일을 수정하지 않았다.

## 8. PebbloScope: 중복을 피하는 실제 코드 기반 경계

검토 대상은 [PebbloScope API 저장소][pebble]의 로컬 체크아웃 `d39926d7214e8d1012b797fa4545045aaee66ad6`이다. 공개 웹 조회는 접근되지 않았으나 확보된 소스를 직접 읽었다. 현재 운영 서비스의 배포 revision이나 응답까지 확인한 것은 아니다.

| 실제 코드에서 확인한 요소 | 역할 | 재사용·연동 제안 |
|---|---|---|
| `VizDataset`, dataset catalog/detail | 데이터셋·DataLens·진단 메타데이터 | 워크벤치가 별도 카탈로그를 중복 소유하지 않도록 ID 참조 |
| `VizSrc` | `Optimization/Reduction`, `2D/3D`, `ClassView/InstanceView`, PCA 및 S3 자산 키 | 좌표·노드·커뮤니티 자산의 출처 재사용 |
| dataset detail 응답 | 노드/커뮤니티 JSON의 presigned URL, 중심 좌표 등 | 서버 측 adapter에서 계약 검증 후 사용; 만료 URL을 영구 ID처럼 저장하지 않음 |
| `data-previews`, `node-color-mapping` | 선택 노드, 미리보기, 정렬·색 매핑 | 이미지 왕복 탐색 UI와 정책 연결 |
| `Snapshot` | 선택 노드, 커뮤니티, 카메라 상태, 설명 | 연구 결과의 시점·선택 상태와 연결 가능 |

검토 파일: `project/web/apps/pebbloscope/urls.py`, `views/datasets_detail.py`, `views/data_previews.py`, `apps/viz_src/models.py`, `apps/snapshot/models.py`.

이 코드에서는 범용 시각화 자산·조회·상태 저장의 경계가 명확하다. 반면 열람한 API·모델에서 H의 정식 거리, OOF hardness, 선택 run별 의사결정 lineage를 제공하는 계약은 확인하지 못했다. 저장소 전체에 해당 기능이 절대 없다고 단정하는 것은 아니다.

따라서 **PebbloScope = DataLens 공간의 범용 시각 탐색**, **Data Clinic 연구 워크벤치 = 표현 기하와 Diet 결정의 실험·설명·검증**이라는 분담이 적절하다. 연결 시 안정적인 sample ID, model revision, normalization, distance policy, run ID를 공통 계약으로 두는 것을 권한다. 이것은 코드 검토에 근거한 설계 제안이며, 이번 리포트가 운영 연동을 실제 배포했다는 의미는 아니다.

## 9. 재현성 및 동반 웹 사용법

### 조작 가능한 요소

1. 네 렌즈를 전환하고 같은 표본의 이웃·선택 상태를 비교한다.
2. 3D 점군을 드래그로 회전한다. 확대/축소 버튼과 키보드 방향키도 지원한다. 휠 확대는 점군에 초점이 있을 때만 동작한다.
3. 입력 해상도를 바꾸어 패치·토큰·attention 관계 수를 비교한다.
4. EMA 모멘텀을 바꾸어 안정성과 지연의 차이를 관찰한다.
5. Gram 교란·보간·직교 회전을 조작하고 실제 계산된 오차와 수치 표를 확인한다.
6. 렌즈별 반복 실험의 효과, 절대 BA, 3×3 seed 행렬을 확인한다.
7. 실제 패치 6장 중 하나를 선택하고 원본·전처리·선택 패치의 cosine 지도를 왕복한다. 수치 표와 모델·전처리 출처를 확인한다.
8. 300개 중 어느 표본을 선택해도 선택 패널의 원본과 고차원 이웃 8장의 썸네일이 표시된다. 이웃 이미지를 누르면 3D 선택, 선택 상태, 원본, 패치 영역이 같은 sample ID로 갱신된다. 렌즈를 바꾸어도 선택 ID는 유지한다.
9. 선택 원본을 눌러 화면 맞춤·100%·200%로 본다. 원본은 500×500이며 200%는 표시만 확대한다. 닫기와 Escape를 지원하고 초점은 원래 확대 버튼으로 돌아온다. 확대 창 안에서 원본 파일명과 SHA-256을 확인할 수 있다.

### 300장 이미지 계약과 패치 범위

`data/images.json`의 `dinov3-sample-images.v1` 계약은 각 표본의 `id`, 기존 상대 파일명, 클래스, 로컬 자산 URL, SHA-256, 바이트 수, `patch_available`을 기록한다. 300장 모두 기존 beans 데이터 목록의 원본 해시와 대조했다. JPEG 바이트는 변경하지 않았으며 썸네일도 별도 재인코딩 없이 CSS로만 줄여 표시한다. 선택된 원본과 현재 이웃만 불러오며, 처음부터 300장 전체를 화면에 내려받게 하지 않는다.

기존 6장(#094, #099, #183, #123, #256, #209)은 기존 패치 폴더의 원본을 그대로 참조한다. 나머지 294장만 `assets/samples/`에 복사했다. `embeddings.json`, `patches.json`, 기존 입력 PNG와 cosine 행렬은 변경하지 않았다. 이미지 로딩이 실패하면 실패한 표본 번호를 명시하며 다른 표본의 이미지로 대체하지 않는다.

패치 계산은 **6장에만** 존재한다. 나머지 294장은 원본과 CLS 이웃을 제공하며 “패치 추론은 없습니다”라고 표시하고 패치 지도를 숨긴다. 3D에서 다른 DataLens를 선택하더라도 실제 패치 특징은 DINOv3-L 고정임을 별도로 표시한다. 패치 cosine은 attention, 병변 확률, 픽셀 기여도 또는 인과적 설명이 아니다. 합성 Gram 실험도 실제 패치 관측과 계속 분리한다.

### Pebblous 디자인 스킬 적용 근거 (1.2 기준; 1.3 변경은 아래 참조)

로컬 `Pebblous-SKILLS/pebblous-design-system/SKILL.md`를 읽고 적용했다. 기준 저장소 commit은 `49aa2a5be8af059cac897a71bffad81c2b9bb89a`이다. 스킬이 가리키는 내부 `README.md` 및 `colors_and_type.css`는 해당 체크아웃에 없어서, 실제 제공된 `CLAUDE.md`, `project/README.md`, `src/styles/design-tokens.css`, `ui_kits/pebblous-web/README.md`와 내비게이션·서체 미리보기를 대조했다.

- 공식 Pebblous 로고·파비콘, Pretendard 본문과 TT Firs Neue 표시 서체를 기존 로컬 자산에서 포함했다. 외부 Google Fonts 요청은 제거했다.
- 기본 강조색 `#F86825`, 어두운 강조 `#C64900` / `#923401`, 중립 배경 `#F7F7F8`, 텍스트 `#171719`, 경계선 `#EAEBEC`를 적용했다. 배경 장식 그라데이션과 블러는 제거했다.
- 브랜드의 의미색은 차트의 범례와 일치시켰다. 실제 패치·합성 Gram 색 눈금은 −1 파랑 `#6096D5`, 0 중립 `#F4F4F5`, +1 주황 `#F86825`로 고정했다. 색만 바꾸었으며 계산값은 그대로다. 과학적 원본 이미지와 전처리 이미지에는 색 보정을 하지 않았다.
- 긴 제목보다 바로 선택할 수 있는 3D·이미지 탐색을 앞에 배치했다. 모바일에서는 선택 이미지와 상세 정보를 3D 위에 놓고 이웃 썸네일을 4열, 좁은 화면에서 2열로 배치했다. 템플릿의 가상 데이터나 대시보드는 추가하지 않았다.

### 파일과 계산의 범위

- 웹 소스: `outputs/dinov3-report-web/`.
- 배포 정적 자산: 위 폴더의 `dist/`.
- 보고서 사본: `dist/report.md`.
- 데이터: `dist/data/embeddings.json`에 PCA 좌표, cosine 이웃, 선택 상태, 기존 실험 결과, 입력 특징 해시를 저장했다. 이 기존 데이터는 수정하지 않았다. 원본 고차원 벡터 전체를 배포하지 않는다.
- 실제 패치: `dist/data/patches.json`에 모델·processor 설정·출력 slicing·정규화·표본 선정·해시·검증값을 기록했다. `dist/assets/patches/`에는 선택한 6장의 원본 JPEG, 입력 미리보기 PNG, cosine 행렬만 추가했다. 가중치와 원시 196×1024 패치 벡터는 배포하지 않는다.
- 전체 원본: `dist/data/images.json`과 `dist/assets/samples/`의 294장, 위 패치 폴더의 6장을 합쳐 300장을 제공한다. 원본 합계는 34,379,162바이트이며 새 고차원 특징이나 모델은 추가하지 않는다. `scripts/prepare_images.cjs EXISTING_REPO`가 원본 해시를 확인하고 기존 파일이 다르면 덮어쓰지 않는다. `scripts/verify_images.cjs`로 이미지 계약을 검증한다.
- 패치 재생성: `scripts/extract_patches.py --repo EXISTING_REPO --cache EXISTING_HF_CACHE --output NEW_OUTPUT_DIR --device cuda:0`. 기존 가중치 캐시만 오프라인으로 읽으며 기존 출력 디렉터리는 덮어쓰지 않는다. 재추론 없이 배포 자료를 검증하는 `scripts/verify_patches.cjs`도 포함했다.
- 재생성: `scripts/prepare_data.py`에 기존 실험 디렉터리와 출력 JSON 경로를 전달한다. 입력은 읽기 전용으로 취급한다.
- 사이트는 브라우저에서 계산하는 정적 인터랙티브 리포트다. 패치 추론은 배포 전에 한 번 수행했고 방문 중에는 저장된 cosine을 조회한다. 외부 추론 서비스, 모델 가중치 다운로드, 서버 훈련 작업은 없다. 기존 사이트의 본인 전용 접근 범위를 유지한다.

### 1.1 검증 기록 (2026-09-19)

- 기존 4×300 데이터 계약, 1,200개 이웃 목록, 보존 수, 토큰 수, EMA 점화식, Gram 직교회전 불변성, 문서 내부 링크 검사 통과.
- 6장 × 196² cosine 값의 유한성·범위·대칭성·자기 유사도, 18개 자산 해시 검사 통과. 별도 `verify_patch_vectors.py`에서 보관한 원시 패치 벡터로 재계산하고 표본 선정 규칙과 원본 이미지 해시도 독립 확인했다. 추가 추론은 하지 않았다.
- 브라우저에서 3D 점 클릭 → 표본 ID 갱신, 6장 전환, 썸네일 → 3D 선택, 원본·입력·지도 연결, 다른 렌즈 표시, 비대상 표본 안내를 확인했다. 패치 클릭·방향키·모서리·행/열 입력·범위 밖 입력 복구·이미지 겹치기·수치 표를 확인했다.
- 기존 해상도 변경(512px → 1,024패치·1,029토큰), 합성 Gram 보간 끝점과 회전, EMA 조작, 렌즈별 실험 표를 브라우저에서 회귀 검사했다. 패치 읽기/선택 도구와 유효하지 않은 요청의 거절도 확인했다.
- 390×844 및 320×800 모바일 크기의 브라우저 뷰포트에서 조작·배치를 확인했다. 문서 가로 넘침은 없고 큰 수치 표는 자기 영역 안에서 가로 스크롤된다. 실제 휴대전화 하드웨어 검증은 아니며 별도 기기 성능 보장은 하지 않는다. 검증 시 브라우저 오류·경고 로그는 없었다.

### 1.2 검증 기록 (2026-09-19)

- 300장의 파일명·ID·클래스·원본 SHA-256·JPEG 500×500 크기, 1,200개 이웃 목록의 이미지 연결, 정확히 6장의 패치 연결을 검사했다. 로컬 HTTP에서도 300장의 응답 형식과 바이트 해시가 모두 일치했다. 이미지 목록 누락 및 이미지 오류 안내는 단위 검사로 확인했다.
- 데스크톱 브라우저에서 #000–#299를 하나씩 선택해 **300회 모두 선택 원본과 이웃 8장의 실제 디코딩 완료**를 확인했다. 각 선택의 이미지 ID와 상세 선택 ID가 일치했다. 3D 점 직접 클릭(#212), 이웃 클릭, 렌즈 전환, 6장 패치 썸네일의 역방향 선택도 확인했다.
- 네 렌즈의 표시된 이웃 ID·cosine 수치가 기존 자료와 일치했고 선택 ID는 유지됐다. 6장 모두 기존 패치 지도와 연결됐으며 비대상 표본의 지도는 숨겨졌다. 다른 렌즈를 선택해도 패치는 DINOv3 고정이라는 안내를 확인했다.
- 원본 확대 창의 화면 맞춤·100%(500px)·200%(1,000px), 선택 변경 시 동기화, 닫기·Escape·초점 복귀를 확인했다. 390×844 및 320×800 브라우저 뷰포트에서 이미지·이웃 선택과 확대를 검사했으며 문서 가로 넘침은 없었다. 확대 이미지의 넘침은 창 내부에서만 스크롤된다. 이는 모바일 크기 검증이며 실제 휴대전화 하드웨어 검증은 아니다.
- 기존 데이터 계약·수학 검사와 6장 행렬 해시 검사를 재실행했다. 보관한 원시 패치 벡터로 cosine을 독립 재계산하는 검사도 통과했으며 모델은 실행하지 않았다. 브라우저에서 512px 토큰 수, Gram 보간 끝점·회전, EMA, 실험 표, 패치 키보드·범위 밖 입력 복구·겹치기를 확인했다. 유효하지 않은 표본 선택 요청은 거절됐고 최종 브라우저 오류·경고 로그는 없었다.

### 1.3 디자인 통합 및 검증 (2026-09-21)

이번 변경은 **연구 도구의 UI 통합**입니다. 새로운 신경망 원리 조사, 모델 학습, 패치 추론, 데이터 재계산은 수행하지 않았습니다. 300장 원본, 4종 임베딩의 좌표·이웃·선택 상태, 6장 패치 자산과 합성 Gram 계산을 그대로 보존했습니다. 계산 코드 `app.js`, `math.js`, `learning.js`, `patches.js`는 변경하지 않았습니다.

#### 디자인 출처와 적용 범위

같은 로컬 Pebblous 저장소 `49aa2a5be8af059cac897a71bffad81c2b9bb89a`의 `SKILL.md`, `CLAUDE.md`, `project/README.md`, `src/styles/design-tokens.css`, `preview/nav.html`, `preview/btn-solid.html`, `preview/inputs.html`, `preview/cards.html`, `ui_kits/pebblous-web/Header.jsx`와 키트 README를 대조했습니다. 스킬에 적힌 루트 `README.md`, `colors_and_type.css`는 이 체크아웃에 없어 실제 존재하는 위 자료를 기준으로 삼았습니다.

| 대상 | 적용한 공식 기준 | 연구 도구에 맞춘 구현 |
|---|---|---|
| 내비게이션 | 밝은 Header, 주황색 밑줄 탭 | 실제 장별 링크와 스크롤 위치에 따른 현재 위치 표시. 홍보용 문의 버튼은 넣지 않음 |
| 글자 위계 | Pretendard 본문, TT Firs Neue 숫자, 음수 제목 자간 | 본문 16px, 일반 조작 14px, 보조 메타데이터 12–13px. 긴 홍보 문구 대신 표본·렌즈·패치 범위 표시 |
| 공간과 카드 | 4/8/12/16/24/32/48/64 간격, 밝은 면, 가는 경계선, 조용한 그림자 | 렌즈·3D·원본·이웃을 하나의 작업 카드로 묶고, 보고서의 그림·계산 설명 카드에 같은 규칙 적용 |
| 버튼과 필드 | 10–12px 모서리, 44px 입력, 어두워지는 hover와 주황 focus | 렌즈 탭, 패치 선택, 학습 목표, 원본 확대 배율에 일관된 선택 상태. `aria-pressed`와 내비게이션 `aria-current` 제공 |
| 실측/합성 구분 | 중립 바탕과 절제된 강조 | 실제 패치와 합성 Gram에 별도 명시적 표식. cosine 지도는 attention 또는 인과 설명이 아니라는 기존 경고 유지 |
| 반응형 | 읽기 가능한 타입과 조작 크기 | 모바일은 선택 이미지·상세를 위에, 3D를 아래에 배치. 이웃은 2열, 확대 이미지는 모달 내부에서만 스크롤 |

마케팅 UI 키트의 가상 대시보드·장식용 이미지·문의 흐름을 옮기지 않았습니다. 과학 이미지의 색상은 보정하지 않았으며, 클래스 색과 cosine 색 눈금은 브랜드 강조색과 역할이 다른 **데이터 부호화**로 보존했습니다. 이 결과는 로컬 디자인 시스템을 이 연구 도구에 적용한 것이며, PebbloScope/Data Clinic 운영 화면의 픽셀 복제나 최신 Figma 원본과의 일치 인증은 아닙니다.

#### 검증 결과와 한계

- 기존 단위·자산 검사: 4×300 데이터 계약, 1,200개 이웃 목록, 선택 수, 토큰 수·EMA·Gram 불변성, 모든 300장 원본 해시·크기, 6장 cosine 행렬과 출처 해시를 재검사했습니다.
- 로컬 Chrome에서 300개 표본을 모두 선택하고, 각 원본과 이웃 8장이 실제로 디코딩되는지와 ID·이웃 순위·3D 상태 동기화를 확인했습니다. 네 렌즈의 이웃 클릭과 선택 상태도 확인했습니다.
- 6장 기존 패치 표시, 비대상 표본의 추론 없음 안내, 패치 썸네일의 3D 역방향 선택, 패치 클릭·방향키·이미지 겹치기를 확인했습니다.
- 원본 확대의 화면 맞춤·100%·200%, Escape 및 닫기 후 초점 복귀, 3D 점 선택·키보드 회전·확대·초기화를 확인했습니다.
- 기존 해상도/토큰 수, 학습 목표 탭, 합성 Gram의 직교 회전 불변성과 보간, 새 내비게이션 현재 위치 표시를 확인했습니다.
- 1440×1000 데스크톱과 390×844·320×844·768×844 뷰포트에서 검사했습니다. 720px 뷰포트의 루트 글자 200% 확대도 페이지 가로 넘침이 없었습니다. 모바일 크기에서 이미지 선택·확대·패치·내비게이션을 조작했으며 런타임 오류는 없었습니다.
- 화면 증거는 변경 전후 동일한 로컬 Chrome 렌더링에서 저장했습니다. 모바일은 뷰포트·터치 에뮬레이션으로, 실제 휴대전화나 Safari 검증이 아닙니다. 전체 WCAG 감사나 모든 상태의 대비 검사를 완료했다고 주장하지 않습니다. 로그인된 운영 사이트 화면의 직접 검증은 이 로컬 검사와 구분합니다.

### 1.4 신경망 층별 실제 텐서 탐색 (2026-09-23)

이 단계는 ‘모델이 새로 공부하는 과정’이 아니라 **이미 학습된 신경망 안에서 사진이 어떻게 변환되는지** 관찰합니다. `docs/MASTER_SPEC.md`와 `docs/tasks/LAYER-001.md`를 먼저 작성하고, 기존 리포트의 `#layers`에 통합했습니다. 새 학습·가중치 다운로드·300장 재추론은 하지 않았습니다. 기존 3D는 최종 CLS 선택용 보조 투영이며 층별 독립 PCA를 연결한 가상 분화 애니메이션은 만들지 않았습니다.

#### 대상·실행·텐서 계약

대상은 기존 최종 CLS 공간에서 클래스 평균 방향과 가장 유사한 #094(모무늬병), #183(녹병), #256(건강)입니다. 설명을 위한 중심 사례이며 클래스 전체의 통계적 대표성이나 진단 정확도 증거가 아닙니다. 나머지 297장에는 층별 자료가 없고, 다른 DataLens에는 DINOv3 자료를 그 렌즈의 중간 표현처럼 보여 주지 않습니다.

기존 H100의 PyTorch `2.7.0+cu126`, Transformers `4.57.6`, float32, `eval()` / `inference_mode()`를 재사용했습니다. 앞서 기록한 모델 revision과 가중치 SHA를 확인하고 오프라인 캐시에서 읽었습니다. 대상 3장과 #094 재현 확인 1회, **총 4 forward**만 수행했습니다. 이후 모든 계산·검증은 저장된 텐서를 읽으며 추론하지 않습니다.

| 웹 단계 | shape | 실제 기록 위치와 해석 |
|---|---|---|
| 원본 RGB | [500, 500, 3] | 계산 서버 Pillow가 JPEG를 복원한 uint8. height × width × RGB |
| 정규화 입력 | [1, 3, 224, 224] | 기존 Fast processor의 pixel_values. batch × RGB × height × width |
| 패치 투영 | [1, 196, 1024] | Conv2d [1, 1024, 14, 14]를 flatten·transpose. Conv2d 원형도 별도 저장 |
| CLS·register 결합 | [1, 201, 1024] | embeddings 출력. token 0은 CLS, 1–4 register, 5–200 패치 |
| 블록 1–24 | 각 [1, 201, 1024] | 각 블록의 두 residual addition 이후 출력. 추가 final LayerNorm 미적용 |
| 최종 LayerNorm | [1, 201, 1024] | model.norm 출력. 모델이 학습한 정규화이며 L2와 다름 |
| 이미지 임베딩 | [1, 1024] | 최종 출력의 CLS slice. 별도 L2 미적용 |

30단계의 원값을 little-endian float32(원본만 uint8)로 저장했습니다. 각 파일의 SHA-256, 바이트 수, 축 의미, 추출 위치와 정규화 상태를 `data/layers.json`에 명시했습니다. 브라우저는 선택한 두 이미지의 단계별 파일을 지연 로드하고 해시를 확인합니다. 수치 표는 특징 0–1023을 32개씩 보여 주며 CLS·선택 패치·register를 선택할 수 있습니다. RGB/입력 단계에서는 선택 패치 중심에 대응하는 한 픽셀의 RGB를 표시하고, 아직 특징 벡터가 아님을 명시합니다.

#### 지도와 곡선은 무엇을 측정하는가

거리는 `1 − cosine`입니다. 비교 시에만 float64로 각 벡터를 L2 정규화하며 저장 텐서와 수치 표의 원값은 바꾸지 않습니다. 주황 실선은 CLS, 회색 점선은 두 이미지의 **동일 격자 위치 패치 196개 거리의 평균**입니다. 같은 격자 위치가 의미적으로 같은 잎 부위라는 보장은 없습니다. 패치 지도는 각 위치의 두 이미지 간 거리이며, 0–2 고정 색 눈금을 사용합니다. 기존 6장 패치 탐색의 ‘한 이미지 내부 유사도’나 합성 Gram 실험과 다릅니다.

인접한 두 단계의 거리 차이 Δ 중 가장 큰 양수와 가장 작은 음수 구간을 각각 표시합니다. 수치 오차 수준인 |Δ|≤1e-12는 구간 후보에서 제외합니다. 이는 최대 변화량의 기술적 요약이며, 통계적 유의성·유일한 인식 시작점·인과적 설명이 아닙니다. LayerNorm 경계는 별도로 이름을 표시합니다.

| 이미지 쌍 | 최종 CLS 거리 | 최종 패치 평균 거리 | CLS 최대 증가 구간 |
|---|---:|---:|---|
| #094 / #183 | 0.111291 | 0.449539 | 블록 23 → 24, Δ +0.049920 |
| #094 / #256 | 0.116925 | 0.500036 | 블록 23 → 24, Δ +0.061606 |
| #183 / #256 | 0.089861 | 0.424524 | 블록 23 → 24, Δ +0.043276 |

세 사례에서 마지막 블록의 CLS 거리 증가가 가장 컸다는 관측을 ‘블록 24에서 병을 인식했다’로 번역할 수는 없습니다. 또한 패치 평균 거리는 블록 24에서 감소하고 최종 LayerNorm에서 다시 증가합니다. 따라서 층마다 계속 더 멀어진다는 가정도 맞지 않습니다.

초기 CLS·register의 원값은 세 이미지에서 완전히 같습니다. 같은 학습 토큰을 붙였기 때문이지 ‘세 장 모두 잎이라고 인식해서’가 아닙니다. 반면 원본·전처리 입력·패치 투영값은 처음부터 다릅니다. 초기 CLS cosine 거리는 부동소수점 계산상 약 1.1e-16이며 화면의 6자리 표시에선 0입니다.

#### 재현과 디코더 주의점

최종 패치와 기존 `patch_features.npz`의 최대 절대차는 세 장 모두 0, 새 CLS와 저장된 임베딩 cosine은 각각 0.9999999729 / 0.9999999540 / 0.9999999845입니다. 반복 추론의 모든 hook 출력 최대 절대차도 0입니다. 모델 로딩·해시 검사를 제외한 기록 시간 약 0.96초를 일반 실행시간 보장으로 해석하지 않습니다.

원래 계산 환경에서 별도 검증 코드로 shape·해시·입력 복원·최종 일치·모든 쌍/단계 거리·강조 구간을 재계산하여 412개 검사를 통과했습니다. JavaScript에서도 바이너리를 읽어 모든 쌍·단계·196개 패치 거리와 구간을 독립 대조했습니다.

**재현 시 주의:** 같은 JPEG 파일 해시라도 디코더에 따라 복원 RGB가 다를 수 있었습니다. H100은 Pillow 11.1.0 / JPEG codec 9.0, Mac 확인 환경은 Pillow 11.3.0 / libjpeg-turbo 3.1.1이었으며 #094의 채널 최대 차이는 30/255였습니다. Mac 재디코딩의 픽셀 완전일치 검사는 통과하지 않았습니다. 임의 허용 오차로 통과 처리하지 않고 원래 환경에서 완전일치를 확인했습니다. 웹에 저장된 입력 텐서와 기존 전처리 PNG는 원래 환경의 값을 사용합니다. 브라우저가 표시하는 원본 JPEG의 디코딩까지 동일하다고 주장하지 않습니다.

#### 디자인·보존·검증 범위

Pebblous 스킬과 브랜드 백서, 실제 디자인 토큰·카드·버튼을 읽고 기존 Pretendard/TT Firs Neue, 오렌지 선택 상태, 24px 카드와 간격 체계에 통합했습니다. 기존 원본·임베딩·6장 패치 자산은 변경하지 않았습니다. 층 선택은 모델 추론을 실행하지 않으며, 원본 확대와 기존 3D/이웃 선택을 연결합니다. 로딩 중 또는 자료 없음·무결성 오류일 때 이전 결과를 현재 결과처럼 남기지 않습니다.

3쌍 × 30단계의 실제 수치 표시, patch/feature 끝점, register, 빠른 전환, 비대상 표본·다른 렌즈, 원본 확대, 손상 자료의 오류/재시도를 브라우저에서 검사합니다. 기존 300장과 이웃 8장 로딩, 4렌즈, 6패치, 3D 조작, Gram/EMA/해상도 도표를 별도 회귀 검사합니다. 데스크톱 1440×1000, 모바일 크기 390×844·320×844, 태블릿 768×844 및 200% 글자 확대를 검사하며 결과 원장은 `outputs/dinov3-layer-review-2026-09-23`에 보존합니다. 실물 휴대전화·Safari·로그인된 운영 화면의 직접 조작·전체 접근성 감사는 확인하지 않은 범위입니다.

### 남아 있는 해석 한계

- 개별 임베딩 차원에 사람이 붙일 수 있는 고정된 의미 이름이 있다는 보장은 없다.
- 3D PCA의 분산 보존률은 클래스 의미나 task 성능의 비율이 아니다.
- 높은 cosine, 높은 밀도, 어려운 표본이라는 지표는 서로 다르다.
- 학습 방식의 차이, backbone 크기, 전처리 해상도, 데이터, pooling이 함께 달라지므로 렌즈 효과를 단일 요인의 결과로 분리할 수 없다.
- DINOv3의 지역·소득군 성능 차이 등 편향은 공식 모델 카드에도 보고된다. 임베딩을 보편적으로 중립적인 좌표로 취급하면 안 된다.

## 참고 자료

- [DINOv3 논문, arXiv v1 (2025)][paper]: 개념과 실험·증류 프로토콜.
- [공식 모델 카드][card]: 모델 계열, 제원, 사용 범위, 한계.
- [Vision Transformer 구현][vit]: 토큰 구성과 출력, 블록 구조.
- [Attention 구현][attention]: QKV와 RoPE 적용.
- [DINO CLS loss][dino], [iBOT patch loss][ibot], [KoLeo loss][koleo], [Gram loss][gram]: 학습 목표의 구체적 동작.
- [기본 SSL 설정][config]: 옵션 이름과 기본값. 특정 훈련 run 전체 설정과 동일시하지 않는다.
- [PebbloScope API 저장소][pebble], [PebbloScope 서비스](https://pebbloscope.ai): 서비스 역할 검토. 코드 링크는 접근 권한이 필요할 수 있다.

공식 DINOv3 코드의 검토 기준 commit은 `6876159a11b4df116f30f667f8c9888617df0751`이다. 기존 beans 실험의 모델 revision은 이 소스 commit과 별개이며 파생 데이터에 각각 보존했다.

[paper]: https://arxiv.org/html/2508.10104v1
[card]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/MODEL_CARD.md
[vit]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/models/vision_transformer.py
[attention]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/layers/attention.py
[dino]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/loss/dino_clstoken_loss.py
[ibot]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/loss/ibot_patch_loss.py
[koleo]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/loss/koleo_loss.py
[gram]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/loss/gram_loss.py
[config]: https://github.com/facebookresearch/dinov3/blob/6876159a11b4df116f30f667f8c9888617df0751/dinov3/configs/ssl_default_config.yaml
[pebble]: https://github.com/pebblousDev/pebbloscope-api-service/tree/d39926d7214e8d1012b797fa4545045aaee66ad6
