자연어처리

(3) 자연어처리_임베딩

빠스무 2023. 7. 11. 02:38
728x90

1. 자연어의 특성

  • 자연어를 기계가 처리하도록 하기 위해서는 먼저 자연어를 기계가 이해할 수 있는 언어로 바꾸는 방법을 알아야함
  • 토큰화 작업의 결과인 단어 사전을 기계가 이해할 수 있는 언어로 표현하는 과정이고 단어 사전 내 단어 하나를 어떻게 표현할까의 문제로 볼 수 있음

 

1-1. 단어의 유사성과 모호성

  • 대부분의 언어에서 단어의 의미는 유사성과 모호성을 가지고 있는데 단어는 겉으로 보이는 형태인 표제어 안에 여러가지 의미를 담고 있음
  • 대부분 사람은 주변 정보에 따라 숨겨진 의미를 파악하고 이해할 수 있으나 기계는 학습의 부재 또는 잘못된 데이터로 의미를 파악하지 못하는 경우가 있음
  • 한 가지 형태의 단어에 여러 의미가 포함되어 생기는 중의성 문제는 자연어 처리에서 매우 중요
    • 동형어와 다의어
      • 동형어 : 형태는 같으나 뜻이 서로 다른 단어(배)
      • 다의어 : 하나의 형태가 여러 의미를 지니면서도 그 의미들이 서로 관련이 있는 단어(먹다)
    • 동의어
      • 서로 다른 형태의 단어들이 동일한 의미를 가지는 단어
    • 상의어와 하위어
      • 상의어 : 상위 개념을 가리키는 단어
      • 하위어 : 하위 개념을 표현하는 단어

 

1-2. 언어의 모호성 해소

  • 동형어나 다의어처럼 여러 의미를 가지는 단어들이 하나의 형태로 공유, 동의어처럼 하나의 형태를 가지는 단어들이 서로 같은 의미를 공유
  • 단어 중의성 해소(WSD) 알고리즘 방법을 통해 단어의 의미를 명확히 함
    • 지식 기반 단어 중의성 해소
      • 컴퓨터가 읽을 수 있는 사전이나 시소러스(어휘집)등을 바탕으로 단어의 의미를 추론하는 접근 방식
      • 사람이 직접 선별해서 데이터를 넣으므로 노이즈가 적음
      • 영어 자연어처리 분야에서 가장 유명한 WordNet이 있음
      • 관계 구축에 많은 리소스가 필요함
      • 시의성을 반영하지 못함
      • 데이터 편향이 생길 수 있음
    • 지도 학습 기반 단어 중의성 해소
      • 지도 학습은 데이터에 정답이 있다는 의미로, 각종 기계 학습 알고리즘을 통해 단어 의미를 분류해내는 방법
      • WSD라고 하면 보통 단어의 세부 의미가 부탁된 코퍼스를 학습 데이터로 사용하여 학습에 쓰이지 않았던 새로운 문장에서 단어 의미를 판별해내는 경우
      • 좋은 성능을 위해서는 질 높은 레이블을 가진 크기가 큰 데이터가 필요함
      • 데이터가 충분할 경우 일반화된 환경에서도 괜찮은 성능을 낼 수 있음
    • 비지도 학습 기반 단어 중의성 해소
      • 비지도 학습 WSD는 단어 의미 추론 작업인 WSI를 가리키는 경우가 많음
      • 문장에 등장하는 각 단어의 의미를 사전적인 의미에 연결하지 않고, 세부 의미가 같은 맥락을 군집화하는 데에 초점을 맞춤
      • 대규모 자연어 코퍼스로부터 추가 작업없이 자동적으로 학습을 수행할 수 있어서 활용 가능성이 높음
      • 사람이 직접 제작한 학습 데이터를 사용하지 않기 때문에 성능을 내기 어려움
 

2. 임베딩 구축 방법

2-1. 임베딩이란

  • 자연어 처리 작업에서 특징 추출을 통해 자연어를 수치화 하는 과정이 필요하고, 이런 벡터화의 과정이자 결과
  • 토큰화 작업의 목표는 사실상 임베딩을 만들기 위한 단어 사전을 구축하는 것
 

