AI 부트캠프 - 28일차

Cookie Baking·2024년 11월 8일

AI 부트 캠프 TIL

목록 보기
21/42

LLM 동작 원리

1. 학습 :
LLM은 대규모 텍스트 데이터셋을 이용해 학습함
여기서 중요한 개념은 "패턴 인식"임.
수많은 텍스트에서 단어와 문장의 패턴을 찾아내어, 새로운 문장이나 답변을 생성할 때 그 패턴을 적용함

2. 추론 :
학습된 LLM은 질문이나 입력을 받으면, 그에 따른 추론을 통해 답변을 생성함
이때, 이전의 맥락을 기억하고 활용하면서 답을 만들어냄

3. 미세 조정 :
LLM은 특정 도메인이나 용도에 맞춰 추가 학습 (미세 조정)할 수 있음
예를 들어, 의료나 법률과 같은 특수한 분야에 맞는 데이터를 추가로 학습시키면 해당 분야에 대한 답변의 정확성이 높아짐


1. 랜덤성

  • LLM은 기본적으로 확률에 기반하여 문장을 생성함
  • 즉, 같은 질문을 하더라도 매번 동일한 답변을 주지 않을 수 있음
  • 이 랜덤성은 모델이 새로운 문장을 만들어내는 능력을 키워주는 핵심 요소임
  • LLM이 결과를 생성할 때, 토큰의 확률 분포를 계산하여 그 중에서 높은 확률을 가진 토큰을 선택해 문장을 만듦
    ex. 온도라는 매개변수가 랜덤성에 영향을 미치는데,
    온도 값이 낮으면 모델이 더 일관되고 예측 가능한 답변을 생성함 (더 적은 랜덤성)
    온도 값이 높으면 답변이 창의적이고 예측하기 어려운 결과가 나올 수 있음 (더 많은 랜덤성)
    질문 : "오늘 날씨 어때?"
    온도 낮음 : "오늘 날씨는 맑습니다."
    온도 높음 : "오늘은 하늘이 쾌청하고, 약간의 바람이 불어요."

2. 조건성

  • LLM은 조건부 확률을 기반으로 결과를 만들어냄
  • 즉, 모델은 이전의 입력 내용에 따라 문장을 조건부로 생성하게 되는데, 이를 컨텍스트라고도 함
  • 이 과정에서 중용한 두 가지 요소가 있음, 프롬프트와 맥락기억
  • 프롬프트란 입력된 문장이나 질문이 무엇인지에 따라 결과가 달라짐
  • 맥락기억 : LLM은 대화를 나누는 동안 이전 문장이나 대화 흐름을 기억하고 그에 맞춰 답변을 생성함

RAG
LLM이 스스로 모든 답을 생성하는 대신, 데이터베이스에서 정보를 검색하고 그것을 기반으로 답변을 생성하는 기법

Vector DB
벡터 데이터베이스는 텍스트를 벡터 형태로 변환하여 유사한 의미를 가진 텍스트를 효율적으로 검색할 수 있게 도와주는 기술임. LLM과 결합하면 더 강력한 검색 및 응답 기능을 구현할 수 있음

LangChain
LangChain은 LLM과 같은 언어 모델을 더욱 효율적으로 활용할 수 있게 도와주는 프레임워크임
LangChain의 목적은 다양한 LLM과 외부 리소스를 결합해 강력한 언어 기반 애플리케이션을 만들 수 있도록 돕는 것임
LLM의 기능을 더욱 확장하고, 데이터 소스, API, 데이터베이스 등을 쉽게 통합할 수 있음

주요 기능으로는

  • LLM과 데이터 소스 결합 : RAG처럼 외부 데이터를 검색해와 LLM이 이를 처리하도록 할 수 있음
  • 작업 흐름 자동화 : 여러 개의 LLM 작업을 순차적으로 실행할 수 있는 워크플로우를 제공함
  • 대화형 AI 개발 : 여러 번의 대화 흐름을 제어할 수 있는 대화 관리 기능을 통해 챗봇이나 대화형 에이전트를 쉽게 구축할 수 있음
  • 메모리 기능을 제공하고 있음

OpenAI Playgrouond

토큰 길이
토큰은 GPT 모델에서 사용하는 단위로, 생성할 수 있는 텍스트의 길이를 조절하는 값임
기본적으로 짧은 응답이 필요하면 낮은 값을, 긴 글을 생성하려면 높은 값을 설정함

  • 짧은 응답 : 50토큰
  • 긴 응답 : 200토큰

