본문 바로가기
TIL _Today I Learned/2024.10

[DAY 60] 자연어 처리 (NLP) 모델

by gamdong2 2024. 10. 15.
[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 9기
학습일 : 2024.10.15

📕 학습 목록

  • 자연어 처리 (NLP) 기술

 

📗 기억할 내용

1. 자연어 처리 (NLP) 기술

1) Transformer 모델

①  정의 및 특징

  • Transformer는 자연어 처리(NLP) 분야에서 매우 중요한 모델
  • 2017년 Google의 연구팀이 발표한 논문 "Attention is All You Need"에서 처음 제안되었으며, 그 이후로 다양한 자연어 처리 작업에 적용되고 있음
  • Transformer는 자연어 처리 모델의 기본 구조로, 텍스트 분류, 기계 번역, 질문 응답 등의 작업에서 뛰어난 성능을 보임

② 작동 방식

  • Self-Attention 메커니즘을 통해 문장의 모든 단어 간 관계를 동시에 고려하는 방식
  • 이전의 RNN이나 LSTM 모델에 비해 병렬 처리가 가능하고, 더 큰 데이터셋에서 학습할 수 있다는 장점이 있음; 자연어 처리의 효율성을 크게 향상시킴

2) 자연어 처리 기술 별 대표 모델

자연어 처리 기술 설명 대표 모델 (Hugging Face)
* 대부분이 Transformer 기반 모델
Text Classification
(텍스트 분류)
텍스트를 미리 정의된 카테고리로 분류 (감정 분석, 뉴스 분류 등) BERT, RoBERTa
Token Classification
(토큰 분류)
텍스트를 여러 토큰으로 나누고, 각 토큰에 특정 라벨을 할당 (NER, 품사 태깅) BERT-NER, SpaCy
Table Question
Answering
(표 기반 질문 응답)
테이블 형태의 데이터를 기반으로 질문에 대한 답을 찾는 작업 TAPAS
Question Answering
(질문 응답)
주어진 문서에서 질문에 대한 답을 추출 BERT QA, T5
Zero-Shot
Classification
(제로샷 분류)
사전 학습된 클래스 외의 새로운 클래스에 대해 텍스트를 분류하는 작업 GPT-3, XLM-RoBERTa
Translation
(번역)
한 언어에서 다른 언어로 텍스트를 번역하는 작업 mBART, MarianMT
Summarization
(요약)
긴 텍스트를 요약하여 중요한 정보만 남기는 작업 T5, BART
Feature Extraction
(특징 추출)
텍스트에서 의미 있는 특징을 추출하여 벡터 형태로 변환 BERT, DistilBERT
Text Generation
(텍스트 생성)
주어진 문장을 기반으로 새로운 문장을 생성하는 작업 GPT-3, BART
Text2Text Generation
(텍스트 간 생성)
입력된 텍스트를 다른 텍스트로 변환 (예: 번역, 요약 등) T5, BART
Fill-Mask
(빈칸 채우기)
문장에서 누락된 단어나 비문법적인 단어를 예측하여 채워 넣는 작업 BERT, RoBERTa
Sentence Similarity
(문장 유사도)
두 문장의 의미적 유사도를 측정하는 작업 SBERT, Universal Sentence Encoder (USE)

 
3) LLM 모델

① 정의

  • LLM (Large Language Models) : 매우 큰 규모의 파라미터를 가진 딥러닝 기반 언어 모델

② 특징

  • 대규모 데이터를 학습하여 텍스트 생성, 번역, 요약, 질문 응답, 대화 등 다양한 작업을 수행함
  • 주로 Transformer 아키텍처를 기반으로 함
  • 자연어 처리 작업에서 놀라운 성능을 발휘함
  • 주로 지도 학습을 통해 대규모 데이터셋을 학습하여, 문맥을 이해하고, 새로운 문장을 생성하거나 입력 텍스트의 의미를 파악하는 데 매우 뛰어난 성능을 보임