2-2. 임베딩의 역할

  • 자연어의 의미적인 정보 함축
    • 자연어의 중요한 특징들을 추출하여 벡터로 압축하는 과정
    • 임베딩으로 표현된 문장은 실제 자연어의 주요 정보들을 포함하고 있음
    • 벡터인 만큼 사칙 연산이 가능하여 단어 벡터간 덧셈/뺄셈을 통해 단어들 사이의 의미적 문법적 관계를 도출
    • 임베딩의 품질을 평가하기 위해 사용되는 단어 유추 평가 예시(https://word2vec.kr/search/)
  • 자연어 간 유사도 계산
    • 자연어를 벡터로 표현하면, 코사인 유사도를 활용하여 두 벡터 간 유사도를 계산할 수 있음
    • 코사인 유사도는 -1이상 1이하의 값을 가지며 값잉 1 에 가까울수록 유사도가 높다고 판단함
  • 전이 학습
    • 품질 좋은 임베딩을 사용할수록 목표로 하는 자연어처리 작업의 학습 속도와 성능이 향상됨
    • 이미 만들어진 임베딩을 다른 작업을 학습하기 위한 입력값으로 쓰임 -> 전이학습
    • 매번 새로운 것을 배울 때 scratch 부터 시작한다면 매 학습이 오래 걸림
    • 파인 튜닝: 학습하는데 임베딩을 초기화하여 사용하면 새로운 작업을 학습함에도 빠르게 학습할 수 있고 성능도 좋아짐
 

2-3. 임베딩을 만들 때 쓰는 통계적인 가설

  • 문장을 구성하는데 어떤 단어가 많이 쓰이는거?
  • 문장에 어떤 단어가 쓰이는가
  • 단어가 어떤 순서로 등장하는가?
 

2-4. 단어 출현 빈도에 기반한 임베딩 구축 방법

  • 원 핫 인코딩
    • 자연어를 0과 1로 구별하겠다는 인코딩 방법
    • 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 나머지 인덱스에는 0을 부여하는 벡터 표현 방식
    • 희소 문제(sparsity problem)
      • 예) 단어 사전의 크기가 10.000이라면, 총 10,000개 중 현재 단어를 표현하는 1개의 차원만 1이고, 나머지 9,999개의 차원은 0으로 표현
      • 대부분의 값들의 0인 행렬을 희소행렬이라 하는데, 단어가 늘어날수록 행렬의 크기는 계속 증가하나 증가하는 크기에 비해 표현의 효율성을 떨어짐
    • 단어의 유사도를 표현하지 못함
  • Bag of words
    • 단어들의 순서는 전혀 고려하지 않고, 단어들의 출현빈도에 집중하는 자연어 코퍼스의 데이터 수치화 방법
    • 각 단어에 고유한 정수 인덱스를 부여하여 단어 집합을 생성하고, 각 인덱스의 위치에 단어 토큰의 등장 횟수를 기록한 벡터를 만듦
    • 단어 단위의 압축 방식이기 때문에 희소 문제와 단어 순서를 반영하지 못함
  • TF-IDF
    • 단어의 빈도와 역문서 빈도를 사용하여 문서-단어 행렬 내 각 단어들의 중요한 정도를 가중치로 주는 표현 방법
    • 문서의 유사도를 구하는 작업, 검색 시스템에서 검색 결과의 중요도를 정하는 작업, 문서 내에서 특정 안어의 중요도를 구하는 작업등에서 효과적으로 쓰일 수 있음
    • https://heytech.tistory.com/337
    • 단어의 중요도를 고려해도 여전히 단어의 빈도로 판단하는 표현 방식이기 때문에 맥락적 유사도를 번영하지 못함
    • 단어 사전의 규모 자체를 축소하는 방법이 아니기 때문에 단어 사전의 규모가 크다면 높은 계산 복잡도를 요구하는 표현 방식(희소 문제)

 

idf(d,t)=log(n1+df(t))

