Skip to content

7주차 과제 #7

Open
Open

Description

@GirinMan

여섯 번째 과제: BERT를 이용한 sentence embedding의 cosine similarity 계산하기

회합 자료 링크: #1 (comment)
image

  • BERT는 Transformer 아키텍처를 기반으로 한 모델로, 문장의 의미를 잘 이해하고 문장을 벡터 형태로 변환할 수 있습니다.
  • Sentence embedding은 문장을 고정된 길이의 벡터로 표현하는 것을 의미하며, 문장 간의 유사도를 계산하는 데 유용합니다. 자세한 내용은 Weekly NLP week4를 참고하세요!
  • 이번 과제에서는 BERT 모델을 사용하여 문장을 임베딩하고, cosine similarity와 같은 유사도 계산을 수행하여 문장 간의 관계를 분석합니다.

Colab Python 노트북을 사용한 BERT sentence embedding 실습

sentence_embeddings.ipynb

Step 1. 예시 노트북을 실행해보며 sentence embedding과 cosine similarity 계산 방법 익히기

  • Google 계정 로그인 후 colab에 접속해서 현재 레포지토리의 /Week7/sentence_embeddings.ipynb 노트북을 실행해보면서 한국어 문장을 임베딩 벡터로 표현하는 과정과, 각 벡터들 사이의 cosine 유사도를 이용해 문장 사이의 의미적 유사도를 계산하는 방법에 대해 살펴봅시다.
  • 예시 데이터 대신 자신만의 데이터를 입력해서 사용해도 좋아요!

Step 2. 입력된 키워드와 유사한 뉴스 기사 추천 프로그램 만들기

  • 위에서 사용했던 BERT 모델을 이용하여, 사용자가 입력한 내용과 가장 유사한 뉴스 제목을 찾아 추천해주는 프로그램을 만들어 봅시다.
  • 프로그램의 뼈대를 이루는 함수 이름과 정의가 마련되어 있으니, 필요한 부분을 자유롭게 구성하여 프로그램을 완성해 봅시다.
  • 주의: main 함수의 정의는 바꾸지 마세요!

작동 예시

입력 > 신재생 에너지
출력 > 입력과 유사한 상위 5개의 뉴스 제목을 출력합니다.
1. 에너지정책 유턴  재생에너지 대신 원전으로	(score: 56.85)
2. 전기 아껴쓴 만큼 현금 돌려받는다...에너지캐쉬백 전국 확대	(score: 54.78)
3. 수자원공사 한국에너지기술연과 그린수소 연구 업무협약	(score: 53.07)
4. 이어지는 폭염 늘어나는 전력수요	(score: 51.01)
5. 코오롱 수소 밸류체인 플랫폼 구축… 생산부터 발전까지 원스톱	(score: 50.95)

Hint

  • Hint 1: news_title에는 뉴스 데이터셋에 포함되어 있는 각 뉴스 기사들의 제목이 포함되어 있습니다. 예시 문장의 임베딩을 계산한 것과 같은 방식을 사용할 수 있습니다.
  • Hint 2: 위에서 정의하고 사용했던 cal_score 함수를 사용하면 사용자가 입력한 요청사항과 뉴스 제목들 사이의 similarity score를 계산할 수 있습니다.

제출 방식

  • 노트북 마지막 부분에 완성한 코드와, 실행 화면을 캡쳐해서 보여주세요.
  • 어떻게 구현했는지 간단하게 설명도 곁들여주세요.