③ 주요 LLM 모델

  • GPT-3 (Generative Pretrained Transformer 3)
    • 개발사: OpenAI
    • 파라미터: 175억 개
    • 설명: 텍스트 생성, 번역, 요약, 대화 등 다양한 작업에서 사용됨. 특히 제로샷 학습원샷 학습 능력이 뛰어나며, 사전 학습된 지식을 바탕으로 여러 새로운 태스크를 처리할 수 있음
  • LLaMA (Large Language Model Meta AI)
    • 개발사: Meta AI
    • 파라미터: 7B, 13B, 30B, 65B (버전별로 다름)
    • 설명: 더 적은 자원으로도 뛰어난 성능을 발휘하는 것이 특징. 연구 목적으로 널리 활용되며, 대규모 데이터를 통해 텍스트 생성 및 질문 응답 작업에 강점을 보임
  • BERT (Bidirectional Encoder Representations from Transformers)
    • 개발사: Google AI
    • 파라미터: BERT-base (110M), BERT-large (340M)
    • 설명: BERT는 양방향 트랜스포머 모델로, 문맥을 양방향에서 동시에 이해함. 주로 텍스트 분류, 질문 응답, 문장 유사도 계산 등에 사용되며, 사전 학습 후 특정 태스크에 맞춰 미세 조정됨
  • T5 (Text-to-Text Transfer Transformer)
    • 개발사: Google AI
    • 파라미터: T5-small (60M), T5-large (770M), T5-3B (3B), T5-11B (11B)
    • 설명: T5는 모든 NLP 태스크를 텍스트-투-텍스트 문제로 변환하여 처리하는 모델. 텍스트 분류, 요약, 번역 등 다양한 작업을 수행할 수 있으며, 단일 아키텍처로 다양한 NLP 작업을 처리할 수 있음
  • PaLM (Pathways Language Model)
    • 개발사: Google AI
    • 파라미터: 540B
    • 설명: PaLM은 초대형 모델로, 트랜스포머 기반의 모델. 여러 태스크에서 뛰어난 성능을 보이며, 자연어 생성, 질문 응답, 요약 등 다양한 작업에 사용됨

④ LLM 모델들의 주요 사용 사례

  • 텍스트 생성: 문서 작성, 대화 응답 생성, 창의적인 글쓰기
  • 질문 응답: 문서에서 정답을 추출하거나, 주어진 질문에 대한 적절한 응답 생성
  • 번역: 한 언어에서 다른 언어로 텍스트 번역
  • 요약: 긴 텍스트에서 중요한 정보만을 추출하여 요약
  • 문장 분류: 텍스트를 특정 카테고리로 분류하는 작업

4) 원하는 출력을 유도하기 위한 방법

① GeDi(Generative Enhanced Discriminator) 방식 

GeDi 모델의 작동 방식

  • 정의: 기존의 언어 모델(예: GPT-2)과 함께 Discriminator(분류기)를 사용하는 방식. 이 기법은 언어 모델이 텍스트를 생성할 때, 특정한 속성(예: 긍정적, 부정적 감정, 정치적 입장 등)을 반영하여 출력을 제어하는 데 사용
  • 특징: GeDi는 생성 도중에 텍스트의 각 토큰을 검토하여, 선택된 토큰이 지정된 속성(예: 긍정적인 문장)과 일치하는지 평가함. 이를 통해 언어 모델의 출력을 더 정밀하게 제어할 수 있음
  • 작동 순서:
    1. 단어 선택: LLM은 문장에서 다음에 나올 가능성이 있는 여러 후보 단어들을 제안함. 각 단어는 문맥에 따라 모델이 학습한 내용에 기반하여 예측됨
    2. 속성 평가: GeDi 모델은 각 후보 단어가 설정된 속성(예: 긍정적, 부정적, 유해하지 않음 등)에 얼마나 부합하는지 평가함. 이 과정은 각 후보 단어를 주어진 속성과 비교해 점수를 매기는 방식으로 이루어짐
    3. 가장 적합한 단어 선택: 속성 평가에서 가장 높은 점수를 받은 단어가 선택됨. 이 단어는 문맥과 속성 모두를 만족하는 단어로, 생성할 텍스트의 흐름을 유지하면서도 설정된 조건에 맞게 선택됨
    4. 다음 단어 생성: 선택된 단어를 바탕으로 모델은 이어지는 문장을 생성. 이전에 선택된 단어들이 새로운 문맥을 형성하며, 다음 단어 후보들이 다시 예측되고, 이 과정을 반복해 문장이 완성됨
  • 사용 예: 긍정적인 문장만 생성하는 챗봇을 만들거나, 특정 정치적 입장과 일치하는 문장만 생성하는 등의 작업에 사용될 수 있음

