AI 부트캠프/챕터2(10.14~11.08)

TIL 28

musukie 2024. 11. 4. 11:26

Transformer 라이브러리 속에 다양한 NLP 모델들이 있다. 허깅 페이스에 올라온 모델들은 트랜스포머스 라이브러리를 통해 불러와서 편하게 사용할 수 있다. 텍스트를 만드는 언어 생성, 감정을 분석해주는 감정 분석, 번역 등 다양한 작업에 활용할 수 있다. 생성형 모델에는 조건을 주었을 때 따라서 생성해주는 모델인 조건형 모델과 임의의 생성을 해주는 비조건형 모델이 있다.

다양한 NLP 모델들 살펴보기

텍스트를 생성하는 모델들에 대해 실습을 통해 알아보자.

GPT-2 ( Generative Pre-trained Transformer 2 )

먼저 우리는 앞 부분 내용을 전달하면 뒷 부분 내용을 작성해주는 사전학습 모델을 활용할 것이다. 우리가 활용할 모델은 GPT-2다.

import warnings
warnings.filterwarnings('ignore')

위의 코드는 언어 모델이나 사전 학습 모델들을 사용할 경우 warning이 발생하는 걸 막아주는 코드다.

from transformers import pipeline

# GPT-2 기반 텍스트 생성 파이프라인 로드
generator = pipeline("text-generation", model="gpt2")
#  model="gpt2"로 모델을 지정했다.

# 텍스트 생성
result = generator("Once upon a time", max_length=50, num_return_sequences=1)
print(result)

위의 코드 2줄을 입력하면 결과를 바로 생성할 수 있다. 결과를 저장할 변수 result를 만들어주고, generator에 본인이 생성하고 싶은 문장을 전달하고, max_length로 문장의 최대 길이를, num_return_sequences로 몇 개의 결과를 생성할 것인지를 지정해주면 된다.

출력 결과 예시는 아래와 같다.

