ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HandsOn] 16. RNN과 어텐션을 사용한 자연어 처리 - 내용 정리2
    [도서완독]Hands On Machine Learning 2022. 8. 18. 20:44

    IMDb 리뷰 데이터셋은 자연어 처리계의 'hello world'라고 한다.

    영어로 쓰인 영화 리뷰 50000개(train 25000, test 25000) 로 구성되어 있음.

    각 리뷰가 부정적인지=0, 긍정적인지=1 나타내는 간단한 이진 타깃이 포함되어 있음.

     

    인기가 높은 이유는, 노트북에서 감당할 시간 안에 처리할 수 있을 만큼 간단하지만 재미있다고 함.ㅋㅋ

    keras에서 바로 받을 수 있음.

     

    (X_train, y_train), (X_test, y_test) = keras.datasets.imdb.load_data()
    X_train[0][:10]

    [1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65]

     

    이 데이터셋은 이미 전처리되어 있음. 각 정수는 하나의 단어를 나타냄.

    구두점을 모두 제거하고, 단어를 소문자로 변환한 다음 공백으로 나누어 빈도에 따라 인덱스를 붙임.

    (낮은 정수가 자주 등장하는 단어에 해당)

     

    0: 패딩 토큰, 1: start of sequence 토큰, 2: 알수 없는 단어를 의미 

     

    실전에서는 직접 텍스트를 전처리해야 하는데, 모델을 배포하고 싶다면 매번 다른 전처리 함수를 쓸수는 없음! 또 텐서플로 연산만을 사용해 전처리 과정을 처리하고 싶을 수도 있는데, 이런 경우 전처리를 모델에 포함시킬 수 있음.

     

    import tensorflow_datasets as tfds
    
    datasets, info = tfds.load("imdb_reviews", as_supervised=True, with_info=True)
    train_size = info.splits["train"].num_examples
    test_size = info.splits["test"].num_examples

    전처리 함수를 만들쟈.

    def preprocess(X_batch, y_batch):
        X_batch = tf.strings.substr(X_batch, 0, 300)
        X_batch = tf.strings.regex_replace(X_batch, rb"<br\s*/?>", b" ")
        X_batch = tf.strings.regex_replace(X_batch, b"[^a-zA-Z']", b" ")
        X_batch = tf.strings.split(X_batch)
        return X_batch.to_tensor(default_value=b"<pad>"), y_batch

    리뷰 텍스트를 잘라내어 각 리뷰에서 처음 300 글자만 남김.(훈련 속도를 높이기 위해)

    또한 일반적으로 처음 한 두 문장에서 리뷰가 긍정적인지 아닌지 판단 가능하기 때문.

    preprocess(X_batch, y_batch)

    그 다음 어휘 사전을 구축.

    Counter로 단어의 등장 횟수를 센다.

    from collections import Counter
    
    vocabulary = Counter()
    for X_batch, y_batch in datasets["train"].batch(32).map(preprocess):
        for review in X_batch:
            vocabulary.update(list(review.numpy()))

    어휘 사전에서 가장 많이 등장하는 단어 만개만 남기고 삭제! 왜냐하면 굳이 사전에 있는 모든 단어를 모델이 알아야 할 필요는 없으니까.

    vocab_size = 10000
    truncated_vocabulary = [
        word for word, count in vocabulary.most_common()[:vocab_size]]

    각 단어를 어휘 사전의 인덱스로 바꾸는 전처리 단계. 전에 13장에서 본 것처럼 1000개의 oov 버킷을 사용하는 룩업 테이블을 만듬. (왜 1000개지..?)

    words = tf.constant(truncated_vocabulary)
    word_ids = tf.range(len(truncated_vocabulary), dtype=tf.int64)
    vocab_init = tf.lookup.KeyValueTensorInitializer(words, word_ids)
    num_oov_buckets = 1000
    table = tf.lookup.StaticVocabularyTable(vocab_init, num_oov_buckets)
     
     
    table.lookup(tf.constant([b"This movie was faaaaaantastic".split()]))
    
     
    이 단어에 대한 id를 알아보면?
    <tf.Tensor: shape=(1, 4), dtype=int64, numpy=array([[   22,    12,    11, 10053]])>

    this, movie, was는 룩업 테이블에 있는데, 판타스틱은 없으니까 oov 버킷 중 하나에 매핑됨!!! 

     

    이제 최종 트레인셋을 만들면 됨. 리뷰를 배치로 묶고 앞서만든 전처리 함수로 전처리. 그 다음 테이블을 사용해서 단어를 인코딩! 프리패치.

    def encode_words(X_batch, y_batch):
        return table.lookup(X_batch), y_batch
    
    train_set = datasets["train"].batch(32).map(preprocess)
    train_set = train_set.map(encode_words).prefetch(1)
    embed_size = 128
    model = keras.models.Sequential([
        keras.layers.Embedding(vocab_size + num_oov_buckets, embed_size,
                               mask_zero=True, # not shown in the book
                               input_shape=[None]),
        keras.layers.GRU(128, return_sequences=True),
        keras.layers.GRU(128),
        keras.layers.Dense(1, activation="sigmoid")
    ])
    model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
    history = model.fit(train_set, epochs=5)

    모델을 훈련. 

    나머지 부분은 간단한데 임베딩 층이 새로 생겼다.

    저기는 [배치 크기, 타임 스텝 수] 를 input으로 받아서 [배치 크기, 타임 스텝 수, 임베딩 크기]를 출력으로 반환.

    배치 크기는 항상 앞에 오고 타임 스텝의 값을 128차원의 배열로 변환하니까 그렇다.

     

    16.2.1 마스킹 

    모델이 패딩 토큰을 무시하도록 학습되어야 함. Embedding 층을 만들 때 mask_zero=True 매개변수를 추가하면 되삼.

    그러면 이어지는 모든 층에서 id=0인 패딩 토큰을 무시한다.

     

    16.2.2 사전훈련된 임베딩 재사용하기

    오.. 나 완전 딥린인데 이거 좀 신기함. 텐서플로 허브에서 원하는 모듈을 찾아서 예제코드를 프로젝트로 복사하면 사전훈련된 가중치를 자동으로 다운로드하여 모델에 포함시킴.

     

    import tensorflow_hub as hub
    
    model = keras.Sequential([
        hub.KerasLayer("https://tfhub.dev/google/tf2-preview/nnlm-en-dim50/1",
                       dtype=tf.string, input_shape=[], output_shape=[50]),
        keras.layers.Dense(128, activation="relu"),
        keras.layers.Dense(1, activation="sigmoid")
    ])
    model.compile(loss="binary_crossentropy", optimizer="adam",
                  metrics=["accuracy"])

    nnlm-en-dim50 문장 임베딩 모듈 버전 1을 감성분석 모델에 사용한 예시!

    hub.KerasLayer층이 모듈을 다운로드함. 이 모듈의 이름은 '문장 인코더'라고 함!

    각 단어를 대규모 코퍼스에서 사전훈련된 임베딩 행렬을 사용해 임베딩 함. 전체 단어수가 70억 개인 코퍼스임!!!

     

    모든 단어의 평균을 계산함. 이 결과가 문장 임베딩임. 기본적으로 이 층은 훈련되지 않지만, 작업에 맞게 미세 조정할 수 있음.

     

    imdb 리뷰 데이터셋을 따로 전처리할 필요 없이 모델에 넣을 수 있음!!! 

     

     

Designed by Tistory.