안녕하세요. 이번 리뷰는 제가 과거에 리뷰했던 reasoning path를 생성하는 Prompt Engineering 방법론인 Chain of Thought (CoT)에 이어, 동일 계열의 후속 논문 중 python code 기반의 prompt 생성 및 인터프리터 모방 실행까지 수행할 수 있는 방법론인 Chain of Code (CoC)입니다. 리뷰 시작하겠습니다.
1. Introduction
적절히 큰 scale 이상의 LLM은 복잡한 추론 문제를 해결하는데 좋은 능력을 보여줘 왔습니다. 과거 제가 리뷰했던 Chain of Thought (CoT)에서도 실험결과를 통해서 엿볼 수 있었는데요. 이외에도 많은 연구들에서 태스크적으로는 수학 프로그램을 작성하거나, 과학 문제를 해결하는 등의 능력도 갖추기도 했습니다. 특히 Chain of Thought (CoT)라는 프롬프팅 방법론을 통해 fine-tuning의 cost를 줄이면서 in-context learning을 수행하며 reasoning path를 유도하는 방식은 LLM의 추론 성능을 더욱 향상시키게 됩니다. 즉 정리하면 CoT는 복잡한 문제를 중간 추론 단계들로 분해하여 처리하는 방식으로, 주로 semantic한 추론 과제에서 강점을 보였습니다. 하지만 이런 CoT도 문제가 있었습니다. numeric(산술적)이거나 symbolic(기호적) 추론에서는 어려움을 겪는 경향이 있었습니다.
이러한 문제를 해결하기 위해 후속 연구에서는 LLM이 코드를 작성하고 실행하도록 유도하는 방식을 채택하였습니다. (추후 언급될 PoT, ScratchPads 등등.) 그럼 왜 하필 코드를 작성하고 실행하도록 유도했을까요. “Code”라는 구조가 이점을 가지는 부분을 생각해보면, 먼저 코드는 복잡한 프로그램을 구성하고 인코딩할 수 있는 “일반적인 문법 구조”를 제공합니다. 논리 구조와 기능적 어휘를 포함하여 튜링 완전성(간단하게 일반적으로 계산이 가능한 컴퓨터처럼 기능할 수 있다.라고 생각하시면 될 것 같습니다.)을 갖춘 방식으로 프로그램을 작성할 수 있다는 점입니다. 두번째로는, API와 인터프리터를 통해 10,000 size짜리 array sorting과 같은 대규모 알고리즘 연산도 정확하게 수행할 수 있는 “인터페이스”를 제공한다는 점입니다. 사실 이런 내용은 코딩을 하는 저희 입장에선 너무도 당연한 일들이고, 익숙한 과정 아닌가 라고 생각이 들 수도 있는데, 사실 이러한 수학적 연산이나 알고리즘적 연산은 다음 토큰을 예측하도록 주로 학습된 LLM의 입장에서는 꽤나 수행하기 어려운 작업일 수도 있습니다. (물론 지금의 더 발전된 GPT4o, GPT4o1 등에서는 이것마저도 식은 죽 먹기가 되었지만요.)
PoT나 ScratchPads 등의 연구에서 이런 코드의 이점을 가진 채 LLM이 코드에 대한 output을 작성하고 실행하는 방식으로 산술적 작업 성능을 크게 향상시킬 수 있었지만, 이 접근 방식에는 한계가 있었습니다. 특히, 많은 semantic 기반의 task들은 코드로 표현하기가 어렵거나 거의 불가능한 경우도 있습니다. 예를 들자면, 문자열에서 풍자적 요소를 감지해 true 또는 false를 내뱉게 한다는 것, 다양한 예외 상황을 모두 다루는 것 모두 사실상 너무 어려운 태스크입니다. 풍자적 요소라는 추상적이고 복잡한 semantic 태스크나, 너무 많은 예외 상황을 가진 태스크의 경우 코드로 딱 규정할 수 없는 형식이 되기 때문이죠.
이외에도 언어 모델이 여러 단계의 텍스트 추론 대신 프로그램 작성에 의존할 경우, 모든 중간 추론 단계가 코드 라인으로 표현되고, 또 그것이 반드시 인터프리터에 의해 실행 가능해야 한다는 제약이 생깁니다. 이건 chatGPT를 많이 써보신 분들이면 공감이 될 것 같습니다. “~~에 대해 코드 짜줘”라고 하면 바로 복붙해도 될 정도로 완성도가 높은 코드를 뚝딱 짜내기도 하지만, 때로는 바로 실행도 안되는 추상적인 코드를 짜기도, 실행가능성이 적은 코드를 짜기도 하니까요.
그렇다면 이러한 제약을 완화하여 코드 기반 추론과 언어 기반 추론의 장점을 모두 살릴 수 있는 방법이 있을까요?
이 연구에서는 LM의 코드 기반 추론 능력을 향상시키기 위해 **Chain of Code (CoC)**라는 간단하면서도 효과적인 확장 방식을 제안합니다. CoC는 LM이 단순히 프로그램을 작성하는 것에 그치지 않고, 인터프리터가 실행할 수 없는 특정 코드 라인의 예상 출력을 직접 생성하여 선택적으로 “시뮬레이션”하는 방식을 포함합니다.
핵심 아이디어는, 의미 기반 하위 작업을 프로그램 내에서 유연한 의사코드 형태로 작성하게 하여 런타임 시 해당 작업을 명시적으로 포착하고 LM이 이를 에뮬레이트(마치 python 인터프리터처럼 실행되는 것처럼 동작하게)하도록 하는 것입니다. 저자들은 이를 ‘LMulator’(LM과 에뮬레이터의 합성어)라는 개념으로 부르게 됩니다. 예를 들어, 어떤 글이 있다고 했을 때 “위의 문단에서 화자가 몇 번 풍자를 사용했는지 세어 보시오”라는 작업이 주어졌다면, LM에게 is_sarcastic(sentence)
와 같은 보조 함수(의미적으로만 존재하는 가상의 수도코드 함수)를 호출하는 프로그램을 작성하도록 프롬프트를 주면, LM은 이 함수에 대해 언어적으로 예측을 수행하고 해당 함수가 내뱉을 만한 결과를 예측해서 반환할 수 있는 것입니다. 이렇게 반환된 값을 가지고 프로그램의 다른 부분에서 처리토록 하는 것이구요.
위 그림1을 보면 CoC의 추론 과정이 대략적으로 나타납니다. LM이 코드를 작성하고, 인터프리터는 각 코드 라인을 하나씩 실행해 나가며(빨간색), 실행할 수 없는 경우에는 LM이 결과를 시뮬레이션(LMulator)하여 프로그램 상태를 업데이트합니다.(보라색으로 표시되며, 업데이트된 상태는 초록색으로 표시됩니다). CoC는 두 가지 장점을 모두 결합합니다. 첫째, 인터프리터에 의해 정밀한 알고리즘 연산을 맡길 수 있는 실행 가능한 코드를 작성하는 점, 둘째, 의미론적 문제를 해결하기 위한 의사코드를 작성하고 그 출력을 생성하는 점입니다. 이러한 접근 방식은 LM이 코드로 사고하는 것을 가능하게 하며, 형식적 변화에도 유연하게 대처할 수 있게 합니다.
2. Chain of Code: Reasoning with an LMulator
2.1 Preliminaries
언어 모델(LM)의 추론에 대한 배경을 간략히 살펴보면, 많은 추론 기법은 **맥락 학습(in-context learning)**에 의해 가능해졌습니다. 이 방식은 모델의 가중치를 변경하지 않고, 추론 시 몇 가지 예시를 제공하여 모델이 새로운 질의에 대해 해당 예시(few-shots prompt)들을 참고하며 적응할 수 있도록 했습니다. 이 특성 덕분에 LM을 다양한 새로운 태스크에 빠르게 적용할 수 있으며, 적은 데이터만으로도 좋은 효과를 발휘했죠.
이후에는 incontext learning 방식으로 언어 모델 성능을 더욱 높이기 위해 “인간의 사고 과정”을 모방하여 모델의 추론 과정에 대한 reasoning path를 생성토록하는 접근법들이 연구되었습니다. 이 중 CoC의 기반이 되는 세 가지 접근법은 다음과 같습니다.
- Chain of Thought (CoT): 문제를 자연어로 서브 단계로 나누어, 복잡한 문제를 해결할 때 인간의 사고 과정처럼 따라가도록 합니다.
- ScratchPad: 코드의 중간 상태값(state)를 유지하며 코드 출력을 시뮬레이션하여, LM이 코드 인터프리터처럼 작동하도록 합니다. (python)
- Program of Thoughts: 직접 코드를 생성하고, 코드 인터프리터가 이를 실행하여 추론 문제를 해결하는 방식입니다. (python)
이러한 접근법들은 각각 문제를 작은 단계로 나누어 해결하는 공통적인 방식을 띄고 있으나, 차이점에 대해서는 그림 3을 보면 더 직관적으로 이해가 잘 되실 것 같습니다.
2.2 Chain of Code
CoC는 크게 두 단계로 진행됩니다.
- 생성(Generation): 해결할 문제에 대한 질문이 주어지면, LM이 문제를 추론하기 위한 “코드를 생성”합니다.
- 실행(Execution): 생성된 코드를 실행가능한 경우 코드 인터프리터로 실행하고, 실행할 수 없는 경우 LM을 통해 시뮬레이션합니다. 즉 try python interpreter, except LMulator
- Chain of Code Generation
CoC는 주어진 문제를 해결하기 위해 문제를 추론하는 코드를 단계 별로 생성합니다. 명시적 코드, 의사코드 또는 자연어 형식으로 제공될 수 있으며, 문제를 해결하기 위한 사고 과정의 틀을 제공합니다. 예를 들어, BIG-Bench의 객체 수 계산 문제를 해결하는 과정이 위 그림 3d에 해당합니다.
- Chain of Code Execution
CoC의 핵심은 사실 생성된 추론 코드를 실행하는 방식에 있습니다. 생성된 코드는 우선 코드 인터프리터(Python)를 통해 실행됩니다. 이 연구에선 python을 기반으로 구성하였지만 방식은 특정 인터프리터에 한정되지 않고, 다른 인터프리터에도 적용 가능하다고는 합니다. 우선 코드가 성공적으로 실행되면 프로그램 상태값이 업데이트되고, 실행이 이어집니다. 반면, 코드가 실행되지 않거나 예외가 발생하는 경우, 언어 모델(LM)이 코드를 대신 실행하여 결과를 시뮬레이션합니다. try-except 구문 같이 말이죠. 이 과정에서 프로그램 상태는 언어 모델의 출력에 따라 업데이트되며, 실행이 이어집니다. 이러한 방식을 앞서 언급했듯이 LMulator라고 부르며, 이로써 의미적 요소와 수치적 요소가 혼합된 다양한 새로운 코드 응용을 가능하게끔 되었습니다. Python 실행기와 LMulator를 전환하며 생성된 코드가 실행되는 과정은 위 그림에서의 3e에 해당합니다.
2.3 Chain of Code Implementation
앞서 말했듯이 CoC의 생성 구현은 PoT와 같은 방식으로 프롬프트와 언어 모델 생성의 단순한 과정으로 이루어지지만, 실행 구현은 Python의 try
와 except
문을 활용하여 프로그램 상태를 유지하는 방식입니다. 우선 CoC는 코드 라인을 하나씩 순차적으로 실행합니다. 코드 인터프리터가 실행할 수 있는 라인이면, 해당 라인을 실행하여 프로그램 상태값을 업데이트하고 계속 진행합니다. 반면에 실행이 불가능한 코드 라인이 나오면, 언어 모델에게 프로그램의 현재 상황(질문, 이전 코드 라인, 프로그램 상태의 이력)을 제공하여 다음 프로그램 상태를 생성하도록 요청합니다.
생성된 프로그램 상태는 코드 인터프리터에 업데이트되어, 이후 제어 흐름(예: for
루프와 if
문)까지 처리 가능한 방식으로 언어 모델 시뮬레이터와 코드 인터프리터가 엮입니다(interweave). 즉 LMulator가 인터프리터 속에 잘 스며든다는 뜻이죠. 이러한 과정은 전체 코드가 실행되고 answer
변수에 최종 값이 저장되거나 복구할 수 없는 오류가 발생하여 언어 모델이 A: answer
라는 형식으로 출력을 생성할 때까지 반복될 수 있다고 합니다.
아까 언급한 어떤 글이 풍자인지 아닌지에 대한 함수 is_sarcastic("you don't say
“) 를 예로 들면,
answer = 0
answer += is_sarcastic('you don’t say')
answer += 1
answer = 0
은 Python이 실행하고, 프로그램 상태는{answer = 0}
으로 업데이트answer += is_sarcastic('you don’t say')
은 Python이 실행을 시도하지만 실패- LMulator가 해당 코드를 시뮬레이션하여
{answer = 1}
이라는 프로그램 상태를 생성, 프로그램에 업데이트 answer += 1
은 Python이 실행하여 프로그램 상태를{answer = 2}
로 업데이트- 최종적으로
answer
의 값2
가 출력
의 과정으로 이루어진다고 이해해 볼 수 있습니다.
2.4 Chain of Code Abilities
자 이렇게 어떤 방식으로 구현이 구현이 되는 지는 슥 살펴봤고, 저자들이 주장하는 CoC의 특성과 컨트리뷰션을 살펴보겠습니다.
- CoC’s properties
- 코드와 언어 모델의 장점 결합
semantic + common sense의 장점이 결합되어, 원래 code로 표현하기 어려운 상황에 대해서도 대체가 가능하게 됩니다.
다시 말하면, Pseudo Code 형태를 바로 실행하게 만들어서 추상적인 코드를 막 적용해 볼 수 있는 것입니다. - 언어 모델의 코드 작성 능력 활용
최신 LLM들의 코딩 능력을 잘 활용 + code 적용. - 코드의 구조적, 계산적 이점 계승
- 중간 단계 추론 (CoT)의 장점 계승
interpretability를 높일 수 있었다고 합니다.
경험적으로, 섹션 3(실험적 평가파트)에서 위와 같은 이점이 다양한 challenging tasks에 대한 추론 성능을 크게 향상시키는 것으로 나타났습니다.
그러나 저는 개인적으로는 할루시네이션 현상 때문에 code generation 자체가 잘못될 수 있는 가능성에 대한 문제가 남아있긴 하다고 생각합니다.
3. Experimental Evaluation
이 연구에서는 다양한 유형의 추론을 요구하는 어려운 문제들(산술, 상식, 기호적 추론)을 선택하여 다음과 같은 질문들에 답하고자 합니다.
- CoC는 다양한 태스크에서 얼마나 잘 수행되는가?
- CoC가 가장 높은 성능을 보이는 태스크 유형은 무엇인가?
- CoC의 각 요소가 성능에 어떤 영향을 미치는가? (ablation)
- CoC는 모델 크기에 따라 어떻게 확장되는가? (scale)
- CoC는 같은 문제에서가 아닌 다양한 문제에서의 프롬프트 예시(cross-task prompting)로 범용적인 추론 도구로서 얼마나 잘 수행되는가?
- CoC는 instruction tuned 대화형 모델과 어떻게 함께 사용할 수 있는가?
- CoC는 프롬프트 variation에 대해 얼마나 강인한가?
- CoC는 언어 추론 과제를 넘어서도 적용될 수 있는가?
이는 아래 table과 figure들을 보면서 차근차근 짚어나가보도록 하겠습니다.
1. Overall Performance
우선 1에 대한 결론은 사실 위 그림 속 table1 과 같습니다. 전체적인 세부 태스크들에 대해서는 Appendix의 A1에도 나와있는데요. CoC는 여러 태스크들에서 좋은 모습을 보이면서 모든 태스크들의 성능을 평균 낸 Single Task에서 Human의 성능의 평균치보다 더 좋은 결과(+29)를 보여주었습니다. text-davinci-003 모델 대신 GPT-4와 결합할 경우는 91까지 향상된다고 합니다. 특히 몇몇 태스크들(특히 알고리즘적 태스크)에서는 거의 100%에 가까운 성능을 보여줬습니다. 하지만 Single Task가 Human을 제친 것은 사실 모든 태스크들에 대한 평균치였던 것이고, Causal Judgement나 Ruin Names, Formal Fallacies 등에서는 Human과 CoT보다 낮은 결과도 보여줬었습니다.
2. Problem Type
위의 Figure 4와 Table A1에서는 CoC의 성능을 크게 ALL, NLP, Alg(알고리즘) 으로 나누었습니다. 역시 코드 기반인지라 CoC는 알고리즘적 태스크에서 CoT(71)에 비해 Inter-weave(95)라는 월등히 높은 성능을 가져옵니다. NLP 태스크에서도 기존의 성능을 유지하는 경향을 보여주었구요. 이는 코드 기반 접근이 언어 중심의 문제에 적합하지 않을 것이라는 예상을 뒤집는 긍정적인 결과였다고 합니다. CoC의 핵심은 LMulator를 사용해 코드 실행 결과를 시뮬레이션함으로써, 자연어 문제에서도 언어 모델의 의미적 추론 능력을 유지할 수 있다는 점에 있었다고 할 수 있겠습니다.
또한 Figure 4와 Table A1에서 질문 응답의 변동 정도와 코드가 Python에서 실행 가능한지 여부에 따라 과제를 추가로 세분화했는데,
(only python vs. python+LM), 일부 태스크에서는 입력만 달라질 뿐, 각 질문이 동일한 코드나 CoT를 따르는 경우가 있습니다. 이를 반복 코드(repeated code)라 하며, 새로운 코드(new code)가 필요한 경우도 있습니다.
역시나 Python에서 입력만 다르고 반복 코드로 실행될 수 있는 과제에서는 CoC가 거의 100%에 가까운 정확도를 기록했습니다. 이러한 과제(예: 다단계 산술 문제)는 다른 기준 모델이나 인간 평가자에게는 특히 어려운 과제로 평가되었습니다. CoC에 더 도전적인 범주도 있었으나, 이 경우에도 CoC는 기준 모델들보다 우수한 성능을 유지했습니다.
3. Ablations
그림 5와 6, 그리고 표 2는 Chain of Code(CoC) 프롬프팅의 각 요소가 성능에 미치는 영향을 보여줍니다. 예상대로 Python 실행을 포함한 접근(CoC (Interweave, Python, try Python except LM, try Python except LM state))은 코드가 정확한 경우 매번 100%의 성능을 기록하며, 일부 과제에서 뛰어난 결과를 보였습니다. 그러나 Python에만 의존하는 CoC (Python) 접근법은 비알고리즘적 과제에서 성능이 저조하여 거의 대부분 실패했습니다. CoC (Python) 접근법은 수치적 문제에서 코드 추론이 효과적이라는 최근 연구(Gao et al., 2023; Chen et al., 2022)와 유사합니다.
Python 인터프리터 없이 LM만으로 실행하는 CoC (LM, LM state)도 낮은 성능을 보였지만, ScratchPad 프롬프팅(Nye et al., 2021)이 제안한 단계별 접근 방식이 각 과제에서 성능을 개선하는 데 기여했습니다.
또한 CoC (try Python except LM, try Python except LM state)와 같은 방법들은 Python 실행을 시도하고 실패 시 LM으로 코드를 시뮬레이션하는 방식으로, 상당히 높은 성능을 기록했습니다. 프로그램 상태를 유지하는 방식이 성능을 향상시키는 데 도움이 되며, 이 방법들은 성능 저하가 거의 없는 단순한 대안으로 활용할 수 있습니다. 그러나 코드와 의미적 요소를 긴밀하게 혼합하는 것이 필요한 경우(예: 이미지 입력을 파싱하거나 외부 데이터베이스에 접근하는 코드와 그 결과를 언어로 해석해야 하는 경우), 이러한 단순화된 접근법은 완전한 CoC보다 훨씬 낮은 성능을 보일 것입니다.
4. Scaling
그림 7은 다양한 모델 크기에서 CoC의 성능을 보여줍니다. CoT 프롬프팅과 유사하게, CoC도 모델 크기가 증가함에 따라 성능이 향상되는 경향을 보입니다. 특히 일부 알고리즘 과제에서는 CoC가 코드에 접근할 수 없는 human rator보다도 우수한 성능을 보였습니다. 그러나 CoT 프롬프팅이 대형 모델(d-3)에서만 성능 향상을 보인 반면, CoC는 더 작은 모델(a-1, b-1, c-1)에서도 직접 질문 응답보다 우수한 성능을 기록했습니다. 이는 작은 모델이 자연어보다 구조화된 코드를 중간 단계로 출력하는 것이 더 쉬움을 시사한다고 합니다.
5. Cross-task Prompting.
여기선 언어 모델에 다양한 문제의 예시를 제공했습니다. 그림 7과 표 1에 따르면, 모든 접근법에서 성능이 감소했지만, CoC는 대규모 모델에서도 CoT와 직접 프롬프팅보다 우수한 성능을 보여주며 human 평균 성능에 거의 도달했습니다. 이는 동일한 유형의 예시가 제공되지 않는 일반적 추론 작업에서도 CoC가 효과적일 가능성이 있다고 볼 수 있겠습니다.
6. Instruction Tuned Models
본 연구에서 CoC의 주 평가 모델로 text-davinci-003(완성형 모델)을 선택한 이유는 BIG-Bench Hard 평가가 주로 몇 가지 예시를 제공하는 few-shot 프롬프팅 방식이기 때문입니다. gpt-3.5-turbo나 gpt-4 같은 instruction tuned 모델 중 고급모델들도 있지만, 이러한 모델들은 few-shot 프롬프팅에 덜 적합할 수 있다고 합니다..
그래도 저자들은 zero-shot과 few-shot prompting에 대해 테스트를 해보았다고 하는데요.
zero-shot의 경우 다음과 같습니다.
베이스라인으로는 Direct : “directly answer”와, CoT : “Think step by step” 을 사용했다고 합니다. (참고로 Think step by step은 zero-shot CoT 논문에서 나온 방식으로 유명합니다.)
Zero shot을 위한 변형 CoC에서는 “Write python code to help solve the problem, if it’s helpful” 프롬프트를 사용했다고 합니다. 프로그램이 작성되면 Python 인터프리터로 코드를 실행하여 결과(또는 실패 시 오류 메시지)를 모델에 다시 제공해 최종 답변을 도출하는 방식인 CoC(python)과 언어 모델이 코드 실행 결과를 시뮬레이션하여 답을 생성하는 방식인(CoC (LM))으로 나누어 실험을 진행해보았을 때, gpt-3.5-turbo와 gpt-4에 대한 성능은 다음과 같았습니다.
- gpt-3.5-turbo: CoT와 CoC (Python) 모두 Direct보다 성능이 우수, but CoC (Interweave)가 훨씬 더 뛰어남.
- gpt-4: text-davinci-003에 비해 모델의 기본적 성능에서 큰 강점이 있음에도 불구하고 CoC (Interweave)가 여전히 우수.
few-shot의 경우는 다음과 같습니다.
우선 gpt-3.5-turbo와 gpt-4가 앞선 text-davinci-003처럼 작동하도록 유도하기 위해 다음과 같은 시스템 메시지를 사용했다고 합니다.
“Pretend you are a completion model that is prompted with three examples. You should follow the pattern of
these examples strictly. At the end of your reply, you should always output an answer”
“자신을 세 가지 예시가 주어지는 완성형 모델이라고 생각하세요. 반드시 이 예시 패턴을 엄격히 따라야 하며, 답변 끝에 항상 답을 출력해야 합니다.”
유저 쿼리로는 single task 혹은 cross task 도메인의 3가지 예시와 함께 질문을 포함하여 text-davinci 모델을 평가할 때와 동일하게 구성했다고 합니다. 결과는 CoC가 Direct 및 CoT 기준 모델보다 여전히 상당한 성능 향상을 보였습니다. gpt-4에서는 기본 모델의 성능이 이미 높아 개선의 여지가 적어 성능 격차가 다소 줄어들었습니다. 이 실험의 의의로는 CoC를 gpt-4와 같은 고급 instruction tuned 모델과 결합할 수 있는 실질적인 방법을 제안했다는 점의 의의가 있을 것 같습니다.
7. Robustness of Chain of Code
CoC는 서로 다른 프롬프트를 통해 동일한 문제 세트에 대해 독립적으로 작성된 3명의 annotator가 제공한 프롬프트로 평가함으로써, 일반적으로 프롬프트 변형에 강한 성능을 보인다는 것을 보여주었습니다. 특히, 새로운 코드 생성을 요구하는 BIG-Bench Hard에서 네 가지 대표적인 task를 선택했습니다(반복 코드가 아니고 매번 새 코드를 생성하는 태스크였습니다). 개별 task의 성능은 다소 변동이 있지만, 4개의 task의 평균 성능은 몇퍼 정도의 오차만 있었습니다.
8. Beyond Language Reasoning
CoC는 언어 추론을 넘어서는 의미적 및 알고리즘적 추론이 필요한 작업에도 잘 적합함을 보여주는데, 특히 robotics 분야에서 CoC가 Python 코드를 통해 로봇의 인식 및 제어 API와 원활하게 상호작용할 수 있음을 시사합니다. 예를 들어, 물체 감지를 실행하거나 매개변수화된 로봇 기술을 호출하면서도 의미적 하위 작업을 “인라인” 방식으로 수행할 수 있습니다(예: 쓰레기를 분리하기 전에 어떤 것이 퇴비화 가능한지 분류). 해당 특징이 저희 로보틱스 팀 입장에서는 CoC의 가장 의미가 있는 점이 아닌 가 싶습니다.
본 논문의 부록에 robotics 관점에서의 CoC에 대한 실험세팅과 결과를 게시했는데 이는 다음과 같습니다.
환경 및 로봇 설정
실험 환경은 탁상 위에 소형 물체(용기, 장난감 등)가 놓여 있으며, UR5 로봇 팔에는 진공 그리퍼와 손목에 부착된 RGB-D 카메라가 장착되어 있었습니다. 사용 가능한 인식 API는 detect_objects()
로, 손목 카메라에서 탐지된 물체 목록(확률, 라벨, 경계 상자, 세분화 마스크)을 반환합니다. 이 API는 먼저 GPT-4V(OpenAI, 2023)로 객체 목록을 생성하고, 이후 Grounding-SAM(Kirillov et al., 2023; Liu et al., 2023)을 사용하여 위치를 지정하는 방식으로 구현되었다고 합니다. 또한, pick_place(obj1, obj2)
라는 제어 API는 obj1을 집어 obj2 위에 놓는 스크립트화된 기본 기술을 제공하며, say(sentence)
텍스트-음성 변환 API를 통해 로봇이 사용자와 소통할 수 있는 방식을 취했습니다.
실험 설정
실험은 탁상 위에서 수행되는 pick-and-place 작업으로, 의미적 추론이 포함된 로봇 작업을 평가합니다. few-shot 프롬프팅 예제로 “사용자의 식이 제한을 준수하는 식사를 제공하라”는 문장을 제공해 언어 모델이 기대하는 구조와 로봇의 API를 이해하도록 했다고합니다. 이후 테스트 시 아래와 같은 지시문으로 모델을 질의했는데 다음과 같습니다.
- “비건 식단을 위한 도시락을 준비해 주세요.”
- “채식주의자를 위한 샌드위치를 조립해 주세요.”
- “접시에 땅콩버터 샌드위치 재료를 모아 주세요.”
- “西红柿炒蛋를 냄비에 준비해 주세요.” (영어와 중국어 혼용)
- “모든 종이 재질의 물체를 잔디색 컨테이너에 넣어 주세요.”
- “테이블 위의 물체를 퇴비통과 재활용통에 분류해 주세요.”
- “스테이크가 너무 싱거운데, 도와줄 수 있나요?”
위의 그림 상의 코드로도 확인해 보실 수 있습니다.
위 그림은 실제 로봇 매니퓰레이터에 적용한 결과라고 합니다.
4. Related Work
Language Model Reasoning
- Brown et al., 2020: Language Models are Few-Shot Learners
- Wei et al., 2022b: Chain of Thought Prompting Elicits Reasoning in Large Language Models (CoT)
- Suzgun et al., 2022: Challenging BIG-Bench Tasks and Whether Chain-of-Thought Can Solve Them
- Mirchandani et al., 2023: Are Symbols Useful for Neural Language Models?
- Lewkowycz et al., 2022: Solving Quantitative Reasoning Problems with Language Models
- Drori et al., 2022: A Neural Network Solves, Explains, and Generates University Math Problems by Program Synthesis
Language Model Tool Use
- Chen et al., 2021: Evaluating Large Language Models Trained on Code
- Chen et al., 2022: Program of Thoughts: Reasoning Engines with Large Language Models and Code Execution (PoT)
- Nye et al., 2021: Show Your Work: Scratchpads for Intermediate Computation with Language Models
- Austin et al., 2021: Program Synthesis with Large Language Models
- Zhou et al., 2022a: Least-to-Most Prompting Enables Complex Reasoning in Large Language Models
- Kojima et al., 2022: Large Language Models are Zero-Shot Reasoners
Language Model Program Synthesis
- Liang et al., 2023: Turing-Complete Neural Networks with Finite Precision: A Code Synthesis Perspective
- Gao et al., 2023: Program-Aided Language Models: Unlocking the Power of Program-Based Reasoning
- Srivastava et al., 2022: Beyond the Imitation Game: Quantifying and Extrapolating the Capabilities of Language Models
5. Conclusions
Chain of Code(CoC)는 코드 작성과 실행을 통해 언어 모델로 추론하는 방법론을 제안했습니다. 코드가 실행되지 않을 경우 코드 interpreter를 사용하거나 코드 실행을 시뮬레이션하는 언어 모델(LMulator)을 통해 실행하는 방식이 단순하면서도 꽤 놀라웠는데요.. Prompt Engineering, 특히 CoT 계열의 reasoning path를 개선하는 연구들은 참 보면 볼 수록 좋게 말하면 창의적인 방식으로 연구가 진행되고 있는 것 같습니다. Prompt Engineering 분야가 곽광받은 지 얼마되지도 않았는데 말이죠.. CoC는 일단 결론적으로 로보틱스에서 action generating과 추상적인 high level function을 구성하고 수행하는 데 큰 역할을 할 수 있을 것이라 생각됩니다.
저자들이 말하는 몇 가지 Limitations도 있긴 한데, 밑에 남겨보고 마무리하겠습니다.
- 코드와 언어 실행을 서로 교차하여 두 단계로 실행하는 방식은 추가적인 컨텍스트 길이와 계산 시간을 요구합니다.
- 태스크들을 통째로 싸잡아 보았을 때 의미적 작업에서 성능 저하를 겪진 않았지만, 사실 코드가 도움이 되지 않는 일부 태스크가 존재합니다. 예를 들어, ‘Ruin Names’라는 작업은 이름을 변경했을 때 그것이 유머러스한지 여부를 묻는 작업으로, 코드가 별로 도움이 되지 않았습니다.
- LM과 코드 실행을 교차하는 현재 구현은 문자열로 프로그램 상태를 추적하고, 이를 Python의 내장 데이터 타입(예: dict, tuple)으로 변환하는 매우 단순한 방식입니다. 현재 방식으로는 LM이 코드 실행을 시뮬레이션하면서 Python의 “사용자 정의 객체”를 수정할 수 없습니다. 그러나 이론적으로는, 각 Python 객체에 serialization(직렬화) 및 deserialization(역직렬화) 메서드(예: Protocol Buffers와 같은 기술)가 있는 한 가능하다고 볼 수 있다고 합니다.
감사합니다.
안녕하세요. 좋은 리뷰 감사합니다.
LLM으로 코드를 생성하고 이를 평가하는 굉장히 혁신적인 시대로 진입한 것 같은 논문이었습니다. 데이터셋이나 다른 방법론과의 비교 등에 대해서는 궁금한 부분이 많지만 이 부분은 차차 팔로업해보겠습니다. 평가 방식에서 궁금한 부분이 있는데, LLM을 통해서 생성하는 것이다 보니까 동일한 prompt를 넣어도 다른 output을 할 때가 많을 것 같습니다. 그럴때는 이 중 하나의 답변만을 선택하여 평가를 수행하나요? 하니면 이를 평균을 내어서 score를 책정하는 걸까요?
감사합니다.
안녕하세요 재찬님, 리뷰 감사합니다.
LMulator라는 것이 interpreter에 잘 녹아들어서 semantic task에서 얻는 이점도 있고, 여러 작업의 성능 향상이 이루어졌다고 이해해도 될까요??