ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TensorFlow 기초 39 - LSTM을 이용한 텍스트 생성, 문맥을 반영하여 다음 단어를 예측하기
    TensorFlow 2022. 12. 14. 11:35

     

     

    # RNN을 이용한 텍스트 생성
    # 문맥을 반영하여 다음 단어를 예측하기
    
    import numpy as np
    from keras.models import Sequential
    from keras.layers import Embedding, Flatten, Dense, LSTM
    from keras.preprocessing.text import Tokenizer
    from keras.utils import pad_sequences, to_categorical
    from anaconda_project.internal.conda_api import result
    """
    text = '''
    경마장에 있는 말이 뛰고 있다
    그의 말이 법이다
    가는 말이 고와야 오는 말이 곱다'''
    """
    
    text = '''수도권 개별 단지들의 전세가격 하락세가 두드러지게 나타나고 있다
    경기 파주 힐스테이트 운정은 지난 10월 16층이 2억8000만원에 전세 거래됐다
    2020년 같은 달 같은 층수는 3억1500만원에 거래됐다
    인천 미추홀구 인천SK스카이뷰 역시 지난달 12층이 3억원에 거래되면서 2년 전 가격보다 5500만원 내렸으며,
    부개주공3단지는 2년 전보다 4500만원 내린 1억8000만원에 거래됐다'''
    
    tok = Tokenizer()
    tok.fit_on_texts([text]) # fit_on_texts의 값으로는 무조건 list type으로 주어야 된다. 단어와 인덱싱을 출력
    print(tok.word_index)
    encoded = tok.texts_to_sequences([text]) # 단어를 정수로 메트릭스화 해서 출력
    print(encoded) # [[2, 3, 1, 4, 5, 6, 1, 7, 8, 1, 9, 10, 1, 11]]
    
    vocab_size = len(tok.word_index) + 1 # Embedding(가능한 토큰 수)
    print(vocab_size)
    
    # 훈련 데이터 만들기
    sequences = list()
    for line in text.split('\n'): # 문장 토큰화
        enco = tok.texts_to_sequences([line])[0]
        # print(enco)
        # 바로 다음 단어를 label로 사용하기 위해 리스트에 벡터 기억
        for i in range(1, len(enco)):
            sequ = enco[:i + 1]
            # print(sequ)
            sequences.append(sequ)
            
    print(sequences) # [[2, 3], [2, 3, 1], [2, 3, 1, 4], [2, 3, 1, 4, 5], [6, 1], ...
    print('학습 참여 샘플 수 :', len(sequences)) # 11
    print(max(len(i) for i in sequences)) # 6
    
    # 가장 긴 벡터의 길이를 기준으로 각 벡터의 크기를 통일
    max_len = max(len(i) for i in sequences)
    
    psequences = pad_sequences(sequences, maxlen=max_len, padding='pre') # pre는 왼쪽을 0 으로 채운다. 'post'는 오른쪽을 0으로 채운다.
    print(psequences)
    
    # 각 벡터의 마지막 요소(단어)를 label로 사용
    x = psequences[:, :-1] # feature, 마지막 숫자(단어) 이외의 것이 feature가 된다.
    y = psequences[:, -1]  # label, 마지막 숫자(단어)가 label이 된다.
    print(x[:2])
    print(y) # [ 3  1  4  5  1  7  1  9 10  1 11]
    
    # 모델의 최종분류 활성화 함수를 softmax로 사용하므로 y를 원핫 처리
    y = to_categorical(y, num_classes=vocab_size)
    print(y[:2]) # [ 3  1  4  5  1  7  1  9 10  1 11]
    
    # model
    model = Sequential()
    model.add(Embedding(vocab_size, 32, input_length=max_len - 1))
    model.add(LSTM(32, activation='tanh'))
    model.add(Flatten())
    model.add(Dense(32, activation='relu'))
    model.add(Dense(32, activation='relu'))
    model.add(Dense(vocab_size, activation='softmax'))
    print(model.summary())
    
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    model.fit(x, y, epochs=200, verbose=0)
    print('model evaluate :', model.evaluate(x, y))
    
    # 문자열 생성 함수
    def seq_gen_text_func(model, t, current_word, n):
        init_word = current_word # 처음 들어온 단어도 마지막 함께 출력할 계획
        sentence = ''
        for _ in range(n):
            encoded = t.texts_to_sequences([current_word])[0]
            encoded = pad_sequences([encoded], maxlen=max_len - 1, padding='pre')
            result = np.argmax(model.predict(encoded, verbose=0), axis = -1)
            # 예측 단어 찾기
            for word, index in t.word_index.items():
                # print(word, ' :', index)
                if index == result: # 예측한 단어, 그리고 인덱스와 동일한 단어가 있다면 해당 단어는 예측단어 이므로 break 
                    break
            current_word = current_word + ' ' + word
            sentence = sentence + ' ' + word
        sentence = init_word + sentence
        return sentence
    
    '''
    print(seq_gen_text_func(model, tok, '경마장', 1))
    print(seq_gen_text_func(model, tok, '그의', 2))
    print(seq_gen_text_func(model, tok, '가는', 3))
    print(seq_gen_text_func(model, tok, '가는', 4))
    print(seq_gen_text_func(model, tok, '경마장에', 4))
    '''
    print(seq_gen_text_func(model, tok, '수도권', 4))
    print(seq_gen_text_func(model, tok, '인천', 4))
    
    
    <console>
    {'거래됐다': 1, '같은': 2, '2년': 3, '수도권': 4, '개별': 5, '단지들의': 6, '전세가격': 7, '하락세가': 8, '두드러지게': 9, '나타나고': 10, '있다': 11, '경기': 12, '파주': 13, '힐스테이트': 14, '운정은': 15, '지난': 16, '10월': 17, '16층이': 18, '2억8000만원에': 19, '전세': 20, '2020년': 21, '달': 22, '층수는': 23, '3억1500만원에': 24, '인천': 25, '미추홀구': 26, '인천sk스카이뷰': 27, '역시': 28, '지난달': 29, '12층이': 30, '3억원에': 31, '거래되면서': 32, '전': 33, '가격보다': 34, '5500만원': 35, '내렸으며': 36, '부개주공3단지는': 37, '전보다': 38, '4500만원': 39, '내린': 40, '1억8000만원에': 41}
    [[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 21, 2, 22, 2, 23, 24, 1, 25, 26, 27, 28, 29, 30, 31, 32, 3, 33, 34, 35, 36, 37, 3, 38, 39, 40, 41, 1]]
    42
    [[4, 5], [4, 5, 6], [4, 5, 6, 7], [4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9], [4, 5, 6, 7, 8, 9, 10], [4, 5, 6, 7, 8, 9, 10, 11], [12, 13], [12, 13, 14], [12, 13, 14, 15], [12, 13, 14, 15, 16], [12, 13, 14, 15, 16, 17], [12, 13, 14, 15, 16, 17, 18], [12, 13, 14, 15, 16, 17, 18, 19], [12, 13, 14, 15, 16, 17, 18, 19, 20], [12, 13, 14, 15, 16, 17, 18, 19, 20, 1], [21, 2], [21, 2, 22], [21, 2, 22, 2], [21, 2, 22, 2, 23], [21, 2, 22, 2, 23, 24], [21, 2, 22, 2, 23, 24, 1], [25, 26], [25, 26, 27], [25, 26, 27, 28], [25, 26, 27, 28, 29], [25, 26, 27, 28, 29, 30], [25, 26, 27, 28, 29, 30, 31], [25, 26, 27, 28, 29, 30, 31, 32], [25, 26, 27, 28, 29, 30, 31, 32, 3], [25, 26, 27, 28, 29, 30, 31, 32, 3, 33], [25, 26, 27, 28, 29, 30, 31, 32, 3, 33, 34], [25, 26, 27, 28, 29, 30, 31, 32, 3, 33, 34, 35], [25, 26, 27, 28, 29, 30, 31, 32, 3, 33, 34, 35, 36], [37, 3], [37, 3, 38], [37, 3, 38, 39], [37, 3, 38, 39, 40], [37, 3, 38, 39, 40, 41], [37, 3, 38, 39, 40, 41, 1]]
    학습 참여 샘플 수 : 40
    13
    [[ 0  0  0  0  0  0  0  0  0  0  0  4  5]
     [ 0  0  0  0  0  0  0  0  0  0  4  5  6]
     [ 0  0  0  0  0  0  0  0  0  4  5  6  7]
     [ 0  0  0  0  0  0  0  0  4  5  6  7  8]
     [ 0  0  0  0  0  0  0  4  5  6  7  8  9]
     [ 0  0  0  0  0  0  4  5  6  7  8  9 10]
     [ 0  0  0  0  0  4  5  6  7  8  9 10 11]
     [ 0  0  0  0  0  0  0  0  0  0  0 12 13]
     [ 0  0  0  0  0  0  0  0  0  0 12 13 14]
     [ 0  0  0  0  0  0  0  0  0 12 13 14 15]
     [ 0  0  0  0  0  0  0  0 12 13 14 15 16]
     [ 0  0  0  0  0  0  0 12 13 14 15 16 17]
     [ 0  0  0  0  0  0 12 13 14 15 16 17 18]
     [ 0  0  0  0  0 12 13 14 15 16 17 18 19]
     [ 0  0  0  0 12 13 14 15 16 17 18 19 20]
     [ 0  0  0 12 13 14 15 16 17 18 19 20  1]
     [ 0  0  0  0  0  0  0  0  0  0  0 21  2]
     [ 0  0  0  0  0  0  0  0  0  0 21  2 22]
     [ 0  0  0  0  0  0  0  0  0 21  2 22  2]
     [ 0  0  0  0  0  0  0  0 21  2 22  2 23]
     [ 0  0  0  0  0  0  0 21  2 22  2 23 24]
     [ 0  0  0  0  0  0 21  2 22  2 23 24  1]
     [ 0  0  0  0  0  0  0  0  0  0  0 25 26]
     [ 0  0  0  0  0  0  0  0  0  0 25 26 27]
     [ 0  0  0  0  0  0  0  0  0 25 26 27 28]
     [ 0  0  0  0  0  0  0  0 25 26 27 28 29]
     [ 0  0  0  0  0  0  0 25 26 27 28 29 30]
     [ 0  0  0  0  0  0 25 26 27 28 29 30 31]
     [ 0  0  0  0  0 25 26 27 28 29 30 31 32]
     [ 0  0  0  0 25 26 27 28 29 30 31 32  3]
     [ 0  0  0 25 26 27 28 29 30 31 32  3 33]
     [ 0  0 25 26 27 28 29 30 31 32  3 33 34]
     [ 0 25 26 27 28 29 30 31 32  3 33 34 35]
     [25 26 27 28 29 30 31 32  3 33 34 35 36]
     [ 0  0  0  0  0  0  0  0  0  0  0 37  3]
     [ 0  0  0  0  0  0  0  0  0  0 37  3 38]
     [ 0  0  0  0  0  0  0  0  0 37  3 38 39]
     [ 0  0  0  0  0  0  0  0 37  3 38 39 40]
     [ 0  0  0  0  0  0  0 37  3 38 39 40 41]
     [ 0  0  0  0  0  0 37  3 38 39 40 41  1]]
    [[0 0 0 0 0 0 0 0 0 0 0 4]
     [0 0 0 0 0 0 0 0 0 0 4 5]]
    [ 5  6  7  8  9 10 11 13 14 15 16 17 18 19 20  1  2 22  2 23 24  1 26 27
     28 29 30 31 32  3 33 34 35 36  3 38 39 40 41  1]
    [[0. 0. 0. 0. 0. 1. 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. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 1. 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. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
    2022-12-14 11:38:38.601465: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX AVX2
    To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    Model: "sequential"
    _________________________________________________________________
     Layer (type)                Output Shape              Param #   
    =================================================================
     embedding (Embedding)       (None, 12, 32)            1344      
                                                                     
     lstm (LSTM)                 (None, 32)                8320      
                                                                     
     flatten (Flatten)           (None, 32)                0         
                                                                     
     dense (Dense)               (None, 32)                1056      
                                                                     
     dense_1 (Dense)             (None, 32)                1056      
                                                                     
     dense_2 (Dense)             (None, 42)                1386      
                                                                     
    =================================================================
    Total params: 13,162
    Trainable params: 13,162
    Non-trainable params: 0
    _________________________________________________________________
    None
    
    1/2 [==============>...............] - ETA: 0s - loss: 0.3459 - accuracy: 0.9688
    2/2 [==============================] - 0s 3ms/step - loss: 0.3261 - accuracy: 0.9750
    model evaluate : [0.326116144657135, 0.9750000238418579]
    수도권 개별 단지들의 전세가격 하락세가
    인천 미추홀구 인천sk스카이뷰 역시 지난달

    token을 생성하고 나서 fit_on_texts의 값으로는 무조건 list type으로 주어야 된다. 단어와 인덱싱을 출력

    texts_to_sequences()  단어를 정수로 메트릭스화 해서 출력한다.

     

    단어를 정수로 바꿔주었기 때문에 predict(x) x에 들어가는 값도 정수로 바꿔서 넣어주어야 된다.

    그리고 예측 후 다시 단어로 바꿔준다.

     

    학습 내용에 따라 그것이 적용되므로 text 안의 내용만 바꿔주면 된다.

     

     

     

    댓글

Designed by Tistory.