[{'generated_text': 'Once upon a time, 
it is impossible to imagine a life without the benefit of an organ in a body. 
We only know the body is an organ in the body. As we age and our need arises, 
so does our need for an organ diminish'}]

max_length로 길이를 지정할 수는 있지만, 지정한다고 해서 항상 그 최대 길이만큼의 문장을 강제로 생성하지는 않는다. 이는 언어 생성형 모델의 특징때문이다. 

num_return_sequences를 2로 지정하면, 결과는 2개가 나오지만 다른 문장이 결과로 출력된다. 그 이유는 생성형 모델은 조건성과 랜덤성이라는 특징을 가지기 때문이다.

더보기

기본적인 GPT-2 모델은 다른 언어들은 잘 생성해내지 못해서 영어로 전달해야 한다.

간단한 감성어 분석

감성어 분석은 어떤 문장이나 단락이 들어왔을 때, 그 문장이 긍정적인지 부정적인지를 분석해주는 것이다. 리뷰 데이터나 다양한 문장들을 처리할 때 유용하게 사용할 수 있다. 예를 들어, 리뷰 데이터가 있을 때, 이를 점수로 바꿀 수 있다. 지금은 긍정과 부정으로 결과가 나오는데, 부정에 마이너스(-) 값을 주면 머신러닝, 즉 테이블 형태의 데이터를 잘 처리하는 모델에서도 리뷰데이터를 활용할 수 있을 것이다.

 여기서 잠깐! 

더보기

왜 머신러닝이 테이블 형태의 데이터를 잘 처리하는 모델인가?

머신러닝 

머신러닝이 테이블 형태의 데이터를 잘 처리하는 이유는 주로 구조화된 데이터의 특성과 머신러닝 모델의 특성이 잘 맞기 때문이다. 테이블 형태의 데이터는 각 행이 개별 샘플을 나타내고, 각 열이 특정한 특성(피처)을 담고 있어서 다음과 같은 장점이 있다.

   1. 명확한 피처 구조

테이블 형식에서는 각 열이 명확하게 정의된 변수나 피처이기 때문에, 머신러닝 알고리즘이 이를 쉽게 학습할 수 있다. 이를 통해 각 특성이 예측에 어떻게 기여하는지 파악하기 쉽다.

   2. 다양한 머신러닝 모델과의 호환성

테이블 데이터를 위해 설계된 머신러닝 모델(예: 결정 트리, 랜덤 포레스트, 로지스틱 회귀 등)은 수치형 또는 범주형 데이터를 입력으로 받아 복잡한 수식 없이도 빠르게 학습한다. 또, 모델들은 각 피처의 영향력을 평가하고 조합하는 데 능숙해서 예측 성능이 좋다.

   3. 간단한 전처리

텍스트나 이미지 데이터와 달리 테이블 데이터는 일반적으로 전처리가 간단하다. 예를 들어, 결측치를 처리하거나, 수치형 데이터를 정규화하는 정도로도 바로 머신러닝에 활용이 가능하기 때문에, 구조화된 데이터를 빠르게 학습할 수 있다.

   4. 효율적인 계산과 빠른 학습

테이블 데이터를 다루는 머신러닝 알고리즘은 빠른 계산이 가능한 구조로 이루어져 있다. 특히 행과 열의 단순한 계산으로도 모델을 구축할 수 있어 대량의 데이터를 빠르게 학습할 수 있다.

 

예를 들어, Pandas 데이터프레임으로 로드한 고객 정보 테이블에서 특정 고객의 구매 여부를 예측하고자 할 때, 각 열에 있는 정보(나이, 소득, 거주지 등)를 그대로 머신러닝 모델에 입력으로 넣어 빠르게 예측 모델을 만들 수 있다. 이와 같은 이유로 머신러닝은 구조화된 테이블 형태의 데이터를 잘 처리하는 모델로 인식되고, 비정형 데이터보다는 정형 데이터에서 패턴을 찾거나 예측을 수행하기 더 쉽다.

딥러닝

반대로 딥러닝 모델은 테이블 형태의 데이터를 잘 처리하지 못하는 경우가 많다. 딥러닝은 이미지, 텍스트, 음성과 같은 비정형 데이터(비구조화 데이터)를 처리하는 데 특화되어 있다. 테이블 데이터는 명확한 피처와 구조가 있는 정형화된 데이터인 반면, 딥러닝은 패턴이나 특성을 자동으로 추출하고 학습하는 데 강점이 있어 다음과 같은 이유로 테이블 데이터를 잘 다루지 못하는 경향이 있다.

   1. 특성 간의 관계 추출이 필요 없음

테이블 데이터에서는 각 피처가 독립적인 정보로 제공되고, 피처 간의 관계를 고려하지 않는 경우가 많다. 반면에 딥러닝은 특성 간의 복잡한 관계 추상적 패턴을 추출하는 데 중점을 두기 때문에, 각 특성이 독립적일 때는 딥러닝의 장점이 잘 발휘되지 않는다.

   2. 과적합 문제

딥러닝 모델은 많은 학습 데이터 복잡한 관계가 있는 데이터에 강점이 있지만, 테이블 데이터는 비교적 단순한 관계를 가진 경우가 많아 오히려 딥러닝 모델이 과적합되기 쉽다. 예를 들어, 고객 나이와 소득을 예측하는 모델이라면 신경망보다 결정 트리나 회귀 모델이 더 효과적일 수 있다.

   3. 연산 자원과 시간 소모

딥러닝 모델은 테이블 데이터보다 이미지나 텍스트와 같은 대용량 데이터를 처리할 때 더 효율적이다. 테이블 데이터는 간단한 모델로도 빠르게 학습할 수 있지만, 딥러닝은 복잡한 네트워크 구조로 인해 많은 연산 자원과 시간이 필요하다.

   4. 추론 해석의 어려움

테이블 데이터를 다룰 때는 어떤 특성이 예측에 얼마나 중요한지를 확인하고, 예측 결과에 대해 이유를 설명하는 일이 중요할 때가 많다. 예를 들어, 특정 고객이 대출 승인을 받을지 예측하는 모델이라면, 어떤 특성들 (예: 연 소득, 신용 점수)이 예측에 중요한 영향을 미쳤는지를 알 필요가 있다.

그러나 딥러닝 모델은 여러 층의 뉴런을 통해 복잡한 계산을 수행하여 결과를 도출하므로, 그 내부의 작동 원리를 직관적으로 설명하기가 어렵다. 이 때문에 딥러닝은 일반적으로 '블랙박스'라고 불리며, 어떤 특성이 결과에 얼마나 영향을 주었는지를 확인하거나 설명하기가 쉽지 않다.

 

최근에는 딥러닝이 테이블 데이터를 잘 다룰 수 있도록 탭넷(TabNet)이나 그래프 신경망(GNN)과 같은 새로운 딥러닝 구조가 개발되고 있지만, 전통적인 머신러닝 알고리즘이 여전히 테이블 데이터에는 효율적이다.

from transformers import pipeline

sentiment_analysis = pipeline("sentiment_analysis")
# 모델을 지정하지 않았다.

result = sentiment_analysis("I love you")

GPT-2와 마찬가지로 위의 코드에서 2줄을 입력하면 결과를 바로 생성할 수 있고, result를 통해 결과를 얻을 수 있다.

 

GPT-2와 감성어 분석 실습을 통해 우리는 알 수 있는 것이 있다. 기본적으로 pipline에는 다양한 작업을 지정해줄 수 있고, 모델을 지정해줄 수 있다(작업에서 어떤 모델을 사용할 지 지정해주는 것)는 것이다. GPT-2 실습 코드를 보면 모델을 직접 지정해주었지만, 작업에 따라서 기본 모델들이 설정돼있는 경우가 있어서, 감성어 분석 실습 코드와 같이 모델을 지정하지 않아도 되는 경우가 있다.

 

출력 결과 예시는 아래와 같다. 감정이 긍정인지 부정인지와, 어느 정도로 감정에 치우쳐져있는 지도 나온다.

# result = sentiment_analysis("I love you")일 때
[{'label': 'POSITIVE', 'score': 0.9998656511306763}]

# "I hate you"를 전달했을 때
[{'label': 'NEGATIVE', 'score': 0.9991129040718079}]

RoBERTa ( Robustly Optimized BERT Approach )

감성어 분석 실습 코드에서 추가적으로 모델만 지정해주어 보겠다.

from transformers import pipeline

sentiment_analysis = pipeline("sentiment_analysis", model = "roberta-base")
# model = "roberta-base"로 모델을 지정했다.

result = sentiment_analysis("I love you")

 

출력 결과 예시는 아래와 같다.

[{'label': 'LABEL_1', 'score': 0.5094813704490662}]

감성어 분석과 달리 다른 결과가 출력된 것을 확인할 수 있다. 그 이유를 알아보자.

BERT 기반 모델은 핵심적인 논리 부분은 대규모 데이터셋을 통해 사전 학습시켜놓았다. 그러나 마지막 레이어, 즉 번역이나 분류 등 목적에 따라 바꿀 필요가 있는 레이어는 학습 자체를 사용자에게 맡기기도 한다. 그렇기 때문에 You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.와 같이 우리가 직접 학습을 해야 할 것이라는 경고 문구가 뜬다.

즉, 사전학습 모델은 항상 완전한 모델을 주는 것이 아니고, 오히려 목적에 따라 적절히 학습된 형태로 모델을 제공해준다고 이해하자.

임베딩

임베딩은 고차원 데이터를 저차원 공간으로 변환하는 기법이다. 주로 벡터 표현으로 구현된다.

 

종류를 살펴보자.

먼저, 자연어처리에서 단어를 벡터로 표현하는 워드 임베딩이다. 고전적인 방법인 Word2Vec, Fast Text 등이 있다. 이들은 단어 간의 유사도를 벡터 공간에서 측정할 수 있게 해준다.

다음으로는, 문장 전체를 벡터로 표현하는 Sentence 임베딩이다. 문장 간의 유사도 분석이나 의미적 관계를 분석할 수 있다. 이는 당연히 머신러닝이나 딥러닝의 입력으로도 활용할 수 있다.

또 이미지 데이터를 벡터로 표현하는 이미지 임베딩이 있다. 이미지의 픽셀 데이터를 저차원 벡터로 변환하고, 이미지 간의 유사도를 분석할 수 있다. CNN을 통해서도 어느 정도 차원 축소와 이미지 분석이 가능하다. 그러나 CNN같은 기본 모델을 단순히 하나만 활용하는 것보다는, 여러 가지 방법에 추가 장치를 도입하는 것이 성능적으로 높을 것이라고 기대할 수 있다.

마지막으로 최근 몇 년 사이 중요해진, 그래프 관련 모델에서 사용하는 그래프 임베딩이다. 그래프 구조를 벡터로 표현한다. 노드 간의 관계를 벡터 공간에서 표현해서 네트워크 분석, 추천 시스템 등에서 활용될 수 있다.

 

유사도는 두 개의 데이터가 얼마나 비슷한지 수치적으로 표현하는 방법이다. 임베딩 벡터에는 주로 유사도를 측정하기 위해 코사인 유사도(대표적), 유클리디안 거리 등 다양한 방법을 활용할 수 있다. 유사도는 주로 벡터 간의 거리나 각도를 측정하는 방식이다. 

 

번역 작업을 해주는 모델로는 M2M100과 NLLB-200 등이 있다. 여기서 우리는 사전학습된 모델이라도 당연히 성능이 다르기 때문에 적절하게 선택해야 한다는 것을 알면 된다. 이 두 모델은 모두 페이스북에서 만든 모델인 것 같은데, 성능은 후자가 더 좋다고 알려져있다. 그러나 당연히 일반적으로 성능이 좋은 것은 아니다. 따라서 본인의 목적에 맞춰 적절한 실험을 통해서 성능을 측정하는 작업도 당연히 필요하다. 즉,  우리가 사전학습된 모델을 사용할 때는 이러한 성능 측정 작업이 필요한 것이다.


강의 외부에서 추가로 알게 된 내용

  • map()

map 함수는 Python의 내장 함수로, 반복 가능한 객체(리스트, 튜플 등)의 각 요소에 함수를 적용하여 새롭게 변환된 요소들을 반환한다. 이를 통해 데이터를 일괄적으로 처리하거나, 각 요소에 대해 동일한 작업을 수행할 수 있다. 기본 사용 방법은 아래와 같다.

map(함수, 반복 가능한 객체)
# 함수: 각 요소에 적용할 함수
# 반복 가능한 객체: 리스트, 튜플, 문자열 등

예시를 통해 살펴보자.

# 리스트의 모든 숫자를 문자열로 변환
numbers = [1, 2, 3, 4]
str_numbers = list(map(str, numbers))
print(str_numbers)  # ['1', '2', '3', '4']
# 위 코드에서 map(str, numbers)는 numbers 리스트의 각 숫자에 str 함수를 적용하여 문자열로 변환한다.
# 결과를 list()로 감싸면 map 객체를 리스트로 변환할 수 있다.

# 리스트의 모든 숫자를 제곱하기
numbers = [1, 2, 3, 4]
squared_numbers = list(map(lambda x: x ** 2, numbers))
print(squared_numbers)  # [1, 4, 9, 16]
# 여기서는 lambda 함수를 사용해 x ** 2를 각 숫자에 적용하여 제곱한 값을 반환한다.
# map을 통해 각 숫자가 제곱된 리스트를 얻을 수 있다.

map 함수의 장점은 코드를 간결하게 할 수 있고 성능을 최적화할 수 있다는 것이다. 즉, for 문을 사용하지 않고도 각 요소에 대해 동일한 작업을 수행할 수 있어 코드가 간단해지며, map 함수는 for 문보다 빠르게 동작할 수 있으며, 특히 많은 데이터를 다룰 때 유용하다. 이렇게 map을 사용하면 각 요소에 일괄적으로 함수를 적용할 수 있어 유용하며, 다양한 데이터 처리 작업에 자주 활용된다.

 

  • 특정한 의미나 기능을 가진 변수 이름과 그 예시
변수 이름 의미 및 용도 예시 코드
item 리스트나 컬렉션의 요소를 나타냄 for item in shopping_list:
print(item)
row 2D 배열이나 테이블의 행을 나타냄 for row in matrix:
print(row)
column 2D 배열이나 테이블의 열을 나타냄 for column in row:
print(column)
key 딕셔너리의 키를 나타냄 for key in dictionary:
print(key)
value 딕셔너리의 값을 나타냄 for key, value in dictionary.items():
print(f"{key}: {value}")
user 사용자 정보를 나타냄 for user in user_list:
print(user.name)
point 2D 또는 3D 좌표를 나타냄 for point in points:
print(f"X: {point[0]}, Y: {point[1]}")
dot 각 점을 나타냄 for dot in dots:
print(f"X: {dot[0]}, Y: {pint[1]})
student 학생 정보를 나타냄 for student in class_list:
print(student.name)
task 작업 또는 할 일을 나타냄 for task in task_list:
print(task)
error 오류나 예외를 나타냄 for error in error_list:
print(error.message)
transaction 금융 거래를 나타냄 for transaction in transactions:
print(transaction.amount)
filename 파일 이름을 나타냄 for filename in file_list:
print(filename)
entry 로그, 데이터베이스의 한 항목을 나타냄 for entry in log_entries:
print(entry)

 

'AI 부트캠프 > 챕터2(10.14~11.08)' 카테고리의 다른 글

TIL 30  (0) 2024.11.06
TIL 29  (1) 2024.11.05
TIL 27  (0) 2024.11.01
TIL 26  (1) 2024.10.31
TIL 25  (0) 2024.10.30