Activity

  1. self-assigned this
    on May 29, 2023
  2. ymnseol commented on Jun 1, 2023

    @ymnseol

    4조

    김율희

    KakaoTalk_Photo_2023-06-01-16-22-40 001
    KakaoTalk_Photo_2023-06-01-16-22-40 002
    get_sentence_embeddings() 함수는 입력 문장들에 대한 임베딩 벡터를 계산합니다. 파라미터로 받은 입력 문장들을 tokenizer를 사용해 토큰 인덱스 배열로 변환하고, 변환된 토큰 인덱스 배열을 모델에 입력하여 임베딩 벡터를 계산합니다.

    get_similarity_scores() 함수는 입력 텍스트와 미리 계산된 임베딩 벡터들과의 유사도 점수를 계산합니다. 두번째 파라미터로 받은 입력 텍스트를 get_sentence_embeddings() 함수를 사용하여 임베딩 벡터로 변환한 후, 미리 계산된 임베딩 벡터들과의 유사도 점수를 계산 후 각 유사도 점수를 scores 리스트에 추가합니다. 이때 emb와 input_text의 크기를 맞추기 위해 get_sentence_embeddings()함수를 호출할 때 input_text를 리스트로 감싸서 전달했습니다.

    설유민

    스크린샷 2023-06-01 오전 11 21 08

    get_sentence_embeddings

    • Input sentences을 tokenizer를 사용해 tokenizing합니다.
      • 입력이 여러 문장으로 이루어진 list인 경우, 각 문장을 모두 tokenizing해줍니다!
      • return_tensors를 pt(torch.Tensor로 반환)로 설정한 경우, 각 문장에 대한 tokenizing 결과가 같은 차원의 벡터여야 합니다. 입력 문장들이 모두 같은 차원의 벡터로 표현되도록, 길이가 부족한 경우에는 padding을 수행하도록 설정합니다.
      • 길이가 모델의 최대 입력 차원보다 긴 경우에는 truncation을 할 수 있도록 설정합니다.
    • Tokenized sentences를 모델에 입력으로 주어, 각 문장에 대한 embedding을 구합니다.

    get_similarity_scores

    • 입력 텍스트의 embedding을 get_sentence_embeddings로 구합니다.
    • 입력 텍스트 한 개의 경우 embeddings의 size가 (1, {number of tokens}, {dim.})입니다. cal_score의 수정 없이 입력 텍스트의 [CLS]의 embedding만 연산에 사용할 수 있도록 squeeze를 수행해줍니다.

    결과

    스크린샷 2023-06-01 오후 12 37 30
  3. t2easure commented on Jun 1, 2023

    @t2easure

    2조

    image

    1. tokenizer를 사용하여 토큰화한다
    2. get_sentence_embeddings함수로 input_text를 임베딩한다
    3. cal_score로 유사도를 계산한다

    결과
    image

    image

    결과
    image

    image

  4. JOHAJUN commented on Jun 1, 2023

    @JOHAJUN

    5조
    5 31 hai

    1. 입력문장들을 tokenizer를 이용하여 토큰인덱스로 변환
    2. 임베딩 계산
    3. 임베딩 둘의 유사도를 계산
  5. YUNHYUNWOO commented on Jun 1, 2023

    @YUNHYUNWOO

    3조

    image

    1. Tokenizer를 통해 입력문장을 변환.
    2. 토큰화된 배열을 model을 통해 임베딩으로 변환
    3. cal_score 함수를 통해 벡터간 유사도를 계산하여 scores 리스트에 저장

    HAI 7-2
    결과

  6. twkang43 commented on Jul 24, 2023

    @twkang43

    강태욱

    1. Cosine Similarity 사용

    Screenshot 2023-07-24 at 22 46 28

    1. Tokenizer를 사용해 뉴스 기사 제목들을 토큰 인덱스 배열로 변환 후, 임베딩을 계산한다.
    2. 입력받은 input_text와 미리 토큰화한 뉴스 제목들 사이의 유사도를 계산해 유사도 점수가 가장 높은 5개의 뉴스 제목을 출력한다.

    결과

    Screenshot 2023-07-24 at 22 50 06

    2. Euclidean Distance 사용

    cal_score 함수를 다음과 같이 변경하여 euclidean distance를 계산하도록 하였다.
    Screenshot 2023-07-24 at 23 09 13

    그러나, 해당 함수는 뉴스 제목 사이의 유사도를 정확히 계산하지 못해 다음과 같이 키워드와 연관 없는 뉴스 제목을 출력하였다.

    Screenshot 2023-07-24 at 23 11 08

  7. mnxcv commented on Jul 25, 2023

    @mnxcv

    임세훈

    코드

    import numpy as np
    import math
    def cal_score(a, b):
        # 0번째 토큰에 해당하는 임베딩 벡터만 사용
        a = a[0:1]
        b = b[0:1]
    
        # 각 벡터 정규화
        a_norm = a / a.norm(dim=1)[:, None]
        b_norm = b / b.norm(dim=1)[:, None]
    
        # 정규화된 두 벡터를 곱하여 유사도 점수 계산
        return torch.mm(a_norm, b_norm.transpose(0, 1)).item() *100
    
    def proj_sim(a, b):
      a = a[0:1]
      b = b[0:1]
    
      diff = torch.matmul(a, b.transpose(0, 1)) / (b.norm(dim = 1) ** 2)[:, None]
      diff = abs(diff[0].item() - 1)
      return 2 / (1 + math.e ** diff)
    from tqdm import tqdm
    def get_sentence_embeddings(sentences):
      # 입력 문장을 tokenizer를 사용하여 토큰 인덱스 배열로 변환합니다.
      inputs = tokenizer(sentences, padding = True, truncation = True, return_tensors = "pt").to(device)
      # 모델을 활용하여 임베딩을 계산합니다..
      with torch.no_grad():
        embeddings, loss = model(**inputs, return_dict = False) 
      return embeddings
    
    def get_similarity_scores(embeddings, input_text, cal):
      # 입력 텍스트에 대한 임베딩을 계산합니다.
      input = []; input.append(input_text);
      input_embedding = get_sentence_embeddings(input)[0] # <- Input text에 대한 Vector
    
      # 입력 텍스트의 임베딩과 미리 계산된 임베딩 사이의 유사도를 계산합니다.
      scores = []
      for emb in embeddings:
        scores.append(cal(emb, input_embedding))
    
      return scores
    # 이 부분은 수정하지 마세요!
    
    def main(cal):
      # 뉴스 기사 제목의 임베딩 벡터 계산
      news_embeddings = get_sentence_embeddings(news_titles)
    
      input_text = input("입력 > ")
      # 입력된 텍스트와 뉴스 기사 제목들 사이의 유사도 계산
      similarity_scores = get_similarity_scores(news_embeddings, input_text, cal)
    
      print("출력 > 입력과 유사한 상위 5개의 뉴스 제목을 출력합니다.")
      # 유사도 점수가 가장 높은 5개의 index 찾기
      top_5_idx = reversed(np.argsort(similarity_scores)[-5:])
    
      # 각 index에 해당하는 뉴스 제목과 유사도 점수 출력
      for i, idx in enumerate(top_5_idx):
        print(f"{i+1}. {news_titles[idx]}\t(score: {format(similarity_scores[idx], '.2f')})")
    • main함수에 함수를 인수로 받도록 추가해서 새로운 Calculation Function을 적용하기 쉽도록 변경하였습니다.
    • 이 글을 참고해서 Projection Similarity를 추가로 구현하였습니다.

    실행

    입력 > 비건
    출력 > 입력과 유사한 상위 5개의 뉴스 제목을 출력합니다.
    1. 현대백화점그룹 비건 시장 본격 출사표	(score: 59.60)
    2. 반도건설 충남 천안 유보라 천안 두정역 분양	(score: 42.14)
    3. 셀바스AI 하나금융파인드 플랫폼서 셀비 체크업 서비스	(score: 41.83)
    4. 그래픽 수학자 허준이 한국계 최초 필즈상 수상	(score: 40.89)
    5. 정유사가 무슨죄 시장원리 모르나…베이조스 또 바이든 저격	(score: 38.35)
    입력 > 채식주의
    출력 > 입력과 유사한 상위 5개의 뉴스 제목을 출력합니다.
    1. 퓨리나의 지속가능한 친환경 실천... 반려동물과 함께하는 삶 꿈꾸죠 Weekend 반려동물	(score: 35.69)
    2. 가정간편식 플랫폼 구스통 엄선한 제철 식재료 및 음식 선보여	(score: 32.36)
    3. 풀무원 알래스칸 명태살 ‘볼카츠’ 출시	(score: 29.07)
    4. 인스웨이브 웹 공유 서비스 ‘W셰어링’ 베타 오픈	(score: 28.78)
    5. 金배추가 한차에 가득	(score: 28.58)
    
    • "비건"과 "채식주의"의 결과가 전혀 다르게 나왔습니다. 뉴스 제목에 "비건"이라고 명시되어있지 않으면 외래어에 대해서는 정확도가 낮게 나오는 것 같습니다.
    • Projection과 Cosine Similarity에 대해서 결과가 매우 비슷하게 나왔습니다. 계산 방식이 약간 차이는 있지만, 결과적으로 벡터가 많이 벌어져 있으면 정확도가 낮게 나오는 점은 동일하기 때문에 생긴 현상으로 보입니다.

    사용한 Colab Notebook 주소는 여기에서 확인할 수 있습니다.

  8. KangMeanWoo commented on Jul 31, 2023

    @KangMeanWoo

    강민우

    from tqdm import tqdm
    def get_sentence_embeddings(sentences):
      # 입력 문장을 tokenizer를 사용하여 토큰 인덱스 배열로 변환합니다.
      inputs = tokenizer(sentences, padding=True, truncation=True, return_tensors="pt").to(device)
      # 모델을 활용하여 임베딩을 계산합니다..
      with torch.no_grad():
        embeddings, loss = model(**inputs, return_dict=False)
      return embeddings
    
    def get_similarity_scores(embeddings, input_text):
      # 입력 텍스트에 대한 임베딩을 계산합니다.
      input_embedding = get_sentence_embeddings([input_text])[0]
    
      # 입력 텍스트의 임베딩과 미리 계산된 임베딩 사이의 유사도를 계산합니다.
      scores = []
      for emb in embeddings:
        scores.append(cal_score(emb,input_embedding))
    
      return scores
    

    1.Tokenizer를 이용하여 문장을 토큰 인덱스로 변환
    2. 임베딩을 코사인 유사도를 통해 계산
    3. 유사도가 비슷한 상위 5개 뉴스 제목 출력

    image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

assignment각 주차별 조별 과제 기록

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions