
Date: 2024.04.13 ~ 2024.05.24

Do it! BERT와 GPT로 배우는 자연어 처리 (트랜스포머 핵심 원리와 허깅페이스 패키지 활용법)
나는 이때까지 인공지능 관련 해서 간단한 선형회귀, 분류, 시계열 데이터 회귀, CV쪽으로만 해봤다. 서비스를 다양하게 제공하려면 CV쪽 뿐만 아니라 NLP 쪽도 알고 있으면 내가 제공할 수 있는 서비스의 폭이 넓어지리라 생각했다. 또한, NLP를 못해봤으니 '내가 CV를 더 재미있어할까 NLP를 더 재미있어할까 그리고 연구실을 컨텍한다면 어디쪽 위주로 하는 곳을 해야할까' 이러한 진로 고민 때문에 NLP를 공부해보기 위해서 우리 학교 인공지능학회인 HYAI의 NLP 반에 들어갔다. 당시 NLP반 다른 학회원분들께서도 다들 NLP를 안해보신 상태에서 공부해보고 싶어 들어온 상황이었다. 그래서 어떠한 NLP를 가지고 프로젝트를 바로 진행하기에 무리가 있었고, 마침 학회에서 책 1권을 지원해 주신다 하여 책 한권을 정하고 빠르게 내용을 보고난 후 프로젝트를 해보자고 팀장님께서 제안하셨다. 팀장님께서 심리 상태 진단을 위한 ChatBot을 만들고 앱 서비스까지 확장시키는 프로젝트를 제안하셨고, 전처리, NLU, NLG, 서비스 구축 이러한 부분이 필요하여 이 책을 제안하셨다. 이 책의 목차를 보면 토큰화 같은 전처리, Transformer 모델의 설명, 문서 분류, 문장 쌍 분류, 개체명 인식 모델, 질의응답 모델, 문장 생성 모델 등과 각각 실습 챕터에서는 Flask 기반 웹 서비스를 만들 수 있었기 때문에 전처리, NLU, NLG, 서비스 구축 모두 포함될 수 있는 책이라고 느껴서 나도 골랐다. 다수의 학회원분들이 투표했기 때문에 이 책으로 선정됐고, 한 학기 동안 이 책을 읽고 학회 활동을 하게 됐다.
책의 목차만 보면 이 책만 읽으면 NLP의 전반적인 과제를 다 해볼 수 있는 것처럼 보여서 여러 NLP 프로젝트를 해볼 수 있겠다고 생각했지만, 실습 부분이 너무 아쉬웠다. 특히 가장 아쉬웠던 부분이 범용적으로 사용하지 않고 책에서만 사용하는 모듈(ratsnlp)을 사용해서 전처리를 하거나, 모델을 가져오거나, 인자를 지정하거나, 말뭉치를 가져오는 등 기능을 수행한다. 이러한 이유로 모르는 부분이 나와도 이 책을 사서 공부해본 사람들 말고는 사용하는 사람이 없기 때문에 정보를 찾기 어려웠다. 또한, 이 책에서 ratnlp 모듈에 대한 의존성이 너무 커서 이 책을 끝낸다고 해서 내가 할 수 있는 프로젝트가 아무것도 없다. 또한, 실습 환경이 Colab에서 할 수 있으나 학습이 약 4~5시간 정도 걸리고, 그 사이에 colab의 gpu 사용 시간이 초과되어 종료되는 등의 실습 환경에 문제가 있다. 그래서 나는 Visual Studio Code로 Local 환경을 구성해서 진행했는데, 동일 코드에서 local 환경에서만 나오는 에러들이 각 실습 장마다 있었다. ratsnlp 모듈의 사용때문에 무언가 안맞았던 부분들이 있었던 것 같다. 실습에 관해서는 남는게 딱히 없었어서 'nlp는 대강 이런 것이고요, 이런 상황에 사용할 수 있어요'를 256 page로 만들어 놓은 느낌이었다.
이론쪽은 내용은 조금 어렵긴 했지만 좋았다. 하지만, 내용의 순서가 조금 이해하기가 어렵게 되어있다. 예를 들어, A를 설명하려고 하면 A에 대한 설명을 간략하게 하고 뒤에 제대로 나온다는 식으로 서술되어 있고, 그 다음에는 A의 용어가 계속 나오고 A를 사용해서 설명한다. 이러한 서술방식으로 쭉 읽다보면, '아니 그래서 A가 뭔데?' 하고 다시 돌아가서 보게 된다. 왜 이런 서술 방식을 택했는지는 용어에 대한 낯선 느낌을 책을 읽어나갈 수록 낮춰가기 위해서 이렇게 했다고는 생각이 드나, 읽을 입장에서는 초반부터 너무 낯선것들이 많았기 때문에 처음 읽어서는 한번에 이해되지 않았다. 그래서 입문서라고는 하나, 입문하는 사람 입장에서는 책의 설명이 불친절하다고 느껴질 수 있을 것 같다. 하지만 이러한 서술 방식의 장점 아닌 장점이 있었는데, 쭉 읽다가 A가 궁금해져서 다시 초반부터 읽어보면 정리가 되면서 이해가 잘 되는 느낌이 있었다. 그래서 한번 봐서는 이해하기 어려웠고, 3번 정도 다시 돌아가서 읽으면 제대로 내용을 습득할 수 있는 구조였다. 정리하자면, 이론 내용 자체는 괜찮은 것 같으나 서술 방식 때문에 입문자에게는 조금 어려울 수 있는 책이라고 생각이 들었다.
특정 태스크를 학습한 모델을 다른 태스크 수행에 재사용하는 기법이다. GPT나 BERT도 트랜스퍼러닝이 적용됐다.
다음 단어 맞히기, 빈칸 채우기 등 대규모 말뭉치의 문맥을 이해하는 과제이다.
문서 분류, 개체명 인식 등 우리가 풀고자 하는 자연어 처리의 구체적인 문제들을 뜻한다.
업스트림 태스크를 학습하는 과정을 뜻한다.
다음 단어 맞히기로 업스트림 태스크를 수행한 모델이다.
빈칸 채우기로 업스트림 태스크를 수행한 모델이다.
언어 모델과 마스크 언어 모델 둘 다 맞추려고 하는 단어가 정답에 해당하는 확률은 높이고 나머지 단어와 관계된 확률은 낮추는 방향으로 학습한다.
문장을 토큰 시퀀스로 나누는 과정이다. 수행 대상에 따라 문자, 단어, 서브워드 등 세가지 방법이 있다.
토큰화를 수행하는 프로그램이다.
단어(어절) 단위로 토큰화를 수행한다. 공백으로 분리하면 별도로 토크나이저를 쓰지 않아도 된다는 장점이 있지만, 어휘 집합의 크기가 매우 커질 수 있다. 한국어에서는 "갔었어, 갔었는데요"와 같이 표현이 조금만 바뀌어도 모든 경우의 수가 어휘 집합에 포함되어야 하기 때문이다.
문자 단위로 토큰화를 수행한다. 한글, 알파벳, 숫자, 기호를 고려한 어휘 집합 크기가 15,000개 정도이다. 그리고 어떤 언어의 모든 문자를 어휘 집합에 포함하므로 미등록 토큰(unknown token) 문제로부터 자유롭다. 하지만 각 문자 토큰이 의미있는 단위가 되기는 어렵다는 점과 다른 토큰화에 비해 토큰 시퀀스의 길이가 상대적으로 길어질 수 있어서 성능이 떨어지게 된다는 단점이 있다.
미등록 토큰(unknown token)은 어휘 집합에 없는 토큰이다.
ex) 신조어
단어와 문자 단위 토큰화 중간에 있는 형태이다. 둘의 장점만을 취한 형태이다. 즉, 어휘 집합 크기가 지나치게 커지지 않으면서도 미등록 토큰 문제를 피하고, 분석된 토큰 시퀀스가 너무 길어지지 않게 한다.
데이터에서 가장 많이 등장한 문자열을 병합해서 데이터를 압축하는 기법이다. GPT 모델이 토큰화를 수행하는 기법이고, 대표적인 서브워드 단위 토큰화이다. 사전 크기 증가를 억제하면서도 정보를 효율적으로 압축할 수 있는 알고리즘이다.
우도(likelihood)를 가장 높이는 글자 쌍을 병합하는 기법이다. BERT 모델이 토큰나이저로 사용하는 기법이다.

