ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tensorflow Keras - 4 (자연어처리,감정분석)
    Machine Learning/Tensorflow 2021. 3. 16. 21:42
    반응형

    간단한 예제를 이용해서 keras를 이용해서 LSTM을 사용해보겠습니다.

     

    실제 데이터를 적용하기 앞서서 개념을 잡기 위해서 간단한 예제를 들고 가겠습니다.

    영단어로 이뤄졌고, 라벨링도 적용을 해놓았습니다.

     

    자연어 처리의 실제 순서는

    Data load -> 불용어처리 -> Word Tokenizing -> OneHotEncoding -> pad sequences ->

    Model create -> Model compile -> Model fit -> Model predict

    입니다.

     

    여기서는 불용어처리와 Word Tokenizing을 제외하고 진행했습니다.

    이미 만들어진 데이터셋으로 진행을 하고서, 다음 작성글에는 Kaggle에서 제공하는 데이터셋을 이용해서

    처음부터 끝까지 진행을 하면서 Self attention을 이용한 예측을 진행해보도록 하겠습니다.

    최대한 이해를 목적으로 작성을 진행했습니다.

     

    그리고 모델을 생성하면서 마지막 Layer에 어떤것을 넣느냐에 따라서 감정분석이 될수도, 새로운 문장을 생성을 해서 

    다른 단어를 추천한다던가, Encoder, Decoder를 이용해서 번역모델을 만들수도 있습니다.

     

    여기서는 감정분석을 진행합니다.

     

    import numpy as np
    from tensorflow.keras.preprocessing.sequence import pad_sequences
    from tensorflow.keras.preprocessing.text import one_hot
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Embedding, Flatten, Dense, Bidirectional, LSTM
    docs = ['Well done!', 'Good work', 'Great effort', 'nice work', 'Excellent!',
            'Weak', 'Poor effort!', 'not good', 'poor work', 'Could have done better.']
    
    labels = np.array([1, 1, 1, 1, 1, 0, 0, 0, 0, 0])

    실제 Tokenizing 까지 이루어졌다고 가정을 하고 진행을 하겠습니다.

     

    own_embedding_vocab_size = 10
    encoded_docs_oe = [one_hot(d, own_embedding_vocab_size) for d in docs]
    print(encoded_docs_oe)
    print(len(encoded_docs_oe))

    [[5, 3], [3, 9], [9, 4], [7, 9], [7], [5], [6, 4], [7, 3], [6, 9], [3, 8, 3, 2]]

     

    10

     

    여기서 vocab_size는 최대 계산할 문장의 갯수입니다.

    결과로 10개가 반환됩니다.

     

    여기서는 양이 작아서 10개로 한정 지었지만, 실제로는 30000~40000개 정도로 한정을 짓고 진행을 합니다.

     

    maxlen = 5
    padded_decs_oe = pad_sequences(encoded_docs_oe, maxlen=maxlen, padding='post')
    print(padded_decs_oe)
    print(padded_decs_oe.shape)

    [[5 3 0 0 0]
     [3 9 0 0 0]
     [9 4 0 0 0]
     [7 9 0 0 0]
     [7 0 0 0 0]
     [5 0 0 0 0]
     [6 4 0 0 0]
     [7 3 0 0 0]
     [6 9 0 0 0]
     [3 8 3 2 0]]
    (10, 5)

     

    여기서 maxlen은 keras에서 제공하는 함수인 pad_sequences를 사용하려고 선언한 변수입니다.

    pad_sequences는 짧은 문장과 긴문장의 길이를 0(zero)로 맞춰주기 위해서 사용합니다.

    Input data로 2문장이 들어갈수도, 5문장, 10문장이 들어갈수도 있는데, 최대 문장길이에 맞춰서

    0(zero)로 채워줍니다.

     

    padding 은 post는 뒤쪽을 0(zero)로 채우고, pre로 설정하면 앞부분을 0(zero)로 채웁니다.

     

    padding = 'pre' 일시

    [[0 0 0 5 3]
     [0 0 0 3 9]
     [0 0 0 9 4]
     [0 0 0 7 9]
     [0 0 0 0 7]
     [0 0 0 0 5]
     [0 0 0 6 4]
     [0 0 0 7 3]
     [0 0 0 6 9]
     [0 3 8 3 2]]
    (10, 5)

     

    Model Create

    model = Sequential()
    model.add(Embedding(input_dim=own_embedding_vocab_size, output_dim=32, input_length=maxlen))
    model.add(Bidirectional(LSTM(32,activation='relu',recurrent_dropout=0.1)))
    model.add(Flatten())
    model.add(Dense(1, activation='sigmoid'))

    여기서 처음 등장하는 Embedding은 Input값으로 들어오는 숫자데이터들을 임의의 Embedding화 시킵니다.

    쉽게 이야기해서는 고차원으로 변경을 합니다.

    예를들어 문장의 수가 많을때, OneHot Encoding을 진행하면 엄청나게 많은 Shape를 가진 array가 반환됩니다.

    정말 Sparse 한 array입니다.

     

    이럴경우 모델의 성능을 많이 저하시키기 때문에, Embedding을 이용해서 고차원으로 변경을 해줍니다.

    걱정하실 필요가 없는게 우리가 계산하는게 아닌 이미 학습된 모델을 한번 적용시켜서, 새로운 데이터를 생성해준다고 보면 쉽게 이해하실수 있습니다.

     

    input_dim 은 input_dimension의 약자입니다.

    우리는 이미 위에서 vocab_size라고 input dimension을 정의해줬습니다.

    그대로 입력을 해줍니다.

     

    그리고 output_dim은 우리의 임의대로 설정이 가능합니다.

    말 그대로 output으로 나오는 차원의 수를 설정해줍니다.

    대체적으로 512 이상으로 2의 배수로 정의를 많이 해주는 편입니다.

    컴퓨터는 2진법이기 때문이라는 이야기가 있습니다...ㅋㅋ

     

    여기서는 32차원으로 output을 반환받겠습니다.

     

    그리고 input_length는 최대 문장의 길이입니다.

    이것도 이미 위에서 정의를 해줬습니다.

     

    적은 양의 데이터이기 때문에 5번까지 진행하는걸로요.

     

    이후 반환되는 값은 다시 Biderectional_LSTM으로 전송됩니다.

    Biderectional은 양방향으로 계산을 진행하게 해줍니다. LSTM을 넣으면 LSTM을 양방향으로 계산을 하게되고,

    GRU를 넣게되면 GRU를 양방향으로 계산합니다.

    양쪽으로 진행하면서 정확도가 올라갑니다.

     

    recurrent_dropout은

     

    "훈련 손실과 검증 손실 곡선을 보면 모델이 과대적합인지 알 수 있습니다. 이를 개선하기 위해 드롭아웃을 사용합니다. 하지만 순환 신경망에 드롭아웃을 올바르게 적용하는 방법은 간단하지 않습니다. 순환 층 이전에 드롭아웃을 적용하면 규제에 도움되는 것보다 학습에 더 방해되는 것으로 알려져있습니다.

    하지만 2015년 Yarin Gal의 베이지안 딥러닝에 관한 박사 논문에서 순환 신경망에서 드롭아웃을 사용하는 방법을 알아냈습니다. 타임스텝마다 랜덤하게 드롭아웃 마스크를 바꾸는 것이 아니라 동일한 드롭아웃 마스크를 모든 타임스텝에 적용해야합니다.

    케라스에서는recurrent_dropout을 이용하여 순환 드롭아웃을 적용할 수 있습니다. 드롭아웃을 하게되면 완전히 수렴하는데 더 오래걸리므로 에포크 수를 2배로 늘립니다."

    출처 : subinium.github.io/Keras-6-2/

     

    [Keras Study] 6장. 텍스트와 시퀀스를 위한 딥러닝 (2)

    텍스트 데이터 + 순환 신경망 + 시퀀스 데이터의 처리

    subinium.github.io

     

    만약 여기서 다른 LSTM Cell을 이용하고 싶다면 파라미터로 return_sequences=True 로 사용하면 됩니다.

    마지막 sequence를 입력된 차원과 동일하게 반환하는겁니다. 즉 Many-to-Many 입니다.

    False로 설정하면 Many-to-one으로 반환됩니다.

     

    Model fit

    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])  # Compile the model
    print(model.summary())  # Summarize the model

    Model: "sequential_3"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    embedding_3 (Embedding)      (None, 5, 32)             320       
    _________________________________________________________________
    bidirectional_1 (Bidirection (None, 64)                16640     
    _________________________________________________________________
    flatten_3 (Flatten)          (None, 64)                0         
    _________________________________________________________________
    dense_3 (Dense)              (None, 1)                 65        
    =================================================================
    Total params: 17,025
    Trainable params: 17,025
    Non-trainable params: 0
    _________________________________________________________________

     

    0과 1을 구하기 때문에 loss값을 binary_crossentropy를 사용합니다.

     

    model.fit(padded_decs_oe, labels, epochs=50, verbose=0)  # Fit the model
    loss, accuracy = model.evaluate(padded_decs_oe, labels, verbose=0)  # Evaluate the model
    print('loss : %0.3f'%loss ,'Accuracy: %0.3f' % accuracy)

    loss : 0.153 Accuracy: 0.900

     

    Model predict

    word = "Good work"
    word_docs_oe = [one_hot(word, own_embedding_vocab_size)]
    word_oe = pad_sequences(word_docs_oe, maxlen=maxlen, padding='post')
    pred = model.predict(word_oe)
    np.round(pred)

    array([[1.]], dtype=float32)

     

    s = padded_decs_oe
    a = model.predict(s)
    np.round(a)

    array([[0.],
           [1.],
           [1.],
           [1.],
           [1.],
           [0.],
           [0.],
           [0.],
           [0.],
           [0.]], dtype=float32)

     

    모델에 사용한 train set을 예측한 결과입니다.

    predict 할때도 당연하겠지만, 모델에 입력한 데이터를 전처리 한것처럼 똑같이 해줘야 합니다.

     

    조금이나마 이해가 되셨으면 좋겠습니다.

    최대한 간략하고 짧게 설명하고 싶어서 많이 축약되었습니다.

    자세한 부분은 추후에 딥러닝 이론을 작성할때 쓰겠습니다.

    감사합니다.

     


     

     

    전체코드

    github.com/Joonyeong97/Tensorflow-tutorial

     

    Joonyeong97/Tensorflow-tutorial

    GitHub Desktop tutorial repository. Contribute to Joonyeong97/Tensorflow-tutorial development by creating an account on GitHub.

    github.com

     

    반응형
Designed by Tistory.