ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • chapter5. 텍스트 유사도
    공부/처음 배우는 딥러닝 챗봇 2023. 4. 13. 20:13
    728x90

    5.1 텍스트 유사도 개요

    자연어 처리에서 문장 간 의미가 얼마나 유사한 지 계산하는 일은 매우 중요

    사람은 의식하진 않지만 두 개의 문장에 동일한 단어나 의미상 비슷한 단어들이 얼마나 분포되어 있는지 직감적으로 파악

    컴퓨터도 동일한 방법으로 두 문장 간의 유사도를 계산할 수 있음

    임베딩으로 각 단어들의 벡터를 구한 다음 벡터 간의 거리를 계산하는 방법으로 단어 간의 의미가 얼마나 유사한지 계산 가능, 문장 역시 단어들의 묶음이기 때문에 하나의 벡터로 묶어서 문장간의 유사도 계산가능

     

    이 책에서는 특정 분야에 적용되는 FAQ에 응대하는 Q&A 챗봇 개발을 다루고 있기 때문에 챗봇 엔진에 입력되는 문장과 시스템에서 해당 주제의 답변과 연관되어 있는 질문이 얼마나 유사한지 계산할 수 있어야 적절한 답변을 출력

    두 문장 간의 유사도를 계산하기 위해서는 문장 내에 존재하는 단어들을 수치화

    이 때 언어모델에 따라 통계를 이용하는 방법과 인공 신경망을 이용하는 방법으로 나눌 수 있음

    이 장에서는 통계적인 방법을 이용해 유사도를 계산하는 방법을 살펴볼 것

    5.2 n-gram 유사도

    주어진 문장에서 n.개의 연속적인 단어 시퀀스(단어 나열)를 의미

    문장에서 n개의 단어를 토큰으로 사용

    이웃한 단어의 출현 횟수를 통계적으로 표현해 텍스트의 유사도를 계산하는 방법

    손쉬운 구현 방식에 비해 학습 말뭉치 품질만 좋다면 괜찮은 성능을 보여줌

    서로 다른 문장을 n-gram으로 비교하면 단어의 출현 빈도에 기반한 유사도를 계산할 수 있으며 이를 통해 논문 인용이나 도용 정도를 조사할 수 있음

     

    n이 1인 경우 1-gram, 유니그램/2인 경우 2-gram, 바이그램/3인 경우 3-gram, 트라이그램/4 이상은 숫자만 앞쪽에 붙여 부름

    n-gram을 이용해 문장 간의 유사도를 계산할 수 있음

    해당 문장을 n-gram으로 토큰을 분리한 후 단어 문서 행렬을 만듦

    이후 두 문장을 서로 비교해 동일한 단어의 출현 빈도를 확률로 계산해 유사도를 구할 수 있음

    similarity=tf(A,B)/tokens(A)

    tf(term frequency)는 두 문장 A와 B에서 동일한 토큰의 출현 빈도

     tokens는 해당 문장에서 전체 토큰 수를 의미, 여기서 토큰이란 n-gram으로 분리된 단어

    즉, 기준이 되는 문장 A에서 나온 전체 토큰 중에서 A와 B에 동일한 토큰이 얼마나 있는지 비율로 표현한 수식

    1.0에 가까울수록 B가 A에 유사하다고 볼 수 있음

    from konlpy.tag import Komoran
    
    #어절 단위 n-gram
    def word_ngram(bow, num_gram):
      text=tuple(bow)
      ngrams=[text[x:x+num_gram]for x in range(0,len(text))]
      return tuple(ngrams)
    
    #유사도 계산
    def similarity(doc1, doc2):
      cnt=0
      for token in doc1:
        if token in doc2:
          cnt+=1
      return cnt/len(doc1)
    
    sentence1='6월에 뉴턴은 선생님의 제안으로 트리니티에 입학했다.'
    sentence2='6월에 뉴턴은 선생님의 제안으로 대학교에 입학했다.'
    sentence3='나는 맛있는 밥을 뉴턴 선생님과 함께 먹었다.'
    
    #형태소 분석기에서 명사(단어)추출
    komoran=Komoran()
    bow1=komoran.nouns(sentence1)
    bow2=komoran.nouns(sentence2)
    bow3=komoran.nouns(sentence3)
    
    #단어 n-gram 토큰 추출
    #2-gram방식으로 추출
    doc1=word_ngram(bow1,2)
    doc2=word_ngram(bow2,2)
    doc3=word_ngram(bow3,2)
    
    #추출된 n-gram토큰 출력
    print(doc1)
    print(doc2)
    
    #유사도 계산
    r1=similarity(doc1, doc2)
    r2=similarity(doc3, doc1)
    
    #계산된 유사도 출력
    print(r1)
    print(r2)

    n-gram은 문장에 존재하는 모든 단어의 출현 빈도를 확인하는 것이 아니라 연속되는 문장에서 일부 단어(n으로 설정된 개수만큼)만 확인하다 보니 전체 문장을 고려한 언어 모델보다 정확도가 떨어질 수 있음

    n을 크게 잡을수록 비교 문장의 토큰과 비교할 때 카운트를 놓칠 확률이 커짐

    n을 작게 잡을수록 카운트 확률은 높아지지만 문맥을 파악하는 정확도는 떨어질 수 밖에 없는 구조

    보통 1~5 사이의 값을 많이 사용

    5.3 코사인 유사도

    단어나 문장을 벡터로 표현할 수 있다면 벡터 간 거리나 각도를 이용해 유사성을 파악할 수 있음

     

    코사인 유사도는 두 벡터 간 코사인 각도를 이용해 유사도를 측정하는 방법

    코사인 유사도는 벡터의 크기가 중요하지 않을 때 그 거리를 측정하기 위해 사용

    단어의 출현 빈도를 통해 유사도 계산을 한다면 동일한 단어가 많이 포함되어 있을수록 벡터의 크기가 커짐

    이 때 코사인 유사도는 벡터의 크기와 상관없이 결과가 안정적

    앞서 배운 n-gram의 경우 동일한 단어가 문서 내에 자주 등장하면 유사도 결과에 안 좋은 영향을 미칠 수밖에 없음

    코사인 유사도는 다양한 차원에서 적용 가능해 실무에서 많이 사용

     

    코사인은 -1~1사이의 값을 가지며,

    • 두 벡터의 방향이 완전한 동일한 경우에는 1
    • 반대 방향인 경우에는 -1
    • 두 벡터가 서로 직각을 이루면 0

    즉, 두 벡터의 방향이 같아질수록 유사하다

    공간 벡터의 내적과 크기를 이용해 코사인 각도를 계산한다는 것을 알 수 있음

    from konlpy.tag import Komoran
    import numpy as np
    from numpy import dot
    from numpy.linalg import norm
    
    #코사인 유사도 계산
    def cos_sim(vec1,vec2):
      return dot(vec1, vec2)/(norm(vec1)*norm(vec2))
    
    #TDM만들기
    def make_term_doc_mat(sentence_bow,word_dics):
      freq_mat={}
    
      for word in word_dics:
        freq_mat[word]=0
    
      for word in word_dics:
        if word in sentence_bow:
          freq_mat[word]+=1
    
      return freq_mat
    
    #단어 벡터만들기
    def make_vector(tdm):
      vec=[]
      for key in tdm:
        vec.append(tdm[key])
      return vec
    
    #문장정의
    sentence1='6월에 뉴턴은 선생님의 제안으로 트리니티에 입학했다.'
    sentence2='6월에 뉴턴은 선생님의 제안으로 대학교에 입학했다.'
    sentence3='나는 맛있는 밥을 뉴턴 선생님과 함께 먹었다.'
    
    #형태소 분석기에서 명사(단어)추출
    komoran=Komoran()
    bow1=komoran.nouns(sentence1)
    bow2=komoran.nouns(sentence2)
    bow3=komoran.nouns(sentence3)
    
    #단어 묶음 리스트를 하나로 합침
    bow=bow1+bow2+bow3
    
    #단어 묶음에서 중복을 제거해 단어 사전 구축
    word_dics=[]
    for token in bow:
      if token not in word_dics:
        word_dics.append(token)
    
    #문장별 단어 문서 행렬 계산
    freq_list1=make_term_doc_mat(bow1, word_dics)
    freq_list2=make_term_doc_mat(bow2, word_dics)
    freq_list3=make_term_doc_mat(bow3, word_dics)
    print(freq_list1)
    print(freq_list2)
    print(freq_list3)
    
    #문장 벡터 생성
    doc1=np.array(make_vector(freq_list1))
    doc2=np.array(make_vector(freq_list2))
    doc3=np.array(make_vector(freq_list3))
    
    #코사인 유사도 계산
    r1=cos_sim(doc1, doc2)
    r2=cos_sim(doc3, doc1)
    print(r1)
    print(r2)

    '공부 > 처음 배우는 딥러닝 챗봇' 카테고리의 다른 글

    chapter6. 챗봇 엔진에 필요한 딥러닝 모델  (0) 2023.05.08
    chatper4. 임베딩  (0) 2023.04.13
    chapter3.토크나이징  (0) 2023.04.13

    댓글

Designed by Tistory.