② PPLM(Plug and Play Language Model) 방식

PPLM 모델의 작동 방식

  • 정의: 대형 사전 학습된 언어 모델에 특정한 속성을 부여하여, 사용자가 원하는 특정 방향으로 출력을 제어할 수 있는 방식. 이 방식은 기존의 LLM을 수정하지 않고, 특정 속성을 부여하는 플러그인 방식을 채택함
  • 특징: PPLM은 기존 언어 모델의 출력을 미세하게 조정하기 위해 제어 벡터를 활용하여, 모델이 문장을 생성하는 동안 실시간으로 출력의 속성을 조절함. 예를 들어, 모델이 생성하는 텍스트를 더 긍정적이거나 더 부정적으로 만들 수 있음
  • 작동 순서:
    1. 기본 언어 모델 선택: PPLM은 사전 학습된 대형 언어 모델(예: GPT-2)을 사용하여 텍스트 생성을 시작. 이 모델은 사전 학습된 데이터를 기반으로 자연스럽게 문장을 생성할 수 있음
    2. 제어 속성 설정: PPLM은 사용자가 지정한 특정 속성(예: 긍정적, 부정적, 정치적 입장 등)을 적용하여 텍스트 생성을 제어함. 이 속성은 특정 주제나 감정을 반영하는 벡터로 변환됨
    3. 제어 벡터 삽입: PPLM은 생성 도중 언어 모델의 숨겨진 상태(hidden states)에 제어 벡터를 삽입. 이 과정에서 기존 언어 모델의 내부 상태를 직접 수정하지 않고, 추가적인 정보를 넣어 텍스트를 제어함
    4. 텍스트 생성 및 속성 조정: 언어 모델은 단어를 예측하며 문장을 생성해 나가는데, PPLM은 각 단어가 생성되는 과정에서 제어 벡터를 통해 텍스트가 속성에 맞도록 조정함. 이 과정은 각 생성된 단어가 속성과 얼마나 부합하는지를 실시간으로 반영하여 다음 단어 선택을 유도함
    5. 출력 결과: 사용자가 설정한 속성에 맞춰 조정된 텍스트가 최종적으로 출력됨. PPLM은 각 단어의 생성을 제어하면서도 기본 모델의 능력을 유지함
  • 사용 예: 감정 조절을 하거나, 특정 주제에 대한 텍스트 생성을 제어하는 데 활용될 수 있음

③ Small-to-Large LLM 방식

  • 정의: 작은 LLM 모델에서 시작하여 더 큰 LLM 모델로 정보를 전달하는 방식. 먼저 작은 LLM을 사용해 텍스트를 생성하거나 처리하고, 그 결과를 더 큰 LLM으로 전달하여 보다 정교한 답변을 생성
  • 특징:
    • 속도 최적화: 작은 모델은 빠르고 경량화되어 있어 초기 처리를 빠르게 수행할 수 있음
    • 계층적 처리: 작은 모델에서 간단한 작업을 처리하고, 더 큰 모델은 보다 복잡한 작업을 처리하는 계층적 접근 방식
    • 자원 효율성: 작은 모델이 초기 작업을 처리함으로써 더 큰 모델이 모든 작업을 처리하는 데 드는 계산 자원을 절감할 수 있음
  • 작동 순서:
    1. 작은 모델의 처리: 작은 모델이 입력 데이터를 먼저 처리하여 기본적인 텍스트 생성이나 정보 검색을 수행
    2. 중간 처리: 작은 모델의 결과는 중간 단계로 전달되어 추가적인 전처리를 거침
    3. 큰 모델의 처리: 최종적으로 큰 모델이 이를 바탕으로 복잡한 분석이나 더 높은 수준의 텍스트 생성을 수행
    4. 결과 반환: 큰 모델에서 생성된 결과가 최종 출력으로 반환
  • 사용 예:
    • 텍스트 생성에서 빠른 초기 처리를 위해 작은 모델을 사용하고, 복잡한 내용 생성에서는 큰 모델을 사용하는 경우
    • 작은 LLM을 통해 주어진 질문에 대한 간단한 답을 제공하고, 필요에 따라 큰 LLM으로 넘어가서 더 복잡한 질문이나 다중 턴 질문을 처리하는 상황