#a, #b는 각각 각 문자의 빈도수, n는 전체 글자 수를 가리킨다.
즉, 분자는 ab가 연이어 등장할 확률이고 분모는 a, b가 각각 등장할 확률의 곱이다.
따라서, 이 전체 값이 커지려면 a, b가 서로 독립일 때 자주 동시에 등장해야 한다.
단어 시퀀스에 확률을 부여하는 모델이다.

전체 단어 스퀀스가 나타날 확률 = 이전 단어들이 주어졌을 때 다음 단어가 등장할 확률의 연쇄
따라서, 이전 단어들이 주어졌을 때 다음 단어가 나타낼 확률을 부여하는 모델이라고도 한다.

컨텍스트(context; 주변 맥락 정보)가 전제된 상태에서 특정 단어(w)가 나타날 조건부 확률을 나타낸다. 단어나 단어 시퀀스로 구성된 컨텍스트를 입력받아 특정 단어가 나타날 확률을 출력한다.
이전 단어들(컨텍스트)이 주어졌을 때 다음 단어을 맞히는 방식이다.
문장을 앞에서 뒤로, 사람이 이해하는 순서대로 계산하는 모델이다.
GPT 모델이 수행하는 방식이다.
문장을 뒤에서부터 앞으로 계산하는 모델이다.
학습 대상 문장에 빈칸을 만들어 놓고 해당 빈칸에 올 단어로 적절한 단어가 무엇일지 분류하는 과정으로 학습한다. BERT가 마스크 언어 모델로 프리트레인 한다. 마스크 언어 모델은 문장 전체의 맥락을 참고할 수 있다. 따라서 마스크 언어 모델은 양방향(bidirectional) 성질이 있다.
어떤 단어 앞뒤에 특정 범위를 정해 두고 범위 내에 어떤 단어들이 올지 분류하는 과정으로 학습한다. 단어 임베딩 기법 중 Word2Vec이 학습하는 방식이다.
구글이 제안한 스퀀스-투-스퀀스(Sequence-to-Sequence) 모델이다. BERT와 GPT 둘 다 트랜스포머 기반 언어 모델이다.
단어 같은 무언가의 나열을 의미한다.
특정 속성을 지닌 시퀀스를 다른 속성의 시퀀스로 변환하는 작업을 가리킨다.
ex) 기계 번역은 Source Language의 토큰 시퀀스를 -> Target Language의 토큰 시퀀스로 변환하는 과제이다.
소스 시퀀스의 정보를 압축해 디코더로 보내는 역할을 담당한다.
인코더 보내준 소스 시퀀스 정보를 받아 타깃 시퀀스를 생성한다.

