|
|
SmolVLA 아키텍처 완전 분해 — 입력부터 로봇 동작까지, 흐름 순서대로
SMOLVLA 구조도(다이어그램)
0. 들어가기 전에 — ViT의 벡터화는 CNN, LLM과 무엇이 다른가
SmolVLA의 심장부에는 ViT(Vision Transformer) 계열의 이미지 인코더가 들어 있다. 그런데 CNN과 트랜스포머(LLM)를 공부한 상태에서 ViT를 처음 접하면 "이미지를 어떻게 토큰으로 만든다는 거지?"라는 지점에서 막히기 쉽다. 본론에 들어가기 전에 이 부분을 확실히 정리한다.
[그림 0] 왼쪽 열: CNN(커널 슬라이딩 → 2D 특징맵 유지), 가운데 열: ViT(패치 분할 → 위치 인코딩 추가),
오른쪽 열: 언어 트랜스포머(단어 토큰화 → sin/cos 위치 인코딩 추가). 세 열이 아래에서 "동일한 self-attention"으로 합류하는 구조.
ViT 원 논문(arXiv:2010.11929) Figure 1을 참고.
0-1. 위치 정보를 다루는 방식의 차이
전문 설명. CNN은 커널이 이미지 위를 슬라이딩하며 지역 특징을 추출하고, 그 출력이 2D 특징맵(H×W×C) 형태를 유지한다. 즉 위치 정보가 격자 구조 자체에 의해 구조적으로 보존된다. 반면 ViT는 이미지를 고정 크기 패치(예: 16×16)로 분할해 각 패치를 벡터로 임베딩하는데, 이 순간 패치들은 순서 정보가 없는 집합(set)이 된다. 트랜스포머는 입력 순서를 구조적으로 알 수 없으므로, 위치 인코딩(positional encoding)을 각 패치 임베딩에 명시적으로 더해(element-wise addition) 위치 정보를 재주입한다. 언어 트랜스포머(LLM)도 단어를 토큰화하는 순간 순서 정보가 사라지므로 sin/cos 위치 인코딩을 더한다 — 이 지점에서 ViT와 LLM은 완전히 동일한 메커니즘을 쓴다.
쉽게 다시 말하면. CNN은 사진을 훑을 때 "이 특징이 사진의 어느 위치에서 나왔는지"가 결과물의 모양 자체에 남는다. 반면 ViT는 사진을 조각조각 잘라서 조각 더미로 만들어버리기 때문에, 각 조각에 "너는 3행 5열에 있던 조각"이라는 이름표를 따로 붙여줘야 한다. 문장을 단어로 쪼갠 뒤 "너는 3번째 단어"라는 이름표를 붙이는 언어 모델과 똑같은 트릭이다. 트랜스포머를 이미 알고 있다면, ViT는 "토큰으로 쪼개는 대상이 단어에서 이미지 조각으로 바뀐 것"뿐이다.
0-2. 그러나 "토큰을 만드는 방법" 자체는 근본적으로 다르다
전문 설명. 언어(LLM)의 토큰화는 미리 정해진 유한한 어휘사전(vocabulary)에서 각 단어(subword)의 고유 ID로 임베딩 테이블을 검색(lookup)하는 이산적 방식이다. 반면 이미지(ViT)에는 어휘사전이 없다. 각 패치의 실제 픽셀 값(예: 16×16×3 = 768개의 RGB 숫자)을 학습된 선형 변환(가중치 행렬 곱)에 통과시켜 실시간으로 벡터를 계산해서 만든다. 즉 언어는 "정해진 의미 단위를 찾아오는 것"이고, 이미지는 "그 조각의 실제 내용을 그대로 계산해 벡터화하는 것"이다.
쉽게 다시 말하면. 언어는 사전(dictionary)이 있어서 "cat"이라는 단어가 나오면 사전 3421번 항목의 벡터를 그대로 꺼내 쓰면 된다. 이미지는 그런 사전이 없다. 매번 그 조각의 픽셀 숫자들을 재료로 넣고 계산기를 돌려서 새 벡터를 뽑아낸다. 결과물(벡터 목록)의 모양은 비슷해 보여도, 만드는 공정은 "검색"과 "제조"만큼 다르다.
0-3. 픽셀 값에서 어떻게 "의미"가 나오는가
전문 설명. 패치 임베딩의 가중치 행렬은 초기에 무작위이며, 그 자체로는 어떤 의미도 만들지 못한다. 의미는 세 가지 요소의 결합으로 생긴다. (1) 픽셀 값의 배열 패턴 자체가 이미 저수준 정보를 담는다 — 경계(edge)는 급격한 값 변화, 평면은 균일한 값, 질감은 반복 패턴으로 나타난다. 가중치 행렬은 이런 패턴을 감지하는 필터로 학습된다(CNN 커널과 원리적으로 동일). (2) 가중치는 수억 회의 역전파를 거치며 "이 픽셀 패턴이 어떤 텍스트 설명과 함께 나타나는가"라는 통계적 상관관계를 압축 저장한 결과물이 된다. (3) 가장 중요하게, 개별 패치 벡터의 의미는 이후 self-attention 단계에서 다른 패치들과의 관계를 통해 비로소 완성된다. 절대값이 아니라 값들 사이의 차이·변화량·관계가 정보를 담는다는 원리이며, 이는 인간 시각 시스템의 측면 억제(lateral inhibition)와도 통한다.
쉽게 다시 말하면. "RGB는 그냥 색인데 어떻게 의미가 되냐"는 의문은 타당하다. 답은: 색 하나하나가 아니라 색들이 이루는 패턴(여기는 갑자기 어두워진다 → 경계다)이 정보이고, 그 패턴 중 뭐가 중요한지를 수억 장의 사진으로 훈련하며 익힌 것이 가중치이며, 결정적으로 조각 하나만 봐서는 여전히 애매하고 주변 조각들과 맞춰봐야("뾰족한 조각들이 삼각형으로 모여 있네 → 고양이 귀") 의미가 완성된다는 것이다.
1. SmolVLA란 무엇인가
전문 설명. SmolVLA는 Hugging Face가 공개한 450M 파라미터의 경량 Vision-Language-Action(VLA) 모델이다(arXiv:2506.01844). 멀티뷰 RGB 이미지, 자연어 태스크 지시, 로봇의 센서모터 상태를 입력받아 연속적인 액션 청크를 출력한다. lerobot 프레임워크에 통합되어 있으며(lerobot/smolvla_base), 3만 개 미만의 커뮤니티 수집 에피소드만으로 사전학습되었음에도 SO-100/SO-101 실기 태스크에서 ACT 등의 베이스라인을 능가한다고 보고되었다. 단일 소비자용 GPU에서 학습과 추론이 가능하도록 설계된 것이 핵심 차별점이다.
쉽게 다시 말하면. "카메라 영상 + '검은 트레이 집어' 같은 말 + 지금 팔 위치"를 넣으면 "앞으로 50스텝 동안 관절을 이렇게 움직여라"가 나오는 모델이다. 연구실 서버가 아니라 내 데스크톱 GPU에서 돌릴 수 있는 크기로 만들어진 것이 가장 큰 특징이다.
전체 구조: 4단계 파이프라인 [입력 3가지] → [VLM 백본 (SmolVLM2)] → [액션 전문가 (Flow Matching)] → [액션 청크 출력]
전체 구조: 4단계 파이프라인
[입력 3가지] → [VLM 백본 (SmolVLM2)] → [액션 전문가 (Flow Matching)] → [액션 청크 출력]
[그림 1] 왼쪽에서 오른쪽으로 "입력 3가지(이미지/언어/상태) → VLM 백본 → 액션 전문가 → 연속 액션 청크"가 흐르는 그림.
SmolVLA 논문 Figure 2 또는 Hugging Face 블로그의 아키텍처 그림을 삽입.
명칭 주의: SmolVLM2 = 전체 VLM의 이름, SigLIP = 그 안의 비전 인코더, SmolLM2 = 그 안의 언어 디코더.
이하 글 전체가 이 파이프라인을 왼쪽부터 순서대로 따라간다.
2. 1단계: 입력 3가지 — 각각 어떻게 토큰이 되는가
세 입력은 데이터 종류가 전부 다르지만, 최종적으로는 모두 "모델 차원(이하 설명 편의상 768차원으로 표기)의 벡터", 즉 토큰이라는 동일한 형식으로 변환된다. 그래야 하나의 시퀀스로 합쳐 같은 attention 계산에 넣을 수 있기 때문이다. 참고로 768이라는 숫자 자체에 논리적 필연은 없다 — 설계자가 표현력과 계산 비용의 균형을 보고 미리 정해둔 내부 규격(hidden dimension)이며, 정해진 트럭 크기에 짐을 효율적으로 싣는 방법을 학습하는 쪽에 가깝다.
2-1. RGB 이미지 → SigLIP 비전 인코더
블록도 상 위치: 파이프라인 맨 앞, VLM 백본(SmolVLM2) 내부의 비전 인코더 블록.
전문 설명. 각 카메라 프레임은 SigLIP(Sigmoid Loss for Language-Image Pre-training) 비전 인코더를 통과한다. SigLIP은 이미지-텍스트 쌍의 대조 학습(contrastive learning)으로 사전학습된 모델(CLIP의 개선판)이며, SmolVLA는 그중 이미지 인코더(ViT) 부분을 재활용한다. 처리 순서는 (1) 이미지를 패치로 균등 분할, (2) 각 패치의 픽셀 값을 패치 임베딩 행렬에 곱해 벡터화(1회성 선형 변환), (3) 위치 인코딩 가산, (4) SigLIP 내부의 트랜스포머 레이어들을 전부 통과하며 패치 간 attention으로 문맥화, (5) PixelShuffle로 토큰 수 압축(SmolVLA 기준 프레임당 약 64개). 멀티 카메라의 경우 각 뷰가 동일한 인코더를 독립적으로 통과하며, 뷰 간의 비교(거리·위치 추론)는 이 단계가 아니라 이후 SmolLM2의 self-attention에서 데이터로부터 암묵적으로 학습된다 — 고전적 스테레오 삼각측량 같은 명시적 기하 계산이 아니다.
여기서 PixelShuffle의 정확한 연산은 다음과 같다:
H × W × D → (H/r) × (W/r) × (D·r²)
인접한 r×r개의 토큰을 하나로 합치되, 정보를 버리는 것이 아니라 그 벡터들을 채널 방향으로 이어붙여 하나의 더 긴 벡터로 재배열하는 space-to-depth 연산이다(SmolVLM은 r=3, 즉 9개 토큰 → 1개 토큰으로 9배 압축을 사용). 압축된 토큰은 이후 MLP projection을 거쳐 언어모델의 차원으로 재정렬된다.
쉽게 다시 말하면. 사진을 격자로 자르고(0장에서 설명한 방식), 각 조각을 벡터로 만들어 SigLIP이라는 "이미 눈이 뜨인" 모델에 통과시킨다. 마지막에 PixelShuffle이 "옆에 붙어 있는 9개 조각의 정보를 한 줄로 길게 이어붙여 한 조각처럼" 만들어서, 조각 수를 9분의 1로 줄인다. 정보를 지우는 게 아니라 서랍 9칸의 내용물을 큰 서랍 1칸에 몰아넣는 재정리다. 카메라가 2대면 이 과정을 각각 하고, "손목캠의 이 물체와 고정캠의 저 물체가 같은 것"이라는 판단은 나중 단계에서 학습으로 이루어진다.
[그림 2] r×r 격자의 인접 토큰들이 채널 방향으로 이어붙어 하나의 긴 토큰이 되는 그림.
SmolVLM 논문(arXiv:2504.05299) Figure 2 또는 pyimagesearch.com의 SmolVLM 리뷰 글의 Pixel Shuffle 그림을 참고.
2-2. 언어 지시 → 토크나이저 + 임베딩 lookup
블록도 상 위치: 파이프라인 맨 앞, SmolLM2 디코더로 직접 입력.
전문 설명. 태스크 지시문(lerobot 데이터 수집 시 --task 인자로 기록한 문자열)은 SmolLM2 토크나이저에 의해 단어/subword 단위로 분할되고, 각 단위가 어휘사전의 고유 ID로 매핑된 뒤, 임베딩 테이블 lookup으로 고정 차원 벡터가 된다(0장에서 설명한 이산적 방식). 위치 인코딩이 더해진 후 SmolLM2 디코더에 입력된다. 주의할 점: --task에는 임의의 자연어를 넣을 수 있으나, 실제 동작 성능은 파인튜닝 데이터에 등장한 태스크 문구와의 유사성에 크게 좌우된다. 이는 ACT가 학습하지 않은 물체 위치에서 성능이 저하되는 것과 동일한 분포 밖(out-of-distribution) 일반화 한계가 언어 축에서 나타나는 것이다.
쉽게 다시 말하면. "pick up the black tray"라는 문장을 단어 조각으로 쪼개고, 사전에서 각 조각의 벡터를 찾아온다. 아무 문장이나 넣을 수는 있지만, 학습 때 본 적 없는 표현이면 문법은 이해해도 "그 말에 맞는 동작"은 배운 적이 없어서 버벅댄다. 그래서 실전 팁: 데이터 수집 때 쓴 --task 문구를 추론 때도 똑같이(최소한 비슷하게) 써야 한다.
2-3. 센서모터 상태 → 선형 투영 1회
블록도 상 위치: 파이프라인 맨 앞, 선형 레이어 하나를 거쳐 SmolLM2 디코더로 입력.
전문 설명. 로봇의 현재 관절 각도값(SO-101 기준 서보 6개 = 6차원 벡터)은 학습된 선형 레이어(6→768 가중치 행렬) 1회 통과로 단일 토큰으로 투영된다. 이미지·언어와 달리 다층 트랜스포머를 거치지 않는 이유는, 관절 각도가 이미 그 자체로 완결된 정보이기 때문이다 — 패치나 단어처럼 주변과의 대조(attention)로 의미를 완성할 필요가 없다. 토큰이 1개뿐이므로 순서를 나타내는 위치 인코딩은 사실상 불필요하며, 구현에 따라 토큰의 종류(이미지/언어/상태)를 구분하는 타입 임베딩(type embedding)을 더하기도 한다 — 이는 순서 정보가 아니라 종류 꼬리표라는 점에서 위치 인코딩과 다른 개념이다. 또한 선형 변환은 "차원만 늘리는" 것이 아니라 6개의 값이 가중치에 의해 선형결합되며 768개의 새 값으로 재계산되는 실제 변환이다. 6→768로의 확장은 정보 손실이 아니라 표현 공간의 확장이며, 원본 각도값의 정확한 복원이 목적이 아니라 액션 예측에 유용한 재표현이 목적이므로 문제가 되지 않는다.
쉽게 다시 말하면. "지금 팔이 어디 있는지"를 나타내는 숫자 6개를, 다른 토큰들과 같은 크기(768개 숫자)의 옷으로 갈아입히는 한 번의 변환이다. 관절 각도는 "90도"라는 값 자체가 이미 명확해서, 사진 조각처럼 여러 번 주변과 맞춰볼 필요가 없다 — 포장만 하면 된다. 그리고 이 포장 과정에서 숫자들이 한 번 섞이는데, 원본이 흐려지는 게 아니냐는 걱정은 타당하지만, 목적이 "원본 보존"이 아니라 "동작 판단에 쓸모 있는 형태로 가공"이기 때문에 괜찮다. 어떻게 섞는 게 쓸모 있는지는 학습이 알아낸다.
3. 2단계: VLM 백본 — 세 토큰이 만나 "상황 이해"가 되는 곳
3-1. 토큰 결합: 차원이 아니라 개수가 늘어난다
블록도 상 위치: SigLIP 출력, 언어 임베딩, 상태 투영이 합류해 SmolLM2 디코더로 들어가는 지점.
전문 설명. 이미지 토큰(프레임당 약 64개), 언어 토큰(문장 길이 N개), 상태 토큰(1개)은 모두 동일한 차원이므로 연결(concatenation)이 가능하다. 결합은 차원 방향이 아니라 시퀀스(행) 방향으로 이루어진다: 각 토큰이 "768개 숫자로 된 한 행"이고, 결합 결과는 (64+N+1) × 768 형태의 2차원 행렬이다. 768×3=2304차원이 되는 것이 아니다. 이렇게 하나의 시퀀스로 합치는 이유는 self-attention이 모든 토큰 쌍(이미지↔언어, 언어↔상태, 이미지↔상태, 카메라A↔카메라B)의 관계를 동시에 계산할 수 있게 하기 위해서다. 각 모달리티를 따로 처리한 뒤 결과만 합치면 "지시문의 'black tray'가 이미지의 어느 패치에 대응하는가" 같은 교차 관계를 학습할 기회 자체가 사라진다.
쉽게 다시 말하면. 세 종류의 토큰을 세로로 쌓는다. 벡터가 옆으로 길어지는 게 아니라 줄 수가 늘어나는 것이다. 이렇게 한 테이블에 모아 앉히는 이유는, "말"이 "사진 속 어디"를 가리키는지 서로 마주 보고 맞춰볼 수 있게 하기 위해서다. 각자 다른 방에서 회의하고 결론만 교환하면 그런 대조가 불가능하다.
[그림 3 ] [이미지 토큰 64행] + [언어 토큰 N행] + [상태 토큰 1행]이 세로로 쌓여 (64+N+1)×768 행렬이 되고,
그 행렬이 SmolLM2로 들어가는 그림. (행렬의 "행 = 토큰"이라는 점이 시각적으로 드러나도록 함.)
3-2. SmolLM2 디코더: 레이어(= Self-attention + FFN)의 반복
블록도 상 위치: VLM 백본(SmolVLM2) 내부의 언어 디코더 블록.
전문 설명. SmolLM2는 원래 Hugging Face의 범용 소형 LLM으로, 다음 토큰 예측으로 사전학습되었고 SmolVLM2에서는 이미지 캡셔닝·VQA 용도로 쓰이던 모델이다. 구조는 표준 트랜스포머 디코더: 레이어 = [self-attention + FFN] 블록이 수십 개 적층된 형태다. 입력 행렬 (64+N+1)×768은 각 레이어를 통과할 때마다 크기는 그대로 유지되고 내용(숫자 값)만 갱신된다. self-attention은 모든 행(토큰)이 다른 모든 행과의 관련도를 계산해 정보를 교환하는 연산이고(순서와 무관하게 전부 서로를 보므로, 위치/타입 정보가 붙어 있는 한 토큰의 나열 순서 자체는 결정적이지 않다), FFN은 각 토큰을 독립적으로 확장(768→3072)→활성화(GELU/ReLU)→축소(3072→768)하는 2층 신경망이다. 확장-축소 구조의 목적은 일시적으로 넓은 공간에서 활성화 함수의 비선형성을 충분히 활용하기 위함이며, 활성화 함수가 없으면 두 선형 변환은 수학적으로 하나의 선형 변환으로 합쳐져 버린다. 활성화 함수 자체는 학습되지 않는 고정 함수이고(ReLU(x)=max(0,x)), 학습되는 것은 그 앞뒤의 가중치 행렬이다. 벡터의 각 차원을 노드(뉴런)로 보면, 활성화 함수는 각 노드를 값의 부호에 따라 통과/차단하는 스위치이며, 어떤 입력에서 어떤 노드 조합이 켜지는지의 패턴 자체가 특징 표현이 된다. 차단은 삭제가 아니라 "이번 계산에서 0으로 만들어 전달을 막는" 동적 필터링이다.
쉽게 다시 말하면. 레이어 하나는 두 단계 공정이다. 1단계(attention): 토큰들이 서로 회의하며 "너랑 나랑 관련 있네" 하고 정보를 주고받는다. 2단계(FFN): 회의가 끝나면 각자 자리로 돌아가 받은 정보를 정리한다 — 이때 좁은 책상(768칸)에서 넓은 창고(3072칸)로 잠깐 옮겨 이것저것 펼쳐보고, 쓸 만한 것만 챙겨 다시 책상으로 돌아온다. 창고에서 물건을 살릴지 버릴지 정하는 문지기(활성화 함수)의 규칙("양수만 통과")은 절대 안 바뀌고, 학습으로 바뀌는 것은 문 앞에 어떤 물건이 도착하느냐다. 이 공정을 수십 번 반복하면, 처음엔 따로 놀던 이미지·말·상태 정보가 점점 "지금 상황이 뭔지"를 담은 하나의 이해로 익어간다.
3-3. 레이어 스키핑: 중간에서 끊고 나머지는 계산하지 않는다
블록도 상 위치: SmolLM2 디코더 내부. SigLIP에는 적용되지 않음 — SigLIP은 전체 레이어를 그대로 사용한다.
전문 설명. SmolVLA는 SmolLM2의 마지막 레이어 출력이 아니라 중간 레이어(대략 전체의 절반, 논문 구현 기준 첫 16개 레이어)의 출력을 특징으로 추출하며, 그 이후 레이어들은 실행 자체를 생략한다. 이것이 계산량이 절반으로 줄어드는 이유다(뒤쪽 레이어를 "가볍게" 도는 것이 아니라 아예 돌지 않는다). 성능 저하 없이 가능한 근거: 트랜스포머의 레이어는 깊이에 따라 다른 추상화 수준을 담으며, 초·중반 레이어는 범용적 의미 이해("이 단어가 이 문맥에서 무슨 뜻인지, 이미지의 어느 부분과 연결되는지")를, 후반 레이어는 원 모델의 사전학습 목적인 텍스트 생성(다음 토큰 선택)에 특화된 표현을 담는다. SmolVLA가 SmolLM2에 요구하는 것은 문장 생성이 아니라 상황 이해 벡터뿐이므로, 후반부는 불필요하다. 실제 ablation에서도 큰 VLM에서 레이어를 자르는 것(78.5%)이 처음부터 작은 VLM을 쓰는 것(75.8%)보다 우수했다.
쉽게 다시 말하면. SmolLM2는 원래 "이미지를 보고 문장을 완성하는" 모델이다. 그 작업의 앞부분은 "상황 파악"이고 뒷부분은 "문법에 맞는 다음 단어 고르기"다. 로봇에게 필요한 건 상황 파악까지이므로, "문장 마무리 공정"은 통째로 건너뛴다. 요리로 치면 재료 손질과 조리까지만 빌려 쓰고, 플레이팅 공정은 쓰지 않는 것이다. 재밌는 건, 처음부터 작은 주방(작은 VLM)을 쓰는 것보다 큰 주방에서 앞 공정만 쓰는 게 결과가 더 좋다는 점이다.
[그림 4] [토큰 결합 행렬] → SmolLM2 레이어 1~16(사용, 색칠) → 레이어 17~끝(생략, 회색/점선) →
중간 지점에서 화살표가 옆으로 빠져나와 "맥락 특징 → 액션 전문가"로 향하는 그림.
3-4. 이 단계의 출력
전문 설명. VLM 백본의 최종 출력은 입력과 동일한 형태인 (64+N+1)×768 행렬로, 이미지·언어·상태 간의 관계가 반영된 **맥락 특징(contextual features)**이다. 중요한 점: VLM은 동작 신호(관절 각도값)를 직접 만들지 않는다. 실제 액션 생성은 다음 단계인 액션 전문가의 몫이다.
쉽게 다시 말하면. 이 단계가 끝나면 "지금 상황이 이렇고, 시킨 일이 이거고, 팔이 여기 있다"를 압축한 요약본이 나온다. 아직 "그래서 어떻게 움직여라"는 없다.
4. 3단계: 액션 전문가 — 노이즈에서 동작을 조각해내는 곳
블록도 상 위치: VLM 백본 다음, 파이프라인의 세 번째 블록. 약 100M 파라미터의 별도 서브모듈(VLM과 가중치를 공유하지 않음). hidden size는 VLM 차원의 0.75배로 축소 사용.
4-1. 액션 토큰은 어디서 오는가
전문 설명. 액션 전문가의 목표 출력은 액션 청크 A_t = (a_t, ..., a_{t+n})으로, 논문 기본값 n=50 스텝의 연속 동작이며 각 스텝은 관절 각도 벡터(SO-101 기준 6차원)다. 학습 시 처리 순서는 다음과 같다.
쉽게 다시 말하면. 액션 토큰은 갑자기 나타나는 게 아니다. "정답 동작에 모래(노이즈)를 뿌려 흐려놓은 숫자들"을, 상태값을 포장했던 것과 같은 방식으로 50줄짜리 토큰으로 포장한 것이다. 학습의 목표는 "이 흐려진 동작을 어느 방향으로 닦아내면 원래 동작이 나오는가"를 배우는 것이다.
4-2. Cross-attention과 Self-attention의 교차 배치
전문 설명. 액션 전문가는 cross-attention(CA) 레이어와 causal self-attention(SA) 레이어를 교대로 쌓는다. CA에서는 액션 토큰이 자체 가중치로 투영되어 Query가 되고, VLM 맥락 특징이 서로 다른 두 가중치 행렬에 각각 투영되어 Key와 Value가 된다 — VLM 출력 행렬이 쪼개져 K/V가 되는 것이 아니라, 동일한 행렬이 K용/V용 가중치에 각각 곱해져 두 결과가 별도로 생성된다(self-attention에서 하나의 입력으로 Q/K/V를 각각 만드는 원리와 동일하고, 출처만 둘로 나뉜 것). SA에는 causal mask가 적용되어 각 액션 토큰이 자기보다 과거의 토큰만 참조할 수 있다. Ablation 결과 CA+SA 교차 배치(85.5%)가 CA 단독(79.0%)이나 SA 단독(74.5%)보다 우수했고, causal(74.5%)이 bidirectional(67.5%)보다 우수했다. 흥미롭게도 CA 단독도 상당히 경쟁력이 있는데, 이는 VLM 조건화만으로도 강력함을 시사한다.
쉽게 다시 말하면. 두 종류의 회의가 번갈아 열린다. 첫째(CA), 액션 토큰들이 VLM의 상황 요약본을 보며 "지금 상황에 비춰 내 동작이 어디로 고쳐져야 하지?"를 묻는다. 둘째(SA), 액션 토큰들끼리 "내 앞 스텝이 이렇게 움직였으니 나는 자연스럽게 이어서 이렇게"를 맞춘다 — 단 미래 스텝을 커닝하는 것은 금지(causal mask). ACT가 temporal ensembling으로 사후에 동작을 부드럽게 만들었다면, SmolVLA는 이 구조 자체로 시간적 일관성을 만든다.
4-3. Flow Matching — 학습과 추론
전문 설명. 레이어들을 통과한 액션 토큰은 마지막 선형 레이어를 통해 다시 (50×6) 형태의 벡터장 v_θ(A_t^τ, o_t)로 투영된다. 학습 목적함수는 이 예측이 실제 방향 u = ε − A_t를 근사하도록 하는 L2 손실이다. 즉 모델은 "혼합 지점 A_t^τ에서 어느 방향으로 이동해야 정답 궤적에 도달하는가"라는 보정 벡터를 배운다. 추론 시에는 정답이 존재하지 않으므로 순수 노이즈(τ=0)에서 시작해, 예측된 보정 방향을 반복 적용(논문 기본값 10 스텝)하며 노이즈를 실제 액션 청크로 점진적으로 복원한다. 이는 확산 모델 계열의 생성 방식이며, ablation에서 flow matching(80.25%)이 단순 회귀(L1, 75.25%)보다 우수했다. ACT가 CVAE(잠재변수 z + KL divergence, 추론 시 z=0 고정)로 행동의 다양성을 다뤘다면, SmolVLA는 노이즈→궤적 복원이라는 전혀 다른 생성 메커니즘을 쓴다.
쉽게 다시 말하면. 조각가의 비유가 정확하다. 학습 때는 "완성된 조각상(정답 동작)에 찰흙을 덧발라 뭉개놓고, 어디를 어떻게 깎으면 원래 조각상이 나오는지"를 반복 훈련한다. 실전(추론)에서는 아예 찰흙 덩어리(순수 노이즈)에서 시작해, 배운 대로 10번 깎아 동작을 조각해낸다. "이 상황에서는 이렇게 깎아라"라는 가이드가 바로 VLM이 준 상황 요약본이다.
[그림 5] [정답 A_t + 노이즈 ε] → 혼합(A_t^τ) → 선형 임베딩(액션 토큰 50개) → [CA(← VLM 특징)
↔ causal SA 교차 반복] → 출력 투영 → 보정 방향 v_θ(50×6) → (추론 시) 10회 반복 적용 → 최종 액션 청크.
세션에서 그린 8단계 다이어그램 구성을 따라 작성.
flow matching의 노이즈→궤적 복원 개념은 SmolVLA 논문 Figure 3 참고
+ 비자기회귀(Non-Autoregressive, 줄여서 NAR)는 쉽게 말해 "다음 단어나 행동을 하나씩 순서대로 예측하지 않고, 모든 요소를 한 번에 통째로(병렬로) 예측하는 방식
5. 4단계: 출력과 비동기 추론 — 계산 시간을 숨기는 시스템 설계 5-1. 출력물
전문 설명. 최종 출력은 n=50 스텝의 연속 액션 청크로, 자기회귀 없이 한 번에 병렬 생성된다(이 발상 자체는 ACT와 동일). Ablation에서 청크 크기는 n=1이면 50.0%로 급락하고 n=100이면 74.5%로 저하되며, n=10 부근(84.0%)~50 사이가 균형점이었다.
쉽게 다시 말하면. "다음 한 걸음"이 아니라 "앞으로 50걸음의 계획"이 통째로 나온다. 계획이 너무 짧으면(1걸음) 매번 멈춰서 다시 생각해야 하고, 너무 길면(100걸음) 상황 변화에 못 따라간다.
[그림 6] 위쪽 줄(동기식) — [청크 실행]→[정지+계산 대기]→[실행] 반복.
아래쪽 줄(비동기) — [청크1 실행]이 진행되는 동안 아래에 겹쳐서 [청크2 계산]이 병렬 진행, 이음새 없이 [청크2 실행]으로 연결.
lerobot 공식 문서(huggingface.co/docs/lerobot/async)의 그림 참고 가능
5-2. 비동기 추론: RobotClient / PolicyServer / 큐
블록도 상 위치: 모델 외부의 실행 시스템. 파이프라인 오른쪽 끝, 로봇과 모델 사이.
전문 설명. SmolVLA는 실행을 두 개의 독립 프로세스로 분리한다. RobotClient는 액션 큐에서 액션을 하나씩 꺼내 로봇에서 실행하고, PolicyServer는 모델 추론(VLM + 액션 전문가 + flow matching 10회 반복)을 전담한다(GPU가 있는 원격 서버도 가능). 트리거 메커니즘: 큐 잔량이 임계값 g(예: 70%) 아래로 떨어지면, RobotClient가 현재 관찰(카메라 프레임 등)을 캡처해 비동기적으로 PolicyServer에 전송한다. 서버가 새 청크를 계산해 돌려주면 클라이언트는 이를 기존 큐에 병합(aggregate)한다. 핵심은 큐가 소진되기 전에 미리 계산을 시작한다는 타이밍 설계다 — 큐가 0이 된 뒤 요청하면 계산 시간만큼 로봇이 정지하지만(동기식), 잔량이 남은 상태에서 요청하면 계산 동안에도 로봇은 남은 큐를 소비하며 계속 움직인다. 결과적으로 태스크 완료 시간 약 30% 단축, 처리량 약 2배가 보고되었다.
쉽게 다시 말하면. 식당 주방(PolicyServer)과 홀 서빙(RobotClient)을 분리한 것이다. 서빙 담당은 준비된 접시(액션)를 계속 나르고, 접시가 70% 아래로 줄어들면 "다음 코스 준비 시작해주세요"라고 주방에 미리 외친다. 접시가 다 떨어진 뒤에 주문하면 손님(로봇)이 멍하니 기다려야 하지만, 미리 주문해두면 서빙이 끊기지 않는다. "비동기"의 실체는 빠른 계산이 아니라 계산을 시작하는 타이밍을 앞당겨 대기 시간을 숨기는 것이다.
6. ACT와의 비교 — 뼈대는 같고, 조건화가 다르다
지난 글에서 다룬 ACT와 비교하면 SmolVLA의 위치가 선명해진다.
공통점(전문). 멀티뷰 이미지 + 로봇 상태 입력, 액션 청크의 비자기회귀 병렬 예측, lerobot 프레임워크 통합.
차이점(전문).
| 언어 입력 | 없음 — 모델 하나 = 태스크 하나 | 자연어 지시로 태스크 스위칭 |
| 비전 인코더 | ResNet-18 (처음부터 학습) | SigLIP (사전학습 재활용) |
| 조건화/생성 | CVAE — 잠재변수 z, KL divergence, 추론 시 z=0 | Flow matching — 노이즈→궤적 보정 반복 |
| 액션 디코더 | 단일 트랜스포머 디코더 + 학습된 위치 쿼리 | 별도 액션 전문가, CA/SA 교차 + causal mask |
| 시간 일관성 | temporal ensembling (사후 보정) | causal SA (구조 내재) + 비동기 실행 |
| 데이터 효율 | 태스크 특화, 데이터 양이 병목 | 사전학습 지식 활용, <30K 에피소드로 경쟁력 |
항목 ACT (~80M) SmolVLA (~450M)
쉽게 다시 말하면. 두 모델의 차이는 결국 하나로 수렴한다: 사전학습된 VLM을 통째로 가져다 쓰는가. ACT는 "이 작업 하나만 잘하는 전용 컨트롤러"를 백지에서 길러내는 것이고, SmolVLA는 "이미 세상을 웬만큼 아는 두뇌"에 팔 조작 능력 하나를 붙이는 것이다. 언어 입력의 유무도, 모델 크기 차이도, 데이터 효율 차이도 전부 이 한 가지 선택에서 파생된다. 그리고 한계도 같은 뿌리를 공유한다 — ACT가 "본 적 없는 물체 위치"에서 약하듯, SmolVLA는 "본 적 없는 태스크 문구"에서 약하다. 분포 밖 일반화라는 딥러닝의 근본 한계가 서로 다른 축에서 나타나는 것뿐이다.
7. 학습은 실제로 어떻게 이루어지는가
전문 설명. SmolVLA의 학습은 2단계다. (1) 사전학습(pretraining): 481개의 커뮤니티 수집 데이터셋(22.9K 에피소드, 1,060만 프레임)으로 200,000 스텝, 글로벌 배치 256, AdamW, 코사인 학습률(1e-4→2.5e-6). 커뮤니티 데이터는 태스크 라벨이 부실한 경우가 많아 별도 VLM(Qwen2.5-VL-3B)으로 지시문을 자동 재생성하고, 제각각인 카메라 뷰 이름을 수동 표준화(OBS_IMAGE_1/2/3)하는 전처리를 거쳤다. (2) 파인튜닝(post-training): 시뮬레이션 벤치마크 100K 스텝, 실기 태스크 200K 스텝. 가장 중요한 사실: VLM(SigLIP + SmolLM2)은 사전학습과 파인튜닝 전 과정에서 완전히 고정(frozen)되며, 학습되는 것은 액션 전문가와 그에 연결된 projection 레이어들뿐이다. 이유는 파괴적 망각(catastrophic forgetting) 방지 — 대규모 데이터로 획득한 VLM의 세계 지식을, 상대적으로 훨씬 적은 로봇 데이터로 재학습시키면 오히려 무너뜨릴 위험이 있기 때문이다.
쉽게 다시 말하면. 450M짜리 모델을 파인튜닝한다고 하면 겁먹기 쉽지만, 실제로 훈련되는 부분은 액션 전문가 쪽뿐이다. "세상을 보는 눈과 말을 알아듣는 귀"(VLM)는 이미 완성된 채로 얼려두고, "팔을 어떻게 움직일지"(액션 전문가)만 내 데이터로 가르친다. 눈과 귀까지 다시 가르치려 들면, 적은 데이터 때문에 오히려 멀쩡하던 눈이 나빠진다. 이것이 SmolVLA가 소비자용 GPU 한 장으로 파인튜닝 가능한 이유이기도 하다.
8. 정리 — 한 문장 요약과 블록도 총정리
전체 흐름을 한 문장으로: "세 종류의 입력을 같은 크기의 토큰으로 통일해 한 테이블에 모으고(VLM), 그 상황 이해를 나침반 삼아 노이즈에서 동작을 조각해내며(액션 전문가, flow matching), 조각이 끝나기 전에 다음 조각을 미리 주문한다(비동기 추론)."
관련 기술이 블록도에서 쓰이는 위치 총정리:
| ViT / 패치 임베딩 / 위치 인코딩 | SigLIP 비전 인코더 내부 (입력단) |
| 대조학습(SigLIP 사전학습) | SigLIP의 출신 배경 (SmolVLA 학습 중에는 frozen) |
| PixelShuffle (space-to-depth) | SigLIP 출력 직후, 토큰 수 압축 |
| 어휘사전 lookup / 텍스트 임베딩 | 언어 지시 입력단 |
| 선형 투영 (1회) | 상태 입력단 + 액션 전문가의 액션 토큰 임베딩 |
| Self-attention + FFN (레이어) | SmolLM2 디코더 및 액션 전문가 내부 전반 |
| 활성화 함수 (고정 스위치) | 모든 FFN 내부 |
| 레이어 스키핑 | SmolLM2 디코더 (첫 ~16개 레이어만 사용; SigLIP에는 미적용) |
| Cross-attention (Q=액션, K/V=VLM 특징 별도 투영) | 액션 전문가 |
| Causal mask self-attention | 액션 전문가 |
| Flow matching (τ 혼합, 보정 벡터, 10회 반복) | 액션 전문가의 학습 목적함수 및 추론 절차 |
| VLM freeze / 파괴적 망각 방지 | 학습 전략 (사전학습·파인튜닝 공통) |
| RobotClient / PolicyServer / 큐 임계값 | 모델 외부 실행 시스템 (비동기 추론) |
기술 블록도 상 위치
참고 자료: SmolVLA 논문 (arXiv:2506.01844), Hugging Face 블로그 (huggingface.co/blog/smolvla), SmolVLM 논문 (arXiv:2504.05299), lerobot 비동기 추론 문서 (huggingface.co/docs/lerobot/async)
|
|