④ 쿼리 벡터 변환 방식

  • 정의: 입력 텍스트(쿼리)를 벡터 형태로 변환하여 모델이 이를 이해할 수 있게 만드는 방식. 텍스트 데이터를 수치 벡터로 변환한 후 유사도 계산, 검색, 분류 작업에 활용함
  • 특징:
    • 텍스트와 벡터 간 매핑: 문장이나 단어를 고정된 길이의 벡터로 변환하여 유사성 측정에 사용
    • 유연한 검색 가능: 벡터 공간에서 텍스트의 유사도를 기반으로 비슷한 문장을 검색하거나 문맥을 파악할 수 있음
    • 다양한 활용: 정보 검색, 문서 분류, 추천 시스템 등에서 널리 사용됨
  • 작동 순서:
    1. 텍스트 입력: 텍스트를 입력
    2. 벡터 변환: 입력된 텍스트를 임베딩 레이어 또는 미리 학습된 모델을 통해 벡터로 변환
    3. 벡터 비교: 데이터베이스에 저장된 다른 벡터들과 유사도를 비교
    4. 결과 반환: 가장 유사한 벡터와 연결된 텍스트 또는 정보를 반환
  • 사용 예:
    • 정보 검색 시스템: 유사한 질문이나 문장을 검색할 때, 쿼리를 벡터로 변환해 벡터 공간에서 비슷한 문서를 찾는 데 사용
    • 추천 시스템: 사용자 프로필을 벡터로 변환하여 가장 유사한 항목을 추천하는 데 활용

 
 

📘 코드 실습

1) 벡터 DB를 활용한 검색 시스템 만들기

import requests
from bs4 import BeautifulSoup
import torch
import numpy as np
import tkinter as tk
from tkinter import scrolledtext
from PIL import Image, ImageTk
from io import BytesIO
from transformers import BertTokenizer, BertModel

# KLUE-BERT 모델 및 토크나이저 로드
model_name = "klue/bert-base"
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)

# 이미지 URL
image_url = "https://kr.object.ncloudstorage.com/changbi/old/uploads/2014/05/20140512_152013.jpg"

# 웹페이지에서 중요한 정보를 파싱하는 함수
def parse_webpage(url):
    response = requests.get(url, verify=False)
    soup = BeautifulSoup(response.text, "html.parser")

    # 책 제목 추출
    title_section = soup.find("h2", class_="Heading-02 M-h2")
    title = title_section.get_text().strip() if title_section else "제목 없음"

    # 저자 정보 추출
    author_section = soup.find("a", class_="Bigtext-600 M-bigtext-600")
    author = author_section.get_text().strip() if author_section else "저자 정보 없음"

    # 책 정보 추출
    information_section = soup.find("div", class_="detail-book-info")
    information = (
        information_section.get_text().strip()
        if information_section
        else "책 정보 없음"
    )

    # 목차 추출
    contents_div = soup.find(
        "div", class_="introduction Midtext-400 M-midtext-400 detail-book-content"
    )
    if contents_div:
        paragraphs = contents_div.find_all("p")
        contents = "\n".join(
            [p.get_text().strip() for p in paragraphs if p.get_text().strip()]
        )
    else:
        contents = "목차 없음"

    # 한 줄 소개 추출
    summary_section = soup.find("h1")
    summary = summary_section.get_text().strip() if summary_section else "한 줄 소개 없음"

    # 책 설명 추출
    description_div = soup.find(
        "div", class_="Midtext-400 M-midtext-400 detail-book-content"
    )
    if description_div:
        paragraphs = description_div.find_all("p")
        description = "\n".join(
            [p.get_text().strip() for p in paragraphs if p.get_text().strip()]
        )
    else:
        description = "책 내용 없음"

    # 리스트로 반환할 데이터
    content_dict = {
        "제목": title,
        "저자": author,
        "출판사": "창비",
        "정보": information,
        "목차": contents,
        "소개": summary,
        "내용": description
    }
    
    return content_dict