인코더와 디코더 입력이 주어졌을 때 정답에 해당하는 단어의 확률값은 높이고, 아닌 단어들은 확률값을 낮추는 방식으로 학습한다.
시퀀스 입력에 수행하는 기계학습 방법의 일종이다. 시퀀스 요소 가운데 중요한 요소에 집중하고, 그렇지 않은 요소는 무시해 태스크 성능을 올리는 기법이다.
트랜스포머의 멀티헤드 어텐션이 셀프 어텐션으로 불린다. 말 그대로 자기 자신에게 수행하는 어텐션 기법이다. 입력 시퀀스 가운데 태스크 수행에 의미 있는 요소들 위주로 정보를 추출한다.
셀프 어텐션은 쿼리(query), 키(key), 벨류(value) 3가지 요소가 서로 영향을 주고 받는 구조이다. 각 단어가 벡터로 입력되면 쿼리, 키, 벨류로 변환된다. 셀프 어텐션은 쿼리 단어 각각을 대상으로 모든 키 단어와 얼마나 유기적인 관계를 맺는지 그 합이 1인 확률값으로 나타낸다.

이 결과에 밸류 벡터들을 가중합(weighted sum)하는 방식으로 계산을 마무리한다.

이러한 방식으로 나머지 단어들도 셀프 어텐션을 각각 수행한다. 모든 시퀀스를 대상으로 셀프 어텐션 계산이 끝나면 그 결과를 다음 블록으로 넘긴다. 즉, 트랜스포머 모델은 셀프 어텐션을 블록(레이어) 수만큼 반복한다.
소스 시퀀스 입력 임베딩에 위치 정보(positional encoding)을 더해서 만든다. positional encoding은 각 토큰이 문장 내에서 몇 번째 위치인지 나타낸다.
출력층의 출력은 타깃 언어의 어휘 수만큼 차원을 갖는 벡터가 된다. 그리고, 각 요솟값을 모두 더하면 그 합이 1이 된다. 이 벡터는 디코더에 입력된 타깃 시퀀스의 다음 토큰 확률 분포를 가리킨다.
트랜스포머의 학습은 인코더와 디코더 입력이 주어졌을 때 모델 최종 출력에서 정답에 해당하는 단어의 확률값을 높이는 방식으로 수행된다.
셀프 어텐션은 트랜스포머의 인코더와 디코더 모두에서 수행된다.
1) 쿼리, 키 벨류 만들기
입력 벡터 시퀀스(X)에 쿼리, 키, 밸류를 만들어 주는 행렬(W) 각각 행렬 곱셈 연산을 한다.