2-5. 분포 가설과 언어 모델

  • 비슷한 위치(문맥) 내에서 등장하는 단어들은 비슷한 의미를 가진다는 가설
  • 분포 가설은 목표 단어의 단어들, 즉 window 크기에 따라 정의되는 문맥의 의미를 이용해 단어를 벡터로 표현하는 것이 목표
  • 분포 가설이라는 가정 하에 만들어진 표현 방법을 분산 표현이라고 함
  • PMI(Pointwise Mutual Infomation)
    • 분포 가설의 대표적인 통계량은 PMI이며, 두 확률변수 사이의 상관성을 계량화하는 단위
      • 1에 가까워 질수록 영향을 줬다 0으로 갈수록 영향 안줌
      • 얼마나 같이 자주 등장하느냐에 따라 수치화한 단위
    • 확률변수가 완전히 독립인 경우에 값이 0이되며, 독립이라는 말은 단어 x가 나타나는 것이 단어 y가 등잘할 확률에 전혀 영향을 주지 않으며 반대로 단어 y의 등장이 단어 x에 영향을 주지 않는 것을 의미함
    • 단어 x가 등장할 때 문맥 내에서 단어 y와 같이 자주 등장한다면 PMI값이 커짐
    • 분포 가설을 활용하는 대표적인 모델은 2013년 google의 Efficient Estimations of Word Representations in Vector Space 논문에서 발표된 Word2Vec이라는 단어 임베딩 기법
 

2-6. 단어가 어떤 순서로 쓰이는가

  • 통계 기반 언어 모델
    • 언어 모델: 일련의 단어 토큰에 확률을 할당하는 모델
    • 단어의 등장 순서를 중요하게 고려하지 않았던 이전 가설들과 다르게, 언어 모델은 단어 시퀀스 정보를 명시적으로 학습함
    • 단어가 n개 주어졌을 때 언어 모델은 n개의 단어가 동시에 나타날 확률을 반환
    • 문장은 어순을 고려하여 여러 단어로 이루어진 단어 시퀀스라고도 부르며, n개의 단어로 구성된 단어 시퀀스를 확률적으로 표현
  • 딥러닝 기반 언어 모델
    • 통계 기반 언어 모델에서는 여전히 등장 빈도라는 통계량을 활용하여 확률을 추산했지만, 딥러닝 기반 언어 모델들이 등장하면서 딥러닝 모델들이 입력과 출력 사이의 관계를 유연하게 정의할 수 있게 되고 그 자체로 확률 모델로 동작할 수 있음
      • MLM(Masked Language Modeling)
        • 문장 중간에 마스크를 씌워서 해당 마스크에 어떤 단어가 올지 예측하는 과정에서 학습을 진행문장 전체를 다 보고 중간에 있는 단어를 예측하기 때문에 양방향 학습이 가능
        • 대표적으로 BERT 모델이 있음
      • Next Token Prediction
        • 주어진 단어 시퀀스를 가지고 다음 단어로 어떤 단어가 올지 예측하는 과정에서 학습
        • 단어를 순차적으로 입력 받은 뒤, 다음 단어를 맞춰야하기 때문에 일반향 학습을 함
        • 대표적으로 GPT, ELMo등
 

3. 텍스트 유사도

  • 두 개의 자연어 텍스트가 얼마나 유사한지를 나타내는 방법
  • 유사도를 정의하거나 판단하는 척도가 주관적이기 때문에, 이를 최대한 정량화 하는 방법을 찾는것이 중요하다.
  • 자연어 처리 분야에서 자주 사용되는 유사도 측정 방법
    • 유클리디안 거리 기반 유사도
    • 맨하탄 거리 기반 유사도
    • 코사인 유사도
    • 자카드 유사도
    • 문자열 간 유사도
 

3-1. 유클리디안 거리 기반 유사도

  • 두 점 사이의 거리를 측정하는 유클리디안 거리를 사용하여 문서의 유사도를 구하는 방법으로 거리가 가까울수록 유사도가 높다고 판단함
  • 자카드 유사도나 코사인 유사도 만큼 유용하게 사용되는 방법은 아니나, 자연어처리 분야뿐만 아니라 다른 분야에서도 범용적으로 사용되는 거리 측정 기법
 

3-2. 맨하탄 거리 기반 유사도

  • 맨하탄 거리를 사용하여 문서의 유사도를 구하는 방법
  • 유클리드 거리와 유사하나, 각 차원의 차를 제곱해서 사용하는 대신 절대값을 바로 합산함
  • 항상 유클리드거리보다 크거나 같음
  • 다차원 공간 상에서 두 좌표간 최단거리를 구하는 방법이 아니다 보니 특별한 상황이 아니면 잘 사용하지 않음
 