# 웹페이지 URL
url = "https://www.changbi.com/BookDetail?bookid=2482"

# 웹페이지 파싱 및 리스트로 변환
content_dict = parse_webpage(url)

# GPU에서 임베딩 생성 함수
def embed_text(text):
    inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True, max_length=512).to(device)
    outputs = model(**inputs)
    return outputs.last_hidden_state.mean(dim=1).cpu().detach().numpy()  # GPU -> CPU로 변환

# 각 key 값을 개별적으로 임베딩하여 유사도 비교
def embed_key_content(content_dict):
    embeddings = {}
    for key in content_dict.keys():  # key값만 임베딩
        embeddings[key] = embed_text(key)
    return embeddings

# content_dict의 key 값에 대한 임베딩 생성
key_embeddings = embed_key_content(content_dict)

# 코사인 유사도를 사용하기 위해 벡터 정규화
for key in key_embeddings:
    key_embeddings[key] = key_embeddings[key] / np.linalg.norm(key_embeddings[key], axis=1, keepdims=True)

# FAISS 코사인 유사도 기반 검색 함수 (key 값에 대한 유사도 확인)
def search(query):
    query_embedding = embed_text(query)
    query_embedding = query_embedding / np.linalg.norm(query_embedding)  # 코사인 유사도를 위한 정규화
    
    max_similarity = -1  # 초기화
    best_match = None
    
    for key, embedding in key_embeddings.items():
        D = np.dot(query_embedding, embedding.T)  # 코사인 유사도 계산
        similarity = D[0][0]  # 가장 유사한 값 가져오기
        
        if similarity > max_similarity:
            max_similarity = similarity
            best_match = key
    
    return best_match, max_similarity
    
# GUI에서 결과를 표시하고 이미지 표시를 제어하는 함수
def search_gui():
    query = entry.get()  # 검색창에 입력된 쿼리 가져오기
    best_match, similarity = search(query)  # 가장 유사한 key와 유사도 가져오기

    result_text.delete(1.0, tk.END)
    
    if best_match is not None:
        result_text.insert(tk.INSERT, f"{best_match} : {content_dict[best_match]}\n")  # 검색된 key와 value 출력
        result_text.insert(tk.INSERT, f"\n유사도: {similarity:.4f}\n")

        # 이미지 표시
        response = requests.get(image_url)
        img_data = response.content
        img = Image.open(BytesIO(img_data))
        img = img.resize((200, 250)) 
        img_tk = ImageTk.PhotoImage(img)
        img_label.config(image=img_tk)
        img_label.image = img_tk  # 이미지가 garbage collection에 의해 제거되지 않도록 참조 유지
    else:
        result_text.insert(tk.INSERT, "해당 키워드에 맞는 결과가 없습니다.\n")
        img_label.config(image="")  # 이미지가 없을 때 이미지 레이블 비우기
        
# GUI 창 생성
window = tk.Tk()
window.title("[소년이 온다] 책 검색 봇")

# 이미지 레이블 (초기에는 빈 상태)
img_label = tk.Label(window)
img_label.pack(side="right")  # 오른쪽에 이미지 배치

# 검색창 및 버튼 설정
entry = tk.Entry(window, width=50)
entry.pack()

search_button = tk.Button(window, text="검색", command=search_gui)
search_button.pack()

# 결과 출력창 설정
result_text = scrolledtext.ScrolledText(window, width=60, height=10)
result_text.pack()

