STUDY/DevCourse

[데브코스][데이터 분석] 단어 임베딩과 문장 임베딩

_알파카 2024. 5. 14. 16:34
728x90

임베딩이란?

언어는 특정 개념을 표현하기 위한 약속의 집합

=> 글자를 컴퓨터에 입력으로 넣어주기 위해서는 컴퓨터가 이해할 수 있는 형태로 변경해야 함

 

컴퓨터는 특정 단어를 숫자의 형태(벡터)로 받아들임. 

따라서 단어를 숫자의 형태로 변형하는 과정이 필요 => 임베딩

 

임베딩, Embedding

: 텍스트 데이터를 벡터로 변환하는 기술

-> 이는 텍스트 마이닝을 비롯해 자연어 처리에서 매우 기본적인 과정

 

데이터 준비 -> 전처리 -> 임베딩 -> 시각화

  • 데이터 준비 : 원문 데이터 혹은 다른 소스로부터 데이터를 수집
  • 전처리 : 불용어, 오타 등의 데이터를 제외
  • 임베딩 : 목적에 맞는 임베딩 알고리즘을 적용
  • 시각화 : 필요시 임베딩 결과를 그려보고 이를 확인

1) 단어 임베딩 : 하나의 단어를 벡터로 변환

2) 문장 임베딩 : 문장 자체를 벡터로 변환

 

임베딩과 벡터 공간

임베딩의 결과는 벡터이므로, 벡터가 존재하는 벡터 공간에 표현 가능

ex. [1, 2] 벡터는 2차원 공간에 표현 가능

단어는 고차원으로 표현됨 -> 그래야 다양한 종류의 단어 포괄 가능

 

원핫 인코딩(One-hot encoding)

특정 단어를 표현하는 위치만 1이고 나머지 위치는 0으로 구성 (전통적인 방법)

=> 단어의 수만큼의 크기를 갖는 벡터 생성

-> 직관적으로 쉽게 단어를 벡터로 변환 가능

 

원핫인코딩의 한계

- 차원의 저주

: 하나의 단어를 표현하는 벡터의 크기는 전체 단어 수와 같음 => 효율성과 계산 복잡도 증가

 

- 의미 부재

: 의미적으로 비슷한 단어끼리 비슷한 공간에 존재하지 않음

ex. 축구-농구 관계와 축구-비행기 관계의 차이가 없음

 

- 정보의 희소성

: 특정 단어의 위치만 1이므로 중요한 정보가 매우 희소. 대부분 0이 많음

 

인코딩과 임베딩

인코딩과 임베딩 모두 데이터를 새로운 형태로 변환하는 과정

인코딩

: 데이터를 표준화된 형식으로 변환

-> 이미 변환 과정은 정의되어있고, 그 정의에 맞춰 변환 진행 => 본질적으로 의미가 변하지 않음

==> 데이터의 형식을 변환하는데 중점

 

임베딩

: 머신러닝 모델이 처리하기 쉬운 형태로 변환.  

=> 데이터의 의미적, 문맥적 특성을 모델이 이해할 수 있는 형태로 변환

 

분산 표현 (Distribution Representation)

: 원핫인코딩의 한계를 극복하기 위해 제안된 개념

정수가 아닌 실수(연속적인 값)로 이루어진 벡터로 임베딩 진행

(원핫인코딩은 0과 1 값으로만 임베딩 진행)

 

- 연속적인 실수의 값으로 단어를 변경하면서 

데이터의 의미를 여러 특성(feature)에 걸쳐 분산시켜 표현

ex. [0.2, -1.1, 2.6, 0.5]

 

=> 단어나 개체의 의미가 하나의 차원 혹은 공간에 집중되어 표현되는 것이 아니라, 

여러 요소에 걸쳐 분산되어 표현됨

==> 다양한 의미 & 문맥적 특성을 풍부하게 포함 가능

 

 

==> 분산표현으로 잘 임베딩이 된다면, 비슷한 의미를 갖는 단어들은 비슷한 분포를 갖게 됨

+ 비슷한 공간에 표현 가능

 


단어 임베딩

원핫 인코딩(One-hot encoding)

: 특정 단어를 표현하는 위치만 1, 나머지는 0

=> 문장을 단어의 형태로 분해 필요 : tokenize

 

- 고유한 단어 집합 생성 ('사과는', '바나나는', '맛있다')