3-3. 코사인 유사도

  • 코사인 유사도는 두 개의 벡터값에서 코사인 각도를 이용하여 구할 수 있는 두 벡터의 유사도를 의미
  • 두 벡터의 방향이 완전히 동일한 경우에는 1의 값을 가지며, 90도의 각을 이루면 0 180도로 반대의 방향을 가지면 -1의 값을 가짐
  • -1이상 1이하의 값을 가지며 값이 1에 가까울수록 유사하는 것을 의미
  • 두 벡터가 가리키는 방향이 얼마나 유사한가를 의미하기 때문에 자연어 내 유사도 계산에 더 적합함
 

3-4. 자카드 유사도

  • 두 문장을 각각 단어의 집합으로 만든 뒤 두 집합을 통해 유사도를 측정하는 방식
  • 수치화된 벡터 없이 단어 집합 만으로 계산할 수 있음
  • 두 집합의 교집합인 공통된 단어의 개수를 두 집합의 합집합, 전체 단어의 개수로 나누는 것
  • 전체 집합 중 공통의 단어의 개수에 따라 0과 1사이의 값을 가지며, 1에 가까울수록 유사도가 높음

4. 유사도 측정 실습

  • sen_1, sen_2 : 의미가 유사한 문장 간 유사도 계산(조사 생략)
  • sen_1, sen_3 : 의미가 유사한 문장 간 유사도 계산(순서 변경)
  • sen_2, sen_4 : 문장 내 단어를 임의의 단어로 치환한 문장과 원본 문장 간 유사도 계산
  • sen_1, sen_5 : 의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산
  • sen_1, sen_6 : 의미가 서로 다른 문장 간 유사도 계산
 sen_1 = '오늘 점심에 배가 너무 고파서 밥을 너무 많이 먹었다.'
 sen_2 = '오늘 점심에 배가 고파서 밥을 많이 먹었다.'
 sen_3 = '오늘 배가 너무 고파서 점심에 밥을 너무 많이 먹었다.'
 sen_4 = '오늘 점심에 배가 고파서 비행기를 많이 먹었다.'
 sen_5 = '어제 저녁에 밥을 많이 먹었더니 배가 부르다.'
 sen_6  = '이따가 오후 7시에 출발하는 비행기가 3시간 연착 되었다고 하네요.'
 
training_documents = [sen_1,sen_2,sen_3,sen_4,sen_5,sen_6]
!pip install newspaper3k
 
from newspaper import Article
 
article = Article(URL, language = 'ko')
 
article.download()
article.parse()

news_title = article.title
news_context = article.text

print('title:',news_title)
print('context:',news_context)

news_context = article.text.split('\n')
 
for text in news_context:
  print(text)

!pip install kss
 
import kss
 
def sentence_seperator(processed_context):
  splited_context = []

  for text in processed_context:
    text = text.strip()
    if text:
      splited_text = kss.split_sentences(text)
      splited_context.extend(splited_text)

  return splited_context
 
splited_context = sentence_seperator(news_context)

for text in enumerate(splited_context):
  print(text)

argumented_training_documents = training_documents + splited_context
 
for text in argumented_training_documents:
  print(text)

# Bag of Words 기반 문서-단어 행렬을 활용한 문장 간 유사도 측정

from sklearn.feature_extraction.text import CountVectorizer
 
bow_vectorizer = CountVectorizer()
bow_vectorizer.fit(argumented_training_documents)
 
word_idxes =  bow_vectorizer.vocabulary_
word_idxes

word_idxes =  bow_vectorizer.vocabulary_

for key, idx in sorted(word_idxes.items()):
  print(f'{key}:{idx}')

import pandas as pd
 
result = []
vocab = list(word_idxes.keys())

for i in range(len(training_documents)):
  result.append([])
  d = training_documents[i]
  for j in range(len(vocab)):
    target = vocab[j]
    result[-1].append(d.count(target))


tf = pd.DataFrame(result, columns = vocab)
tf

result = []
vocab = list(word_idxes.keys())

for i in range(len(argumented_training_documents)):
  result.append([])
  d = argumented_training_documents[i]
  for j in range(len(vocab)):
    target = vocab[j]
    result[-1].append(d.count(target))

tf2 = pd.DataFrame(result, columns = vocab)
tf2