W(Q), W(K), W(V) 세 가지 행렬은 태스크를 가장 잘 수행하는 방향으로 학습 과정에서 업데이트 된다.
2) 쿼리를 셀프 어텐션 계산

책에서 예시를 통해서 계산 과정을 설명해주고 있으니 자세히 보고 싶다면 책 참조.
셀프 어텐션을 동시에 여러 번 수행하는 것을 가리킨다. 여러 헤드가 독자적으로 셀프 어텐션을 계산한다.
디스틸레이션(distillation), 퀀타이제이션(quantization), 프루닝(pruning), 파라미터 공유(weight sharing) 등의 기법으로 모델 성능을 최대한 유지하면서 계산량 혹은 모델의 크기를 줄이려는 시도가 지속되고 있다.
프리트레인을 마친 모델과 그 위 작은 모듈을 포함한 전체 모델을 테스크에 맞는 다운스트림 데이터로 업데이트 하는 과정이다.
각 실습 쳅터들은 각 Task에 대해 간략하게 설명한 뒤, 모델을 제작하고 서비스화를 하는 형식으로 진행됐다. 그래서 간략한 Task 소개와 모델 제작 후 서비스화를 한 결과를 정리해봤다.
문서 분류(document classification)는 문서가 주어졌을 때 해당 문서의 범주를 분류하는 과제이다. 예를 들어, 대표적으로 뉴스를 입력으로 하고 정치, 경제, 연예 등의 범주를 맞히거나, 영화 리뷰가 긍정인지 부정인지 등의 어떤 극성 (polarity)를 가지는지 분류하는 작업이 있다.


문장 쌍 분류(sentence pair classification)의 대표 예시로 자연어 추론(Natural Language Inference, NLI) 과제를 실습했다.
문장 쌍 분류는 문장 2개가 주어졌을 때 해당 문장 사이의 관계가 어떤 범주인지 분류하는 과제이다.
자연어 추론은 2개의 문장 또는 문서가 참(entailment, 함의), 거짓(contradiction, 모순), 중립(neutral, 판단불가)인지 가려내는 것이다.



개체명 인식(named enitity recognition)은 문장을 토큰화 한 뒤 토큰 각각이 어떤 개체명 태그에 속하는지 확률을 구해서 인명, 지명, 기관명 등 개체명 태그를 붙여주는 과제이다.

질의 응답은 질문에 답을 하는 과제이다.
질문에 대한 답을 지문(context)에서 찾는 것이다.
각 입력 토큰이 [정답의 시작일 확률, 정답의 끝인 확률]을 구한다.
아래는 이 결과를 후처리하면 다음과 같이 만들 수 있다.

문장 생성은 문장을 만들어 내는 과제이다.
컨텍스트(이전 단어들)가 주어졌을 때 다음 단어로 어떤 단어가 오는게 적절한지 분류하는 과제.
네이버 영화 리뷰 데이터(NSMC) 학습
레이블(긍정 or 부정) + 리뷰 문장을 입력으로 준다.
'긍정 아 정말' 까지만 프롬프트를 입력했을 때 아래와 같은 생성 결과가 나온다.

'부정 아 정말' 까지만 프롬프트를 입력했을 때 아래와 같은 생성 결과가 나온다.

NLP를 아직 내 프로젝트에 사용할만큼 공부를 못해봤기 때문에 이번에는 내가 데이터를 모으고 그 데이터를 활용해서 실습해볼 수 있는 책을 선정하여 공부해볼 예정이다.