Andrej Karpathy와 함께하는 Microsoft Build 2023: GPT 최신 동향 (2/2) — GPT assistants를 애플리케이션에 효율적으로 사용하는 방법
본 페이지는 이전 블로그 페이지에 이어 안드레이 카파시의 MS Build 2023 “State of GPT” 발표 중 두번째 파트인 GPT assistants를 애플리케이션에 효율적으로 사용하는 방법에 대해서 정리하였다.
인간의 텍스트 생성 방법
인간이 캘리포니아와 알래스카의 인구를 비교하는 블로그 글을 작성한다면 가장 먼저해야 하는 일은 두 지역의 인구를 잘 모르기 때문에 캘리포니아의 인구 정보와 알래스카의 인구 정보를 가져오는 것이다.
이를 위해 위키피디아에서 캘리포니아의 인구가 39.2M명, 알래스카의 인구가 0.74M명인 사실을 찾는다. 이후 39.2를 0.74로 나누기를 실행한다. 머리 속에서 암산으로 하기엔 너무 어려우니 계산기를 사용하기로 하자.
계산기를 사용하여 나누기를 실행하면 대충 53이 나온다. 캘리포니아는 가장 인구가 많은 주이니 계산 결과가 꽤 합리적이라는 생각이 들 것이다. 계산 결과를 이용하여 “캘리포니아는 53배 더 넓다”라고 썼다가 어색한 표현임을 확인하고 “캘리포니아의 인구가 알래스카의 인구보다 53배 더 많다”라고 다시 고친 후 그 결과물에 만족스러워 할 수 있다.
LLM의 텍스트 생성 방법
내면의 독백을 통해 텍스트를 생성하는 인간에 비해 GPT의 관점에서 볼 때 문장은 토큰의 시퀀스로 보일 뿐이다. GPT는 이러한 토큰을 읽거나 생성할 때 한 덩어리(chunk), 한 덩어리로 진행되며 각 덩어리는 각 토큰에 대해 거의 동일한 계산 작업을 수행한다.
Transformer는 80개의 추론 계층을 가지고 있지만 80개는 여전히 많지 않다. 이 Transformer는 모방하기 위해 최선을 다하지만 인간의 텍스트 생성 과정과 매우 다르다. GPT는 사람과 달리 모든 토큰을 살펴보고 모든 토큰에 동일한 양의 컴퓨팅을 소비한다.
기본적으로 transformer는 토큰 시뮬레이터와 같아 그들은 자신이 모른다는 사실을 모른다. Transformer는 그저 다음 토큰을 모방할 뿐 자신이 무엇을 잘하고 못하는지 모른다. 기본적으로 실수를 수정하지 않고 토큰 시퀀스를 샘플링할 뿐이다.
Transformer는 일종의 인지적 장점을 가지고 있는데 수십 B의 파라미터를 가지고 있기 때문에 매우 방대한 영역에 걸쳐 매우 큰 사실기반 지식(Fact-based Knowledge)을 가지고 있다라고 말할 수 있다. 또한 많은 사실을 저장할 수 있는 공간이 있으며, 비교적 크고 완벽한 워킹 메모리를 가지고 있다. Context window에 들어오는 것은 무엇이든 어텐션 메커니즘을 통해 transformer에 즉시 사용될 수 있다. Transformer의 context window는 완벽하게 메모리의 일종이다. 그 크기는 제한적이지만 transformer는 매우 직접적으로 context window에 접근할 수 있으며 context window 안에 모든 것은 손실없이 기억할 수 있다.
Chain of thought
프롬프트는 인간의 뇌와 LLM, 두 종류의 아키텍처 간의 인지적 차이를 보완하는 역할을 한다. 예를 들어 사람들이 실제로 꽤 잘 동작한다는 것을 발견한 사실이 있다. 추론이 필요한 작업을 할 때 transformer가 토큰 당 너무 많은 추론을 수행하길 기대해선 안 된다. 사용자는 transformer로 하여금 점점 더 많은 토큰에 걸쳐 추론하도록 분산시켜야 한다.
예를 들어 transformer에게 매우 복잡한 질문을 던지고 하나의 토큰으로 대답하라는 것을 기대할 수 없다. Transformer에서 그럴 시간이 충분하지 않으며, 생각하는데 토큰이 필요하기 때문이다. 아래 그림의 Few-shot COT(Chain Of Thought) 예제에서 볼 수 있듯이 transformer에게 몇 가지 예시를 제시하면 그 템플릿을 모방하여 더 잘 작동한다.
또한 zero-shot COT 예제처럼 transformer에게 단계별로 생각해보자(“ Let’s think step by step.”)라고 명령하면 동일한 종류의 동작을 이끌어낼 수 있다. 더 느리게 추론하기 때문에 결과적으로 성공할 가능성이 높다.
Self-Consistency
우리가 글을 쓰려고 시도하지만 잘 되지 않는다고 가정해보자. 우리는 여러 번 시도해보고 가장 효과가 좋았던 것을 선택할 수 있다. 이러한 접근 방식에서는 한 번만 샘플링하는 것이 아니라 여러 번 샘플링한 후 좋은 샘플을 찾아 그 샘플을 유지하거나 다수결 투표를 하는 등의 방법을 사용할 수 있다.
Transformer 또한 다음 토큰을 예측하는 과정에서 인간과 같이 그다지 좋은 토큰이 아닌 샘플을 추출할 수 있고 때론 추론 관점에서 일종의 막다른 골목에 빠질 있다. 하지만 transformer는 인간과 달리 그들을 복구할 수 없으며 이 시퀀스가 제대로 동작하지 않을 것이라는 것을 알더라도 시퀀스를 계속 진행한다. 따라서 transformer가 되돌아보고 검사하거나, 기본적으로 주변에서 샘플링을 시도할 수 있는 기능을 제공해야 한다.
이를 위해 한 가지 기술이 있다. 실제로 AI는 자신이 언제 실수했는지 알고 있다는 사실이 밝혀졌다. 아래의 왼쪽 예시는 사용자가 운율(rhyme)에 맞지 않은 시를 작성하라고 요청하였을 때 GPT-4의 응답이다. 하지만 GPT-4에 “Did the poem meet the assignment?(시가 과제를 만족하였는가?)”를 물어보면 GPT-4는 과제를 충족하지 못했다는 사실을 잘 알고 있다. 단지 샘플링 시 운이 나빴을 뿐이므로 GPT-4는 다시 non-rhyming poem을 다시 작성한다.
LLM은 이와 같이 확인을 요청하지 않으면 스스로 확인하지 않는 토큰 시뮬레이터일 뿐이다. 따라서 프롬프트로 이를 보완해야 한다.
일반적으로 이러한 기술 중 상당수는 시스템 2를 재창조(Recreate)하는 범주에 속한다라고 생각한다.
- 시스템 1: 빠르고 자동화된 프로세스. 토큰을 샘플링하는 LLM에 해당
- 시스템 2: 더 느리고 신중한 계획을 세우는 두뇌의 일부
최근 Tree of Thoughts라는 제목의 논문에서 저자들은 주어진 프롬프트에 대해 여러 개의 completion을 유지할 것을 제안하고 있다. 그리고 그 과정에서 점수를 매겨 잘 진행되고 있는 프롬프트는 계속 유지한다. 그래서 많은 사람들이 기본적으로 LLM을 위해 우리 뇌에 있는 이러한 능력을 되살리기 위해 일종의 프롬프트 엔지니어링을 활용하고 있다.
여기서 주목해야 하는 점은 이것이 단순한 프롬프트가 아니라는 점이다. 실제로 여러 프롬프트를 유지 관리해야 하고 어떤 프롬프트를 확장할지 등을 파악하기 위해 Tree 검색 알고리즘을 수행해야 하기 때문에 일부 파이썬 글루 코드와 함께 사용되는 프롬프트이다.
이는 알파고와 멋진 유사점이 있다라고 생각한다. 알파고는 바둑을 둘 때 다음 돌을 놓는 규칙을 가지고 있는데 이 규칙은 원래 인간을 모방하여 학습한 것이다. 하지만 이 정책 외에도 몬테카를로 Tree 검색도 수행한다.
Tree of Thoughts와 마찬가지로 사람들이 단순한 질문/답변 프롬프트가 아니라 파이썬 글루 코드처럼 여러 프롬프트를 묶는 좀 더 일반적인 기법을 탐구하기 시작하였다. 위 그림의 오른쪽 예시는 ReAct 논문에서 프롬프트에 대한 답을 생각, 행동, 관찰 → 생각, 행동, 관찰의 순서로 구조화한 예이다. 이것은 질문에 답하기 위한 일종의 사고 과정이며 모델은 도구를 사용할 수 있다.
위 그림의 왼쪽 예시는 Auto-GPT 프로젝트에 대한 예시로 LLM이 일종의 작업 목록을 유지하고 작업을 계속 재귀적으로 세분화할 수 있도록 하는 프로젝트이다. Auto-GPT 프로젝트는 현재는 그다지 잘 작동하지 않으나 시간이 지남에 따라 이 방식이 어디로 가고 있는지 영감을 얻을 수 있는 방법이다. 즉 모델 시스템에 사고력을 부여하는 것과 같다.
LLM에서 좋은 성능을 얻는 조건
LLM의 심리적 특성은 성공(Succeed)하기 보다는 학습 데이터셋을 모방(Imitate)하길 원한다. 따라서 사용자는 LLM이 성공할 것을 요구해야 한다.
Transformer를 학습하려면 학습 데이터셋이 있어야 하는데 학습 데이터셋에는 다양한 성능 특성이 있을 수 있다. 예를 들어 물리학 문제와 같은 유형의 프롬프트와 답변이 있을 때, 완전히 틀린 학생의 답변이 있을 수도 있고 매우 정확한 전문가의 답변이 있을 수도 있다.
Transformer는 낮은 품질의 솔루션(e.g. 학생의 답변)과 높은 품질의 솔루션(e.g. 전문가의 답변)을 구분할 수 없지만 기본적으로 모든 것을 모방하려 한다. 그래서 테스트 시간에 Transformer에 좋은 성능을 요구해야 한다.
예를 들어, “Let’s think step by step.”과 같은 프롬프트는 매우 강력하다. 왜냐하면 추론을 많은 토큰에 걸쳐 분산시키는 역할하기 때문이다. 이것보다 더 나은 결과를 얻기 위해서 “Let’s work this out in a step by step way to be sure we have the right answer.”와 같은 프롬프트를 사용하면 transformer에서 실제로 더 잘 동작한다. 왜냐하면 transformer가 낮은 품질의 솔루션에서 답변을 찾을 필요가 없기 때문이다. 그러므로 transformer에게 기본적으로 강력한 솔루션을 편안하게 요구하라.
LLM을 위한 Tools & Plugins
앞서 사람들은 문제를 해결하고자 할 때 자신이 잘하는 것과 못하는 것을 알고 계산적인 도구에 의존한다. LLM 또한 계산기, 코드 인터프리터 등과 같이 검색할 수 있는 기능을 사용할 수 있으며, LLM이 잘 하지 못하는 태스크들은 오프로드로 시켜라.
이때 명심해야 할 것은 transformer는 기본적으로 자신이 모른다라는 사실을 모를 수 있다는 것이다. 기본적으로 모델은 인간처럼 자신이 잘하는 것과 못하는 것을 잘 모르기 때문에 “special token”을 사용하여 외부 APIs를 호출할 수 있다.
예를 들어, 아래 Toolformer 논문의 예시처럼 “special token” 조합을 사용하면 LLM이 자동으로 외부 APIs를 호출하여 텍스트의 일부를 완성할 수 있다.
- “QA” token: Question Answering System
- “Calculator” token: Calculator
- “MT” token: Machine Translation system
- “WikiSearch”: Wiki search engine
검색 증강 LLMs (Retrieval-Augmented LLMs)
다음으로 매우 흥미로운 점은 검색만이 가능했던 세상에서 LLM이 추가되면서 검색과 LLM간의 전체 공간이 존재하며 실제로 매우 잘 동작하는 점이다.
Transformer의 context window는 working memory이다. 작업과 관련된 정보를 working memory에 로드할 수 있다면 모델은 모든 메모리에 즉시 접근할 수 있기 때문에 매우 잘 동작한다. 최근 많은 사람들이 검색 증강 생성(Retrieval Augmented Generation)에 대해서 깊은 관심을 가지고 있다.
LLamaIndex는 LLM을 위한 orchestration framework로 모든 데이터를 인덱싱화하여 LLM이 접근할 수 있도록 만들 수 있다. LLamaIndex는 관련 문서를 가져와 잘게 쪼개서 모두 임베딩화하여 해당 데이터를 나타내는 임베딩 벡터를 얻는 것이다. 이것들을 벡터 저장소에 저장한 다음 테스트 시점에 벡터 저장소에 일종의 쿼리를 수행하고 태스크에 관련이 있을 수 있는 chunk들을 가져와 프롬프트에 넣은 후 출력을 생성할 수 있다. 이와 같은 방법은 꽤 잘 동작한다.
Transformer는 매우 크고 광범위한 메모리를 가지고 있지만 기본 문서를 참조하는 것은 굉장히 큰 도움이 된다. 예를 들어 사람들은 무언가를 찾기 위해 교과서와 라이브러리의 문서를 참고하는 것과 같이 transformer 역시 외부 정보를 찾아보는 것이 훨씬 더 도움이 된다.
제한적 프롬프트(Constrained Prompting)
이는 기본적으로 LLM의 출력에 특정 템플릿을 적용하는 기술이다. 아래는 MS의 guidance의 한 예시이다. 여기서는 LLM의 출력이 JSON이 되도록 강제하고 있어 transformer는 JSON의 빈칸을 채우는 역할만을 한다.
Finetuning
모델을 finetuning한다는 것은 모델의 weight를 변경한다는 의미로 최근 개발되고 있는 여러가지 기술로 인해 finetuning하는 작업이 훨씬 쉬워지고 있다.
Parameter Efficient FineTuning(PEFT. e.g. LoRA)
예를 들어 MS가 발표한 LoRA(Low-Rank Adaptation)와 같은 효율적인 파라미터 finetuning 방법은 모델의 대부분은 베이스 모델로 고정되어 있고 일부만 변경할 수 있도록 허용한다. LoRA는 경험적으로 잘 작동하며 모델 작은 부분만 조정하므로 훨씬 값싼 finetuning 방법이다.
Low-precision inference (e.g. bitsandbytes)
LoRA는 대부분의 모델 파라미터가 고정되어 있기 때문에 gradient descent에 의해 업데이트 되지 않기 때문에 해당 LoRA 파트를 컴퓨팅할 때 매우 낮은 precision으로 추론을 사용할 수 있다.
Open-sourced high quality base models (e.g. LLaMA)
비록 상업용 라이선스를 부여하지 않았지만 LLaMA와 같은 오픈소스 LLM을 finetuning하여 Alpaca와 Vicuna와 같은 우수한 성능의 새로운 모델들을 만들 수 있다.
하지만 한 가지 명심해야 하는 사실은 기본적으로 finetuning은 기술적으로 훨씬 더 많은 작업이 필요하다는 것이다. 제대로 하려면 훨씬 더 많은 기술적 전문 지식이 필요하다. 매우 복잡한 데이터셋과 합성 데이터 파이프라인에 대한 인간 데이터 계약자를 요구하므로 반복 주기가 확실히 많이 느려진다.
그리고 언어 모델 작업을 계속하기 때문에 일반적인 사용자들 또한 비교적 간단한 SFT(Supervised FineTuning)을 달성할 수 있으나, RLHF는 연구 영역이 매우 넓고 실무에 적용하기가 훨씬 더 어렵다. RLHF는 불안정하고 학습하기 매우 어렵기 때문에 초보자들이 RLHF를 직접 구현하는 것을 권장하지 않는다. 또한 앞으로 꽤 빠르게 변화할 가능성이 높은 분야이기도 하다.
LLM 사용을 위한 가이드
아래는 LLM을 사용할 때 추천하는 기본사항이다. 사용자들의 과제를 목표에 따라 두 가지로 나눌 수 있으며 각 목표에 따라 다음과 같은 LLM을 사용하는 것이 효과적이다.
과제 목표 1: 최고의 성능을 달성
- GPT-4를 사용할 것
- 매우 상세한 태스크 컨텍스트, 관련 정보, 명령어를 가진 프롬프트를 사용
- LLM의 심리를 잘 파악하고 그에 맞는 프롬프트를 제공해야 함
- 관련 컨텍스트와 정보를 검색하여 프롬프트에 추가하고 기본적으로 많은 프롬프트 엔지니어링 기법을 참고할 것
- 가능하다면 많은 예시를 보여줌. 사용자가 의미하는 것을 이해하는데 도움이 될 수 있는 모든 예를 제공할 것
- LLM이 기본적으로 수행하기 어려운 작업을 오프로딩할 수 있는 도구와 플러그인을 실험 후 하나의 프롬프트와 답만 생각하지 말고 잠재적인 변화와 반영을 어떻게 결합할지 어떻게 여러 개의 샘플을 만들 수 있을지 생각할 것
- 현재 SFT보다 RLHF이 더 잘 작동하지만 매우 복잡함
과제 목표 2: 비용을 최적화
- 저용량 모델(e.g. GPT-3.5)이나 더 짧은 프롬프트를 사용함
LLM의 Usecase
오늘날 LLM은 많은 제약이 있다는 점을 유의해야 한다. 모델은 편향적일 수 있으며 정보를 조작하거나 환각을 일으킬 수 있다. 추론 오류가 있을 수 있으며 지식 단절이 있어 2021년 9월 이후 정보를 전혀 모른다. 프롬프트 인젝션(Prompt Injection), 탈옥 공격(Jailbreak Attack), 데이터 중독 공격(Data Poisoning Attacks) 등 다양한 공격에 취약하다.
따라서 위험도가 낮은 애플리케이션에 LLM을 사용하고, 항상 사람의 감독과 결합하며 영감과 제안의 원천으로 활용해야 한다. 그리고 완전 자율 에이전트 대신 co-pilot라고 생각해야 한다. 현재로서는 완전 자율 에이전트 모델이 가능한지 아직 명확하지 않기 때문이다.