Sequence : unordered여도 된단다.
텍스트는 문법이란 규칙이 있는데,
언어 모델(Language Model)이라 함은
: $
: 즉, 라는 파라미터로 개 까지의 단어가 주어졌을 때 번째 단어가 나올 확률을 계산하는 모델
ReGex
\1
(backslash one) references the first capturing group.sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence)
\1
뜻은 ()
가 그룹이 되어서 1첫째 그룹 중 맞는 것을 지칭하게 된다.Tokenize
tf.keras.preprocessing.text.Tokenizer()
사용해서 객체 생성tokenizer.fit_on_texts(corpus)
로 텍스트 넣어서 kind of 학습tokenizer.texts_to_sequences(corpus)
로 tensor로 출력tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post')
로 padding된 텐서 출력하면 끝!tokenizer.index_word
속성으로 저장된 사전 인덱스 및 단어 딕셔너리 확인 가능
tf.data.Dataset.from_tensor_slices()
의 사용법
# Two tensors can be combined into one Dataset object.
features = tf.constant([[1, 3], [2, 1], [3, 3]]) # ==> 3x2 tensor
labels = tf.constant(['A', 'B', 'A']) # ==> 3x1 tensor
dataset = Dataset.from_tensor_slices((features, labels))
>>> # Both the features and the labels tensors can be converted
>>> # to a Dataset object separately and combined after.
# 하나씩만 넣을 경우
>>> features_dataset = Dataset.from_tensor_slices(features)
>>> labels_dataset = Dataset.from_tensor_slices(labels)
self.att
가 아니어도 클래스 내에 self.att
로 쓸 수 있다.class TextGenerator(tf.keras.Model):
def __init__(self, vocab_size, embedding_size, hidden_size):
super().__init__()
# 인자로 embedding은 없지만, 이렇게 쓸 수 있고
# 다만 이 안에서만 존재하는 변수명이다.
self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_size)
self.rnn_1 = tf.keras.layers.LSTM(hidden_size, return_sequences=True)
self.rnn_2 = tf.keras.layers.LSTM(hidden_size, return_sequences=True)
self.linear = tf.keras.layers.Dense(vocab_size)
def call(self, x):
out = self.embedding(x)
out = self.rnn_1(out)
out = self.rnn_2(out)
out = self.linear(out)
return out
embedding_size = 256
hidden_size = 1024
model = TextGenerator(tokenizer.num_words + 1, embedding_size , hidden_size)
for src_sample, tgt_sample in dataset.take(1): break
로 바로 break
해도 src_sample
, tgt_sample
변수는 생성된다.def preprocess_sentence(sentence):
sentence = sentence.lower().strip() # 1
sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence) # 2
sentence = re.sub(r'[" "]+', " ", sentence) # 3
sentence = re.sub(r"[^a-zA-Z?.!,¿]+", " ", sentence) # 4
sentence = sentence.strip() # 5
if len(sentence.split()) < 16:
sentence = '<start> ' + sentence + ' <end>' # 6
return sentence # 이러면 16 이상인 것만 들어오는 줄 알았다.
# 근데 생각해보니 if 밖에서 return이 없으면 None이 return된다
def preprocess_sentence(sentence):
sentence = sentence.lower().strip() # 1
sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence) # 2
sentence = re.sub(r'[" "]+', " ", sentence) # 3
sentence = re.sub(r"[^a-zA-Z?.!,¿]+", " ", sentence) # 4
sentence = sentence.strip() # 5
# 정제 후 단어 15개 이하만 반환한다.
if len(sentence.split()) < 16:
sentence = '<start> ' + sentence + ' <end>' # 6
else:
not_included = sentence
return sentence, not_included # not_included은 버릴 예정
#이것도 안됨. not_included이 16개 이상인 경우에는 할당된 적이 없어서 오류 뜸
train_test_split()
나눈 후 train 데이터의 갯수가 약 12만 개인 거란다.<start>
, <end>
제외하면 13개), 즉 13개 이하인 것만 뽑아내는 코드로 내가 바꾼 것이다.기존 코드
def preprocess_sentence(sentence):
sentence = sentence.lower().strip() # 1
sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence) # 2
sentence = re.sub(r'[" "]+', " ", sentence) # 3
sentence = re.sub(r"[^a-zA-Z?.!,¿]+", " ", sentence) # 4
sentence = sentence.strip() # 5
sentence = '<start> ' + sentence + ' <end>' # 6
return sentence
>> 이거 후 for loop으로 전체 문장에 이것을 해주는 형식이었다.
내코드
# 패키지 불러오기
import re
# 함수 조금 변경
def preprocess_sentence(sentences):
corpus = []
# 문장 전체를 불러 오고
for sentence in sentences:
sentence = sentence.lower().strip()
sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence)
sentence = re.sub(r'[" "]+', " ", sentence)
sentence = re.sub(r"[^a-zA-Z?.!,¿]+", " ", sentence)
sentence = sentence.strip() # 모든 정제를 마친 후
if len(sentence.split()) > 13:
continue # 단어 13개 이상이면 건너 뛰기
else:
sentence = '<start> ' + sentence + ' <end>' # 6
corpus.append(sentence)
return corpus
처음 겪어본 NLP 코드 구현 과정 정리
1) 문자열 정제(regex 사용)
2) 데이터의 tokenize화
- tokenizer = tf.keras.preprocessing.text.Tokenizer()
로 객체 생성
- tokenizer.fit_on_texts(corpus(문장이 요소로 있는 리스트))
로 토큰화(단어 사전 완성)
- tensor = tokenizer.texts_to_sequences(corpus)
로 단어 사전 속 정수에 맞게 배열화(텐서화)
- tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post')
로 padding을 붙여준다. 여기서 return 값이 Numpy.ndarray
로 바뀐다.
3) 데이터 train, test로 나누기
- np.ndarray
상태여서 train_test_split()
을 쓸 수 있다.
- tf.data.Dataset
타입은 train_test_split()
사용이 안되는 것 같다.
- 이 때 train데이터는 소스 문장을 알려주는 토큰인 <start>
를 제거한다. # 소스 문장, 타겟 문장 나누기 src_input = tensor[:, :-1]
- test 는 맨 뒷 단어인 <end>
를 제거한다. tgt_input = tensor[:, 1:]
3) tf.data.Dataset화 및 batch 나누기
- tf.data.Dataset.from_tensor_slices((src_input, tgt_input))
로 데이터셋 객체 만들기
- dataset.shuffle() 및 batch()
로 나눈 후 할당
4) 모델 만들기
- 오늘은 Embedding -> LSTM -> LSTM -> Dense
- 아이펠에서 제공한 코드 사용
- 이것도 봐야겠다...
5) 모델 컴파일
6) 모델 학습
7) 글자 생성
- 아이펠에서 제공한 코드 사용
- 이거 좀 어렵다...
tf.data.Dataset
이라는 데이터 타입 객체가 있는데, 모델 훈련시킬 때 np.ndarray
보다 그것을 주로 쓰니까 좀 파악해놓자.