견리더의 알(R)파(Python)고

word2vec을 이용하여 딥러닝에 적용하기(word2vec + lstm) 본문

파이썬(Python)/여러 기술

word2vec을 이용하여 딥러닝에 적용하기(word2vec + lstm)

견리더 2020. 12. 2. 18:19

기존 lstm 딥러닝에 word2vec을 사용하여 가중치를 줘보았다. 

오류가 많이나서 힘들었다... 하지만 극복

 

(참고 블로그)

keras를 활용한 word2vec pre-trained 모델을 로딩하여 IMDB 감정분석 분류문제 해결하기 (teddylee777.github.io)

 

대부분의 설명은 주석으로 적어 놓았다.

앞의 기본적인 패키지 임포트는 따로 프로젝트 탭에서 포스팅 해 놓았고, 추가적으로 필요한 패키지만 여기에 적었다.

#데이터 가져오기 감성점수와 형태소 분석이 완료된 데이터 필요
data = pd.read_excel('C:/Users/USER/Desktop/news_sentiment_words.xlsx', index_col=0)
data['words'] = [i.replace("'", "").replace('[', '').replace(']', '').replace(' ', '').split(',') for i in
          list(data['words'])]  # words가 텍스트 형식으로 되어 있을 경우
data = data.reset_index(drop=True) #인덱스 초기화

나는 운좋게도 감성지수가 라벨링된 기사를 얻을 수 있었다. 

물론 비밀이다.

기본 data

대충 이렇게 생겼으며 data['word']에는 형태소 분석이 된 명사 list가 있다.

 

 

#word2vec 사용하기
embedding_model = Word2Vec(data['words'], size=100, window = 4, min_count=30, workers=4, iter=200)
match_index = pd.DataFrame(embedding_model.wv.vocab.keys(), columns=['name']) #벡터화된 단어들
word_vector = pd.DataFrame(embedding_model.wv.vectors) #백터화된 단어들의 벡터값 
data_v = pd.concat([match_index, word_vector], axis=1) #백터화된 단어들과 그 벡터값들을 하나로 합침
embedding_model.most_similar('취업') #벡터화 결과 살펴보기

word2vec를 너무 많이 해서 이젠 도사가 됐다.

이렇게 하면 어떤 단어가 벡터화가 되었는지 어떻게 되었는지 알 수 있다. 

data_v

word2vec을 일단 해놓으면 벡터화가 된 단어도 있고 안된단어도 있는데, 앞으로의 분석을 위해 벡터화가 안된 단어들은 제외 시킨다. 

#뉴스기사에서 벡터화된 단어만 남기고 나머지 단어들 제거
data['vec_words'] = ['na' for i in range(len(data))]
match_index['name']
vec_words = []
for num,i in enumerate(data['words']):
    for j in match_index['name']:
        if j in i:
            vec_words.append(j)
    data['vec_words'][num] = vec_words
    vec_words = []

이제 기본적인 작업은 해 놓았고 이제 뉴스기사의 단어들을 토크나이징 시킨다.

#tokenization 토큰화 하기 형태소분석으로 일단 다 나눠놈
from keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer()
tokenizer.fit_on_texts(data['vec_words']) #형태소 분석에서 벡터화된 단어list를 tokenizer dictionary에 추가
print(len(tokenizer.word_index)) #벡터단어 list의 길이와 같음

text_sequence = tokenizer.texts_to_sequences(data['vec_words']) # 만들어진 dict을 기준으로 텍스트를 숫자로 변경

 

 

 

기사 마다 길이가 다르니 이걸 맞춰줘야 딥러닝이 가능하다 이 작업을 padding이라고 하는 것 같다.

#길이 맞추기 (기사 단어 수 맞추기 , 짧은 기사는 뒤에 0 채우기)
from keras.preprocessing import sequence
max_length = max([len(i) for i in data['vec_words']]) #기사의 최대길이
pad_text = sequence.pad_sequences(text_sequence,
                                  maxlen=max_length,
                                  padding='post', value= 0) #padding = "post" 뒤에 0 채우기, 기본값은 앞에 0 채우기
pad_text[:5]

 

이제 x,y데이터들을 만들어 준다. 스플릿 사용~

#x,y 데이터 만들기
from sklearn.model_selection import train_test_split
#y data 생성
y = [0 if i < 15 else 1 for i in data['sum'] ]
Y_data = np.array(y)

x_train, x_valid, y_train, y_valid = train_test_split(pad_text, Y_data, test_size=0.1, random_state=30)

 

이제 단어가 숫자가 되었고, 그 숫자에 맞는 벡터들을 조합시켜준다. 

#숫자화된 기사 속 단어와 벡터 맞춰주기
VOCAB_SIZE = len(tokenizer.index_word) + 1
embedding_dim = 100
embedding_matrix = np.zeros((VOCAB_SIZE, embedding_dim))

# tokenizer에 있는 단어 사전을 순회하면서 word2vec의 300차원 vector를 가져옵니다
for word, idx in tokenizer.word_index.items():
    embedding_vector = embedding_model[word] if word in embedding_model else None
    if embedding_vector is not None:
        embedding_matrix[idx] = embedding_vector

embedding_matrix.shape

 

이제 모델을 만들어 보자 

 

#모델 만들기
import tensorflow as tf
from tensorflow.keras.layers import Embedding, Dense, LSTM, Bidirectional #패키지 다운
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import load_model
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.layers import Flatten, Dropout
from keras.layers import Conv1D, MaxPooling1D
from keras import optimizers

deep_model = Sequential() #기본 토대
deep_model.add(Embedding(VOCAB_SIZE,embedding_dim,input_length=max_length,
                         weights=[embedding_matrix],trainable=False)) # embedding layer에 대한 train은 꼭 false로 지정
deep_model.add(Bidirectional(LSTM(128, return_sequences=False)))
deep_model.add(Dropout(0.2))
deep_model.add(Dense(64))
deep_model.add(Dropout(0.2))
deep_model.add(Dense(1, activation='sigmoid'))

es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4) # 손실 최소화에서 4번째 까지 에포크 돌리기
checkpoint_path='C:/Users/USER/Desktop/news_sentiment_test.h5'
mc = ModelCheckpoint(checkpoint_path, monitor='val_acc', mode='max', verbose=1, save_best_only=True) #정확도 제일 높을때 모델저장
deep_model.compile(optimizer='adam', loss = 'binary_crossentropy', metrics=['acc'])

with tf.device('/cpu:0'):
    history = deep_model.fit(x_train, y_train,validation_data=(x_valid, y_valid), epochs=20, callbacks=[es, mc], batch_size=32, validation_split=0.1)
    #배치 사이즈, 한번에 32개를 넣어 돌리겠다는 뜻, validation_split 검증데이터 크기

 

여러가지 블로그와 다른 사람의 도움을 받아 만들어진거라 조금 더러울 수 있지만 만드느라 많이 배웠다. 

일반 lstm보다 더 좋은 효과를 낸다고 한다. 

 

 

여기까지 정말 많은 오류가 있었다... 이제 딥러닝에 조금 더 가까워진것 같다~

정확도 넘 높다 넘 좋다. ㅎㅎ