-> 고유 단어에 독립된 인덱스 부여 (사과는 = 0, 바나나는 = 1, 맛있다 = 2)

-> 벡터 생성 : 각 단어의 인덱스에 1 부여 ( 사과는 = [1, 0, 0] / 바나나는 = [0, 1, 0] / 맛있다 = [0, 0, 1] )

 

원핫 인코딩 실습

from sklearn.preprocessing import OneHotEncoder

# OneHotEncoder 객체 생성
# sparse_output=False : 0과 1로 이루어진 행렬의 형태로 변환
encoder = OneHotEncoder(sparse_output=False)
one_hot_encoded = encoder.fit_transform("사과는 맛있다 바나나는 맛있다")

# [[0. 0. 1.]
# [1. 0. 0.]
# [0. 1. 0.]
# [1. 0. 0.]]

encoder.get_feature_names_out() # 각 열이 어떤 단어를 나타내는지를 표시
# array(['x0_맛있다', 'x0_바나나는', 'x0_사과는'], dtype=object)

 

함수화해보기

# 함수화
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()

 

학습 기반 임베딩

분산 가설 (Distribution Hypothesis)

: 분산 표현의 이론적 기반

: 1950년대 제안된 언어학 이론으로 "단어의 의미는 그 단어가 나타나는 문맥에 의해서 결정된다"는 아이디어를 중심으로 함

=> 최신 임베딩 기법은 분포 가설을 기반으로 연구됨

-> 특정 단어의 의미를 숫자 벡터로 표현하기 위해 문맥과 주변 단어를 이용해 학습 진행

 

Word2Vec

: 2013년 구글 연구진에 의해 개발된 알고리즘

: 윈도우가 이동하며 동일한 개수의 단어 인식 -> 이들 사이의 연산을 진행해 각 단어들 임베딩

 

<두 가지 방법으로 단어를 벡터로 변환>

- CBOW : 이웃한 단어들을 바탕으로 가운데 단어가 무엇인지 예측하는 과정에서 임베딩 진행

- Skip-gram : 가운데 단어로 이웃한 단어들을 예측하는 과정으로 임베딩 진행

 

Word2Vec 실습

: Gensim 패키지 이용

: 내장 함수 모델 사용 -> 기본 모델을 다운받는데 시간 소요 & 학습에 사용되지 않은 단어는 활용 불가

- 기본 word2vec 모델은 특정 단어를 300개의 실수 값을 이용해 표현

-> 이를 이용해 유사도 관련 어플리케이션 적용 가능

  • 유사도 계산 (Cos similarity)
  • 가장 유사한 단어 찾기
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 "단어가 모델의 어휘에 없습니다."
        
# word2vec-google-news-300 : 기본 Word2Vec 모델, 구글의 뉴스 데이터로 하나의 단어를 300차원으로 변경
word2vec_model = load('word2vec-google-news-300')

use_word2vec('apple', word2vec_model)
# [-0.06445312 -0.16015625 -0.01208496  0.13476562 -0.22949219  0.16210938
#  0.3046875  -0.1796875  -0.12109375  0.25390625 -0.01428223 -0.06396484
# -0.08056641 -0.05688477 -0.19628906  0.2890625  -0.05151367  0 .........]
## 학습 당시 존재하지 않는 단어는 임베딩 불가

 

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))
# football & basketball 유사도 :  0.668246865272522
# football & airplane 유사도 :  0.1512438803911209

# 특정 단어와 가장 유사한 단어 보여주기
print('football과 가장 유사한 단어 5개는 : ' , most_similar('football', word2vec_model, topn=5))
# football과 가장 유사한 단어 5개는 :  [('soccer', 0.731354832649231), ('fooball', 0.7139959335327148), ('Football', 0.7124834060668945), ('basketball', 0.668246865272522), ('footbal', 0.6649289727210999)]

 

 

GloVe (Global Vectors for Word Representation)

: 2014년 스탠포드 대학에서 연구된 알고리즘

: 전체 글에 단어간 공동 출현 통계를 이용해 각 단어의 의미를 벡터로 표현, '공동출현행렬'

=> 공동으로 자주 출현하는 단어들을 벡터 공간 내 비슷한 위치에 존재하도록 임베딩

 

GloVe 실습

: Gensim 패키지 이용

def use_glove(word):
	# 기본 GloVe 모델
	model = load('glove-wiki-gigaword-300')
    word_vector = model[word]
    return word_vector
    
