이 강좌에서는 대규모언어모델(LLM, Large Language Model)의 기초기술과 이를 이용하여 자연어 처리(natural language processing)의 다양한 작업을 해결하는 방법을 설명합니다.
자연어처리란 인간이 일상적으로 사용하는 언어를 컴퓨터가 어떻게 처리할 것인가를 연구하는 학문입니다. 최근에는 대규모로 훈련된 신경망(nerual network)인 대규모언어모델을 이용한 방법이 자연어 처리의 표준이 되고 있습니다.
이 강좌에서는 Python을 사용하여 소스 코드를 작성하고, 신경망 작성에는 표준 라이브러리 중 하나인 PyTorch를 사용합니다. 이 책에서 제공하는 소스 코드는 브라우저에서 Python 코드를 작성 및 실행할 수 있는 Google Colaboratory(Colab)를 사용하여 간단하게 동작시킬 수 있습니다. Colab에서는 Colab 노트북에 셀(cell)을 추가하여 코드를 작성합니다. 셀에는 코드를 기재하는 코드 셀과 Markdown 형식으로 텍스트를 기재할 수 있는 텍스트 셀이 있습니다. 이 강좌의 본문에서는 코드 셀만 사용합니다. 본 강좌에서는 셀의 코드와 그 출력에 대해 다음과 같은 형식으로 설명합니다.
In[1]: print("대규모언어모델 입문하기!")
Out[1]: 대규모언어모델 입문하기!
또한, 셀에서 시스템 명령을 실행할 수 있습니다. 시스템 명령은 파이썬 코드와 구분하기 위해 먼저 !를 붙여서 작성하며, Colab에서 사용하는 리눅스 버전을 살펴봅시다.
In[2]: !cat /etc/os-release | head -n 2
Out[2]: PRETTY_NAME="Ubuntu 22.04.3 LTS" NAME="Ubuntu"
이 글의 작성 시점에는 Ubuntu 22.04.3 LTS가 사용되고 있었습니다.되고 있음을 알 수 있다. Colab은 오픈소스 Jupyter 라이브러리와 호환되며, Colab 노트북에서 Jupyter 노트북 형식의 파일(ipynb 파일)을 다운로드하여 원하는 환경에서 실행할 수 있습니다. 대규모 언어 모델을 프로그램에서 다루기 위한 표준 라이브러리가 transformers입니다. 이 라이브러리를 개발한 Hugging Face는 2016년에 설립된 회사로, transformers 외에도 데이터셋을 다루는 라이브러리인 datasets와 텍스트 분할을 위한 라이브러리인 tokenizers를 제공하고 있습니다. 또한, 클라우드 상에서 모델과 데이터셋 등을 무료로 공유할 수 있는 Hugging Face Hub를 제공하고 있습니다. 이 강좌에서는 학습한 모든 모델을 Hugging Face Hub에 공개하고 있으며, 아래에서 소개하는 것처럼 transformers에서 쉽게 사용할 수 있도록 하고 있습니다. 또한, 데이터세트도 Hugging Face Hub에 공개하여 데이터세트를 통해 사용할 수 있도록 하고 있습니다. 먼저 Python의 패키지 매니저인 pip 명령어를 사용하여 transformers를 설치합니다. 한국어를 다루기 위한 라이브러리를 설치하는 “ko” 옵션을 사용하며, 설명할 SentencePiece를 설치하는 “sentencepiece” 옵션, PyTorch와 관련 라이브러리를 설치하는 “torch” 옵션을 지정합니다.
!pip install transformers[ko,sentencepiece,torch]
transformers에는 모델을 쉽게 다룰 수 있는 pipelines라는 기능이 있습니다. 여기서 자연어 처리의 주요 작업에 대해 이 강좌에서 구축하는 모델을 실제로 움직이면서 개괄적으로 살펴봅시다. pipelines는 pipeline 함수를 통해 사용합니다.
from transformers import pipeline
문서분류(document classification)는 텍스트를 미리 정해진 레이블로 분류하는 작업입니다. 문서분류의 예로는 뉴스 기사를 자동으로 '스포츠', '엔터테인먼트' 등의 장르로 분류하는 작업이나 메일을 스팸인지 아닌지를 자동으로 판단하는 작업 등이 있습니다. 또한, 텍스트에서 읽을 수 있는 감정을 감지하는 문서 분류를 감정 분석(sentiment analysis)이라고 합니다.
text_classification_pipeline = pipeline(
model="llm-lecture/bert-base-korean-marc_en”
)
positive_text = “세상에는 말이 통하지 않아도 감동을 주는 음악이 있습니다.”
# positive_text의 극성예측
print(text_classification_pipeline(positive_text)[0])
{'label': 'positive', 'score': 0.9993619322776794}
# negative_text의 극성예측
negative_text = “세상에는 말문이 막힐 정도로 끔찍한 음악이 있습니다.”
print(text_classification_pipeline(negative_text)[0])
{'label': 'negative', 'score': 0.9636247754096985}
“score"는 예측 확률을 나타내며, 위의 예시에서는 모두 96% 이상의 높은 확률로 적절한 라벨을 예측하고 있습니다.
자연어 추론(natural language inference, NLI)은 두 텍스트의 논리적 관계를 예측하는 작업입니다. 나중에 구축한 자연어 추론 모델 llm-lecture/bert-base-korean-v1을 구동해 봅시다.
nli_pipeline = pipeline(model=“llm-lecture/bert-base-korean-v1”)
text = “두 사람이 제트기를 보고 있습니다.”
entailment_text = “두 사람이 제트기를 보고 있습니다.”
# text와 entailment_text의 논리적 관계 예측
print(nli_pipeline({“text”: text, “text_pair”: entailment_text}))
{'label': 'entailment', 'score': 0.9964311122894287}
contradiction_text = “두 남자가 날고 있습니다”
# text와 contradiction_text의 논리적 관계예측
print(nli_pipeline({“text”: text, “text_pair”: contradiction_text}))
{'label': 'contradiction', 'score': 0.9990535378456116}
neutral_text = “두 남자가 하얀색 비행기를 바라보고 있습니다.”
# text와 neutral_text의 논리적 관계 예측
print(nli_pipeline({“text”: text, “text_pair”: neutral_text}))
{'label': 'neutral', 'score': 0.9959145188331604}
“entailment"는 ‘함축’을 의미하며, 위의 예에서 ‘두 남자가 제트기를 보고 있습니다’가 성립한다면 ‘제트기를 보고 있는 사람이 두 명 있습니다’도 성립한다는 관계를 나타냅니다. "contradiction"은 '모순'으로, '두 남자가 제트기를 보고 있습니다'라는 상황은 '두 남자가 날고 있습니다'와 모순되기 때문에 이 라벨이 예측됩니다. “neutral"은 ‘중립’으로, ‘함축’도 ‘모순’도 판단할 수 없는 텍스트 쌍에 부여되는 레이블입니다.
의미적 유사도 계산(semantic textual similarity, STS)은 두 텍스트의 의미 유사도를 점수로 예측하는 작업입니다. 정보 검색이나 여러 텍스트의 내용 정합성을 확인할 때 유용하게 사용할 수 있습니다. 나중에 설명하며 만든 의미적 유사도 계산 모델 llm-lecture/bert-base-korean-v1을 실행해 봅시다. 이 모델은 주어진 두 텍스트의 의미적 유사도를 0에서 5까지의 범위로 예측합니다.
text_sim_pipeline = pipeline(
model=“llm-lecture/bert-base-korean-v1”,
function_to_apply=“none”,
)
text = “강변에 서핑보드를 들고 있는 사람들이 있습니다.”
sim_text = “서퍼들이 강둑에 서 있습니다.”
# text와 sim_text의 유사도 계산
result = text_sim_pipeline({“text”: text, “text_pair”: sim_text})
print(result[“score”])
3.5703558921813965
dissim_text = “화장실 벽에 검은색 수건이 걸려있습니다.”
# text와 dissim_text의 유사도를 계산함
result = text_sim_pipeline({“text”: text, “text_pair”: dissim_text})
print(result[“score”])
0.04162175580859184
내용이 비슷한 텍스트 쌍을 입력한 경우 약 3.6, 관련이 없는 쌍에 대해서는 0에 가까운 값이 출력됩니다. 또한, 나중에 설명하며 텍스트의 의미를 벡터로 표현하는 문장 임베딩(sentence embedding) 모델을 소개합니다. 이 모델에서 얻은 텍스트 벡터의 코사인 유사도를 의미적 유사도로 간주할 수 있습니다. 나중에 만든 문장 임베딩 모델 llm-lecture/bert-base-korean-v1-unsup-simcse을 사용하여 의미적 유사도를 계산해 봅시다.
from torch.nn.functional import cosine_similarity
sim_enc_pipeline = pipeline(
model=“llm-book/bert-base-korean-v1-unsup-simcse”,
task=“feature-extraction”,
)
# text 및 sim_text의 백터 가져오기
text_emb = sim_enc_pipeline(text, return_tensors=True)[0][0]
sim_emb = sim_enc_pipeline(sim_text, return_tensors=True)[0][0]
# text 및 sim_text의 유사도 계산
sim_pair_score = 코사인_유사도(text_emb, sim_emb, dim=0)
print(sim_pair_score.item())
0.8568589687347412
# dissim_text 벡터 가져오기
dissim_emb = sim_enc_pipeline(dissim_text, return_tensors=True)[0][0] # text와 dissim_text의 유사도 계산함
dissim_pair_score = cosine_similarity(text_emb, dissim_emb, dim=0)
print(dissim_pair_score.item())
0.45887047052383423
코사인 유사도 값의 범위는 -1에서 1까지입니다. 내용이 유사한 텍스트 쌍을 입력한 경우 약 0.86, 관련이 없는 쌍의 경우 약 0.46으로 의미의 근접성에 따른 값을 얻을 수 있습니다.