AI연구회
경남ICT협회 AI 연구 모임
아래내용은 Bea Stollnitz블로그에서 가져온 내용입니다. GPT를 이해하는데 조금이나마 도움이 되었으면 합니다.
------
생성 날짜: 19년 2023월 <>일
주제: 대규모 언어 모델
GPT 모델을 사용하여 처음 몇 줄의 코드를 작성한 것은 2021년이었고, 그때 텍스트 생성이 변곡점에 도달했음을 깨달았습니다. 그 전에는 대학원에서 언어 모델을 처음부터 작성했고 다른 텍스트 생성 시스템으로 작업한 경험이 있었기 때문에 유용한 결과를 생성하는 것이 얼마나 어려운지 알고 있었습니다. 저는 운이 좋게도 Azure OpenAI Service 내에서 GPT-3 릴리스 발표에 대한 작업의 일환으로 GPT-3에 대한 조기 액세스 권한을 얻었고 출시를 준비하기 위해 사용해 보았습니다. 나는 GPT-3에게 긴 문서를 요약하도록 요청하고 몇 번의 프롬프트로 실험했습니다. 결과가 이전 모델보다 훨씬 더 발전된 것을 볼 수 있었고, 기술에 대해 흥분하고 구현 방법을 배우고 싶어했습니다. 그리고 후속 GPT-5.4, ChatGPT 및 GPT-<> 모델이 빠르게 널리 채택됨에 따라 현장의 더 많은 사람들이 작동 방식에 대해 궁금해하고 있습니다. 내부 작동의 세부 사항은 독점적이고 복잡하지만 모든 GPT 모델은 이해하기 어렵지 않은 몇 가지 기본 아이디어를 공유합니다. 이 게시물의 목표는 데이터 과학자 및 기계 학습 엔지니어를 대상으로 한 설명과 함께 일반적인 언어 모델 및 특히 GPT 모델의 핵심 개념을 설명하는 것입니다. AI 분야에 대한 배경 지식이 없다면 보다 일반적인 청중을 위해 작성된 대체 게시물을 선호할 수 있습니다.
생성 언어 모델의 작동 방식을 살펴보는 것부터 시작하겠습니다. 가장 기본적인 아이디어는 다음과 같습니다 : 토큰을 입력으로 사용하고 하나의 토큰을 출력으로 생성합니다.
이것은 매우 간단한 개념처럼 보이지만 실제로 이해하려면 토큰이 무엇인지 알아야 합니다.
토큰은 텍스트 덩어리입니다. OpenAI GPT 모델의 맥락에서 일반적이고 짧은 단어는 일반적으로 아래 이미지의 "We"라는 단어와 같은 단일 토큰에 해당합니다. 길고 덜 일반적으로 사용되는 단어는 일반적으로 여러 토큰으로 나뉩니다. 예를 들어 아래 이미지에서 "의인화"라는 단어는 세 개의 토큰으로 나뉩니다. "ChatGPT"와 같은 약어는 문자가 함께 나타나는 빈도에 따라 단일 토큰으로 표시되거나 여러 개로 나눌 수 있습니다. OpenAI의 토크나이저 페이지로 이동하여 텍스트를 입력하고 토큰으로 분할되는 방법을 확인할 수 있습니다. 텍스트에 사용되는 "GPT-3" 토큰화와 코드에 사용되는 "Codex" 토큰화 중에서 선택할 수 있습니다. 기본 설정인 'GPT-3'은 그대로 유지됩니다.
OpenAI의 오픈 소스 tiktoken 라이브러리를 사용하여 Python 코드를 사용하여 토큰화할 수도 있습니다. OpenAI는 각각 약간 다른 동작을 하는 몇 가지 다른 토크나이저를 제공합니다. 아래 코드에서는 GPT-3 모델인 "davinci"에 토크나이저를 사용하여 UI를 사용하여 본 동작과 일치시킵니다.
import tiktoken # Get the encoding for the davinci GPT3 model, which is the "r50k_base" encoding. encoding = tiktoken.encoding_for_model("davinci") text = "We need to stop anthropomorphizing ChatGPT." print(f"text: {text}") token_integers = encoding.encode(text) print(f"total number of tokens: {encoding.n_vocab}") print(f"token integers: {token_integers}") token_strings = [encoding.decode_single_token_bytes(token) for token in token_integers] print(f"token strings: {token_strings}") print(f"number of tokens in text: {len(token_integers)}") encoded_decoded_text = encoding.decode(token_integers) print(f"encoded-decoded text: {encoded_decoded_text}")
text: We need to stop anthropomorphizing ChatGPT. total number of tokens: 50257 token integers: [1135, 761, 284, 2245, 17911, 25831, 2890, 24101, 38, 11571, 13] token strings: [b'We', b' need', b' to', b' stop', b' anthrop', b'omorph', b'izing', b' Chat', b'G', b'PT', b'.'] number of tokens in text: 11 encoded-decoded text: We need to stop anthropomorphizing ChatGPT.
코드 출력에서 이 토크나이저에 50,257개의 서로 다른 토큰이 포함되어 있고 각 토큰이 내부적으로 정수 인덱스에 매핑되어 있음을 알 수 있습니다. 문자열이 주어지면 정수 토큰으로 분할할 수 있으며 해당 정수를 해당하는 문자 시퀀스로 변환할 수 있습니다. 문자열을 인코딩하고 디코딩하면 항상 원래 문자열을 다시 제공해야 합니다.
이를 통해 OpenAI의 토크나이저가 작동하는 방식에 대한 좋은 직관력을 얻을 수 있지만 왜 이러한 토큰 길이를 선택했는지 궁금할 수 있습니다. 토큰화를 위한 몇 가지 다른 옵션을 고려해 보겠습니다. 각 문자가 토큰인 가장 간단한 구현을 시도한다고 가정해 보겠습니다. 이렇게 하면 텍스트를 토큰으로 쉽게 나눌 수 있고 서로 다른 토큰의 총 수를 작게 유지할 수 있습니다. 그러나 OpenAI의 접근 방식만큼 많은 정보를 인코딩할 수는 없습니다. 위의 예에서 문자 기반 토큰을 사용한 경우 11개의 토큰은 "We need to"만 인코딩할 수 있는 반면 OpenAI의 토큰 중 11개는 전체 문장을 인코딩할 수 있습니다. 현재 언어 모델에는 받을 수 있는 최대 토큰 수에 제한이 있는 것으로 나타났습니다. 따라서 각 토큰에 가능한 한 많은 정보를 담고자 합니다.
이제 각 단어가 토큰인 시나리오를 살펴보겠습니다. OpenAI의 접근 방식과 비교할 때 동일한 문장을 나타내는 데 7개의 토큰만 필요하므로 더 효율적입니다. 그리고 단어로 나누는 것도 구현하기 어렵습니다. 그러나 언어 모델에는 발생할 수 있는 토큰의 전체 목록이 있어야 하며, 이는 사전에 너무 많은 단어가 있을 뿐만 아니라 도메인별 용어 및 발명된 새로운 단어를 따라잡기 어렵기 때문에 전체 단어에 대해 실현 가능하지 않습니다.
따라서 OpenAI 가 이 두 극단 사이 어딘가에 솔루션을 찾은 것은 놀라운 일이 아닙니다. 다른 회사들도 비슷한 접근 방식을 따르는 토크나이저를 출시했습니다(예: Google의 Sentence Piece).
이제 토큰에 대해 더 잘 이해했으므로 원래 다이어그램으로 돌아가서 조금 더 잘 이해할 수 있는지 살펴보겠습니다. 생성 모델은 몇 단어, 몇 단락 또는 몇 페이지가 될 수 있는 토큰을 사용합니다. 그리고 그들은 짧은 단어 또는 단어의 일부가 될 수 있는 단일 토큰을 생성합니다.
이제 좀 더 이해가 됩니다.
그러나 OpenAI의 ChatGPT를 사용해 본 적이 있다면 단일 토큰이 아니라 많은 토큰을 생성한다는 것을 알고 있습니다. 이 기본 아이디어가 확장 창 패턴에 적용되기 때문입니다. 토큰을 제공하면 하나의 토큰이 생성되고 해당 출력 토큰이 다음 반복 입력의 일부로 통합되고 새 토큰이 출력되는 식입니다. 이 패턴은 중지 조건에 도달할 때까지 계속 반복되어 필요한 모든 텍스트 생성이 완료되었음을 나타냅니다.
예를 들어 모델에 대한 입력으로 "We need to"를 입력하면 알고리즘이 아래와 같은 결과를 생성할 수 있습니다.
ChatGPT를 가지고 노는 동안 모델이 결정론적이지 않다는 것을 눈치채셨을 수도 있습니다: 정확히 같은 질문을 두 번 하면 두 가지 다른 답을 얻을 수 있습니다. 이는 모델이 실제로 단일 예측 토큰을 생성하지 않기 때문입니다. 대신 가능한 모든 토큰에 대한 확률 분포를 반환합니다. 즉, 각 항목이 특정 토큰이 선택될 확률을 나타내는 벡터를 반환합니다. 그런 다음 모델은 해당 배포에서 샘플링하여 출력 토큰을 생성합니다.
모델은 어떻게 그 확률 분포를 제시합니까? 그것이 바로 훈련 단계의 목적입니다. 학습하는 동안 모델은 많은 텍스트에 노출되며, 입력 토큰 시퀀스가 주어지면 좋은 확률 분포를 예측하도록 가중치가 조정됩니다. GPT 모델은 인터넷의 많은 부분을 사용하여 훈련되므로 예측은 그들이 본 정보의 혼합을 반영합니다.
이제 생성 모델의 이면에 있는 아이디어를 아주 잘 이해하게 되었습니다. 나는 단지 그 아이디어를 설명했다. 아직 알고리즘을 제공하지 않았습니다. 이 아이디어는 수십 년 동안 사용되어 왔으며 수년에 걸쳐 여러 알고리즘을 사용하여 구현되었습니다. 다음으로 이러한 알고리즘 중 일부를 살펴보겠습니다.
Hidden Markov Models (HMM)는 1970 년대에 인기를 얻었습니다. 그들의 내부 표현은 문장의 문법 구조(명사, 동사 등)를 인코딩하고 새로운 단어를 예측할 때 그 지식을 사용합니다. 그러나 Markov 프로세스이기 때문에 새 토큰을 생성할 때 가장 최근의 토큰만 고려합니다. 그래서 그들은 "tokens in, one token out"아이디어의 매우 간단한 버전을 구현합니다. 결과적으로 매우 정교한 출력을 생성하지 않습니다. 다음 예를 살펴보겠습니다.
언어 모델에 "The quick brown fox jumps over the"를 입력하면 "lazy"가 반환될 것으로 예상합니다. 그러나 HMM은 마지막 토큰인 "the"만 볼 수 있으며 정보가 거의 없기 때문에 우리가 기대하는 예측을 제공할 가능성은 거의 없습니다. 사람들이 HMM을 실험하면서 언어 모델이 좋은 출력을 생성하기 위해 둘 이상의 입력 토큰을 지원해야 한다는 것이 분명해졌습니다.
N-그램은 1990년대에 하나 이상의 토큰을 입력으로 사용하여 HMM의 주요 제한 사항을 수정했기 때문에 인기를 얻었습니다. n-gram 모델은 이전 예제에서 "lazy"라는 단어를 예측하는 데 매우 효과적일 것입니다.
n-그램의 가장 간단한 구현은 문자 기반 토큰이 있는 바이그램으로, 단일 문자가 주어지면 시퀀스의 다음 문자를 예측할 수 있습니다. 단 몇 줄의 코드로 이들 중 하나를 만들 수 있으며 시도해 보는 것이 좋습니다. 먼저, 학습 텍스트에 있는 다른 문자의 수를 세고( ) 2으로 초기화된 <>D 행렬입니다. 각 입력 문자 쌍은 첫 번째 문자에 해당하는 행과 두 번째 문자에 해당하는 열을 선택하여 이 행렬에서 특정 항목을 찾는 데 사용할 수 있습니다. 학습 데이터를 구문 분석할 때 모든 문자 쌍에 대해 해당 행렬 셀에 하나를 추가하기만 하면 됩니다. 예를 들어 학습 데이터에 "car"라는 단어가 포함된 경우 "c" 행과 "a" 열의 셀에 하나를 추가한 다음 "a" 행과 "r" 열의 셀에 하나를 추가합니다. 모든 학습 데이터에 대한 카운트를 누적한 후에는 각 셀을 해당 행의 합계로 나누어 각 행을 확률 분포로 변환합니다.
그런 다음 예측을 하려면 시작할 단일 문자(예: "c")를 지정해야 합니다. "c" 행에 해당하는 확률 분포를 조회하고 해당 분포를 샘플링하여 다음 문자를 생성합니다. 그런 다음 생성한 캐릭터를 가져와 정지 상태에 도달할 때까지 이 과정을 반복합니다. 고차 n-그램은 동일한 기본 아이디어를 따르지만 n차원 텐서를 사용하여 더 긴 시퀀스의 입력 토큰을 볼 수 있습니다.
N-그램은 구현이 간단합니다. 그러나 입력 토큰 수가 증가함에 따라 행렬의 크기가 기하급수적으로 증가하기 때문에 더 많은 수의 토큰으로 잘 확장되지 않습니다. 그리고 몇 개의 입력 토큰만으로는 좋은 결과를 얻을 수 없습니다. 이 분야에서 계속 발전하기 위해서는 새로운 기술이 필요했습니다.
2000년대에 RNN(Recurrent Neural Networks)은 이전 기술보다 훨씬 더 많은 수의 입력 토큰을 수용할 수 있기 때문에 꽤 인기를 얻었습니다. 특히 RNN의 일종인 LSTM과 GRU가 널리 사용되어 상당히 좋은 결과를 얻을 수 있음이 입증되었습니다.
RNN은 신경망의 한 유형이지만 기존의 피드포워드 신경망과 달리 해당 아키텍처는 원하는 수의 입력을 수용하고 원하는 수의 출력을 생성하는 데 적응할 수 있습니다. 예를 들어, RNN에 "We", "need" 및 "to"라는 입력 토큰을 제공하고 전체 지점에 도달할 때까지 토큰을 몇 개 더 생성하려는 경우 RNN의 구조는 다음과 같을 수 있습니다.
위 구조의 각 노드는 동일한 가중치를 갖습니다. 자체에 연결되고 반복적으로 실행되는 단일 노드(따라서 "recurrent"라는 이름)로 생각하거나 위의 이미지에 표시된 확장된 형태로 생각할 수 있습니다. 기본 RNN을 통해 LSTM 및 GRU에 추가된 한 가지 주요 기능은 한 노드에서 다음 노드로 전달되는 내부 메모리 셀의 존재입니다. 이를 통해 이후 노드는 이전 노드의 특정 측면을 기억할 수 있으며, 이는 좋은 텍스트 예측을 수행하는 데 필수적입니다.
그러나 RNN은 매우 긴 텍스트 시퀀스에서 불안정성 문제가 있습니다. 모델의 그래디언트는 기하급수적으로 증가하거나("폭발 그라데이션"이라고 함) 0으로 감소하여("소실하는 그라데이션"이라고 함) 모델이 학습 데이터에서 계속 학습하지 못하게 하는 경향이 있습니다. LSTM 및 GRU는 그라디언트 소실 문제를 완화하지만 완전히 방지하지는 않습니다. 따라서 이론적으로 아키텍처는 모든 길이의 입력을 허용하지만 실제로는 해당 길이에 제한이 있습니다. 다시 한 번, 텍스트 생성의 품질은 알고리즘이 지원하는 입력 토큰의 수에 의해 제한되었으며 새로운 돌파구가 필요했습니다.
2017년, 트랜스포머를 소개한 논문이 구글에서 발표되면서 우리는 텍스트 생성의 새로운 시대를 열었습니다. 트랜스포머에 사용된 아키텍처는 입력 토큰의 수를 크게 늘리고, RNN에서 볼 수 있는 그래디언트 불안정성(gradient instability) 문제를 제거하며, 병렬화가 가능하여 GPU의 성능을 활용할 수 있습니다. 트랜스포머는 오늘날 널리 사용되며 OpenAI가 최신 GPT 텍스트 생성 모델을 위해 선택한 기술입니다.
트랜스포머는 "주의 메커니즘"을 기반으로 하며, 이를 통해 모델은 입력 시퀀스에서 나타나는 위치에 관계없이 다른 입력보다 일부 입력에 더 많은 주의를 기울일 수 있습니다. 예를 들어, 다음 문장을 생각해 봅시다.
이 시나리오에서 모델이 동사 "bought"를 예측할 때 동사 "went"의 과거 시제와 일치해야 합니다. 그러기 위해서는 토큰 "갔다"에 많은 관심을 기울여야 합니다. 사실, "went"가 입력 시퀀스에서 훨씬 더 일찍 나타난다는 사실에도 불구하고 토큰 "and"보다 토큰 "went"에 더 많은 주의를 기울일 수 있습니다.
GPT 모델의 이러한 선택적 주의 행동은 2017년 논문의 새로운 아이디어인 "가려진 다중 머리 주의" 계층의 사용에 의해 가능합니다. 이 용어를 세분화하고 각 구성 요소에 대해 자세히 알아보겠습니다.
LSTM 및 GRU의 메모리 셀은 또한 이후 토큰이 이전 토큰의 일부 측면을 기억할 수 있도록 합니다. 그러나 두 개의 관련 토큰이 매우 멀리 떨어져 있으면 그라데이션 문제가 방해가 될 수 있습니다. 트랜스포머는 각 토큰이 그 앞에 있는 다른 모든 토큰과 직접 연결되어 있기 때문에 이러한 문제가 없습니다.
이제 GPT 모델에 사용되는 트랜스포머 아키텍처의 주요 아이디어를 이해했으므로 현재 사용 가능한 다양한 GPT 모델 간의 차이점을 살펴보겠습니다.
작성 당시 OpenAI에서 출시한 최신 텍스트 생성 모델은 GPT-3.5, ChatGPT, GPT-4의 세 가지이며 모두 Transformer 아키텍처를 기반으로 합니다. 실제로 "GPT"는 "Generative Pre-trained Transformer"의 약자입니다.
GPT-3.5는 완성형 모델로 훈련된 트랜스포머로, 입력으로 몇 단어를 제공하면 학습 데이터에서 따라올 가능성이 있는 몇 단어를 더 생성할 수 있습니다.
반면 ChatGPT는 대화 스타일 모델로 훈련되어 마치 대화를 나누는 것처럼 소통할 때 가장 잘 수행됩니다. GPT-3.5와 동일한 트랜스포머 기본 모델을 기반으로 하지만 대화 데이터로 미세 조정됩니다. 그런 다음 OpenAI가 2022년 InstructGPT 논문에서 소개한 기술인 RLHF(Reinforcement Learning with Human Feedback)를 사용하여 더욱 미세 조정됩니다. 이 기술에서는 모델에 동일한 입력을 두 번 제공하고, 두 개의 다른 출력을 반환하고, 인간 랭커에게 어떤 출력을 선호하는지 묻습니다. 그런 다음 이 선택은 미세 조정을 통해 모델을 개선하는 데 사용됩니다. 이 기술은 모델의 출력과 인간의 기대 사이의 정렬을 가져오며 OpenAI의 최신 모델의 성공에 매우 중요합니다.
반면 GPT-4는 완성과 대화 모두에 사용할 수 있으며 완전히 새로운 기본 모델을 가지고 있습니다. 이 기본 모델은 또한 인간의 기대에 더 잘 부합하도록 RLHF로 미세 조정됩니다.
GPT 모델을 사용하는 코드를 작성하는 두 가지 옵션, 즉 OpenAI API를 직접 사용하거나 Azure에서 OpenAI API를 사용할 수 있습니다. 어느 쪽이든 OpenAI의 API 참조 페이지에서 배울 수 있는 동일한 API 호출을 사용하여 코드를 작성합니다.
둘 사이의 주요 차이점은 Azure가 다음과 같은 추가 기능을 제공한다는 것입니다.
이러한 모델을 사용하는 코드를 작성하는 경우 사용할 특정 버전을 선택해야 합니다. 다음은 Azure OpenAI 서비스에서 현재 사용할 수 있는 버전이 포함된 빠른 치트 시트입니다.
두 GPT-4 버전은 주로 지원하는 토큰 수가 다릅니다: gpt-4는 8,000개의 토큰을 지원하고 gpt-4-32k는 32,000개의 토큰을 지원합니다. 반면 GPT-3.5 모델은 4,000개의 토큰만 지원합니다.
GPT-4는 현재 가장 비싼 옵션이므로 다른 모델 중 하나로 시작하고 필요한 경우에만 업그레이드하는 것이 좋습니다. 이러한 모델에 대한 자세한 내용은 설명서를 참조하세요.
이 기사에서는 모든 생성 언어 모델에 공통적인 기본 원칙과 특히 OpenAI의 최신 GPT 모델의 고유한 측면을 다루었습니다.
그 과정에서 우리는 언어 모델의 핵심 아이디어인 "토큰 입력, 하나의 토큰 출력"을 강조했습니다. 우리는 토큰이 어떻게 분할되는지, 그리고 왜 그런 식으로 분할되는지 탐구했습니다. 그리고 우리는 히든 마르코프 모델(Hidden Markov Models)의 초창기부터 최근의 트랜스포머 기반 모델에 이르기까지 수십 년에 걸친 언어 모델의 진화를 추적했습니다. 마지막으로 OpenAI의 세 가지 최신 트랜스포머 기반 GPT 모델, 각 모델의 구현 방법 및 이를 활용하는 코드를 작성하는 방법에 대해 설명했습니다.
지금쯤이면 GPT 모델에 대한 정보에 입각한 대화를 나누고 자신의 코딩 프로젝트에서 사용할 수 있는 준비가 잘 되어 있어야 합니다. 언어 모델에 대한 이러한 설명자를 더 많이 작성할 계획이므로 다루고 싶은 주제가 있으면 알려주십시오. 읽어 주셔서 감사합니다!
기업 홍보를 위한 확실한 방법협회 홈페이지에 회사정보를 보강해 보세요.