KT 에이블스쿨 55일차(1)

박기범·2023년 4월 18일
0

에이블스쿨

목록 보기
61/95
post-custom-banner

오늘은 미니프로젝트6 2일차로 어제에 이어 자연어처리 프로젝트를 진행했습니다.



실습 내용

어제는 간단한 모델을 통해서 챗봇을 진행했다면 오늘은 LSTM과 pre-trained된 모델을 가지고 챗봇을 만들어 보았습니다만 pre-trained 모델은 FastText를 사용했는데 잘못 설계했는지 계속 예측을 이상하게 해서 이번 포스팅에는 LSTM만 작성하도록 하겠습니다.



실습 코드

    # 각각의 토큰에 인덱스 부여하는 토크나이저 선언
    tokenizer = Tokenizer()

    # .fit_on_tests 이용하여 토크나이저 만들기
    clean_train_questions_a = tokenizer.fit_on_texts(clean_train_questions)
    clean_test_questions_a = tokenizer.fit_on_texts(clean_test_questions)

tokenizer을 선언해줍니다.

    x_train = tokenizer.texts_to_sequences(clean_train_questions)
    x_val = tokenizer.texts_to_sequences(clean_test_questions)

tokenizer가 되었다면 시퀀스를 진행해줍니다.

    # 각 토큰과 인덱스로 구성된 딕셔너리 생성
    word_to_index = tokenizer.word_index

    # <PAD> 토큰 추가 및 0으로 매핑
    word_to_index['<PAD>'] = 0

    # 인덱스를 토큰으로 매핑하는 딕셔너리 생성
    index_to_word = {index: word for word, index in word_to_index.items()}
    from tensorflow.keras.preprocessing.sequence import pad_sequences
    import numpy as np

    # MAX_SEQUENCE_LENGTH 설정
    MAX_SEQUENCE_LENGTH = 50

    # train 데이터의 문장을 시퀀스 데이터로 변환
    x_train = tokenizer.texts_to_sequences(clean_train_questions)
    x_train = pad_sequences(x_train, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')

    # test 데이터의 문장을 시퀀스 데이터로 변환
    x_test = tokenizer.texts_to_sequences(clean_test_questions)
    x_test = pad_sequences(x_test, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')

    # y_train과 y_test 생성
    y_train = np.array(train_df['type'])
    y_test = np.array(test_df['type'])

학습을 위한 문장 크기를 맞춰줍니다.

    # vocab_size 다시 정의
    vocab_size = len(tokenizer.word_index)

    # 모델 구성
    model = Sequential()
    model.add(Embedding(input_dim=vocab_size+1, output_dim=100, input_length=MAX_SEQUENCE_LENGTH))
    model.add(LSTM(units=128, activation='relu'))
    model.add(Dense(units=1, activation='sigmoid'))

    # 모델 컴파일
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

    # 모델 요약 출력
    model.summary()

후에 간단한 모델링을 진행해줍니다.

    import gensim
    pre_wv_model = gensim.models.Word2Vec.load(path + 'ko.bin')

먼저 Word2Vec을 위한 ko.bin파일로부터 모델을 가져옵니다.

    # 모델의 벡터크기 조회

    vector_size = pre_wv_model.vector_size
    print("Word2Vec 모델의 벡터 크기:", vector_size)
    # train 데이터의 문장을 시퀀스 데이터로 변환
    x_train = tokenizer.texts_to_sequences(clean_train_questions)
    x_train = pad_sequences(x_train, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')

    def get_sent_embedding(row, wv_model):
        question = row['Q']
        embedding = []
        for word in question.split():
            if word in wv_model.wv:
                embedding.append(wv_model.wv[word])
            else:
                embedding.append(np.zeros(wv_model.vector_size))
        return embedding



    # train_df에 대해 get_sent_embedding 함수를 적용하여 임베딩 결과 저장
    train_df['embedding'] = train_df.apply(lambda row: get_sent_embedding(row, wv_model), axis=1)

임베딩을 결과를 train 데이터프레임에 저장해주는 코드를 작성해줍니다.

    import random

    # 예측을 위한 입력 형태로 변환하는 함수
    def prepare_input(question):
        # 입력된 질문을 토큰화
        question_tokens = tokenizer.texts_to_sequences([question])
        # 시퀀스 데이터로 변환
        question_seq = pad_sequences(question_tokens, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')
        return question_seq

    # 선택된 질문
    selected_question = "액정을 부셔버렸어요 어떻게 하죠?"
    # 예측을 위한 입력 형태로 변환
    input_question = prepare_input(selected_question)
    # 모델을 이용하여 type 0 또는 1로 분류
    prediction = model.predict(input_question)
    predicted_type = 1 if prediction[0][0] > 0.5 else 0

    # train 데이터의 문장을 시퀀스 데이터로 변환
    x_train = tokenizer.texts_to_sequences(train_df['Q'])
    x_train = pad_sequences(x_train, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')

    # 선택된 질문과 train 데이터의 모든 Q와의 코사인 유사도 계산
    cosine_similarities = cosine_similarity(input_question, x_train)

    # 코사인 유사도가 가장 높은 index 선택
    most_similar_index = cosine_similarities.argmax()

    # 선택된 Q의 intent에 맵핑된 답변 중 하나를 무작위로 선택
    selected_answer = random.choice(train_df[train_df.index == most_similar_index]['A'].values)

    print("입력된 질문:", selected_question)
    print("예측된 타입:", predicted_type)
    print("가장 유사한 질문:", train_df.iloc[most_similar_index]['Q'])
    print("선택된 답변:", selected_answer)

해당 코드를 통해 이제 입력된 질문을 통해 답변을 해주는 챗봇이 완성됩니다.







날 잡고 자연어처리에 대해 조금 더 공부해야할 것 같습니다.




※공부하고 있어 다소 틀린점이 있을 수 있습니다. 언제든지 말해주시면 수정하도록 하겠습니다.
※용어에 대해 조금 공부 더 해서 수정하겠습니다.

profile
개발자가 되기 위한 한걸음
post-custom-banner

0개의 댓글