2023. 11. 3. 17:03ㆍML&DL/NLP
워드 임베딩
- 인공 신경망을 이용하여 단어의 벡터값을 얻는 방법
- 학습 후에는 각 단어 벡터 간의 유사도를 계산 할 수 있다.
1) 랜덤 초기화 임베딩
- 초기에 모든 단어의 임베딩 벡터값은 랜덤 초기화 됨.
- 오차를 구하는 과정(역전파 하는 과정)에서 embedding table을 학습
2) 사전 훈련된 임베딩 (Pre-trained Word Embedding)
- 방대한 양의 텍스트 데이터로 이미 훈련되어있는 임베딩 벡터값을 사용하는 것
- 대표적인 알고리즘으로 word2Vec, FastText, GloVe가 존재함
💻 실습
Word2Vec (영어)
라이브러리 불러오기
import gensim
gensim.__version__
import re
from lxml import etree
import urllib.request
import zipfile
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
nltk.download('punkt')
데이터 불러오기
urllib.request.urlretrieve("https://raw.githubusercontent.com/GaoleMeng/RNN-and-FFNN-textClassification/master/ted_en-20160408.xml", filename="ted_en-20160408.xml")
데이터 전처리
- 특수 문자 제거
targetXML = open('ted_en-20160408.xml', 'r', encoding='UTF8')
target_text = etree.parse(targetXML)
# xml 파일로부터 <content>와 </content> 사이의 내용만 가져온다.
parse_text = '\n'.join(target_text.xpath('//content/text()'))
# 정규 표현식의 sub 모듈을 통해 content 중간에 등장하는 (Audio), (Laughter) 등의 배경음 부분을 제거.
# 해당 코드는 괄호로 구성된 내용을 제거.
content_text = re.sub(r'\([^)]*\)', '', parse_text)
- 문장 토큰화
# 입력 코퍼스에 대해서 NLTK를 이용하여 문장 토큰화를 수행.
sent_text = sent_tokenize(content_text)
# 각 문장에 대해서 구두점을 제거하고, 대문자를 소문자로 변환.
normalized_text = []
for string in sent_text:
tokens = re.sub(r"[^a-z0-9]+", " ", string.lower())
normalized_text.append(tokens)
- 단어 토큰화
# 각 문장에 대해서 NLTK를 이용하여 단어 토큰화를 수행.
result = [word_tokenize(sentence) for sentence in normalized_text]
- Word2Vec 훈련
* 하이퍼파라미터값
vector_size = 워드 벡터의 특징 값. 즉, 임베딩 된 벡터의 차원.
window = 컨텍스트 윈도우 크기
min_count = 단어 최소 빈도 수 제한 (빈도가 적은 단어들은 학습하지 않는다.)
workers = 학습을 위한 프로세스 수
sg = 0은 CBOW, 1은 Skip-gram.
from gensim.models import Word2Vec
model = Word2Vec(sentences=result, vector_size=100, window=5, min_count=5, workers=4, sg=0)
- 훈련된 모델 테스트
* man 과 유사한 단어
model_result = model.wv.most_similar("man")
print(model_result)
[('woman', 0.8469663262367249), ('guy', 0.7982245087623596), ('boy', 0.7504032850265503), ('lady', 0.7486523389816284), ('girl', 0.7446972131729126), ('soldier', 0.7413182854652405), ('kid', 0.7310553193092346), ('gentleman', 0.7181988954544067), ('david', 0.6683082580566406), ('friend', 0.6598968505859375)]
=> 1과 가까울수록 유사도가 높은 것
model.wv["man"]
- 훈련된 모델 저장 & 테스트
from gensim.models import KeyedVectors
model.wv.save_word2vec_format('eng_w2v') # 모델 저장
loaded_model = KeyedVectors.load_word2vec_format("eng_w2v") # 모델 로드
model_result = loaded_model.most_similar("man")
print(model_result)
Word2Vec (한국어)
라이브러리 불러오기
!pip install konlpy
!pip install mecab-python
!bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh)
import urllib.request
from konlpy.tag import Mecab
from gensim.models.word2vec import Word2Vec
import pandas as pd
import matplotlib.pyplot as plt
데이터 불러오기
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings.txt", filename="ratings.txt")
train_data = pd.read_table('ratings.txt')
데이터 확인
train_data[:5] # 상위 5개 출력
데이터 전처리
train_data = train_data.dropna(how = 'any') # Null 값이 존재하는 행 제거
print(train_data.isnull().values.any()) # Null 값이 존재하는지 확인
# 정규 표현식을 통한 한글 외 문자 제거
train_data['document'] = train_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
- 형태소 토큰화
* 의미가 중요하지 않은 단어는 불용어 처리하여 제거 해줌
* mecab 사용
# 불용어 정의
stopwords = ['도', '는', '다', '의', '가', '이', '은', '한', '에', '하', '고', '을', '를', '인', '듯', '과', '와', '네', '들', '듯', '지', '임', '게']
# 형태소 분석기 mecab을 사용한 토큰화 작업 (다소 시간 소요)
mecab = Mecab()
tokenized_data = []
for sentence in train_data['document']:
temp_X = mecab.morphs(sentence) # 토큰화
temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
tokenized_data.append(temp_X)
- Word2Vec 훈련
from gensim.models import Word2Vec
model = Word2Vec(sentences = tokenized_data, vector_size = 100, window = 5, min_count = 5, workers = 4, sg = 0)
- 임베딩 매트릭스 확인
# 완성된 임베딩 매트릭스의 크기 확인
model.wv.vectors.shape
- 훈련된 Word2Vec 모델 테스트
print(model.wv.most_similar("최민식"))
[('한석규', 0.8762632012367249), ('안성기', 0.8671063780784607), ('송강호', 0.8488789796829224), ('박신양', 0.8463734984397888), ('드니로', 0.84193354845047), ('김혜수', 0.8415705561637878), ('신들린', 0.8410726189613342), ('설경구', 0.8391404151916504), ('채민서', 0.8342630863189697), ('조진웅', 0.8342404961585999)]
print(model.wv.most_similar("히어로"))
[('호러', 0.8413481116294861), ('슬래셔', 0.8230418562889099), ('하이틴', 0.7898564338684082), ('정통', 0.7874332070350647), ('최고봉', 0.7855408787727356), ('패러디', 0.782534658908844), ('고어', 0.7777903079986572), ('로코', 0.7744789123535156), ('무비', 0.7713674902915955), ('블록버스터', 0.7706264853477478)]
- 모델 저장
from gensim.models import KeyedVectors
model.wv.save_word2vec_format('kor_w2v') # 모델 저장
loaded_model = KeyedVectors.load_word2vec_format("eng_w2v") # Word2Vec 모델 로드
Word2Vec의 문제점 살펴보기
* OOV 문제(Out-Of-Vocabulary Problem) : Vocabulary에 존재하지 않는 단어가 등장하는 문제
-> memory 의 유사도는 구할 수 있지만, 이와 비슷한 memorry(vocabulary에 존재 x)의 유사도를 구할 수 없다는 문제점 발생
FastText
* Word2Vec의 OOV 문제를 해결할 수 있음
- FastText 훈련
from gensim.models import FastText
fasttext_model = FastText(result, vector_size=100, window=5, min_count=5, workers=4, sg=1)
-> Word2Vec에서 구할 수 없었던 'memorry'의 벡터 간 유사도를 출력 가능한 것을 볼 수 있음.
'ML&DL > NLP' 카테고리의 다른 글
[NLP] Seq2Seq(Sequence-to-Sequence) (0) | 2023.11.06 |
---|---|
[NLP] 시퀀스 모델 - RNN, LSTM, GRU (0) | 2023.11.06 |
[NLP] 텍스트 벡터화 : TF-IDF 실습 (1) | 2023.11.03 |
[NLP] 텍스트 벡터화 (0) | 2023.11.03 |
[NLP] 데이터 전처리 - 정수 인코딩 / 패딩 실습 (0) | 2023.11.02 |