# 유사도를 측정할 문장들을 문장 - 단어 행렬 기반 임베딩으로 변환
bow_vector_sen_1 = bow_vectorizer.transform([sen_1]).toarray()[0]
bow_vector_sen_2 = bow_vectorizer.transform([sen_2]).toarray()[0]
bow_vector_sen_3 = bow_vectorizer.transform([sen_3]).toarray()[0]
bow_vector_sen_4 = bow_vectorizer.transform([sen_4]).toarray()[0]
bow_vector_sen_5 = bow_vectorizer.transform([sen_5]).toarray()[0]
bow_vector_sen_6 = bow_vectorizer.transform([sen_6]).toarray()[0]
print(bow_vector_sen_1)
print(bow_vector_sen_2)
print(bow_vector_sen_3)
print(bow_vector_sen_4)
print(bow_vector_sen_5)
print(bow_vector_sen_6)

# 코사인 기반 유사도 계산을 위해 함수를 정의
import numpy as np
from numpy import dot
from numpy.linalg import norm
def cos_sim(A,B):
  return dot(A,B) / (norm(A) * norm(B))
print(f'의미가 유사한 문장 간 유사도 계산(조사 생략): {cos_sim(bow_vector_sen_1,bow_vector_sen_2)}')
print(f'의미가 유사한 문장 간 유사도 계산(순서 변경): {cos_sim(bow_vector_sen_1,bow_vector_sen_3)}')
print(f'문장 내 단어를 임의의 단어로 치환한 문장과 원본 문장 간 유사도 계산: {cos_sim(bow_vector_sen_2,bow_vector_sen_4)}')
print(f'의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산: {cos_sim(bow_vector_sen_1,bow_vector_sen_5)}')
print(f'의미가 서로 다른 문장 간 유사도 계산: {cos_sim(bow_vector_sen_1,bow_vector_sen_6)}')

from sklearn.feature_extraction.text import TfidfVectorizer
 
tfidfv = TfidfVectorizer().fit(argumented_training_documents)
 
for key, idx in sorted(tfidfv.vocabulary_.items()):
  print(f'{key}: {idx}')

sk_tf_idf = tfidfv.transform(argumented_training_documents).toarray()
print(sk_tf_idf)

# TF-IDF 행렬에서 얻어지는 유사도의 값을 0~1로 스케일링하기 위해 L1 정규화를 진행
def l1_normalize(v):
  norm = np.sum(v)
  return v / norm
 
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix_l1 = tfidf_vectorizer.fit_transform(argumented_training_documents)
tfidf_norm_l1 = l1_normalize(tfidf_matrix_l1)
 
tf_sen_1 = tfidf_norm_l1[0:1]
tf_sen_2 = tfidf_norm_l1[1:2]
tf_sen_3 = tfidf_norm_l1[2:3]
tf_sen_4 = tfidf_norm_l1[3:4]
tf_sen_5 = tfidf_norm_l1[4:5]
tf_sen_6 = tfidf_norm_l1[5:6]
 
tf_sen_1.toarray()

# 유클리디안 거리 기반 유사도 측정
from sklearn.metrics.pairwise import euclidean_distances
 
euclidean_distances(tf_sen_1, tf_sen_2)
 
def euclidean_distances_value(vec_1, vec_2):
  return round(euclidean_distances(vec_1,vec_2)[0][0],3)
 
print(f'의미가 유사한 문장 간 유사도 계산(조사 생략): {euclidean_distances_value(tf_sen_1, tf_sen_2)}')
print(f'의미가 유사한 문장 간 유사도 계산(순서 변경): {euclidean_distances_value(tf_sen_1, tf_sen_3)}')
print(f'문장 내 단어를 임의의 단어로 치환한 문장과 원 문장 간 유사도 계산: {euclidean_distances_value(tf_sen_2, tf_sen_4)}')
print(f'의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산: {euclidean_distances_value(tf_sen_1, tf_sen_5)}')
print(f'의미가 서로 다른 문장 간 유사도 계산: {euclidean_distances_value(tf_sen_1, tf_sen_6)}')

from sklearn.metrics.pairwise import manhattan_distances, cosine_similarity
 
# 맨해튼 거리 기반 유사도 측정
def manhattan_distances_value(vec_1, vec_2):
  return round(manhattan_distances(vec_1,vec_2)[0][0],3)

