AI를 작게 구현하다.
이 문서는 일종의 경이로움, 옛 의미에서의 경이로움을 보고합니다. LLM(대규모 언어 모델) 지원 작업을 4시간 만에 우리는 기계 학습의 일상적인 핵심 요소들—나이브 베이즈 (Naive Bayes), 최근접 이웃 (nearest neighbor), tf-idf, 이산화 (discretization), 순위 지정 (ranking)—을 gawk를 사용해 400줄 미만으로 재구축했습니다. 모든 스크립트는 한 화면에 들어옵니다. 전체 시스템은 오후 안에 읽을 수 있으며, 그 비용은 산업용 사촌격의 시스템들에 비해 극히 일부 수준입니다. 이를 가능하게 한 방법론은 단 하나의 문장으로 요약됩니다: “좋다—이제 더 작게 써라.”
이러한 기행 뒤에는 하나의 제안이 있습니다. AI 도구 코딩은 코드가 단순해질 때까지 계속되어야 한다는 것입니다. 달리 말하면, 코드가 단순할 때 비로소 끝난 것이 아닙니다. 따라서 스크립팅은 시작이자 동시에 끝입니다. 먼저 작은 스크립트로 문제의 본질을 이해하는 것부터 시작하십시오. 질문이 요구하는 만큼 많은 언어, 도구, CPU를 사용하며 중간 과정을 탐색하십시오. 그런 다음 돌아와서 가능한 한 유용하게 단순한 것으로 마무리해야 합니다. 마지막에 작성된 스크립트는 프로토타입이 아닙니다. 그것은 기록된 이해 그 자체입니다.
이는 중요합니다. 우리의 일상적인 데이터 작업—이것을 분류하고, 저것의 순위를 매기고, 이런 형태의 행(row)을 찾는 것—은 현재 아무도 읽지 않은 수백만 줄의 코드 스택에 의존하고 있으며, LLM이 생성한 코드는 이 홍수를 더욱 악화시키고 있습니다. 우리는 매일 설명할 수 없는 시스템들을 운영합니다. 하지만 이러한 작업들의 핵심은 작습니다: 나이브 베이즈는 20줄이고; 최근접 이웃은 30줄입니다. 나머지는 내용(content)이라기보다는 형식적인 절차에 가깝습니다. 우리는 그 내용을 원합니다.
다음 내용은 먼저 주장 자체—지능의 요점은 '덜 지능적'이라는 것—그리고 그것이 함축하는 표준, 그 배경 역사, 이에 대한 열 가지 논거, 그리고 공정하게도 사용하지 말아야 할 경우에 대해 다룹니다. 이 문서는 도구(gawk)와 한 시간 분량의 학습 계획으로 마무리됩니다.
이제 급진적인 진술을 합니다. 우리는 더 간단한 방법이 충분할 때에도 습관적으로 복잡한 방법을 추구하도록 재촉받습니다. 우리는 왜 그런지 질문하고, 이에 반대해야 합니다. 지능의 목적은 더 많은 지능을 생산하는 것이 아닙니다. 그것은 '덜함'을 생산하는 것입니다: 주의를 기울일 것이 적고, 따라야 할 단계가 적으며, 한 번에 머릿속에 담아둘 부분이 적은 상태 말입니다.
반대되는 베팅의 가장 거대한 버전을 고려해 보십시오. AGI(범용 인공지능)에 대한 현대적인 탐색은 Dario Amodei가 2017년에 작성한 메모에서 'Big Blob of Compute 가설'이라고 불린 것에 의존하고 있습니다. 이 가설은 지능적인 행동이 주로 학습을 통해 형성된, 최소한으로 구조화된 거대한 연산의 덩어리이며, 정교한 알고리즘들은 대부분 동일한 연산을 재배열하는 것뿐이라는 것입니다. Kevin Roose가 보도하기를, 그 메모는 AI 경쟁을 시작하게 만든 에세이입니다. 이제 청구서를 살펴보십시오: 2025년에 발표된 AI 데이터센터 구축 비용만 반조(half a trillion dollars) 달러에 달하며 계속 증가하고 있습니다. 우리는 이 '덩어리'가 잘 되기를 바랍니다. 하지만 기록으로 남겨야 할 것은, 우리 대부분이 그 자체의 챔피언들이 실존적 위험이라고 부르는 터무니없이 비싼 목표를 쫓고 있는 것이 아니라는 점입니다. 우리 대부분은 해야 할 일이 있습니다—금요일까지 마감되는 AGI보다 작은 수천 가지의 과제들 말입니다.
머리부터 시작합시다. 인간의 주의력은 고정되어 있고 적은 예산입니다. 끊임없이 증가하는 새로운 아이디어의 흐름으로 이를 공격하면 곧 소진됩니다. 따라서 진정한 전문성은 반대 방향으로 작동합니다. Larkin, McDermott, Simon와 Simon은 Science (1980)에서 전문가들은 전문가인 이유가 그들의 특징 추출기(feature extractors)가 가장 통찰력 있는 몇 가지 것만을 보고하기 때문이라고 말했습니다. 초보자에게 체스판을 보여주면 검은색과 흰색 조각들이 격자에 흩어져 있는 것을 봅니다. 하지만 마스터에게 보여주면, 그들은 단 하나의 것—퀸이나 룩 중 하나를 가져가기 때문에 방어할 수 없는 나이트 포크(knight fork)—만을 봅니다. 수년간의 공부는 마스터에게 더 많이 보는 법을 가르치지 않았습니다. 그것은 마스터에게 적게 보는 법, 그리고 '적절하게' 적게 보는 법을 가르쳤을 뿐입니다. 성숙한 지능이란 압축(compression)입니다.
그렇다면 왜 우리는 계속 추가하는 것일까요? 부분적으로는 빼기(subtraction)가 사각지대이기 때문입니다. Adams 등은 (Nature, 2021)에서 사람들이 체계적으로 감산적 변화를 간과한다는 것을 보여주었습니다. 무언가를 개선하라고 요청받으면, 우리는 추가할 수 있는 것에 손을 대고, 심지어 무엇인가를 제거하는 옵션조차 거의 생성하지 않습니다. 더 단순한 디자인은 가치 면에서 실패하는 것이 아니라, 고려되지 않음으로써 실패합니다.
부분적으로는, 단순함과는 달리 복잡성이 더 잘 팔리기 때문입니다. 이 저장소에는 판매하는 거대 소프트웨어 기업이 없습니다. 왜냐하면 여기에는 팔 것이 아무것도 없기 때문입니다. 코드가 너무 간단해서 스스로 작성할 수 있고, CPU 요구 사항도 너무 작아서 구매해야 할 방대한 인프라가 없기 때문입니다. 전체 비즈니스 모델은 여러분의 문제가 50줄 이상의 코드와 하나의 코어보다 더 많은 자원을 필요로 한다고 믿게 만드는 데 달려 있습니다. 복잡성에 대한 모든 권장 사항을 종종 그렇듯이 — 영업 사원들의 발표(sales pitch) — 로 취급하고, 먼저 감산적 질문을 던지십시오. 무엇을 제거할 수 있을까요?
또 다른 관점, 어쩌면 가장 좋은 관점입니다. 이것은 복잡성에 대한 전쟁이 아닙니다. 복잡성에게는 역할이 있습니다. 그 역할은 저 너머의 단순함을 찾아내는 것입니다. 올리버 웬델 홈즈(Oliver Wendell Holmes)는 이렇게 말한 것으로 알려져 있습니다. “나는 복잡성의 이편에 있는 단순함에는 전혀 관심이 없지만, 복잡성의 저편에 있는 단순함에는 내 목숨을 걸겠다.” 생트-엑쥐페리(Saint-Exupéry)는 더 적은 단어로 이를 표현했습니다. 완벽함은 무언가를 더 추가할 것이 없을 때가 아니라, 아무것도 제거할 것이 남지 않을 때 달성된다고 말입니다.
따라서, CPU를 태워버리십시오. 감당할 수 있는 가장 크고 복잡한 분석을 실행하십시오. 하지만 끝난 후에는 하나가 아닌 두 가지를 제시해야 합니다. 첫째는 최첨단(state-of-the-art) 결과입니다. 둘째는 자원의 아주 작은 부분만으로 거의 같은 답을 얻어내는 미세한 기준선(tiny baseline)입니다. 대규모 실행은 지식을 사주고, 소규모 실행은 여러분이 그 지식을 가지고 있음을 증명합니다.
이를 표준으로 선언하십시오. 우리는 결과를 더 이상 단순화하는 방법을 알기 전까지는 이해하지 못합니다. 즉, 그 구성 요소들을 가장 중요한 것부터 덜 중요한 것 순서로 나열하고 어떤 부분이 실제로 작동했는지 소리 내어 말할 수 있을 때까지 이해하지 못합니다. 축소할 수 없는 방법은 아직 이해하지 못한 방법입니다. 단순함은 분석이 시작되는 곳이 아닙니다. 이해가 도달하는 곳입니다.
'작은 도구(small-tool)' 마인드셋에는 탄생 증명서가 있습니다. 1964년 10월 11일자 벨 연구소(Bell Labs) 메모에서 더그 맥일로이(Doug McIlroy)는 다음과 같이 썼습니다:
"우리는 프로그램들을 정원 호스처럼 연결하는 몇 가지 방법을 가져야 합니다. 다른 방식으로 데이터를 처리할 필요가 생길 때마다 또 다른 세그먼트를 끼워 넣을 수 있어야 합니다."
그 메모는 유닉스 파이프(Unix pipe)가 되었습니다. McIlroy는 나중에 이 전체 철학을 세 가지 규칙으로 압축했습니다. 첫째, 한 가지 일만 하고 그것을 잘 수행하는 프로그램을 작성하라. 둘째, 함께 작동하도록 프로그램을 작성하라. 셋째, 텍스트 스트림을 처리하는 프로그램을 작성하라. 왜냐하면 그것이 보편적인 인터페이스이기 때문입니다.
20년 후, 이러한 사고방식은 유명한 대결에서 승리했습니다. 1986년, Jon Bentley의 "Programming Pearls" 칼럼은 Donald Knuth에게 문해형 프로그래밍(literate programming)을 시연하도록 요청했습니다. 과제는 파일에서 가장 흔한 k개의 단어를 출력하는 것이었습니다. Knuth는 맞춤형 트라이(trie)를 중심으로 구축된, 아름답게 문서화된 파스칼어(Pascal)로 이루어진 10페이지 분량의 걸작을 선보였습니다. 초청 심사위원이었던 McIlroy는 그 예술성에 찬사를 보냈습니다. 그러고 나서 그는 이 모든 작업을 단 여섯 줄로 처리했습니다:
tr -cs A-Za-z '\n' | tr A-Z a-z | sort | uniq -c | sort -rn | sed ${1}q
이 거대한 구조(monolith)는 예술이었습니다. 파이프라인은 공학이었습니다. 이 저장소(repo)는 파이프라인 쪽에 무게를 둡니다.
"gawk에서 AI" 역시 예외가 아닙니다. 1996년, Ronald Loui는 자신의 학부 AI 수업 프로젝트가 gawk로 작성한 결과물이 C, C++, 또는 LISP로 작성된 것보다 가장 좋고 일관성이 있다는 보고를 했습니다. 그의 이유는 여전히 유효합니다. AI 프로그래밍은 탐색적(exploratory)입니다. 오늘날의 코드는 내일 재구상되고 폐기되므로, 언어는 재작성을 저렴하게 만들어야 합니다. gawk는 LISP처럼 하나의 통일된 자료 구조(연관 배열, associative array)와 사소한 구문(trivial syntax)을 제공하여, 단순한 블록들이 복잡한 접근 방식으로 구성될 수 있게 합니다. 그리고 AI 프로그래머들은 "곤충이 아닌 정신을 원해야" 합니다. 즉, 실행의 효율성보다는 프로그램의 내용물을 최대화해야 한다는 것입니다. Loui는 단도직입적으로 결론지었습니다. "프로그램하려는 사람의 말을 듣고, 어떻게 프로그램해야 하는지 말하려는 사람의 말을 들으십시오."
다른 베테랑들도 동의합니다. Kernighan은 이 언어가 어떤 언어보다 "가장 큰 가치를 제공한다(most bang for the buck)"고 언급했습니다. 즉, 한 시간 만에 학습할 수 있고, 일반적인 프로그램도 몇 줄에 불과하다는 것입니다.
Robbins와 Beebe는 Classic Shell Scripting에서 다음과 같이 고백했습니다: "우리는 그것을 좋아합니다. 아주 많이." 그리고 gawk 프로그램을 C나 C++로 다시 작성했을 때의 결과물은 보통 훨씬 길고 디버깅하기가 훨씬 어렵다는 점을 지적했습니다.
이 모든 코드는 약 네 시간의 작업으로 완성되었습니다. 표준 LLM 세션과 달리, 생성된 모든 코드는 짧고 탐색하기 쉬웠습니다. 프롬프팅 과정 역시 간단했습니다. 결과는 실제로 실행됩니다. 작다는 것이 핸디캡이 아닙니다. 오히려 작은 크기 덕분에 아예 구현할 수 있었습니다.
성능 또한 그에 미치지 못하지 않습니다. 여기에 있는 모든 도구는 평소 분석가가 사용했을 라이브러리를 기준으로 점검되었습니다. 동일한 파일, 동일한 분할(splits), 동일한 점수 산정 방식을 사용했습니다. 10개의 MOOT 분류 파일(20개 셔플, 50:50 학습:테스트)에 대해 이산화된 숫자(discretized numbers)를 사용한 나이브 베이즈(naive Bayes)는 LightGBM의 84.3% 대비 평균 79.6%의 정확도를 보였습니다. gawk 도구는 10개 파일 중 5개에서 최고 기록을 세우거나 동률이었고, LightGBM은 9개 파일에서 최고 기록이었습니다. 그리고 전체 gawk 실험은 439초 대비 26초 만에 완료됩니다. 희귀 클래스(rare classes)를 가진 텍스트(4개 파일, 약 1% "예")의 경우, tf-idf 피딩을 보완한 나이브 베이즈는 클래스 균형화된 LinearSVC의 65.0 대비 평균 81.7%의 매크로 재현율(macro recall)을 기록하며 네 개 파일 모두에서 승리합니다. 비록 여기서는 SVM 실험 시간이 더 짧아 285초 대비 154초가 걸렸지만 말입니다.
그 수치들을 솔직하게 읽어보십시오. LightGBM이 더 나은 분류기이며, 이는 이 파일들보다 훨씬 큰 데이터에 맞춰진 기본 설정(defaults)으로 실행되고 있습니다. 46개의 학습 행을 맞추고 min_child_samples=20을 사용하도록 요청하면, 깊이가 더 깊은 분할은 불가능하기 때문에 백 개의 두 리프 스텀프(two-leaf stumps)를 구축합니다. 이를 작은 데이터에 맞춰 조정하면 성능이 더욱 높아집니다. 따라서 주장은 gawk가 이긴다는 것이 아닙니다. 주장은 교환 비율입니다. 정확도 몇 퍼센트 포인트를 얻는 대신, 설치하고 읽고 신뢰해야 할 코드가 두 자릿수(two orders of magnitude) 적게 드는 것입니다.
여기서의 방법론적 선례는 이 작업보다 훨씬 오래되었습니다. Cohen은 1995년 저서 『Empirical Methods for Artificial Intelligence』에서, 겉보기에 매우 정교한 방법들조차도 항상 덜 복잡해 보이는 것들과 비교하여 기준을 설정해야 한다고 주장했습니다. 그는 이를 과학적 검증에 대한 "허수아비(straw man)" 접근법이라고 불렀습니다. 우리는 입증할 수 있습니다. 우리가 정교한 방법을 더 단순한 방법과 비교해 본 적이 있을 때마다, 그 단순한 것들 중 유용한 무언가가 있었습니다. 대부분의 경우, 1년 후에는 저희가 그 단순한 접근 방식으로 전환했습니다.
더 단순한 장치로 결과를 재현하는 것은 단순한 공학적 작업에 그치지 않습니다. 그것은 좋은 과학입니다. 어떤 방법을 본질적인 요소만 남기고 분리(strip)하는 재현 과정은, 어느 부분이 지탱하는 핵심이었고 어느 부분이 형식적인 절차였는지를 테스트합니다. 여기에 있는 각 스크립트가 바로 그러한 재현의 예시입니다. 20줄의 코드가 출판된 결과를 복구해낼 때, 참고 구현체의 나머지 만 줄은 비계 구조물(scaffolding)이었음이 드러나고, 그 아이디어 자체가 더욱 명확하게 부각됩니다.
증거 기반 추론을 검토한 철학자 Nancy Cartwright는 유명한 경고를 했습니다. '거기서' 작동했던 것이 '여기서' 작동한다는 보장이 없다는 것입니다. 그곳에서 이곳으로 가는 경로는 절대 문자 그대로의 재사용이 아닙니다. 그것은 추상화(abstraction)입니다. 즉, 이전 작업을 본질적인 특징만 남기고 분리한 다음, 그 특징들을 새로운 영역에 맞게 적응시키는 과정입니다. 이러한 관점에서 볼 때, 우리는 코드를 재사용하는 것을 매우 드물어야 합니다. 대신, 코드 뒤에 숨겨진 원칙을 재사용하는 것이 더 좋습니다. 그리고 이것은 코드 자체에 요구사항을 부과합니다. 즉, 다른 사람들이 그 원칙들을 뽑아 다른 곳으로 가져갈 수 있도록, 그 원칙들을 눈에 보이게 입증해야 한다는 것입니다. 20줄의 투명한 코드가 하나의 원칙을 입증합니다. 반면, 프레임워크는 그것을 숨겨버립니다.
이 관점에 의문을 제기하는 사람들에게는, 소프트웨어 엔지니어링이 이를 계속 재학습하고 있다는 점에 주목해야 합니다. 이 분야는 너무나 다양한 영역을 포괄하는 기업(enterprise)이라서, 다른 곳에서 나온 솔루션들은 이곳에서 작동하기 전에 일상적으로 광범위한 적응이 필요합니다. 이는 로컬 모델 대 글로벌 모델에 관한 문헌에서 길게 문서화된 교훈입니다. 저의 경우로 보자면, 저는 NASA의 소프트웨어 검증 및 유효성 확인(Software Verification and Validation, IV&V) 센터에서 근무하며 문자 그대로의 재사용(verbatim reuse)이 가진 악덕을 배웠습니다. NASA 센터가 광범위한 재사용에 기반한 코드를 전달할 때마다, IV&V 팀은 그 소프트웨어를 테스트하는 팀의 규모를 증가시켰습니다(감소시키지 않았습니다).
이 경험을 통해 우리는 프롬프팅(prompting)에 대해 무언가를 배웠습니다. 우리가 일반적으로 겪는 LLM 지원 코딩 경험은 압도되는 느낌을 받는 것입니다. 작업에 대한 대화량과 그 자체가 되는 코드의 양 모두가 그렇습니다. 여기서는 세션을 다르게 진행했습니다. 무언가가 이해되지 않을 때, 우리는 "명확히 해 주세요(please clarify)"라고 말했고, 더 짧고 명료한 스크립트가 돌아왔습니다. 일단 무언가가 실행된 후, 다음 프롬프트는 "좋아요—이제 더 작게 작성해 주세요(good — now write it smaller)\