# GUI 메인 루프 실행
window.mainloop()

 
2) Fill-Mask 응용

① 응용 1 : 구멍 뚫린 <mask> 부분에 어떤 단어가 올지 예측
from transformers import pipeline

model = pipeline('fill-mask')

# fill-mask 응용1 : 구멍 뚫린 <mask> 부분에 어떤 단어가 올지 예측하기
question = 'The <mask> considered for a moment, and then he said, in a less furious tone'
result = model(question, top_k=100)

x = result[0]['token_str']
y = result[-1]['token_str']

answer = input(f'''다음 중 빈 칸에 들어갈 수 있는 단어로 적절한 것은?
     
A: {x},      B: {y}''')
               
if answer.upper() == 'A':
    print('정답')
else:
    print('오답')​

 

② 응용2 : 문장 내 비문법적인 단어 교정
from transformers import pipeline

# Fill-Mask 파이프라인 로드 (BERT 모델 사용)
fill_mask = pipeline("fill-mask", model="bert-base-uncased", top_k=5)

# 고유명사 여부를 확인하는 함수 (첫 글자가 대문자인지 확인)
def is_proper_noun(token):
    return token[0].isupper()

# 문장을 교정하는 함수
def correct_sentence(sentence):
    tokens = sentence.split()
    corrected_sentence = sentence

    for i, token in enumerate(tokens):
        # 고유명사는 교정하지 않음
        if is_proper_noun(token):
            continue

        # 마스킹할 단어를 [MASK]로 변경
        tokens_with_mask = tokens.copy()
        tokens_with_mask[i] = "[MASK]"
        masked_sentence = " ".join(tokens_with_mask)

        # fill-mask 모델을 사용해 예측
        result = fill_mask(masked_sentence)

        # 여러 대안을 출력
        print(f"Original token: {token}")
        for idx, prediction in enumerate(result):
            print(f"Alternative {idx+1}: {prediction['token_str']} (Score: {prediction['score']})")

        # 문법적으로 가장 높은 확률의 단어로 교정
        predicted_token = result[0]["token_str"]
        
        # 현재 문맥에서 오류가 해결되면 종료
        if predicted_token != token:
            corrected_sentence = corrected_sentence.replace(token, predicted_token, 1)

        # 문맥이 맞는지 확인하고, 맞으면 더 이상 수정하지 않음
        if is_sentence_correct(corrected_sentence):
            print("\nNo further corrections needed.")
            break

    return corrected_sentence

# 간단한 문맥 오류 확인 함수 (자유롭게 정의 가능)
def is_sentence_correct(sentence):
    # 이 부분에 문맥이나 오류 검사를 위한 추가 로직을 넣을 수 있음
    # 여기서는 단순히 확인을 하지 않지만, 맞춤법 검사를 추가하거나, 간단한 문맥 오류 검사를 넣을 수 있음
    # 예시로 간단하게 오류가 없다고 가정함
    return True

# 테스트 문장 (standing -> steending)
sentence = "Gamdong2 is steending in front of the barbecue restaurant, smelling the scent of grilled meat."

# 문장 교정
corrected = correct_sentence(sentence)
print(f"\nOriginal: {sentence}")
print(f"Corrected: {corrected}")​


③ 응용 3 : 긴 문장 요약하기

from transformers import pipeline

summarizer = pipeline("summarization", model="facebook/bart-large-cnn")

text = 'Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, "and what is the use of a book," thought Alice, "without pictures or conversations?'
rtn = summarizer(text, min_length=10, max_length=50)

rtn

 

 

📙 내일 일정

  • 자연어 처리(NLP) 실습

 
 
 

 

'TIL _Today I Learned > 2024.10' 카테고리의 다른 글

[DAY 62] 자연어 처리 (NLP) 복습  (4) 2024.10.17
[DAY 61] NLP 실습????????  (0) 2024.10.16
[DAY 59] 자연어 처리 (NLP)  (2) 2024.10.14
[DAY 58] 자연어 처리 (NLP)  (1) 2024.10.11
[DAY 57] SQL 실습  (0) 2024.10.10