User

  • User는 대화의 주체로, 프롬프트를 입력하는 역할을 담당함
  • 주로 질문을 하거나 특정 작업을 요청하는 사용자 역할로, "질문"이나 "요구"를 담당함

Assistant

  • Assistant는 User의 요청에 응답하는 역할을 맡음
    즉, GPT 모델이 답변을 생성하는 역할을 수행하며, 대화의 주요 흐름을 이어감

System

  • System은 대화의 전반적인 규칙이나 지침을 제공하는 역할임
  • System 역할은 Assistant가 어떻게 응답할 지 지침을 제공하는 데 사용되며, 프롬프트 설정에 따라 Assistant의 성격이나 스타일을 조정할 수 있음

-> System 역할을 이용해 Assistant가 특정 역할을 수행할 수 있음
예를 들어, System 지침으로 "Assistant는 프로그래밍 전문가로서 답변합니다"라고 설정하면, 기술적 질문에 전문적인 답변을 하게끔 유도할 수 있음

  • 단 토큰마다 비용이 발생하기 때문에 과금을 주의해야 함

프롬프트 엔지니어링

  • 생각하는 키 포인트 : 어떤 구문/형태여야 모델이 제대로 인식할 수 있는지를 정리할 수 있는지
  • 니민의 프롬프트 순위를 정하는 것이 좋겠음
    Completion 정의
    원하는 응답 설정
    부가 사항입력
    추가 정보 content입력
  • 시행착오를 통해 프롬프트를 생성하자
  • 예시를 추가할 경우에는 """로 구분자를 생성

간단한 프롬프트 엔지니어링 실습

  • system_messages 정의
  • messages 정의 (사용자의 messages도 포함)
  • 사용자의 input값 messages에 재할당
from dotenv import load_dotenv
import os
import openai

# .env 파일 불러오기
load_dotenv()
openai.api_key = os.getenv("OPEN_API_TOKEN")


# system message 배열 설정
system_message = {
    "role" : "system",
    "content" : "너는 환영 인사를 하는 인공지능이야. 너의 이름은 Sooya야. 농담을 섞어서 응대해줘. 영어로도 말해줘",
    "content" : "도서관은 공학관 옆에 위치하고 있고 동상은 꼭대기 언덕에 위치하고 있어."
}

# 모든 메시지들 담는 배열 messages
# 초기에 user 맞춤화된 정보를 제공하고 싶다면 초기 설정에 user 값을 넣어줄 수 있겠음
messages = [system_message,
            {"role": "user", "content" : "직업은 대학생"}
            ]

while True:
	
    # 기본 프롬프트 설정해서 응답 API 받아와 completion 생성
    completion = openai.ChatCompletion.create(
        model="gpt-4o",  
        messages=messages
    )
	
    # 기본 환영인사를 만드는 GPT
    # GPT의 응답 생성
    reply = completion.choices[0].message.content
    messages.append({"role": "assistant", "content" : reply})
    # GPT의 응딥 print
    print("AI SOOYA : " + reply)
	
    # GPT에게 물어볼 입력값을 받음
    user_input = input("무엇을 물어보고 싶으신가요 >>> ")

    if user_input == "exit":
        print("즐거운 대화였습니다! 감사합니다!")
        break
    
    # GPT messages에 추가함
    messages.append({"role" : "user", "content" : user_input})

성능을 높일 수 있는 간단한 방법

  • 단계별로 계산해줘

(기본 원칙)

  • 명확한 요청 사항을 전달해라
  • 정보를 제공하여 최신 정보를 반영해라.
  • 제약 조건을 줘라.
  • 복잡한 작업은 단계별로 분할하라.

Shot 계열의 프롬프팅 기법

  • 예제를 안 주면 : Zero-Shot
  • 예제를 하나 주면 : One-Shot
  • 여러 개 주면 : Few-Shot
    프롬프팅이라고 부름
    Shot을 많이 줄수록 더 원하는 방향으로 답변을 유도할 확률이 높아짐
  1. Zero-Shot 프롬프팅
    Zero-Shot은 아무런 예제를 주지 않고 지침만 전달하는 방식

실습 생략


Act As 류의 프롬프팅 기법 배우기

  • 페르소나를 부여하여 프롬프팅

CoT 적용해보기

  • 중간 추론 단계를 직접 넣어주는 방식으로 프롬프팅 (중간과정을 직접 넣어주어, 더 구체적이고 세밀한 논리적 추론을 유도할 수 있음

예시로 GPT-4o 에 아래 문제를 넣어봤는데 CoT를 부여하지 않아도 잘 푸는 것을 확인할 수 있었다.
생각보다 성능이 많이 좋구나

자동차가 3대 있어, 오토바이는 12대 있어. 이중 바퀴가 모두 터진 장비는 총 3대야. 그런데 터진 바퀴가 총 12개면 자동차와 오토바이는 각각 몇 대 고장났을까?

대화형 프롬프팅 기법

  • 답변을 유도할 수 있다.
  • RAG 기법의 핵심이 될 수 있다.
  • 대화를 얼마나 기억할 지 설정해야 함

형식 지정 기법 (GPT에게 지정된 형식으로 알아듣기 쉽게 하기 위해 사용)

  • Markdown : 구조화된 문서를 예쁘게 표현하는 방식
  • json : 데이터 전달을 위해 자주 사용되는 키-값 구조
  • Symbol : 특수 기호를 사용해 중요한 부분을 강조

Markdown 기본 문법
"#" 헤더, 제목과 세션을 나누는 데 사용 (역할, 지침 등등...을 나눠서 부여할 수도 있겠음)
"-" 리스트, 항목을 나열할 수 있음
"|", "--"를 사용해 표를 만들 수 있음

JSON 활용하기
데이터 처리나 시스템과의 연동이 필요한 경우 JSON 형식을 많이 사용

symbol은 크게 영향을 주지 않았다고 함


보안 강화하기

  1. 민감 정보 필터링
    입력된 데이터를 처리하기 전에 민감한 정보를 자동으로 걸러내는 필터링 시스템을 구축함

  2. 암호화
    데이터는 저장 및 전송 중에 암호화되어야 함
    특히 SSL/TLS와 같은 안전한 전송 프로토콜을 사용해야 함

  3. 데이터 저장 최소화
    필요 이상으로 데이터를 저장하지 말고, 필요한 경우에도 데이터 보존 주기를 설정해 자동 삭제하도록 함

  4. 접근 통제
    LLM을 사용할 수 있는 사람의 권한을 제한하고, 모델이 민감한 데이터에 접근하지 않도록 제한해야 함


API의 개념

  • API는 서로 다른 소프트웨어 시스템 간에 데이터와 기능을 주고 받을 수 있도록 해주는 인터페이스임
  • Client-Server : 클라이언트가 서버에게 데이터를 요청하면, 서버는 해당 데이터를 처리하여 클라이언트에게 반환함
  • HTTP/HTTPS 프로토콜 :
  • Restful API : 각 엔드포인트(URL)와 HTTP 메소드 (GET, POST, PUT, DELETE 등)를 사용해 데이터를 주고 받음

벡터 DB와 LangChain

비슷한 문자라면 비슷한 숫자 벡터를 부열하자는 개념이 인베딩 모델과 벡터 DB의 개념

라이브러리와 프레임워크의 차이:
특정 패키지가 사용자를 조정하느나
사용자가 조정해서 그 패키지를 사용할 수 있냐


Vector DB

Vector DB는 데이터를 벡터 형식으로 저장하고, 그 벡터들을 효율적으로 검색할 수 있는 데이터베이스임
일반적인 데이터베이스는 정확한 일치를 바탕으로 데이터를 검색하지만, Vector DB는 유사한 벡터 간의 검색을 지원함

벡터(임베딩)의 역할
텍스트나 이미지 등의 비정형 데이터를 벡터화(임베딩)해서 저장함
이 벡터는 데이터의 의미나 특징을 수치로 표현한 것이며, 이를 바탕으로 유사도를 계산해 관련성이 높은 항목을 찾음

예를 들어, "강아지"라는 텍스트는 벡터로 변환되며, 비슷한 의미를 가진 "반려견"도 벡터화되어 유사도가 높은 항목으로 검색될 수 있음

Faiss
Faiss는 Facebook AI Research에서 개발한 벡터 검색 엔진으로, Vector DB를 구현할 때 자주 사용됨
대규모 벡터를 효율적으로 검색하고, 유사도를 계산하는 데 탁월한 성능을 발휘함
특히 빠른 속도와 확장성이 필요한 애플리케이션에서 많이 쓰임

Word2Vec은 특정 단어가 주변 단어와 함께 등장할 확률을 예측하는 방식으로 학습됨
단어 주변의 맥락을 파악하고 비슷한 단어들의 가까운 벡터 위치를 찾을 수 있게 됨

GloVe는 전체 말뭉치에서 단어 상의 공분산을 학습함
의미상 유사하다면 가까운 벡터로 표현되도록 학습이 됨
각 단어가 다른 단어와 어떻게 관계되는지를 학습하게 됨


RAG

  • 검색 시스템과의 차이점은 검색된 데이터를 기반으로 사용자 질문에 대한 맥락 있는 답변을 생성하는 걸 목표로 함
  • 질의, 검색, 반환의 프로세스를 가진 검색 시스템과는 대비되게 질의, 검색, 생성, 반환의 프로세스를 거치게 됨
  • LLM이 학습한 데이터 외의 최신 문서를 검색해 정보의 정확도를 높일 수 있음, LLM이 모르는 정보도 외부 검색을 통해 답변할 수 있어 지식의 확장성이 뛰어남, 학습 데이터에만 의존하지 않고, 외부 데이터베이스에서 실시간 정보를 제공받아 더욱 풍부한 답변을 할 수 있음

실습

from sentence_transformers import SentenceTransformer
import numpy as np
from dotenv import load_dotenv
import os


# .env 파일 불러오기
load_dotenv()
api_key = os.getenv("API_TOKEN")


model = SentenceTransformer('intfloat/multilingual-e5-large',token=api_key)

sentences = [
    "참새는 짹짹하고 웁니다.",
    "LangChain과 Faiss를 활용한 예시입니다.",
    "자연어 처리를 위한 임베딩 모델 사용법을 배워봅시다.",
    "유사한 문장을 검색하는 방법을 살펴보겠습니다.",
    "강좌를 수강하시는 수강생 여러분 감사합니다!"
]


# 문장이 문맥과 의미 분석을 위해 차원이 부여되게 됨
# 문장을 숫자의 나열로 바꿔주는 게 임베딩임
embeddings = model.encode(sentences)

print(embeddings.shape) # (5, 1024) : 5개의 문장이 1024 차원의 벡터로 변환됨

텍스트 처리

텍스트 처리는 데이터의 품질을 높이고 모델의 성능을 향상시키기 위한 필수 작업임
자연어는 매우 복잡하고 다양하기 때문에, LLM이 텍스트를 정확하게 이해하고 처리하기 위해서는 데이터가 구조화되고 정제될 필요가 있음

목표
노이즈 제거 : 텍스트 내 불필요한 정보나 오류를 제거해 정확한 분석을 할 수 있도록 함
일관성 확보 : 문장의 구조나 형태를 일관되게 유지하여 모델이 더 쉽게 패턴을 학습하게 도움
효율적인 처리 : 불필요한 단어를 제거하고 중요한 정보만 남겨, 모델이 더 빠르게 계산할 수 있도록 함


주요 텍스트 처리 기법

  1. 토큰화
    토큰화는 텍스트를 단어 또는 서브워드 단위로 나누는 작업임
    이 과정은 텍스트를 숫자로 변환하기 전의 가장 중요한 단계에 해당함

단어 단위 토큰화 : 텍스트를 단어 단위로 나누는 기본 방법임
서브워드 토큰화 : 단어를 더 작은 단위로 분리해 새로운 단어를 처리할 수 있도록 함
BPE나 WordPiece같은 방법이 있음
ex. "나는 오늘 책을 읽었다." -> ["나는", "오늘", "책을", "읽었다"]

  1. 정규화
    정규화는 텍스트를 표준화된 형식으로 변환하는 작업임
    텍스트에 포함된 대소문자, 특수문자 등을 일관되게 변환하여, 모델이 불필요한 변동에 혼란을 겪지 않도록 함

소문자 변환 : 대문자와 소문자를 통일하여 같은 단어로 인식하게 함
ex. "OpenAI" -> "openai"
불필요한 기호 제거 : 분석에 필요 없는 특수 문자나 기호를 제거

  1. 불용어 제거 : 자주 등장하지만 정보가 없는 단어 (ex : 그리고, 이, 는)

  2. 형태소 분석 : 교착어에서는 형태소 분석이 필수적임

  3. 어간 추출과 표제어 추출 : 텍스트에서 동사나 형용사의 변형을 기본 형태로 돌리는 작업을 말함 (이를 통해 동일한 단어를 일관되게 처리할 수 있음)

  4. 문장 분리 및 길이 조절 : 텍스트가 너무 길거나 복잡할 경우, 적절하게 나누거나 길이를 조정해야 함


임베딩 기법

  1. Bag of Words(BoW)
    Bag of Words는 단어의 빈도만을 기반으로 텍스트를 벡터화하는 가장 단순한 방법이기 때문에 단어의 순서나 문맥을 고려하지 않기 때문에 의미 파악에 한계가 있지만, 간단한 문서 분류나 텍스트 분석에 유용함
문장 : "고양이가 야옹했다"
벡터 표현 : [1, 1, 1, 0, 0] (각 단어의 빈도수)
  1. TF-IDF
    TF-IDF는 단순한 단어 빈도 외에도 단어의 중요도를 반영한 임베딩 기법임.
    특정 단어가 문서 내에서 자주 등장하지만 전체 문서에서 드물게 등장한다면, 그 단어는 해당 문서에서 중요한 단어로 간주됨
  • TF : 단어의 빈도
  • IDF : 단어의 전체 문성에서의 등장 빈도 반비례값
    이를 통해 문서 내에서 의미 있는 단어를 강조할 수 있음
    단 문맥을 반영하지 않기 때문에 그에는 열세를 보임

그런데 관사랑 중요하게 사용되는 고유 명사와는 어떻게 구별하는 것일까??
-> 관사같은 경우에는 거의 모든 문서에 등장을 한다. 때문에 IDF에 주는 영향이 훨씬 많으며 이는 TF보다 IDF에 결과값이 더 민감하게 반응하기 때문이라고 결론을 내릴 수 있음

TF-IDF 구조는 둘을 곱해서 가중치를 계산하게 되는데 

단어 빈도(TF): 문서 내에서 단어가 얼마나 자주 등장하는지를 반영합니다. 많이 등장할수록 TF가 높아집니다.

역문서 빈도(IDF): 여러 문서에서 등장하는 단어일수록 IDF 값이 낮아지도록 설계되어 있습니다. IDF는 일반적으로 다음과 같은 식으로 계산됩니다:

IDF = logN/df

N은 전체 문서의 수, df는 해당 단어가 등장한 문서의 수이다.
관사같은 경우에는 전체 문서에서 등장하기 때문에 df가 커지게 되고 그에따라 IDF가 작아지게 됨
BUT 고유 명사같은 경우에는 df가 낮기 때문에 역문서 빈도가 낮아지게 됨

이렇게 IDF가 낮아지면서 관사나 전치사와 같이 자주 등장하는 단어들은 TF-IDF 값도 자동으로 낮아져 가중치가 작아지게 되는 것입니다. 이 방법 덕분에 고유 명사나 주제와 관련된 중요한 단어들에 더 높은 가중치를 주고, 불필요한 단어들의 영향을 줄일 수 있습니다.

TF-IDF임베딩 처리를 한다면 Attention 알고리즘을 적용하는 것이 무의미해지는 것이 아닐까??
TF-IDF는 단순하게 문서에서의 중요도민을 생각하지만 Attention알고리즘의 경우에는 문맥까지 생각하기 때문에 구체적인 사항은 다르다고 할 수 있음


CBow : 주변단어로 중심단어를 예측함
SkipGram : 중심단어로 주변단어를 예측함

단어 간의 의미적 유사성을 반영하는 임베딩 기법 (단어를 고차원 벡터로 변환하여, 단어 간의 관계를 학습)

  1. Word2Vec : 주위 단어들에 기반해 단어의 의미를 학습 (저차원 밀집 벡터 사용)
    GloVe : 전체 문맥을 기반으로 단어 간의 공통 패턴을 학습함 (단어가 등장하는 전체 문맥을 고려함)
  • 단, 임베딩이 고정되어 학습 후에는 새로운 단어를 추가할 수 없음

  1. Transformer 기반 임베딩 (BERT, GPT)
    BERT나 GPT 같은 Attention기반의 Transformer
  • 모델들은 문장의 문맥을 고려하여 더 깊이 있는 의미를 반영한 임베딩을 생성함 -> 특히 문장 단위로 텍스트를 벡터화할 수 있어 문장 간의 유사도를 정확하게 파악함
  • BERT (양방향으로 문맥을 고려한 임베딩 생성), GPT (자동 완성 및 생성에 강점을 둔 임베딩 생성)

번외
GPT API가 유료이다 보니 토큰 수에 주의를 해야겠다고 생각되어서 billing을 참고했는데
물론 4가 성능이 나아진 것이 맞긴 하지만 billing에서 꽤나 차이를 보이고 있다.
그래도 4를 사용하는 것이 맞을까?!

hugging face 이용 방법

CLI 설치

pip install huggingface_hub

CLI 로그인

huggingface-cli login

LEFT

GPT Playgrouond 사용해보기

  • 피보나치 사용해보기

LangChain

0개의 댓글