목차
시퀀스 데이터
- 독립형 데이터: 시퀀스가 아님, ex) 이미지 데이터
- 의존형 데이터: 시퀀스, 데이터 항목에 의존하는 데이터 ex) 글 데이터, 주가데이터, 날씨 데이터, 영상데이터
- 데이터의 엘리먼트가 전후에 오는 내용과 관계를 지님
- 독립형 데이터와 다른 접급방식 필요
구현하기 전 읽어 볼 지식
- 📌필수📌[ ]
목표
- RNN(Recurrent Neural Network)에 사용할 시퀀스 데이터 준비
- 단어 예측을 수행할 모델 구축 및 트레이닝
- 헤드라인 생성기 제작
- 검색 창, 휴대폰 또는 텍스트 편집기 등에서 문장 자동완성을 제공하는 텍스트 예측 변수
데이터 읽기
몇 개월에 걸쳐 뉴욕 타임즈 신문에서 발췌된 헤드라인으로 구성되어 있음
먼저 기사의 모든 헤드라인을 읽어보겠다
CSV 형식의 데이터다!
import os
import pandas as pd
nyt_dir = 'data/nyt_dataset/articles/' ## 쓰고 싶은 데이터의 경로를 설정하면 된다!
all_headlines = []
for filename in os.listdir(nyt_dir):
if 'Articles' in filename:
# Read in all all the data from the CSV file
headlines_df = pd.read_csv(nyt_dir + filename)
# Add all of the headlines to our list
all_headlines.extend(list(headlines_df.headline.values))
len(all_headlines)
# 9335
첫 헤드라인을 확인해보자!!
👀 결과 보기
['My Beijing: The Sacred City',
'6 Million Riders a Day, 1930s Technology',
'Seeking a Cross-Border Conference',
'Questions for: ‘Despite the “Yuck Factor,” Leeches Are Big in Russian Medicine’',
'Who Is a ‘Criminal’?',
'An Antidote to Europe’s Populism',
'The Cost of a Speech',
'Degradation of the Language',
'On the Power of Being Awful',
'Trump Garbles Pitch on a Revised Health Bill',
'What’s Going On in This Picture? | May 1, 2017',
'Unknown',
'When Patients Hit a Medical Wall',
'Unknown',
'For Pregnant Women, Getting Serious About Whooping Cough',
'Unknown',
'New York City Transit Reporter in Wonderland: Riding the London Tube',
'How to Cut an Avocado Without Cutting Yourself',
'In Fictional Suicide, Health Experts Say They See a Real Cause for Alarm',
'Claims of Liberal Media Bias Hit ESPN, Too']
데이터 정리
NLP 작업의 중요한 부분은 컴퓨터가 이해할 수 있는 방식으로 텍스트를 처리하는 것이다
1️⃣ NULL제거: 이러한 항목은 트레이닝 세트에 포함하지 않아야 하므로 필터링을 통해 제거
2️⃣ 특수문자 제거: 이를 단어로 인식하지 않게 제거해야 한다 -> 하지만 Keras Tokenizer
를 사용하여 이러한 작업을 전부 수행 가능하므로 필요 X
3️⃣ 토큰화: 데이터셋에 나타나는 각 단어를 숫자로 표현하는 것
1️⃣ NULL제거
# Remove all headlines with the value of "Unknown"
all_headlines = [h for h in all_headlines if h != "Unknown"]
len(all_headlines)
## 결과: 8603
all_headlines[:20]
👀 제거 결과 보기
['My Beijing: The Sacred City',
'6 Million Riders a Day, 1930s Technology',
'Seeking a Cross-Border Conference',
'Questions for: ‘Despite the “Yuck Factor,” Leeches Are Big in Russian Medicine’',
'Who Is a ‘Criminal’?',
'An Antidote to Europe’s Populism',
'The Cost of a Speech',
'Degradation of the Language',
'On the Power of Being Awful',
'Trump Garbles Pitch on a Revised Health Bill',
'What’s Going On in This Picture? | May 1, 2017',
'When Patients Hit a Medical Wall',
'For Pregnant Women, Getting Serious About Whooping Cough',
'New York City Transit Reporter in Wonderland: Riding the London Tube',
'How to Cut an Avocado Without Cutting Yourself',
'In Fictional Suicide, Health Experts Say They See a Real Cause for Alarm',
'Claims of Liberal Media Bias Hit ESPN, Too',
'Is the dream in Australia crumbling?',
'Police in Texas Change Account in Officer’s Fatal Shooting of 15-Year-Old',
'Most Adults Favor Sex Ed. Most Students Don’t Get It.']
위의 결과와 비교해보면 ‘Unknown’ 값이 제거되었다!!
3️⃣ 토큰화
현재 데이터세트가 각각 일련의 단어로 이루어진 헤드라인 세트로 구성되어 있음
- 우리는 모델이 이해 가능한 방식으로 이러한 단어를 표현할 수 있는 방법을 모델에 제공해야 함
이를 위해 토큰화 사용
- 1) 텍스트의 조각을 더 작은 청크(토큰)으로 분리(여기선 단어 단위)
- 2) 각 고유 단어에 숫자가 할당 됨
이런 방법을 통해 모델이 데이터를 이해가능
[Keras의 데이터의 토큰화를 도와주는 클래스]
filters
: 문자열은 미리 구두점을 제거lower
: 단어를 소문자로 설정num_words
: 단어 빈도를 기준으로 유지할 최대 단어 수split
: 토큰화 하는 기준(여기서는 공백으로하여 띄어쓰기(단어)로 나눔)char_level
: True이면 모든 문자가 토큰으로 처리됨oov_token
: 지정된 경우 text_to_sequence 호출 중에 단어 외 단어를 대체하는 데 사용됨
tf.keras.preprocessing.text.Tokenizer(
num_words=None, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True,
split=' ', char_level=False, oov_token=None, document_count=0, **kwargs
)
from tensorflow.keras.preprocessing.text import Tokenizer
# Tokenize the words in our headlines
tokenizer = Tokenizer()
tokenizer.fit_on_texts(all_headlines)
total_words = len(tokenizer.word_index) + 1
print('Total words: ', total_words)
## 결과
## Total words: 11753
[단어 저장 방식 확인]
word_index
: 토크나이저가 단어를 어떻게 저장하는지 확인가능(사전 역할)
texts_to_sequences
: 토크나이저가 단어를 저장하는 방식을 확인 가능
from tensorflow.keras.preprocessing.text import Tokenizer
# Print a subset of the word_index dictionary created by Tokenizer
subset_dict = {key: value for key, value in tokenizer.word_index.items() \
if key in ['a','man','a','plan','a','canal','panama']}
print(subset_dict))
## 결과
## {'a': 2, 'plan': 82, 'man': 139, 'panama': 2732, 'canal': 7047}
tokenizer.texts_to_sequences(['a','man','a','plan','a','canal','panama'])
## 결과
## [[2], [139], [2], [82], [2], [7047], [2732]]
시퀀스 생성
이제 각 단어를 표현 숫자로 변환하면 헤드라인에서 토큰의 시퀀스가 생성됨
이러한 시퀀스를 바탕으로 딥러닝 모델을 트레이닝
이제 토크나이저를 이용해 헤드라인을 시퀀스로 바꾸겠다
# Convert data to sequence of tokens
input_sequences = []
for line in all_headlines:
# Convert our headline into a sequence of tokens
token_list = tokenizer.texts_to_sequences([line])[0]
# Create a series of sequences for each headline
for i in range(1, len(token_list)):
partial_sequence = token_list[:i+1]
input_sequences.append(partial_sequence)
print(tokenizer.sequences_to_texts(input_sequences[:5]))
input_sequences[:5]
👀 결과 보기
['my beijing', 'my beijing the', 'my beijing the sacred', 'my beijing the sacred city', '6 million']
[[52, 1616],
[52, 1616, 1],
[52, 1616, 1, 1992],
[52, 1616, 1, 1992, 125],
[126, 346]]
시퀀스 패딩
패딩이란 뭔가요? 지금은 시퀀스의 길이가 다양함
하지만 모델을 데이터에 대해 트레이닝할 수 있으려면 모든 시퀀스를 같은 길이로 만들어야 함
pad_sequences
: Keras에 내장되어 있는 패딩을 만들어 주는 매서드
Args
: List of sequences(각 시퀀스는 정수 목록임)maxlen
: 선택 사항 Int,모든 시퀀스의 최대 길이. 제공되지 않을 경우 시퀀스는 가장 긴 개별 시퀀스의 길이로 패딩됨dtype
: (선택사항, 기본값은 int32) 출력 시퀀스의 유형padding
pre
: defaults값, 시퀀스 앞에 패딩 추가post
: 시퀀스 뒤에 패딩 추가
truncating
pre
: defaults값, maxlen보다 큰 시퀀스의 시작에서 값을 제거post
: maxlen보다 큰 시퀀스의 끝에서 값을 제거
value
: Float or String, 패딩 값(선택 사항, 기본값은 0).
from tensorflow.keras.preprocessing.sequence import pad_sequences
import numpy as np
# Determine max sequence length
max_sequence_len = max([len(x) for x in input_sequences])
# Pad all sequences with zeros at the beginning to make them all max length
input_sequences = np.array(pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre'))
input_sequences[0]
👀 결과 보기
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 52, 1616], dtype=int32)
예측변수 및 타깃 생성
추가설명 시퀀스를 예측 변수 및 타깃으로 분할하는 것이 좋음
- 타깃: 시퀀스의 마지막 단어
- 예측 변수: 시퀀스의 첫 번째 단어
# Predictors are every word except the last
predictors = input_sequences[:,:-1]
# Labels are the last word
labels = input_sequences[:,-1]
labels[:5]
## 결과
## array([1616, 1, 1992, 125, 346], dtype=int32)
이미지 분류에서와 마찬가지로 이러한 타깃은 범주형임
가능한 전체 어휘 중에서 한 개의 단어를 예측해야 함.
네트워크가 스칼라 숫자를 예측하는 대신 바이너리 범주를 예측하는 것
from tensorflow.keras import utils
labels = utils.to_categorical(labels, num_classes=total_words)
모델 생성
순차 데이터를 처리할 수 있도록 몇 개의 새 레이어를 사용하겠다
임베딩 레이어
토큰화된 시퀀스를 취하여 트레이닝 데이터세트의 모든 단어에 대한 임베딩을 학습함
- 수학적 임베딩: 뉴럴 네트워크의 뉴럴과 같은 방식으로 작동
- 개념상 임베딩*: 이 목표는 피처의 일부나 전부의 차원 수를 줄이는 것
- 이 경우, 각 단어를 벡터로 표현
- 벡터 내의 정보에 각 단어 간의 관계가 포함됨
model.add(Embedding(input_dimension, output_dimension, input_length=input_len))
LSTM(Long Short Term Memory Layer)
LSTM은 RNN(Recurrent Neural Network)의 한 유형
지금까지 본 기존의 피드 포워드 네트워크와 달리, 순환 네트워크는 루프가 포함되어 있어 정보 지속이 가능하게 함
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout
from tensorflow.keras.models import Sequential
# Input is max sequence length - 1, as we've removed the last word for the label
input_len = max_sequence_len - 1
model = Sequential()
# Add input embedding layer
model.add(Embedding(total_words, 10, input_length=input_len))
# Add LSTM layer with 100 units
model.add(LSTM(100))
model.add(Dropout(0.1))
# Add output layer
model.add(Dense(total_words, activation='softmax'))
model.summary()
👀 결과 보기
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) (None, 27, 10) 117530
_________________________________________________________________
lstm (LSTM) (None, 100) 44400
_________________________________________________________________
dropout (Dropout) (None, 100) 0
_________________________________________________________________
dense (Dense) (None, 11753) 1187053
=================================================================
Total params: 1,348,983
Trainable params: 1,348,983
Non-trainable params: 0
_________________________________________________________________
모델 컴파일
범주형 크로스 엔트로피로 모델을 컴파일: 전체 어휘에서 한 단어를 범주적으로 예측하기 때문
- 이 경우에는 텍스트 예측이 이미지 분류와 어느 정도 동일한 정확도로 측정되지 않으므로 정확도를 지표로 사용하지 않음
Adam: LSTM 작업에 적합
model.compile(loss='categorical_crossentropy', optimizer='adam')
모델 트레이닝
모델을 같은 방식으로 맞춰야 함
- 30에포크에 대해 트레이닝할 것임
model.fit(predictors, labels, epochs=30, verbose=1)
결과 분석
👀 결과 보기
Epoch 1/30
1666/1666 [==============================] - 7s 4ms/step - loss: 7.8878
Epoch 2/30
1666/1666 [==============================] - 7s 4ms/step - loss: 7.4762
Epoch 3/30
1666/1666 [==============================] - 7s 4ms/step - loss: 7.2884
Epoch 4/30
1666/1666 [==============================] - 8s 5ms/step - loss: 7.0803
Epoch 5/30
1666/1666 [==============================] - 7s 4ms/step - loss: 6.8526
Epoch 6/30
1666/1666 [==============================] - 7s 4ms/step - loss: 6.6031
Epoch 7/30
1666/1666 [==============================] - 7s 4ms/step - loss: 6.3513
Epoch 8/30
1666/1666 [==============================] - 7s 4ms/step - loss: 6.0987
Epoch 9/30
1666/1666 [==============================] - 7s 4ms/step - loss: 5.8597
Epoch 10/30
1666/1666 [==============================] - 7s 4ms/step - loss: 5.6192
Epoch 11/30
1666/1666 [==============================] - 7s 4ms/step - loss: 5.4023
Epoch 12/30
1666/1666 [==============================] - 7s 4ms/step - loss: 5.1901
Epoch 13/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.9913
Epoch 14/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.8028
Epoch 15/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.6247
Epoch 16/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.4579
Epoch 17/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.3036
Epoch 18/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.1574
Epoch 19/30
1666/1666 [==============================] - 7s 4ms/step - loss: 4.0225
Epoch 20/30
1666/1666 [==============================] - 8s 5ms/step - loss: 3.8956
Epoch 21/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.7719
Epoch 22/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.6607
Epoch 23/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.5537
Epoch 24/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.4617
Epoch 25/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.3671
Epoch 26/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.2778
Epoch 27/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.1999
Epoch 28/30
1666/1666 [==============================] - 8s 5ms/step - loss: 3.1162
Epoch 29/30
1666/1666 [==============================] - 7s 4ms/step - loss: 3.0433
Epoch 30/30
1666/1666 [==============================] - 7s 4ms/step - loss: 2.9722
<tensorflow.python.keras.callbacks.History at 0x7f03e89a7048>
트레이닝이 진행되는 동안 손실이 감소
➡ 모델을 추가적으로 트레이닝하여 손실 감소 가능(하지만 시간이 너무 오래 걸림)
예측 수행
예측을 수행하려면 토큰화와 패딩 수행 필요
토큰화와 패딩이 완료되면 모델에 전달하여 예측을 수행 가능
predict_next_token
: 이를 수행하기 위한 함수
뭔지 추가 필료
def predict_next_token(seed_text):
token_list = tokenizer.texts_to_sequences([seed_text])[0]
token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre')
prediction = model.predict_classes(token_list, verbose=0)
return prediction
prediction = predict_next_token("today in new york")
prediction
👀 결과 보기
WARNING:tensorflow:From <ipython-input-31-bd91571ab9e2>:4: Sequential.predict_classes (from tensorflow.python.keras.engine.sequential) is deprecated and will be removed after 2021-01-01.
Instructions for updating:
Please use instead:* `np.argmax(model.predict(x), axis=-1)`, if your model does multi-class classification (e.g. if it uses a `softmax` last-layer activation).* `(model.predict(x) > 0.5).astype("int32")`, if your model does binary classification (e.g. if it uses a `sigmoid` last-layer activation).
array([145])
이렇게 숫자로 나오면 무슨 단어인지 모른다ㅠㅠㅠ
그러므로 토크나이저를 사용하여 디코딩이 필요하다
tokenizer.sequences_to_texts([prediction])
## ['rules']
새 헤드라인 생성
새 단어를 예측할 수 있게 되었으니 이제 단어 2개 이상으로 된 헤드라인을 예측할 수 있는 함수를 만들겠다!!
def generate_headline(seed_text, next_words=1):
for _ in range(next_words):
# Predict next token
prediction = predict_next_token(seed_text)
# Convert token to word
next_word = tokenizer.sequences_to_texts([prediction])[0]
# Add next word to the headline. This headline will be used in the next pass of the loop.
seed_text += " " + next_word
# Return headline as title-case
return seed_text.title()
그럼 이제 열심히 만든 모델을 써보자!!
seed_texts = [
'washington dc is',
'today in new york',
'the school district has',
'crime has become']
for seed in seed_texts:
print(generate_headline(seed, next_words=5))
Washington Dc Is Wiser Really It Don’T Just
Today In New York Rules With The Global Year
The School District Has The Broken Lifts East History
Crime Has Become The Fictional Vibe Sandwiches The
막 잘 예측하는건 아닌 것 같다 왜냐하면 문법도 그렇고 어색한 부분이 보이기 때문이다.
➡ 30 에포크로 트레이닝 했기 때문이다
➡ 더 좋은 결과값을 원하면 에폭을 늘려보자!!
메모리
넘어가기 전에 다음 셀을 실행하여 GPU 메모리를 지우기
이는 다음 노트북으로 넘어가기 위한 필수 작업
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)