Word2Vec란?
단어의 의미나 연관성을 벡터로 표현하는것을 의미합니다.
단어의 의미를 벡터로 표현하면 연관된 단어나 단어의 유사도에게 확인할 수 있어요.
그리고 의미 선형관계를 계산할 수 있기때문에 왕자-남성 + 여성=>공주 와 같은 계산을 할 수 있습니다.
Word2Vec는 즉! 문장 내부의 단어를 벡터로 변환해주는 도구이고,
단어의 연결을 기반으로 단어의 연관성을 벡터로 만들어줍니다 결국! 단어를 벡터로 표현해주는거죠
유사도를 쉽게확인하기 위해서도 쓰입니다.
아래처럼 어떤 txt를 가져오고 보면
어떤 txt를 가져오고 보면
\n제1편 어둠의 발소리\n서(序)\n1897년의 한가위.\n까치들이 울타리 안 감나무에 와서 아침 인사를 하기도 전에, 무색 옷에 댕기꼬리를 늘인 아이들은 송편을 입에 물고 마을길을 쏘다니며 기뻐서 날뛴다. 어른들은 해가 중천에서 좀 기울어질 무렵이래야, 차례를 치러야 했고 성묘를 해야 했고 이웃끼리 음식을 나누다 보면 한나절은 넘는다. 이때부터 타작마당에 사람들이 모이기 시작하고 들뜨기 시작하고 -- 남정네 노인들보다 아낙들의 채비는 아무래도 더디어지는데 그럴 수밖에 없는 것이 식구들 시중에 음식 간수를 끝내어도 제 자신의 치장이 남아 있었으니까. 이 바람에 고개가 무거운 벼이삭이 황금빛 물결을 이루는 들판에서는, 마음놓은 새떼들이 모여들어 풍성한 향연을 벌인다.\n"후우이이 -- 요놈의 새떼들아!" 극성스럽게 새를 쫓던 할망구는 와삭와삭 풀발이 선 출입옷으로 갈아입고 타작마당에서 굿을 보고 있을 것이다. 추석은 마을의 남녀노유, 사람들에게뿐만 아니라 강아지나 돼지나 소나 말이나 새들에게, 시궁창을 드나드는 쥐새끼까지 포식의 날인가 보다.\n빠른 장단의 꽹과리 소리, 느린 장단의 둔중한 여음으로 울려퍼지는 징 소리는 타작마당과 거리가 먼 최참판댁 사랑에서는 흐느낌같이 슬프게 들려온다. 농부들은 지금 꽃 달린 고깔을 흔들면서 신명을 내고 괴롭고 한스러운 일상(日常)을 잊으며 굿놀이에 열중하고 있을 것이다. 최참판댁에서 섭섭찮게 전곡(錢穀)이 나갔고, 풍년에는 미치지 못했으나 실한 평작임엔 틀림이 없을 것인즉 모처럼 허리끈을 풀어놓고 쌀밥에 식구들은 배를 두드렸을 테니 하루의 근심은 잊을 만했을 것이다.\n이날은 수수개비를 꺾어도 아이들은 매를 맞지 않는다. 여러 달 만에 솟증(素症) 풀었다고 느긋해하던 늙은이들은 뒷간 출입이 잦아진다. 힘 좋은 젊은이들은 벌써 읍내에 가고 없었다. 황소 한 마리 끌고 돌아오는 꿈을 꾸며 읍내 씨름판에 몰려간 것이다.\n최참판댁 사랑은 무인지경처럼 적막하다. 햇빛은 맑게 뜰을 비쳐주는데 사람들은 모두 어디로 가버렸을까. 새로....
이것을 어미, 조사, 구두점을 제거해보려고 합니다. 왜 하냐면
명사 동사 형용사만 학습시키기 위해서고 동사,형용사는 기본형으로만 학습시키는 조건이 있습니다!
실습해보기
okt = Okt()
results = []
lines = text.split('\n')
for line in lines:
# 형태소 분석
# 단어의 기본형 사용
malist = okt.pos(line, norm=True, stem=True)
r = []
for word in malist:
# 어미 / 조사 / 구두점 제외
if not word[1] in ['Josa', 'Eomi', 'Punctuation']:
r.append(word[0])
rl = (" ".join(r)).strip()
results.append(rl)
print(rl)
모두다 기본 형태로 변경된 것 또한 볼 수 있습니다. ex)오다 가다 ..
불필요한 품사들의 말뭉치를 만들어내보고 이것을 wakati_file이라는 변수로하고 모델을 만들겠습니다.
wakati_file = os.path.join(base_path, 'tojo.wakati')
with open(wakati_file, 'w', encoding='utf-8') as fp:
fp.write("\n".join(results))
그냥 word2Vec으로 돌릴수없으니 학습용 형식으로 준비하는 전처리단계입니다.
불필요한 품사들을 말뭉치를 만들어낸겁니다. 이걸가지고 모델을 만들어보겠습니다.
# Word2Vec 모델 만들기
data = word2vec.LineSentence(wakati_file)
data
<gensim.models.word2vec.LineSentence at 0x7b8c320462c0>
# 딥러닝을 통한 워드 벡터 모델 생성
model = word2vec.Word2Vec(data, vector_size=200, window=10, hs=1, min_count=2, sg=1)
# vector_size : 문장의 벡터의 차원
# window: 한 문장 내에서의 최대 거리값.
# hs=1 : hierarchical softmax 학습
# min_count : 발생빈도가 이보다 낮으면 무시
# sg : 학습 알고리즘 선택 1 이면 -> skip-gram 사용
model
(하이퍼파라미터)
hs=1은 학습방법이고 나머지는 또 우측에 설명을 달아놨으니 확인하기!
model변수로 model을 생성했고 저장-> 불러오는것까지는 아래코드입니다.
# 학습한 모델 저장
model.save(os.path.join(base_path, 'toji.model'))
# 저장한 모델 불러오기
model = None
model = word2vec.Word2Vec.load(os.path.join(base_path, 'toji.model'))
.load를 통해 그 모델에 학습된 말뭉치 개수 확인해보기!(코푸스)
# 학습된 말뭉치 (corpus) 개수
model.corpus_count
# 3376
# 말뭉치(corpus) 내 전체 단어 개수
model.corpus_total_words
#55860
이렇게 직관적으로 확인할 수 있습니다. 물론 학습할때마다 조금씩 다를 수 있습니다!그래서 결과가 다를 수 있다는 이야기
model.wv.most_similar(positive=['땅'])
[('작정', 0.8686302900314331),
('조상', 0.8478798270225525),
('꾼', 0.8375515937805176),
('치우다', 0.8326576352119446),
('장차', 0.8315990567207336),
('원님', 0.825384795665741),
('앙앙거리다', 0.8253158926963806),
('원귀', 0.8240906596183777),
('우쩌겄소', 0.8220126032829285),
('재작년', 0.8217443823814392)]
model.wv.most_similar(positive=['집'])
[('제', 0.7872245907783508),
('구석', 0.7528969049453735),
('볼일', 0.7230401039123535),
('그까짓', 0.7127760052680969),
('마침', 0.695249617099762),
('말짱', 0.6936712861061096),
('그랬더니', 0.6913782358169556),
('하모', 0.6913228631019592),
('가다', 0.688928484916687),
('이지마', 0.687778890132904)]
유사도 연산을 해주는 매소드wv.most_siliar(positive=['확인하고싶은 연관도'])를 적게되면
그 의미랑 가장 가까운것들이 나오게됩니다.
유사도가 높은것순으로 나오게되는거죠!
위는 소설을 가지고 하는것이기때문에... 살짝 이상할수도있어요!
그래서 위키피디아 데이터를 다운로드해서 사용해서 정확도를 높이겠습니다.
근데 이거 용량이 꽤 커서 시간이 10시간이상걸릴수도있어요
그래서 쌤이 따로 주신파일을 가지고 압축을 풀어보았습니다.
https://dumps.wikimedia.org/kowiki/latest
# 위 페이지에서 kowiki-latest-pages-articles.xml.bz2 파일을 다운 받아서 압축을 풉니다.
model = word2vec.Word2Vec.load(os.path.join(base_path, 'wiki.model'))
파이썬 혹은 파이썬과 비슷한 것들은 무엇이 있는지 찾아보기를 진행하면 아래처럼 나옵니다.
model.wv.most_similar(positive=['Python', '파이썬'])
[('Perl', 0.9213457107543945),
('Java', 0.9069113731384277),
('Tcl', 0.9054787755012512),
('MATLAB', 0.8736515641212463),
('Lisp', 0.869271457195282),
('자바스크립트', 0.8669256567955017),
('하스켈', 0.8633923530578613),
('JSP', 0.8586523532867432),
('IDL', 0.8562408089637756),
('CLI', 0.8507612943649292)]
파이썬과 혹은 파이썬과 비슷한 것들은 아래에 표시되는
Perl, Java, Tcl , 자바스크립트 등등... 보통 프로그래밍언어가 추출되는것을 확인할 수 있습니다.
# 아빠 - 남성 + 여성
model.wv.most_similar(positive=['아빠', '여성'], negative=['남성'])
[('엄마', 0.8517739772796631),
('아저씨', 0.6820619702339172),
('어디가', 0.6796489357948303),
('친구', 0.6589521169662476),
('신혼', 0.6444262266159058),
('괴짜', 0.6426041126251221),
('할머니', 0.6371489763259888),
('아줌마', 0.6364408135414124),
('룸메이트', 0.6234321594238281),
('아내', 0.619864821434021)]
아빠 백터와 여성백터는 더하고 남성백터는 빼는것으로 출력해보니 엄마가 제일 높은 연관성을 가지고 있다는것을 확인할 수 있습니다.
# 왕자 - 남성 + 여성
model.wv.most_similar(positive=['왕자', '여성'], negative=['남성'])
[('왕녀', 0.7314919233322144),
('여왕', 0.617167055606842),
('이아손', 0.5895238518714905),
('아들', 0.5856923460960388),
('대왕', 0.5848724246025085),
('왕비', 0.5842419862747192),
('삼촌', 0.5803187489509583),
('왕세자', 0.5697871446609497),
('시녀', 0.5668401718139648),
('공주', 0.5660519599914551)]
똑같이 왕자를빼고 남성과 여성벡터는 더한것! 의 결과를 확인할 수 있습니다.
# 한국에서 서울에 해당하는 곳이 일본에서는 어디일까요?
model.wv.most_similar(positive=['서울', '일본'], negative=['한국'])
[('도쿄', 0.6773518919944763),
('교토', 0.6354460120201111),
('오사카', 0.6219913363456726),
('서울특별시', 0.5624314546585083),
('후쿠오카', 0.5568024516105652),
('도쿄도', 0.5443399548530579),
('나고야', 0.5367217659950256),
('오사카부', 0.5236438512802124),
('홋카이도', 0.5192624926567078),
('요코하마', 0.5188096761703491)]
model.wv.most_similar(positive=['서울', '중국'], negative=['한국'])
[('베이징', 0.6821848154067993),
('북경', 0.6481270790100098),
('절강성', 0.6373119354248047),
('상하이', 0.6292018890380859),
('봉천', 0.620449960231781),
('산동성', 0.613395094871521),
('北京', 0.6115888357162476),
('광동성', 0.6005773544311523),
('충칭', 0.598031222820282),
('산동', 0.5958592891693115)]
그리고 서울 맛집에 대한것들도 검색해보았습니다.
model.wv.most_similar(positive=['서울', '맛집'])
[('강남', 0.6851244568824768),
('인사동', 0.6402742266654968),
('서울특별시', 0.6207907199859619),
('연희동', 0.617041289806366),
('압구정동', 0.6069210171699524),
('서울시', 0.60683673620224),
('부산', 0.6065455079078674),
('춘천', 0.602898895740509),
('명동', 0.5961471199989319),
('노량진', 0.5898142457008362)]
강남이 가장 많은것을 확인할 수 있습니다. 여기까진 200차원입니다.
model.wv['고양이']
array([-1.1542174e+00, 1.4745393e+00, -7.9733324e-01, -5.5900455e-01,
-6.6307449e-01, 9.2782109e-04, 3.6092591e+00, -1.5235772e+00,
2.0633450e+00, -1.6057447e+00, 1.5326804e-01, -2.2927985e+00,
-1.0125110e+00, -1.1354420e+00, 3.3545346e+00, -1.3055078e+00,
-1.1653799e+00, 2.7230087e-01, 2.4801822e+00, -2.5385299e+00,
2.7152933e-02, 2.7477446e+00, 1.1618546e+00, 2.9348221e-01,
2.4446231e-01, -4.2186599e-02, 1.4659742e+00, -1.3442420e+00,
-1.7345996e+00, 1.6330991e+00, -1.7024884e+00, -1.4333612e+00,
-2.8042972e+00, 2.4347486e+00, 1.8691258e-01, 1.9883758e+00,
-2.1475420e+00, 3.9240709e-01, 1.6318704e+00, 1.2634866e+00,
-2.4041352e+00, 3.7154386e+00, 6.9826150e-01, -9.8208046e-01,
3.5579875e-01, 1.2745339e-01, 2.2055113e-01, -1.0895270e+00,
3.2937765e-01, 2.6084111e+00, 2.9336080e-01, -2.2053027e+00,
2.9885385e+00, -9.5456719e-01, 1.3786117e+00, -9.8494941e-01,
-1.0946046e+00, 1.3351594e+00, -1.3717122e+00, -1.0095539e+00,
-3.1787407e+00, 5.8116406e-01, -9.0793264e-01, 1.5016379e+00,
5.4166639e-01, 5.6927681e-01, -6.9126540e-01, -2.1516631e+00,
3.4873679e-01, -2.1284442e+00, -5.4845948e+00, 5.4757065e-01,
4.5885763e-01, -6.6594863e-01, 8.2989365e-01, -7.2227013e-01,
-1.3221562e+00, 1.2688708e+00, -1.7069147e+00, 1.9606873e+00,
-7.3036259e-01, -1.6601384e-01, 6.7513406e-01, -1.1760267e+00,
-5.2177966e-01, -4.0551597e-01, 1.9159936e+00, -7.4244136e-01,
-3.3973749e+00, 2.9921930e+00, 1.3513365e+00, 1.8686411e+00,
1.3707920e+00, -2.0566709e+00, -1.6780134e+00, -8.9390242e-01,
-5.9907657e-01, 9.4608074e-01, -5.6657642e-01, 8.8828903e-01],
dtype=float32)
고양이라는 벡터가 어떻게 표현되는지 볼 수 있는 코드입니다.
이 숫자가 어떤느낌이냐면 그냥 200차원에서의(당연히 상상안감) 하나의 점 이라고 생각하면됩니다.
그냥 관계로 이해하면되는데 그 관계란 유사성, 거리, 방향을 의미하니 이게 뭐 어딨는지 찾을필요는없을거같습니다.
벡터로 이루어진 공간에서 각 차원은 데이터의 문맥적, 의미적 속성을 나타냅니다!
즉 이 벡터의 각 요소(숫자)는 단어의 속성(특징)을 표현합니다.
-문맥적 속성?
단어가 주변에서 어떤 단어와 함께 자주 등장하는지를 학습
ex) 고양이 - 강아지, 사료-애완동물 <- 요런것들
그래서 고양이의 벡터는 이런 단어들과 연관성이 높아지고 이 정보가 각 차원에 반영됩니다.
-의미적 속성?
단어 자체의 의미와 유사성을 숫자로 나타냄
ex) 고양이,강아지 => 애완동물 => 벡턱가 비슷한 값을 가집니다.
고양이,자동차 => 관련도 없음 = > 벡터가 크기 다름
여기서 결국 분류가 되고 그 벡터값을 반환을 하니 분류모델인가? 라고 생각했는데
이것은 분류모델처럼 결과를 나누는것이 아니라 단어의 의미를 벡터로 표현해서 단어간의 관계를 계산 혹은 다른 NLP 작업에서 활용할 수 있도록 도와준다고 합니다. 결국 언어임베딩모델 이라고합니다.!!
즉 전에 배운 분류랑 회귀랑은 전혀 관련이 없습니다.
그림으로 보자면 유사도를 확인할 수 있는 시각화 자료입니다!
'AI > 자연어처리' 카테고리의 다른 글
[AI활용 자연어처리 챗봇프로젝트] LSTM이란? (1) | 2024.12.17 |
---|---|
[AI활용 자연어처리 챗봇프로젝트] 순차데이터, 순환데이터 (1) | 2024.12.13 |
순환신경망을 이용한 IMDB 리뷰 분류해보기(28) (4) | 2024.12.10 |
[AI활용 자연어처리 챗봇프로젝트] Padding, 원핫인코딩 (5) | 2024.12.09 |
[AI활용 자연어처리 챗봇프로젝트] OOV란? oov인덱스 번호는? (0) | 2024.12.06 |