728x90
반응형

RNN 응용

규칙기반 챗봇

  • 라이브러리 정의
    import tensorflow as tf
    ''' 단어사전 만들기 '''
    from tensorflow.keras.preprocessing.text import Tokenizer
    from tensorflow.keras.preprocessing.sequence import pad_sequences
  • 규칙기반 데이터 정의하기 (질문 / 답변)
    - "03_RNN응용에_사용할_규칙기반_데이터셋(질문_답변)"  txt파일 사용

단어사전 만들기

  • 텍스트 데이터를 토큰화하여 단어 사전을 구축하기
    tokenizer = Tokenizer()
    tokenizer
  • 단어에 인덱스 부여하기
    - 질문과 답변을 하나의 데이터로 합쳐서 전체 텍스트 데이터로 사용
    - 이를 기반으로 토크나이저가 단어 사전을 구축하게 됨
    - 각 단어들은 순차적인 인덱스 번호를 부여받게 됨
    - 토크나이저가 인식하는 문장 내에서 단어의 의미 : 띄어쓰기가 없이 연결되어 있으면 하나의 단어로 인지
    - fit_on_texts(텍스트 문장) : 문장 내에서 단어들을 추출하여 순차적 인덱스 부여하기
    tokenizer.fit_on_texts(questions + answers)​
  • 단어별 부여된 인덱스 확인하기
    print("단어 갯수 : ", len(tokenizer.word_index))
    tokenizer.word_index​


  • 신경망에서 사용할 단어의 크기 설정
     - 하나 더 크게 설정해야 함
    - 인덱스 [0:18]이면 17번째까지 불러지므로 전체 값을 부르려면 현재 길이에 +1 해야 나중에 부를때 전체가 불러짐
    vocab_size = len(tokenizer.word_index) + 1
    vocab_size​
  • 질문에 대한 텍스트 문장을 단어사전의 인덱스 번호로 변환하기
    questions_sequences = tokenizer.texts_to_sequences(questions)
    print(len(questions_sequences))
    questions_sequences​
  • 질문 데이터 단어의 길이 통일 시키기(정규화)
    - 잘라낼 max 길이 기준 : 문장들 중 최대 max 단어길이 기준으로
    - maxlen을 넣지 않으면, 문장들의 길이가 가장 긴 것을 기준으로 한다.(default : 알아서 가장 긴 갯수를 찾아낸다)
    - padding="post" : 채우기는 뒤쪽
    questions_padded = pad_sequences(questions_sequences, padding="post")
    print(len(questions_padded))
    questions_padded​


  • 답변에 대한 데이터로 각 단어를 단어사전의 인덱스 번호로 변환하기
    answers_sequences = tokenizer.texts_to_sequences(answers)
    print(len(answers_sequences))
    answers_sequences​
  • 답변 데이터 단어의 길이 통일 시키기(정규화)
    answers_padded = pad_sequences(answers_sequences, padding="post")
    print(len(answers_padded))
    answers_padded

모델 처리

  • 모델 생성 및 계층 추가하기
    ''' <모델 생성하기> '''
    model = tf.keras.Sequential()
    
    '''
    <계층 추가하기>
     - 단어 임베딩(입력계층) : 출력 64
     - Simple Rnn 사용 : 출력 128, 활성화함수 : RelU
    '''
    model.add(tf.keras.layers.Embedding(vocab_size, 64, input_length=questions_padded.shape[1]))
    model.add(tf.keras.layers.SimpleRNN(128, activation="relu"))
    ''' 입력을 복제하는 전처리 계층 : 텍스트에 대한 Encoder와 Decoder를 담당함 '''
    model.add(tf.keras.layers.RepeatVector(answers_padded.shape[1]))
    model.add(tf.keras.layers.SimpleRNN(128, activation="relu", return_sequences=True))
    '''
     - 각 타임별로 동일한 가중치를 적용하도록 처리하며, 
     	전체 시퀀스들의 이전/다음 인덱트 처리 값을 가지고 있다고 보면 됨
     - 예측에 주로 사용되는 계층
     - 최종 출력 계층을 감싸고 있음
    '''
    model.add(tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(vocab_size,
                                                                   activation="softmax")))
    
    model.summary()​


  • 모델 설정 및 훈련하기
    ''' 모델 설정하기 '''
    model.compile(optimizer="adam",
                 loss="sparse_categorical_crossentropy",
                 metrics=["accuracy"])
    
    ''' 모델 훈련하기 '''
    model.fit(questions_padded, answers_padded, epochs=100,
             batch_size=64, verbose=1)​
  • 질문 / 답변 테스트
    ''' 질문/답변 테스트'''
    user_input = "너 이름이 뭐니?"
    
    ''' 새로운 질문 텍스트를 단어사전의 인덱스번호로 변환하기 '''
    input_seq = tokenizer.texts_to_sequences([user_input])
    input_seq
    
    ''' 단어의 길이를 훈련에서 사용한 길이로 통일시키기 (정규화) '''
    padded_seq = pad_sequences(input_seq, padding="post", maxlen=questions_padded.shape[1])
    padded_seq
    
    ''' 예측하기 : 새로운 질문에 대한 답변 추출하기 '''
    pred = model.predict(padded_seq)
    len(pred[0][1])
    
    '''' 답변으로 가장 확률이 높은 값 추출하기 '''
    pred_index = tf.argmax(pred, axis=-1).numpy()[0]
    print(len(pred_index), pred_index)
    
    ''' 시퀀스에 해당하는 텍스트 추출하기
     - 인덱스에 해당하는 실제 텍스트 추출하기
    '''
    response = tokenizer.sequences_to_texts([pred_index])[0]
    response​

답변 함수 만들기

def get_Generate_Response(model, tokenizer, user_input) :

    ''' 새로운 질문 텍스트를 단어사전의 인덱스번호로 변환하기 '''
    input_seq = tokenizer.texts_to_sequences([user_input])
    
    ''' 단어의 길이를 훈련에서 사용한 길이로 통일시키기 (정규화) '''
    padded_seq = pad_sequences(input_seq, padding="post", maxlen=questions_padded.shape[1])

    ''' 예측하기 : 새로운 질문에 대한 답변 추출하기 '''
    pred = model.predict(padded_seq)
    
    '''' 답변으로 가장 확률이 높은 값 추출하기 '''
    pred_index = tf.argmax(pred, axis=-1).numpy()[0]
    
    ''' 시퀀스에 해당하는 텍스트 추출하기
     - 인덱스에 해당하는 실제 텍스트 추출하기
    '''
    response = tokenizer.sequences_to_texts([pred_index])[0]

    return response

질문 받고 응답하기 : 무한반복 만들기

while True : 
    ''' 새로운 질문 입력 받기 '''
    user_input = input("사용자 : ")

    ''' 반복을 종료시키기 '''
    if user_input == "종료" :
        print("채팅 종료")
        break

    ''' 함수 호출하여 질문에 대한 답변 받아오기 '''
    response = get_Generate_Response(model, tokenizer, user_input)

    ''' 답변 출력하기 '''
    print("챗봇 : ", response)

 

728x90
반응형

+ Recent posts