[AIFFEL] 22.Jan.13 - Exploration, NLP_RNN

Deok Jong Moon·2022년 1월 13일
0
post-thumbnail

오늘의 학습 리스트

  • Sequence : unordered여도 된단다.

  • 텍스트는 문법이란 규칙이 있는데,

    • 그걸 기계가 학습하긴 어렵고,
    • 그래서 통계를 사용!
  • 언어 모델(Language Model)이라 함은
    : $P(wnw1,...,wn1;θ)P(w n∣w 1,...,w n−1;θ)
    : 즉, θθ라는 파라미터로 n1n-1개 까지의 단어가 주어졌을 때 nn번째 단어가 나올 확률을 계산하는 모델

  • ReGex

    • The backreference \1 (backslash one) references the first capturing group.
    • 예제 코드
    • sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence)
    • \1뜻은 ()가 그룹이 되어서 1첫째 그룹 중 맞는 것을 지칭하게 된다.
  • Tokenize

    • 단어를 벡터화 및 사전에 넣어서 각각 단어에 대응되는 숫자로 표현된 텐서를 만들어줌
    • 단계
      1) tf.keras.preprocessing.text.Tokenizer() 사용해서 객체 생성
      2) tokenizer.fit_on_texts(corpus)로 텍스트 넣어서 kind of 학습
      3) tokenizer.texts_to_sequences(corpus)로 tensor로 출력
      4) tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post') 로 padding된 텐서 출력하면 끝!
  • tokenizer.index_word 속성으로 저장된 사전 인덱스 및 단어 딕셔너리 확인 가능

  • tf.data.Dataset.from_tensor_slices()의 사용법

    • arguments로 소스 문장, 타겟 문장 둘 다 넣길래 뭘 하나 찾아 봄
# 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)
  • class 정의에서 클래스 내 로컬 변수와 관련해서...
    : attribute 생성 시 꼭 self.att가 아니어도 클래스 내에 self.att로 쓸 수 있다.
    : 다만, 해당 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 변수는 생성된다.

오늘 헤맨 것

  • 문장에서 단어 15개 이하만 갖고 데이터를 만들자는데, 그 조건을 만드는 게 너무 어렵다
    • 해보니까 ','이 끼어있다
    • 해보니까 None이 끼어있다
      : 왜 끼었는지 알 것 같다. 아래의 코드 참고
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개 이상인 경우에는 할당된 적이 없어서 오류 뜸
  • 헤맨 과정(2)
    • 아 문장 단어 15개 이하로 만드는 것으로 엄청 헤맸다... 데이터가 12만개로 줄어들어야 한다는데 계속 16만~17만 개였다.
    • 근데 알고 보니 train_test_split() 나눈 후 train 데이터의 갯수가 약 12만 개인 거란다.
    • 그리고 보니까 내 코드가 맞았었다...
    • 결과적으로 약 3~4시간을 이걸로 헤맸는데, 앞으로 차근차근 읽어보자...
    • 텍스트 데이터에서 문장당 단어 15개 이하(앞, 뒤 소스, 타겟 문장 확인용으로 넣어줄 <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) 글자 생성
    - 아이펠에서 제공한 코드 사용
    - 이거 좀 어렵다...

더 공부할 것

  • tensorflow는 tf.data.Dataset이라는 데이터 타입 객체가 있는데, 모델 훈련시킬 때 np.ndarray 보다 그것을 주로 쓰니까 좀 파악해놓자.
  • Word2Vec
  • LSTM
  • RNN
  • 셋 다 도대체 어떤 말들인가...
profile
'어떻게든 자야겠어'라는 저 아이를 닮고 싶습니다

0개의 댓글