print(use_glove('airpods') # 역시 학습 당시에 없던 단어는 임베딩 불가
# [-0.20842   -0.019668   0.063981  -0.71403   -0.21181   -0.59283
#  -0.15316    0.044217   0.63289   -0.84821   -0.21129   -0.19763
# ...........


# 두 단어 사이의 유사도 확인 (GloVe)
print('football & basketball 유사도 : ' , word_similarity('football', 'basketball', glove_model))
print('football & airplane 유사도 : ' , word_similarity('football', 'airplane', glove_model))

# football & basketball 유사도 :  0.7341024279594421
# football & airplane 유사도 :  0.002223522402346134
## -> 전체 문맥 안의 유사도를 보기 때문에 Word2Vec 보다 성능이 좋다

 

딥러닝을 활용한 학습 기반 단어 임베딩

- BERT : 2018년 구글, 문장 내적 & 외적 관계를 바탕으로 임베딩

- CLIP : 2021년 OpenAI, 이미지와 텍스트의 공동 의미를 임베딩에 활용

- 등

 


문장 임베딩

: 문장 자체를 숫자의 형태로 변환

-> 단어를 넘어 문장 자체가 갖고 있는 의미를 벡터로 표현

 

단어 임베딩과 문장 임베딩의 차이점

문장 임베딩과 단어 임베딩은 서로 다른 목적과 사용 사례를 기반으로 개발

=> 즉, 문제를 해결하는 서로 다른 도구임! 

 

단어 임베딩은..

단어의 의미, 문맥적 유사성, 동의어 등과 같이 단어 수준에서 의미를 활용하는 경우에 사용

 

문장 임베딩은..

전반적인 글의 이해, 문맥 파악, 글 생성 등과 같이 문장 단위에서 정보를 포착하는 경우에 사용

 

원핫 인코딩

: 단어 인코딩과 마찬가지로 각 단어에 독립된 인덱싱 진행

=> 단어의 인덱스 위치에 1 부여

 

원핫 인코딩 실습

  • CountVectorizer 활용
    • 각 문장에 나온 단어를 독립적인 인덱스로 바꿔주는 과정
    • 또한, 해당 인덱스에 1의 값을 넣어주는 과정 지원
  • binary=True 라는 값을 넣어주면 중복된 단어가 나와도 1로 표현
    • 만약 Flase라면 BoW의 형태의 코드가 됨
from sklearn.feature_extraction.text import CountVectorizer

# CountVectorizer를 생성
# CountVectorizer : 텍스트 데이터를 단어 빈도(count)로 변환하는 객체
# binary=True : 빈도가 2 이상이어도 1로 표현
# binary=False : BoW 코드로 사용 가능
vectorizer = CountVectorizer(binary=True)
vectorizer.fit(sentences)

vectorizer.vocabulary_
# {'사과는': 6, '맛있다': 3, '바나나는': 5, '딸기는': 2, '김치는': 0, '맵다': 4, ..}

vectorizer.transform("소고기는 맛있다").toarray()
# [0 0 0 1 0 0 0 1 0 0]

 

다양한 문장 임베딩 기법

문장은 단어를 기반으로 만들어지는 개념

=> 따라서 각 단어들의 임베딩을 이용해 문장의 임베딩 생성

 

- 각 단어의 임베딩의 평균을 활용

: 가장 직관적인 방법, 그러나 다른 의미의 문장이 서로 비슷한 임베딩 값을 가질 수 있음

ex. "고양이가 강아지를 쫒는다", "강아지가 고양이를 쫒는다"는 다른 의미지만 평균 임베딩은 동일

 

- TF-IDF를 활용한 단어 가중치를 적용해 문장 임베딩을 생성

: TF-IDF란 문장 내 단어의 중요도를 나타내는 척도

-> 이를 이용해 각 단어 임베딩에 가중치를 주고, 가중된 값들을 활용해 평균 값 활용

 

 

딥러닝을 활용한 학습 기반 문장 임베딩

: 딥러닝 모델이 단어를 임베딩하는 과정에서 전체 문장의 의미를 담는 벡터 생성

=> 문장을 구성하는 각 단어에서 정보를 공급받아 임베딩 벡터를 생성

 

즉, 단어 임베딩을 진행하고 이를 이용하는 문장 임베딩 진행! 

 

 

 

728x90