Do LMs Know What Variables Do? Interpreting Code Representations via Variable Roles
0. Summary
- 기본 정보 : ArXiv,2026.10.16, Do LMs Know What Variables Do? Interpreting Code Representations via Variable Roles
- 연구 배경 : LLM은 코드 완성부터 계획·수정·테스트를 수행하는 에이전트까지 폭넓게 소스 코드를 다루지만, 코딩에 성공한다는 사실만으로 모델이 어떤 프로그램 속성을 내부에 표현하는지는 알 수 없다. 모델은 식별자(변수 이름)나 익숙한 코드 패턴 같은 표면 단서에 의존할 수 있고, 통제된 입력 변환 아래에서 성능이 흔들리기도 한다. 이 논문은 이 질문을 개별 변수의 행동(behavior) 수준에서 던진다. 어떤 변수는 예측 가능한 순서로 전진하고, 어떤 변수는 값을 누적하며, 어떤 변수는 지금까지 본 것 중 최선의 후보를 보관한다. 이런 행동은 여러 번의 갱신 사이의 관계에 의존하므로 덧셈 하나를 인식하는 것만으로는 규칙적 진행과 입력 의존적 누적을 구별할 수 없고, 같은 행동이 다른 이름과 다른 언어 구문으로 구현될 수도 있다. 그래서 세 가지 질문이 나온다. (1) 어떤 역할 구분이 모델 표현에서 복원 가능한가, (2) 희소 오토인코더(SAE)는 그 구분을 얼마나 충실히 보존하는가, (3) 관련 방향(direction)으로 정확성을 유지한 채 생성을 바꿀 수 있는가.
- 제안 방법 : 프로그래밍 심리학에서 모델과 독립적으로 정의된 Sajaniemi의 변수 역할(variable roles) 분류체계(11개 역할) 를 기준 개념으로 채택한다. Joern Code Property Graph(CPG) 위의 명시적 “역할 계약(role contract)”으로 11개 역할 전부를 정적 분석으로 자동 주석하여, 5개 언어(C, C++, JavaScript, Python, Ruby) 126,926개 파일 · 3,525,530개 변수(그중 1,737,758개가 하나 이상의 역할 보유)의 자연 코드 코퍼스와 벤치마크를 구축한다. 다섯 개의 모델–SAE 시스템(Gemma 2 2B, Gemma 3 4B/12B, Llama 3.1 8B, Qwen3.5 9B, 각 4개 레이어)에 대해 잔차 스트림 프로브, SAE 재구성 프로브, 상위 64개 SAE 피처 프로브, 단일 SAE 피처 예측기, 그리고 이름·코드 표면(lexical) 베이스라인을 같은 매칭 쌍(matched pairs) 위에서 비교한다. 여기에 LLM이 검토한 역할 제거 편집(counterfactual edits)과 역할 보존 중립 이름 변경(neutral renaming) 통제를 추가하고, 마지막으로 MBPP에서 SAE 피처 방향의 activation addition과 direction removal(orthogonalization)로 생성 개입을 수행해 역할 주석 변화와 테스트 통과 여부를 함께 측정한다.
- 발견 사실 : 잔차 프로브는 모든 역할·모델 비교에서 단일 SAE 피처와 표면 베이스라인을 능가한다(매칭 쌍 AP 평균 0.90 vs 단일 피처 0.72, AUROC 0.906–0.913). SAE 피처 64개를 결합하거나 SAE 재구성 위에 프로브를 올리면 단일 피처와의 격차는 대부분 좁혀지지만(AUROC 0.853–0.881), 재구성 프로브는 LLM이 검토한 역할 변경 편집에 대한 민감도가 잔차 프로브보다 4.0–12.3%p 낮다(5개 모델 모두 신뢰구간이 0을 제외). 쌍 단위 순위 정확도(0.813–0.877)는 높지만, 고정 임계값에서는 편집된 음성 예제의 68–71%를 양성으로 분류하는 빈번한 거짓 양성이 공존한다. 중립 이름 변경은 잔차 AUROC를 0.6–1.7%p만 떨어뜨리는 반면 이름 베이스라인은 우연 수준으로 붕괴한다. 생성 개입에서는 방향 제거가 역할 주석을 자주 지우지만 정확성 손실이 크고(Pass@1 −0.33, −0.29 등), 주석 변화와 테스트 통과가 동시에 일어나는 비율은 무작위 통제와 비교해 유의한 차이가 없으며, 정확성 제약을 걸고 강도를 보정하면 11개 셀 중 10개에서 “개입하지 않음(0)”이 선택된다.
- 핵심 기여 :
- 대규모 다국어 데이터셋과 벤치마크 : 11개 Sajaniemi 역할 전부를 자동 주석한 최초의 대규모(126,926 파일) 자연 코드 코퍼스를 만들고, 매칭·채굴 음성 예제, LLM 검토 역할 변경 편집, 역할 보존 이름 변경을 갖춘 벤치마크를 구성했다(벤치마크·주석·분할·추출 파이프라인 공개 예정).
- 복원 가능성(recoverability)과 SAE 충실도(fidelity)의 분리 측정 : 다섯 모델–SAE 시스템에서 잔차 프로브, 재구성 프로브, 단일 피처, 64피처 결합 프로브를 선택된 연산 직후의 관찰 지점에서 비교하고, 통제된 편집으로 매칭 예측을 넘어선 민감도를, 언어·구현·readout 비교로 복원 가능성의 조건을 밝혔다.
- 개입 기반 제어의 한계 : 역할 유도(induction)와 억제(suppression)를 기능적 정확성 및 무작위 방향 통제와 나란히 측정하여, 주석 변화는 흔하지만 테스트 통과를 동반한 변화는 드물고 무작위 통제 대비 뚜렷한 이점이 없음을 보였다.
관련 개념
Sajaniemi의 변수 역할(Variable Roles) 분류체계
변수 역할(variable role) 은 프로그램 안에서 한 변수가 어떤 값들을 차례로 갖고, 그 값들이 어떻게 얻어지는지로 변수를 특징짓는 개념입니다. Sajaniemi(2002)가 프로그래밍 심리학(psychology of programming)에서 초보자 교육용으로 제안했고, 이후 전문 프로그래머 대상 카드 소팅·인터뷰(Sajaniemi & Navarro Prieto, 2005)에서도 일관된 그룹이 재발견되었습니다. 핵심은 역할이 모델과 무관하게 독립적으로 정의된 행동 기준이라는 점입니다. 그래서 모델 내부 표현을 검사할 때 “모델이 만든 개념”이 아니라 “사람이 먼저 정의한 개념”을 기준으로 삼을 수 있습니다.
📋 1. 열한 개 역할
논문이 다루는 11개 역할과 추출 계약에 쓰인 대표 패턴은 다음과 같습니다.
| 역할 | 행동 설명 | 대표 패턴 (논문 Appendix C) |
|---|---|---|
| Fixed value (고정값) | 한 번 초기화된 뒤 다시 바뀌지 않는 값 | limit = input_limit; use(limit) |
| Stepper (스테퍼) | 예측 가능한 순서로 전진하는 값 (반복 인덱스 등) | i = 0; while i < limit: i += stride |
| Most-recent holder (최근값 보관자) | 일련의 값 중 가장 최근에 얻은 값을 보관 | while more: current = read(); consume(current) |
| Most-wanted holder (최선값 보관자) | 지금까지 본 후보 중 “가장 원하는” 것(최대·최소 등)을 보관 | if score > best: best = score; winner = i |
| Gatherer (수집자) | 여러 기여를 누적·결합 (합계, 곱 등) | score *= 5; score += points[item] |
| Follower (추종자) | 다른 변수(master)의 이전 값을 따라가는 변수 | prev = current; current = next(current); use(prev) |
| One-way flag (단방향 플래그) | 한 번 바뀌면 되돌아오지 않는 Boolean | found = false; ...; found = found \|\| match |
| Temporary (임시값) | 아주 짧은 구간에서만 쓰이는 값 | tmp = parse(item); emit(tmp) |
| Organizer (정리자) | 원소 집합은 그대로 두고 재배열만 하는 컬렉션 | items.reverse() |
| Container (컨테이너) | 원소가 추가·삭제·변경되는 컬렉션 | items.append(x); items.sort() |
| Walker (워커) | 자료구조를 순회하며 이전 위치에 의존해 이동하는 변수 | while p: use(p); p = p.next |
🔍 2. 역할 보존 ≠ 프로그램 동치
역할은 변수의 행동을 기술하므로 프로그램의 의미와는 다른 층위입니다.
- 최솟값 계산과 최댓값 계산은 프로그램으로는 다르지만 같은 역할(most-wanted holder) 을 공유합니다.
- 반대로 동치인 두 프로그램이 서로 다른 역할의 변수를 쓸 수 있습니다(예: 누적을 gatherer로 하거나 내장 함수로 대체).
- 역할은 식별자(
best,count)나 구문(range,+=)과 상관될 수 있으므로, 표현을 검사하려면 이런 표면 단서를 통제해야 합니다. 이 점이 논문 설계 전체를 관통합니다.
🧠 3. 왜 이 분류체계인가
| 선행 연구 | 신호 | 언어 | 역할 수 | 규모 |
|---|---|---|---|---|
| Gerdt & Sajaniemi (2006) | 정적 분석 + 학습 | Pascal | 9 | 87 프로그램, 305 변수 |
| Lui et al. (2020) | 실행 트레이스 + NN | C | 4 클래스 | 110 프로그램 |
| Hussain et al. (2023) | 구문 규칙 | Java | 2 (stepper, walker) | 1.4M 변수 |
| 본 논문 | 정적 CPG 분석 | C, C++, JS, Python, Ruby | 11 | 126,926 파일, 1.74M 변수 |
기존 시스템은 분류체계의 일부만 다루거나 실행 트레이스를 요구했습니다. 이 논문은 11개 전부를 실행 없이, 빌드 가능한 프로젝트 없이 고립된 소스 파일에서 주석합니다.
💡 Key Takeaway 변수 역할은 “이 변수가 무슨 타입인가”가 아니라 “이 변수가 시간에 따라 어떻게 행동하는가” 를 묻는 개념입니다. 모델과 독립적으로 정의된 행동 개념이기 때문에, 모델이 표면 패턴을 외운 것인지 행동을 표현하는 것인지 가르는 시험대로 쓸 수 있습니다.
Code Property Graph 기반 정적 역할 추출과 코퍼스
Code Property Graph(CPG, Yamaguchi et al., 2014) 는 구문(AST), 제어 흐름(CFG), 데이터 의존성을 하나의 그래프에 합친 표현입니다. 논문은 Joern이 만든 CPG 위에 역할마다 명시적 “역할 계약(role contract)” 을 질의로 작성하여, 변수의 초기화·갱신·사용을 복원하고 그 관계가 계약을 만족하는지 검사합니다.
⚙️ 1. 역할 계약의 구조
각 계약은 $v$(선언 identity), $W$(바인딩 쓰기), $I$(초기화 이벤트), $U = W \setminus I$(갱신), $M$(관측된 상태 변이) 같은 사실(fact) 위에서 정의됩니다. 예를 들어:
- Most-wanted holder : 보관자–후보 비교(guarded comparison, min/max, 또는 null 시드 후 첫 만족 후보)가 조건부 교체로 이어지는지 확인하고, 시드와 다른 모든 쓰기가 설명되는지(seed/selection/unset fallback), 변이가 없는지 검사합니다. Stepper·Walker·Gatherer·Follower이면 primary 지위를 제거합니다.
- Stepper : 암묵적 수치 반복자 $N$에서 시작해, “모든 이후 쓰기가 단항 $\pm$ 또는 이항 $+,-,\times,/$ 의 직접 자기 갱신”이고 의존성이 고정값 또는 다른 stepper에만 있는 변수를 고정점 반복으로 확장합니다.
- Container vs Organizer vs Fixed : 컬렉션 $v$에 대해 구성 이후 변경 $E_c$에서 증명된 순열(permutation) 이벤트 $P_c$를 뺀 나머지가 비어 있지 않으면 Container, 비어 있고 순열이 있으면 Organizer, 완전한 생명주기가 확인되면 Fixed value로 결정합니다.
마지막에 배출 규칙이 다중 라벨을 정리합니다. Fixed value 이외의 역할과 Temporary가 공존하면 Temporary를 억제하고, 그렇지 않으면 Temporary가 Fixed value를 억제합니다. 멤버 변수는 Temporary·Gatherer·Most-wanted holder를 받지 않습니다.
📦 2. 코퍼스 규모와 분포
CodeParrot GitHub-Code에 계약을 적용하고 이전의 역할 강화 서브셋(Ruby 포함)과 합쳐 다음 코퍼스를 얻습니다.
| 항목 | 값 |
|---|---|
| 파일 | 126,926 (C 32,492 / C++ 31,910 / JS 29,673 / Python 32,798 / Ruby 53) |
| 물리 라인 | 14,624,580 |
| 고유 변수 | 3,525,530 (지역 2,428,645 / 매개변수 865,797 / 멤버 231,088) |
| 역할 보유 변수 | 1,737,758 / 역할 없음 1,787,772 |
| 분할 | 역할·언어로 층화한 5개 폴드, exact-source·클론 그룹(122,458개)은 폴드를 넘지 않음 |
역할 분포는 극도로 불균형합니다. Fixed value가 전체 역할 멤버십의 74.4% 를 차지하는 반면 Follower와 Organizer는 각각 724개, 747개뿐입니다. 다중 역할 변수는 9,866개이며 가장 큰 겹침은 fixed value–walker(5,665개)입니다.
👤 3. 사람 평가와 그 한계
660개 층화 표본(역할당 추출기 양성 20개 + 이름이 역할을 암시하는 비양성 20개 + 무역할 220개)에 대해 한 명의 주석자가 11개 역할 또는 “no role”을 부여했습니다.
| 역할 | Precision | Recall | F1 |
|---|---|---|---|
| Most-wanted holder | 0.905 | 1.000 | 0.950 |
| One-way flag | 1.000 | 0.808 | 0.894 |
| Walker | 1.000 | 0.786 | 0.880 |
| Fixed value | 0.830 | 0.607 | 0.701 |
| Most-recent holder | 0.667 | 0.467 | 0.549 |
| 마이크로 평균 | 0.855 | 0.678 | 0.756 |
표본이 의도적으로 역할을 균형 잡고 음성을 의미적 사전으로 강화했기 때문에, 이 점수는 코퍼스 전체의 정밀도·재현율 추정치가 아니라 선택된 서브셋의 특성입니다. 논문은 이를 한계로 명시하며, “추출기 라벨 예측”과 “검토된 편집에 대한 민감도”를 구분해 보고합니다.
💡 Key Takeaway 주석은 실행 없는 정적 계약으로 만들어지므로 대규모·다국어로 확장되지만, 지원되는 정적 패턴에만 커버리지가 한정되고 역할마다 품질이 다릅니다(특히 most-recent holder). 이후의 모든 프로브 결과는 “자동 라벨을 복원하는가”로 읽어야 하며, 논문도 그렇게 표현합니다.
매칭 쌍 예측(Matched Prediction)과 진단 Readout
표현 분석의 첫 단계는 “모델 표현에서 역할 주석을 얼마나 복원할 수 있는가” 입니다. 그런데 역할은 표면 단서와 상관되므로, 양성·음성이 표면적으로 너무 다르면 프로브는 역할이 아니라 표면을 배웁니다. 논문은 이를 매칭 쌍과 진단 readout 위치로 통제합니다.
🎯 1. 매칭 음성 선택
주석된 양성 변수 하나마다 같은 언어, 같은 선언 종류(지역/매개변수/멤버) 이면서 해당 역할 주석이 없는 변수를 짝지어 줍니다. 검색은 표준화된 문맥 길이, 출현 횟수, 이름 길이·모양, 반복문·분기·대입·호출 수, 파서 상태, 식별자 철자 유사도로 후보를 순위화하며, 같은 소스 그룹의 후보는 제외합니다.
| 평가 집단 | 규모 |
|---|---|
| 표현 피팅 | 훈련 5,321쌍 / 검증 9,547쌍 (Test와 소스 그룹 분리) |
| 매칭 Test | 4,238쌍 (11개 역할, C/C++/JS/Python) |
| 반사실 Test | 1,698쌍 (948 소스 그룹) |
| 중립 이름 Test | 역할당 100쌍 |
Appendix L의 더 넓은 sweep에서는 neighboring-role(경쟁 역할을 가진 음성), same-context(같은 문맥 안의 다른 바인딩), hard-mined(타깃 마스킹 코드에 로지스틱 분류기를 훈련해 채굴) 음성 전략도 비교하지만, 본문 비교는 매칭 음성으로 훈련합니다.
📍 2. 진단 readout: “선택된 연산 직후”에서 읽기
디코더 전용 모델은 인과적 어텐션을 쓰므로, 대입문 best = score에서 식별자 best의 표현은 그 뒤에 오는 우변 표현식을 아직 볼 수 없습니다. 그런데 역할을 결정하는 것은 바로 그 우변과 갱신 관계입니다. 그래서 논문은 선택된 문장 또는 반복문·조건문 헤더 뒤에 타깃 변수 참조를 삽입하고 그 위치의 상태를 읽습니다(그림에서는 print(v)와 같은 readout으로 예시).
이 선택이 얼마나 중요한지는 Appendix H의 readout 비교가 보여 줍니다. 두 번째 지정 레이어에서 검토된 편집에 대한 잔차 쌍 정확도는:
| Readout 위치 | 쌍 정확도 |
|---|---|
| 원래 식별자 위치(native identifier) | 0.495–0.594 (거의 우연) |
| 문장 끝(statement end, 입력 수정 없음) | 0.790–0.915 |
| 삽입된 식별자(diagnostic identifier) | 0.856–0.920 |
즉 같은 모델, 같은 편집이라도 어디서 읽느냐에 따라 민감도가 우연 수준에서 0.9 이상으로 달라집니다.
💡 Key Takeaway 코드 표현을 프로브할 때 “변수 이름 토큰”을 읽는 것은 인과 어텐션 때문에 역할을 결정하는 정보가 아직 도착하지 않은 위치를 읽는 셈입니다. 진단 readout은 이 문제를 피하지만, 입력에 텍스트를 추가하므로 이후 모든 결과는 이 readout 조건 아래의 결과입니다.
네 가지 예측기: 잔차 프로브 · 재구성 프로브 · 64피처 프로브 · 단일 SAE 피처
논문은 “SAE가 역할 정보를 잃는가?”라는 질문을 두 가지 손실 원인으로 분해합니다. 하나는 SAE 재구성 자체의 손실이고, 다른 하나는 읽기를 피처 하나로 제한해서 생기는 손실입니다. 네 가지 예측기가 이 둘을 분리합니다.
🧮 1. 예측기 정의
SAE는 잔차 활성 $h$를 희소 피처 벡터 $z = \mathrm{enc}(h)$로 인코딩하고 선형 디코더로 $\hat{h} = W_{\mathrm{dec}}^\top z$를 재구성합니다.
| 예측기 | 입력 | 분리하는 요인 |
|---|---|---|
| 잔차 프로브(Residual probe) | 잔차 활성 $h$ 위의 ridge 회귀 | 상한(참조) |
| SAE 재구성 프로브 | $\hat{h}$ 위의 ridge 회귀 | 재구성 손실만 |
| Top-64 SAE 프로브 | 훈련 AUROC 상위 64개 SAE 좌표 위의 ridge 회귀 | 피처 제한(64개) |
| 단일 SAE 피처 | 검증으로 고른 한 좌표의 값(극성 고정) | 피처 제한(1개) |
피팅 규칙은 고정되어 있습니다. 훈련 집합이 표준화(좌표 표준편차 하한 $10^{-6}$, 차원 제곱근으로 나눔)·피처 순위($\max(\mathrm{AUROC}, 1-\mathrm{AUROC})$)·극성을 정하고, 검증 집합이 ridge 벌점(${10^{-6},10^{-4},10^{-2},1,100}$), 단일 피처, 결정 임계값(민감도 − 거짓양성률 최대화)을 고릅니다. 모든 피팅은 평가 전에 동결됩니다.
🖥️ 2. 다섯 개 모델–SAE 시스템
| 모델 | SAE 릴리스 | 레이어 |
|---|---|---|
| Gemma 2 2B | Gemma Scope (gemma-scope-2b-pt-res-canonical, width 16k) |
6, 13, 17, 22 |
| Gemma 3 4B | Gemma Scope 2 (gemma-scope-2-4b-pt-res, width 65k) |
9, 17, 22, 29 |
| Gemma 3 12B | Gemma Scope 2 (gemma-scope-2-12b-pt-res, width 65k) |
12, 24, 31, 41 |
| Llama 3.1 8B | Llama Scope (llama_scope_lxr_32x) |
8, 16, 21, 27 |
| Qwen3.5 9B | Qwen-Scope (qwen-scope-3.5-9b-base-w64k-l100) |
8, 16, 21, 27 |
레이어는 미리 지정된 4개를 Test 기반 선택 없이 평균합니다.
📊 3. 결과: 피처 제한의 비용
| 예측기 | 매칭 AUROC | 반사실 쌍 정확도 |
|---|---|---|
| 잔차 프로브 | 0.906–0.913 | 0.813–0.877 |
| SAE 재구성 프로브 | 0.857–0.881 | 0.739–0.784 |
| Top-64 SAE 프로브 | 0.853–0.878 | 0.722–0.753 |
| 단일 SAE 피처 | 0.722–0.782 | 0.622–0.713 |
(값은 5개 모델 평균의 범위, 각 모델은 11개 역할 × 4개 레이어를 균등 가중)
- 역할·모델·레이어를 균등 평균한 AP는 잔차 프로브 0.90, 단일 피처 0.72 이며 상수 점수 AP는 0.50입니다.
- 재구성 프로브와 Top-64 프로브는 단일 피처와의 격차 대부분을 메웁니다. 즉 단일 피처 성능이 낮은 주된 이유는 “좌표 하나로 제한”한 것이지 SAE가 정보를 통째로 버린 것은 아닙니다.
- 그러나 재구성 프로브는 반사실 민감도에서 잔차 프로브보다 4.0–12.3%p 낮고, 5개 모델 모두에서 쌍 95% 소스 그룹 부트스트랩 구간이 0을 제외합니다. 선형 재구성이 역할 변경 편집에 반응하는 성분의 일부를 잃는다는 뜻입니다.
💡 Key Takeaway “SAE 피처 하나가 개념을 표현한다”는 기대는 변수 역할에서는 충족되지 않습니다. 다만 그 손실은 대부분 단일 좌표 제한에서 오고, SAE 재구성 자체는 매칭 예측은 잘 보존하되 행동을 바꾸는 편집에 대한 민감도를 일부 잃습니다. 매칭 AUROC만 봐서는 이 차이가 드러나지 않습니다.
표면(Lexical) 베이스라인과 중립 이름 변경 통제
프로브가 높은 점수를 얻어도 그것이 변수 이름이나 주변 코드 토큰만으로도 가능한 일이라면 “모델이 역할을 표현한다”고 말하기 어렵습니다. 논문은 두 종류의 표면 베이스라인과 역할 보존 이름 변경 실험으로 이를 점검합니다.
🔤 1. 매칭 쌍 위의 표면 베이스라인
| 베이스라인 | 입력 | 모델 |
|---|---|---|
| 이름(N) | 타깃 이름의 문자 2–5-gram | TF–IDF + 로지스틱 회귀 (12,000 피처 상한) |
| 코드 접두(C) | 진단 토큰까지의 코드 접두 문자 3–5-gram | TF–IDF + 로지스틱 회귀 (30,000 피처 상한) |
같은 훈련 쌍으로 피팅하고 검증으로 $C \in {0.1, 1, 10}$과 임계값을 고릅니다. 결과적으로 잔차 프로브는 모든 역할–모델 조합에서 두 베이스라인을 상회합니다. 흥미로운 점은 코드 접두 베이스라인이 단일 SAE 피처와 경쟁할 만하다는 것입니다. Most-wanted holder에서 코드 베이스라인 AP 0.90, 단일 피처 0.75, 잔차 프로브 0.95입니다. 반사실 편집에서도 코드 접두 베이스라인은 쌍 정확도 0.750에 이르고(이름은 바뀌지 않으므로 이름 베이스라인은 0.500), 잔차 프로브(0.813–0.877)만이 이를 분명히 넘습니다.
Appendix F의 전체 코퍼스(352만 변수, 매칭 없음) 실험에서는 이름만으로 macro AP 0.142, 지역 코드 0.487, 결합 0.533을 얻는데, 이는 자동 라벨이 표면 단서와 상당히 상관됨을 보여 주며 매칭 쌍 설계가 왜 필요한지 설명합니다.
✏️ 2. 중립 타깃 이름 변경(Neutral Target Renaming)
역할을 보존하는 통제입니다. 역할당 100개 Test 쌍을 점수를 보지 않고 고른 뒤, 양성·음성 양쪽 모두의 타깃 바인딩 모든 출현을 역할과 무관한 해시 기반 중립 식별자로 바꿉니다. 다른 식별자·주석·구현 단서는 그대로 두므로 타깃 철자에 대한 민감도만 분리됩니다. 피팅과 임계값은 고정합니다.
| 예측기 | 변경 전 AUROC | 변경 후 AUROC |
|---|---|---|
| 잔차 프로브 | — | 0.878–0.887 (−0.6 ~ −1.7%p) |
| 단일 SAE 피처 | — | 0.693–0.760 (−0.8 ~ +0.1%p) |
| 코드 표면 | 0.740 | 0.723 |
| 이름 표면 | 0.602 | 0.492 (우연 수준) |
잔차 프로브는 순위 성능을 대부분 유지합니다. 다만 동결된 이진 결정은 양성의 10.8%, 음성의 12.4%에서 바뀌고 균형 정확도는 0.830에서 0.809로 떨어집니다. 안정적인 순위와 안정적인 임계값 결정은 별개입니다.
💡 Key Takeaway 모델 표현은 변수 이름에 조금 의존하지만(1–2%p), 이름이 사라져도 대부분의 판별력을 유지합니다. 반면 “코드 주변 텍스트”는 꽤 강한 베이스라인이어서, 단일 SAE 피처 수준의 성능은 표면 단서로도 설명될 수 있습니다.
반사실 편집(Counterfactual Edits)과 순위 vs 분류의 괴리
매칭 예측은 “라벨과 상관된 무언가”를 복원하는지만 말해 줍니다. 그것이 역할을 정의하는 행동인지 확인하려면, 역할을 제거하는 소스 편집에 점수가 반응해야 합니다.
🔁 1. LLM 검토 역할 변경 편집
적격 소스 패턴에서 타깃 역할을 없애는 편집(예: stepper의 자기 갱신을 외부 입력 대입으로 바꾸기, gatherer의 누적을 덮어쓰기로 바꾸기)을 생성하고, LLM 리뷰어가 원본이 실제로 그 역할을 갖는지, 편집이 그 역할을 제거하는지, 소스 수준에서 유효한지를 바인딩 수명 전체(변이·별칭 포함)를 보며 판정합니다. 최종 검토(GPT-5.6 Terra)는 보류 333건 중 330건을 수용, 3건을 거부했고(1건은 역할 보존, 2건은 원본 역할 라벨 오류), 그 결과 948 소스 그룹의 1,698쌍이 남습니다. 이 판정은 사람의 독립 판정이나 실행 검증이 아니며 리뷰어 간 일치도도 측정되지 않았다는 점을 논문은 명시합니다.
⚖️ 2. 쌍 순위 정확도 vs 고정 임계값 분류
쌍 순위 정확도는 원본 점수가 편집본 점수보다 높은 빈도입니다(동점은 절반).
\[\mathrm{PairedAcc} = \mathbb{E}\big[\mathbf{1}(s_{\mathrm{original}} > s_{\mathrm{edit}}) + \tfrac{1}{2}\,\mathbf{1}(s_{\mathrm{original}} = s_{\mathrm{edit}})\big]\]| 지표 | 잔차 프로브 |
|---|---|
| 쌍 순위 정확도 | 0.813–0.877 |
| 편집된 음성의 거짓 양성률(검증 임계값) | 0.684–0.713 |
| 균형 정확도 | 0.610–0.637 |
즉 원본과 편집본을 나란히 놓으면 80% 이상 올바르게 순위를 매기지만, 편집본 하나만 보여 주면 68–71%는 여전히 “역할 있음”으로 분류합니다. 점수는 편집에 반응하되, 그 반응이 임계값을 넘길 만큼 크지 않은 경우가 많습니다.
🌐 3. 언어와 구현에 따른 차이
- 다국어 훈련 상태에서 stepper AUROC는 JavaScript 0.682 ~ Python 0.972 로 크게 갈립니다. Gatherer와 one-way flag는 네 언어 모두에서 높습니다.
- 단일 피처 stepper는 for-loop 갱신과 기타 갱신에서 AUROC는 비슷하지만(0.728 vs 0.757) 검증 임계값에서의 재현율은 0.895 → 0.624 로 떨어집니다.
- Most-wanted holder는 guarded replacement와 min/max selection 모두에서 잔차 프로브 재현율이 높습니다(0.994, 0.966).
- Walker의 implicit(전부 Python) vs structural(50개 중 49개가 C/C++) 대조는 언어와 얽혀 있어 구현 효과로 귀속할 수 없습니다.
💡 Key Takeaway “높은 순위 정확도”와 “쓸 만한 분류기”는 다릅니다. 역할 변경 편집은 점수를 낮추지만 결정을 뒤집을 만큼은 아닌 경우가 많아, 이 프로브를 그대로 모니터로 쓰면 거짓 양성이 많습니다. 또한 복원 가능성은 언어·구현 조건에 따라 달라지므로 “모델이 stepper를 표현한다”는 문장에는 조건이 붙어야 합니다.
생성 개입: Activation Addition과 Direction Removal
표현에서 역할을 읽어낼 수 있다고 해서 그 방향이 생성을 제어하는 것은 아닙니다. 논문은 MBPP(Mostly Basic Programming Problems)에서 SAE 피처 방향으로 두 종류의 개입을 수행하고, 역할 주석 변화와 테스트 통과를 함께 측정합니다.
➕ 1. 참조 조건부 유도(Reference-conditioned Induction)
피처 $f$의 디코더 행 $d_f = W_{\mathrm{dec}}[f,:]$를 생성되는 모든 토큰의 잔차 스트림에 $\alpha d_f$만큼 더합니다. 참조 해답($R_{\mathrm{ref}}$)과 무개입 생성($R_0$)에 추출기를 돌려 역할 비트를 얻고, 코호트를 정의합니다.
\[\mathrm{Sufficiency}_r = P\big(R_{\alpha^\star} = 1 \mid R_{\mathrm{ref}} = 1,\; R_0 = 0\big)\]“참조에는 있는데 기본 생성에는 없는 역할”을 개입이 만들어 내는 빈도입니다. 적격 예제를 보정/Test로 반씩 나누고, $\alpha^\star$는 사전 정의된 강도 그리드에서 보정 집합의 sufficiency를 최대화하도록 고정합니다. 참조에도 없는 역할을 만들어 내는 spurious induction $P(R_{\alpha^\star}=1 \mid R_{\mathrm{ref}}=0, R_0=0)$ 도 별도 코호트로 측정합니다(참조와 다른 역할을 써도 정답일 수 있으므로 정확성은 따로 평가).
➖ 2. 참조 조건부 억제(Reference-conditioned Suppression)
정규화한 방향 $\hat{d}_f$를 잔차 스트림에 쓰는 모든 가중치 행렬에서 직교화(orthogonalization)로 제거합니다(Arditi et al., 2024 방식).
\[W_{\mathrm{out}}' = W_{\mathrm{out}} - \big(W_{\mathrm{out}}\hat{d}_f^{\top}\big)\hat{d}_f\] \[\mathrm{Necessity}_r = P\big(R_{\mathrm{ort}} = 0 \mid R_{\mathrm{ref}} = 1,\; R_0 = 1\big)\]“참조와 기본 생성 모두에 있던 역할”이 제거 후 사라지는 빈도입니다. 강도 보정이 없으므로 모든 적격 예제를 씁니다. 다만 이 전역 제거는 프롬프트 처리까지 바꾸므로 생성 시점 addition과는 섭동 범위가 다릅니다.
🎲 3. 통제와 평가
| 항목 | 설정 |
|---|---|
| 모델 | Gemma 2 2B, Gemma 3 4B/12B (피처 규모 실험) |
| 타깃 | 2B/4B 각 11개 SAE 피처, 12B 9개 (5개 역할) |
| 통제 | 타깃당 같은 레이어의 무작위 SAE 피처 10개 |
| 과제 | 121개 MBPP 과제 합집합, 역할별 코호트 |
| 정확성 | Pass@1 (제공된 3개 assertion 통과 여부) |
| 기본 통과 수 | 33/121, 14/121, 67/121 |
💡 Key Takeaway Sufficiency·Necessity는 모두 “추출기가 역할 주석을 바꾸었는가” 를 재는 운영적 점수입니다. 역할 비트는 구현을 기술할 뿐이므로, 주석이 바뀌었다는 것과 프로그램이 여전히 맞는다는 것은 반드시 따로 확인해야 합니다. 논문의 핵심 설계는 이 둘을 분리하지 않고 동시 결과(joint outcome) 로 보는 것입니다.
개입 결과: 주석은 바뀌지만 정확성은 무너진다
📉 1. 제거(removal): 인과적 관여는 있으나 특이성이 낮다
Gemma 2 2B에서 일부 피처는 높은 necessity를 보입니다. Gatherer 억제는 무작위 통제 범위를 넘고, most-wanted holder는 1.00이지만 통제 최댓값과 동률입니다. 그런데 이들의 Pass@1 손실은 −0.33, −0.29 로, 억제가 역할 특이적 제어라기보다 생성 전반의 붕괴를 반영할 수 있습니다.
모든 선택 피처로 넓히면:
| 모델 | 제거로 주석 사라짐 | 그중 테스트 통과 | 기본·개입 모두 통과 |
|---|---|---|---|
| Gemma 2 2B | 41/91 | 2/91 | 0 |
| Gemma 3 4B | 72/109 | 4/109 | 3 |
| Gemma 3 12B | 131/187 | 15/187 | 13 |
“주석 변화 + 테스트 통과”의 비율은 매칭 무작위 통제보다 제거에서 1.3–3.7%p, addition에서 0.9–1.9%p 높지만, 과제 단위 부트스트랩 95% 구간 여섯 개 모두 0을 포함합니다.
📈 2. 추가(addition): 약한 충분성, 부분적 구조 변화
양의 스티어링의 sufficiency는 무작위 범위를 넘는 경우에도 0.10–0.19 에 그칩니다. 그러나 Tree-sitter 패턴 빈도로 본 역할 인접 구문은 움직입니다.
| 역할 | 대표 구문 | G2 2B 양의 스티어링 | G3 4B 양의 스티어링 |
|---|---|---|---|
| Stepper | range 호출 |
+20.3%p (59쌍) | +9.3%p (54쌍) |
| Gatherer | 복합 대입(+=) |
+1.9%p (107) | +2.3%p (44) |
| Most-wanted holder | if 문 |
−4.3%p (92) | +17.6%p (17) |
구조적 상관물이 늘어난다고 해서 완전한 역할이 유도된 것은 아니며(패턴은 역할 정의가 아님), 두 출력이 모두 깨끗하게 파싱되는 쌍만 집계되므로 Gemma 3 4B 제거는 gatherer 4/30, stepper 11/48 쌍만 남아 일반화가 제한됩니다.
🔒 3. 정확성 제약 보정은 대개 “0”을 고른다 (Appendix N)
프로브 방향과 SAE 방향을 같은 예산으로 비교하는 정규화 실험입니다. 한 레이어의 생성 토큰 위치에 중앙값 잔차 norm의 1%, 3%, 10%(또는 0)를 더하고, 보정 정확성을 5%p 이상 잃지 않는 조건 아래에서 “유도 + 테스트 통과”의 평균을 최대화하는 강도를 고릅니다.
- 11개 완료된 모델–역할 셀 중 10개가 강도 0(개입 없음) 을 선택합니다.
- 유일한 비영 셀(Gemma 2 2B most-wanted holder, 10%)에서 프로브·SAE 방향은 5개 적격 과제 중 3/5, 4/5에서 역할을 유도하지만, 테스트를 통과하는 유도는 각각 1/5 로 무작위 잔차 방향(1/5)과 같습니다.
- Gemma 3 12B stepper 파일럿(48 보정 / 144 Test 과제, 5개 프로브 피팅)에서도 4개 피팅이 0을, 1개가 1%를 선택하며, 그 피팅에서 유도는 2/53에 불과합니다.
🖼️ 4. 질적 사례
292개 타깃–과제 쌍 중 실패→통과 전이는 8건(6개 모델–과제)입니다. Figure 1의 사례처럼 most-wanted holder 피처 스티어링이 스텁(stub)을 실제 탐색 코드로 바꾼 수리도 있지만, 어떤 수리는 테스트를 모두 통과하면서도 타깃 역할 주석은 0으로 남고, 무작위로 뽑은 6개 사례는 모두 테스트에 실패합니다. 선택된 성공 사례가 타깃 역할이 개선의 원인임을 입증하지는 않습니다.
💡 Key Takeaway 역할 방향으로 밀거나 지우면 주석은 쉽게 바뀌지만, 그 변화 대부분은 프로그램을 망가뜨립니다. 정확성을 조건으로 걸면 무작위 방향보다 나을 것이 없고, 보정 절차는 “아예 개입하지 않는 것”을 선호합니다. 이는 “예측력 있는 SAE 피처가 스티어링에 효과적이라는 보장은 없다”는 선행 관찰(Tahimic & Cheng, 2025)을 변수 역할로 확장한 결과입니다.
벤치마크가 분리하는 세 가지: 복원 가능성 · SAE 충실도 · 정확성 보존 제어
이 논문의 가장 중요한 구조적 기여는 흔히 하나로 뭉뚱그려지는 세 질문을 서로 다른 측정으로 분리한 것입니다.
🧭 1. 세 층위와 측정 도구
| 층위 | 질문 | 측정 | 핵심 결과 |
|---|---|---|---|
| 복원 가능성(Recoverability) | 표현에서 역할 주석을 읽어낼 수 있는가? | 매칭 쌍 AP/AUROC, 표면 베이스라인, 중립 이름 변경 | 잔차 프로브 AUROC ~0.91, 이름 변경에 강건 |
| SAE 충실도(Fidelity) | SAE가 그 구분을 얼마나 보존하는가? | 재구성·64피처·단일 피처 프로브, 반사실 쌍 정확도 | 결합하면 격차 대부분 회복, 그러나 편집 민감도 −4~−12%p |
| 정확성 보존 제어(Control) | 방향으로 생성을 바꾸면서 맞는 코드를 유지할 수 있는가? | Sufficiency/Necessity + Pass@1 + 무작위 통제 | 주석 변화 ≫ 통과 동반 변화, 통제 대비 무유의 |
각 층위의 “예”가 다음 층위의 “예”를 함의하지 않습니다. 복원이 잘 되어도 SAE 단일 피처는 그것을 담지 못하고, SAE 피처가 역할과 상관되어도(Appendix O의 Neuronpedia 문맥은 극값·Boolean·인덱싱 같은 넓은 개념을 보여 줌) 제어에 쓰이지는 않습니다. 실제로 Appendix O의 피처들은 매칭 AUROC가 0.85–0.95여도 반사실 AUROC는 0.35–0.54에 머뭅니다.
📝 2. 프롬프트 기반 행동 인식과의 대비 (Appendix J)
표현 프로브와 별도로 12개 사전학습 체크포인트(Llama 3.2/3.1, Gemma 3 1B–27B, Qwen3/3.5)에 역할 정의와 코드를 주고 Yes/No를 묻는 행동 평가도 수행합니다. $s = \log P(\texttt{Yes}) - \log P(\texttt{No})$ 로 채점하면 Gemma 3 27B가 8-shot에서 macro 정확도/AP 72.1/77.2%로 최고이고, 크기가 커질수록 오르지만 Qwen3 1.7B/4B/8B는 데모 추가 이득이 유의하지 않습니다. 잔차 프로브의 ~0.91 AUROC와 비교하면, 모델이 내부에 가진 정보와 프롬프트로 끌어낼 수 있는 정보 사이에 간극이 있습니다.
⚠️ 3. 한계 (논문이 명시한 것)
- 주석 품질이 역할마다 크게 다르며(특히 most-recent holder), 사람 평가는 층화 표본이라 코퍼스 전체 정밀도·재현율을 추정하지 못하고 주석자 간 신뢰도도 미측정.
- 디코딩은 모델당 4개 레이어, 하나의 소스 그룹 분할에 한정되며 불확실성은 피팅된 예측기에 조건부.
- 코퍼스가 개발 데이터를 포함하고 저장소 수준 홀드아웃이 없으며, 타깃 이름 변경은 다른 어휘 단서를 남김.
- 개입은 작고 겹치는 코호트와 유한한 프롬프트 노출 테스트를 쓰며, 역사적 피처 규모(scale)의 출처가 미해결(22개 중 20개가 선택 산출물의 훈련 양성 최댓값과 불일치)이라 모델 간 차이를 크기나 공통 선량에 귀속할 수 없음.
- LLM 리뷰어는 원본 주석과 제안 편집을 보고 판정하므로 블라인드가 아님.
💡 Key Takeaway 이 벤치마크는 “모델이 X를 안다”는 주장을 읽기(recoverability) → 분해(fidelity) → 쓰기(control) 의 세 시험으로 쪼개고, 각 단계에 표면 베이스라인·역할 변경 편집·무작위 통제라는 반증 장치를 붙입니다. 변수 역할에 대해서는 첫 시험은 통과, 둘째는 부분 통과, 셋째는 아직 통과하지 못했다는 것이 이 논문의 답입니다.