언어 (Language)
: 특정 개념을 표현하기 위한 약속의 집합
컴퓨터가 언어를 이해하는 방식
- 사람이 특정 단어를 컴퓨터에 입력하고 싶어함
- 컴퓨터는 특정 단어를 숫자(벡터)의 형태로 받아들임 → 단어를 숫자의 형태로 변환
- 벡터 값을 바탕으로 컴퓨터는 특정 단어를 인식함
임베딩 (Embedding)
: 텍스트 데이터를 벡터로 변환하는 기술
임베딩 프로세스
- 데이터 준비 : 원문 데이터 or 다른 소스로부터 데이터 수집
- 전처리 : 불용어, 오타 등의 데이터 제거
- 임베딩 : 목적에 맞는 알고리즘 적용
- 시각화 : 필요시 임베딩 결과를 그려보고 이를 확인
임베딩의 종류
- 단어 임베딩 : 단어 → 벡터
- 문장 임베딩 : 문장 → 벡터
벡터 공간
: 벡터가 존재하는 공간
- 임베딩의 결과 = 벡터 → 임베딩의 결과를 벡터 공간에 표현 가능
- 예시) 단어들을 2차원 벡터로 표현 → 단어들을 평면 위에 점의 형태로 표시 가능
- 좋은 임베딩이 이루어지면 비슷한 의미의 단어는 비슷한 공간에 존재
- 일반적으로 단어는 고차원으로 표현됨 ← 다양한 종류의 단어를 포괄 + 단어의 의미를 담은 벡터 생성 가능
임베딩 발전 과정
1. 원핫 인코딩 (One-hot Encoding)
: 특정 단어를 표현하는 위치만 1로, 나머지의 위치는 0으로 구성하는 임베딩 방법
- 단어의 수 만큼의 크기를 갖는 벡터가 생성
- 각 단어의 위치(=1이 표현되는 위치)는 설정하기에 따라 다름
- 단어를 직관적으로 벡터 변환 가능
- 예시) 전체 단어가 ʻdog’, ʻcat’, ʻapple’ 이 있다고 할 때
- dog : [1, 0, 0]
- cat : [0, 1, 0]
- apple : [0, 0, 1]
인코딩 vs. 임베딩
인코딩(Encoding) | 임베딩(Embedding) |
데이터를 새로운 형태로 변환하는 과정 | |
- 본질적으로 의미가 변하지 않음(정보 손실 X) - 압축과 비슷한 과정 - 저장, 데이터 전송에 용이 - 데이터의 '형식'을 변환 |
- ML 모델이 처리하기 쉬운 형태로 변환 - 데이터의 의미적, 문맥적 특성을 모델이 이해할 수 있는 형태로 변환 |
한계점
1. 차원의 저주
- 하나의 단어를 표현하는 벡터의 크기는 전체 단어 수와 같음
- 즉, 매우 큰 차원을 갖을 수 있음
- 차원이 크면 효율성과 계산 복잡도가 증가함
2. 의미 부재
- 의미적으로 비슷한 단어끼리 비슷한 공간에 존재하지 않음
- 축구 ↔ 농구의 관계와 축구 ↔ 비행기의 관계의 차이가 없음
3. 정보의 희소성
- 특정 단어의 위치만 1이므로
- 중요한 정보가 매우 매우 희소함
- 대부분 0이 많음
2. 분산 표현 (Distribution Representation)
: 정수가 아닌 실수(연속적인 값)로 이루어진 벡터로 임베딩하는 방법
- 연속적인 실수의 값으로 단어를 변경하면서 데이터의 의미를 여러 특성(feature)에 걸쳐 분산시켜 표현
- 다양한 의미와 문맥적 특성을 풍부하게 포착 가능
- 분산 표현으로 임베딩이 잘 될 경우 :
- 비슷한 의미를 갖는 단어들은 비슷한 분포를 갖게 됨
- 농구는 의미적으로 축구와 비슷
- 비행기는 농구와 축구와는 의미적으로 비슷하지 않음
- 따라서 벡터 공간에 멀리 위치
- 임베딩 벡터도 수의 집합이기 때문에 의미 차원에서 연산 가능
- 왕 ‒ 남자 + 여자 = 여왕
- 서울 ‒ 대한민국 + 일본 = 도쿄
- 비슷한 의미를 갖는 단어들은 비슷한 분포를 갖게 됨
단어 임베딩 (Word Embedding)
: 단어를 숫자의 형태로 변환하는 과정
- 단어의 의미, 문맥적 유사성, 동의어 등과 같이 단어 수준에서 의미를 활용하는 경우에 사용
- 전체적인 문장의 의미를 한번에 포착하기는 어려움
단어에 원핫 인코딩 적용
- 문장을 단어의 형태로 분해해야 함 (Tokenize)
► "사과는 맛있다. 바나나는 맛있다" → "사과는" "맛있다." "바나나는" "맛있다" - 고유한 단어 집합 생성
- 고유한 단어에 인덱스 부여
► 사과는 = 0, 바나나는 = 1, 맛있다 = 2
- 벡터 생성 : 각 단어의 인덱스에 1 부여, 나머지 자리에 0 채우기
► 사과는 = [1, 0, 0] / 바나나는 = [0, 1, 0] / 맛있다 = [0, 0, 1]
But, 원핫 인코딩은 한계점이 존재
↓
↓
↓
분포 가설 (Distribution Hypothesis)
: 단어의 의미는 그 단어가 나타나는 문맥에 의해서 결정된다.
► 특정 단어의 의미를 숫자 벡터로 표현하기 위해 문맥과 주변 단어를 이용해서 학습 진행
임베딩 알고리즘 (1) - Word2Vec
: 2013년 Google에 의해 개발된 임베딩 알고리즘
프로세스
- 문장 위를 움직이는 슬라이딩 윈도우 만듦 (7:00~)
- 해당 윈도우는 이동하면서 동일한 개수의 단어를 포함
- 포함된 단어들 사이의 연산을 진행해 각 단어들을 임베딩
임베딩 방법 :
- CBOW : 이웃한 단어들로 가운데 단어가 무엇인지 예측하는 과정에서 임베딩을 진행
- Skip-gram : 가운데 단어로 이웃한 단어들을 예측하는 과정으로 임베딩 진행
📌 윈도우 (window)
: 기준으로 삼은 scope
임베딩 알고리즘 (2) -GloVe (Global Vectors for Word Representation)
: 공동으로 자주 출현하는 단어들을 벡터 공간 내 비슷한 위치에 존재하도록 임베딩하는 알고리즘
프로세스
- 전체 글에 단어 간 공동 출현 통계를 이용해서 각 단어의 의미를 벡터로 표현
- 각 단어 쌍이 얼마나 자주 나타나는 지를 '공동출현행렬'로 기록
임베딩 알고리즘 (3) - BERT (딥러닝 기반)
- 2018년 구글에서 개발된 알고리즘
- 단어 별 중요도 기반의 모듈을 활용해 문장 내적 & 외적 관계를 바탕으로 임베딩을 진행
- 과정에서 단어 임베딩 이외에 문장 임베딩도 생성
임베딩 알고리즘 (4) - CLIP (딥러닝 기반)
- 2021년 OpenAI에서 개발된 알고리즘
- 이미지를 설명하는 글에서 이미지와 텍스트의 공동 의미를 임베딩
OneHotEncoding 실습
📌 OneHotEncoder 클래스
- `sklearn`의 클래스
- 전체 문장을 입력해야 각 단어의 벡터 생성 가능
- `get_feature_names_out()` 메서드 : 특정 벡터가 어떤 단어를 표현하는지 확인 가능
1단계. 필요한 패키지 불러오기
# 필요한 패키지 불러오기
from sklearn.preprocessing import OneHotEncoder
import numpy as np
# 사용할 문장
sentence = "사과는 맛있다 바나나는 맛있다"
2단계. 문장을 단어로 분리
# 문장을 단어로 분리
# 띄어쓰기 단위를 사용
words = sentence.split()
print(words)
3단계. 단어 배열을 Numpy 배열로 변환
원핫 인코더에 넣을 수 있게 넘파이 형식으로 바꿔줘야 한다.
# 단어 배열을 NumPy 배열로 변환
words_array = np.array(words).reshape(-1, 1)
print(words_array)
4단계. 원핫 인코딩 적용
# OneHotEncoder 객체 생성
encoder = OneHotEncoder(sparse_output=False) # sparse_output=False : 수업에서 다룬 0과 1로 이루어진 행렬의 형태로 변환
# 원핫 인코딩 적용
one_hot_encoded = encoder.fit_transform(words_array)
print(one_hot_encoded)
encoder.get_feature_names_out() # 각 열이 어떤 단어를 나타내는지를 표시
위의 과정을 함수로 정의하면 호출만으로도 단어 임베딩이 가능하다.
# 원핫 인코딩 함수 정의
def one_hot_encode_words(sentence):
words = sentence.split()
words_array = np.array(words).reshape(-1, 1)
encoder = OneHotEncoder(sparse_output=False)
one_hot_encoded = encoder.fit_transform(words_array)
return one_hot_encoded, encoder.get_feature_names_out()
# 예제 문장
example_sentence = '오늘 날씨가 참 맑습니다.'
encoded_words, feature_names = one_hot_encode_words(example_sentence)
encoded_words, feature_names
Word2Vec 실습
📌 Gensim 패키지
- 내장 함수로 모델 다운로드 가능
- 전체 단어를 이용해 학습한 모델로, 학습 당시 사용되지 않았던 단어는 이해하지 못함
1단계. 필요한 패키지 불러오기
from gensim.models import KeyedVectors
from gensim.downloader import load
def use_word2vec(word, model):
try:
word_vector = model[word]
return word_vector
except KeyError:
return "단어가 모델의 어휘에 없습니다."
word2
2018년 까지의 구글 뉴스 데이터를 모아둔 것이기 때문에 2018년 이후의 어휘에 대해서는 임베딩 하지 못한다.
# 제공하는 기본 Word2Vec 모델 불러오기
# 약 10~12분 정도 소요
word2vec_model = load('word2vec-google-news-300')
print(use_word2vec('apple', word2vec_model))
print(use_word2vec('instagram', word2vec_model)) # 학습 당시에 존재하지 않던 단어는 임베딩 불가
2단계. 두 단어 사이의 유사도 구하기
from scipy.spatial.distance import cosine
# 코사인 유사도 함수 정의
def word_similarity(word1, word2, model):
try:
vector1 = model[word1]
vector2 = model[word2]
similarity = 1 - cosine(vector1, vector2) # 코사인 유사도 계산
return similarity
except KeyError as e:
return str(e)
# 가장 유사한 단어를 보여주는 함수 정의
def most_similar(word, model, topn=5):
try:
similar_words = model.most_similar(word, topn=topn) # 가장 유사한 단어 찾기
return similar_words
except KeyError as e:
return str(e)
# 두 단어 사이의 유사도 확인
print('football & basketball 유사도 : ' , word_similarity('football', 'basketball', word2vec_model))
print('football & airplane 유사도 : ' , word_similarity('football', 'airplane', word2vec_model))
GloVe 실습
2019년 까지의 단어만 학습되어있기 때문에 그 이후의 단어를 임베딩할 수 없다.
# gloVe 함수 정의
def use_glove(word, model):
try:
word_vector = model[word]
return word_vector
except KeyError:
return "단어가 모델의 어휘에 없습니다."
# 제공하는 GloVe 모델 불러오기
# 약 5분정도 소요
glove_model = load('glove-wiki-gigaword-300')
문장 임베딩 (Sentence Embedding)
: 문장 자체를 숫자의 형태(벡터)로 변환하는 과정
- 전반적인 글의 이해, 문맥 파악, 글 생성 등과 같이 문장 혹은 그 이상의 단위에서 정보를 포착하는 경우에 사용
- 글의 전반적인 이해가 쉽게 가능
- 보다 많은 자원과 계산이 필요
- 단어 수준의 미묘한 변화를 잡아내기가 어려움
문장에 원핫 인코딩 적용
: 문장에 소속된 각 단어를 해당 단어의 인덱스 위치에 1을 부여하고 나머지 부분을 0으로 채움
임베딩 알고리즘 (1) - 단어 임베딩을 활용한 문자 임베딩
: 각 단어들의 임베딩 평균을 활용해 문장의 임베딩을 생성
임베딩 알고리즘 (2) - TF-IDF를 활용한 문장 임베딩
: 문장 내 단어의 중요도를 나타내는 척도(=TF-IDF)를 활용한 단어 가중치를 적용해 문장 임베딩을 생성
- TF-IDF를 이용해 각 단어 임베딩에 가중
- 가중된 값들을 활용해 평균 값 활용
임베딩 알고리즘 (3) - 딥러닝을 활용한 문장 임베딩
: 문장을 구성하는 단어를 입력으로 받으면 딥러닝적 연산을 통해 각 단어에서 정보를 공급받아 각각의 단어 임베딩 벡터를 생성
문장 임베딩 실습
📌 CountVectorizer 라이브러리
- 각 문장에 나온 단어를 독립적인 인덱스로 바꿔줌
- 또한, 해당 인덱스에 1의 값을 넣어줌
1단계. 필요한 라이브러리 불러오기
## 필요한 라이브러리 불러오기
from sklearn.feature_extraction.text import CountVectorizer
## 예제 문장
# 문장 리스트
sentences = ["사과는 맛있다",
"바나나는 맛있다",
"딸기는 맛있다",
"김치는 맵다",
"짜장면은 달다",
"소고기는 좋다"]
2단계. CountVectorizer 객체 생성
# CountVectorizer를 생성
# CountVectorizer : 텍스트 데이터를 단어 빈도(count)로 변환하는 객체
# binary=True : 빈도가 2 이상이어도 1로 표현
# binary=False : BoW 코드로 사용 가능
vectorizer = CountVectorizer(binary=True)
vectorizer.fit(sentences)
3단계. 단어 - 인덱스 매핑
# 단어-인덱스 매핑
word_to_index = vectorizer.vocabulary_
print("단어-인덱스 매핑:", word_to_index)
4단계. 문장 임베딩
# 문장을 벡터로 변환
input_sentence = ["소고기는 맛있다"]
# input_sentence = ["소고기는 소고기는 소고기는 맛있다"]
sentence_vectors = vectorizer.transform(input_sentence).toarray()
print(f"입력 문장 '{input_sentence[0]}'의 원핫 임베딩 벡터 :", sentence_vectors[0])
`binary=True`로 설정했기 때문에 '소고기는'이 여러번 나와도 1로 임베딩 해준다.
# 문장을 벡터로 변환
# input_sentence = ["소고기는 맛있다"]
input_sentence = ["소고기는 소고기는 소고기는 맛있다"]
sentence_vectors = vectorizer.transform(input_sentence).toarray()
print(f"입력 문장 '{input_sentence[0]}'의 원핫 임베딩 벡터 :", sentence_vectors[0])