print(f'의미가 유사한 문장 간 유사도 계산(조사 생략): {manhattan_distances_value(tf_sen_1, tf_sen_2)}')
print(f'의미가 유사한 문장 간 유사도 계산(순서 변경): {manhattan_distances_value(tf_sen_1, tf_sen_3)}')
print(f'문장 내 단어를 임의의 단어로 치환한 문장과 원 문장 간 유사도 계산: {manhattan_distances_value(tf_sen_2, tf_sen_4)}')
print(f'의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산: {manhattan_distances_value(tf_sen_1, tf_sen_5)}')
print(f'의미가 서로 다른 문장 간 유사도 계산: {manhattan_distances_value(tf_sen_1, tf_sen_6)}')

# 코사인 유사도 측정
def cosine_similarity_value(vec_1, vec_2):
  return round(cosine_similarity(vec_1,vec_2)[0][0],3)

print(f'의미가 유사한 문장 간 유사도 계산(조사 생략): {cosine_similarity_value(tf_sen_1, tf_sen_2)}')
print(f'의미가 유사한 문장 간 유사도 계산(순서 변경): {cosine_similarity_value(tf_sen_1, tf_sen_3)}')
print(f'문장 내 단어를 임의의 단어로 치환한 문장과 원 문장 간 유사도 계산: {cosine_similarity_value(tf_sen_2, tf_sen_4)}')
print(f'의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산: {cosine_similarity_value(tf_sen_1, tf_sen_5)}')
print(f'의미가 서로 다른 문장 간 유사도 계산: {cosine_similarity_value(tf_sen_1, tf_sen_6)}')

# 언어 모델을 활용한 문장 간 유사도 측정
!pip install transformers
from transformers import AutoModel, AutoTokenizer, BertTokenizer
MODEL_NAME = 'bert-base-multilingual-cased'
model = AutoModel.from_pretrained(MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
bert_sen_1 = tokenizer(sen_1, return_tensors='pt')
bert_sen_2 = tokenizer(sen_2, return_tensors='pt')
bert_sen_3 = tokenizer(sen_3, return_tensors='pt')
bert_sen_4 = tokenizer(sen_4, return_tensors='pt')
bert_sen_5 = tokenizer(sen_5, return_tensors='pt')
bert_sen_6 = tokenizer(sen_6, return_tensors='pt')
sen_1_outputs = model(**bert_sen_1) # ** 이 기호는 딕셔너리형태
sen_1_pooler_output = sen_1_outputs.pooler_output # 임베딩된 기울기

sen_2_outputs = model(**bert_sen_2) # ** 이 기호는 딕셔너리형태
sen_2_pooler_output = sen_2_outputs.pooler_output # 임베딩된 기울기

sen_3_outputs = model(**bert_sen_3) # ** 이 기호는 딕셔너리형태
sen_3_pooler_output = sen_3_outputs.pooler_output # 임베딩된 기울기

sen_4_outputs = model(**bert_sen_4) # ** 이 기호는 딕셔너리형태
sen_4_pooler_output = sen_4_outputs.pooler_output # 임베딩된 기울기

sen_5_outputs = model(**bert_sen_5) # ** 이 기호는 딕셔너리형태
sen_5_pooler_output = sen_5_outputs.pooler_output # 임베딩된 기울기

sen_6_outputs = model(**bert_sen_6) # ** 이 기호는 딕셔너리형태
sen_6_pooler_output = sen_6_outputs.pooler_output # 임베딩된 기울기
from torch import nn
 
cos_sim = nn.CosineSimilarity(dim = 1, eps = 1e-6)
 
# 코사인 유사도 측정
def cosine_similarity_value(vec_1, vec_2):
  return round(cosine_similarity(vec_1,vec_2)[0][0],3)

print(f'의미가 유사한 문장 간 유사도 계산(조사 생략): {cos_sim(sen_1_pooler_output, sen_2_pooler_output)}')
print(f'의미가 유사한 문장 간 유사도 계산(순서 변경): {cos_sim(sen_1_pooler_output, sen_3_pooler_output)}')
print(f'문장 내 단어를 임의의 단어로 치환한 문장과 원 문장 간 유사도 계산: {cos_sim(sen_2_pooler_output, sen_4_pooler_output)}')
print(f'의미는 다르지만 비슷한 주제를 가지는 문장 간 유사도 계산: {cos_sim(sen_1_pooler_output, sen_5_pooler_output)}')
print(f'의미가 서로 다른 문장 간 유사도 계산: {cos_sim(sen_1_pooler_output, sen_6_pooler_output)}')