주제: 감성 분석 or 사용자 맞춤 데이터 출력
이번 실습의 조건이 한국어 데이터셋을 구하고 한국어 지원 모델을 찾는 것 이었는데 한국어로 된 데이터셋을 구하는 데에 생각보다 시간이 걸렸다. 다른 사람들도 비슷한 과정을 겪었는지 조건이 한국어 임에도 영어 데이터셋을 사용한 친구들도 있었고 한국어 데이터셋을 사용한 친구들 중엔 같은 데이터셋을 가져온 친구들도 더러 있었다.
내가 사용한 데이터셋은 kaggle에 올라와 있는 네이버 웹툰 데이터셋 Webtoon Dataset in Korean 으로 수업시간에 사용했던 영화 데이터셋과 비슷하여 실습을 진행하는 과정에 큰 어려움은 없었지만 실제 쿼리를 입력 하였을 때 모델의 한국어 임베딩 이슈로 좋은 결과를 얻지는 못했다.
임베딩 모델은 수업 시간에 사용했던 all-MiniLM-L6-v2 모델이 한국어 문맥을 꽤나 잘 이해한다고 생각하여 우선 사용해 보았고 비슷한 다국어 모델인 paraphrase-multilingual-MiniLM-L12-v2을 사용하여 두 모델을 비교해 보았다.
실습 과정은 데이터 로드 > 사용한 컬럼의 결측치 제거 > genre + description 컬럼 벡터화 > faiss 인덱스 생성 > 데이터 삽입 > 쿼리 입력 > 응답 순으로 진행하였고 아래는 두 임베딩 모델의 결과 비교이다. (참고로 당연하게도(?) 두 모델 모두 1번째 추천으로 query_title을 가져와서 제목이 금수저인 웹툰은 제외하도록 했다)
# 쿼리 대상인 금수저의 장르와 설명
title: 금수저
genre: 스토리, 드라마
description: 부모님을 선택할 수 있다고!? '후천적 금수저가 된 아이의 인생 어드벤처'
# all-MiniLM-L6-v2 모델
query_title = "금수저"
recommended_webtoons = recommend_webtoons(query_title, top_n=6)
# 추천된 웹툰에서 입력한 웹툰(query_title) 제외
if recommended_webtoons is not None:
filtered_recommendations = recommended_webtoons[recommended_webtoons["title"] != query_title].head(5)
for i, row in enumerate(filtered_recommendations.itertuples(), start=1):
print(f"✅{i}번째 추천: {row.title} | {row.genre} | {row.description[:50]}...")
# 응답
✅1번째 추천: 월남특급 | 스토리, 드라마 | 유쾌상쾌통쾌! 지긋지긋한 현실을 벗어나 베트남으로!돈가방을 들고 튄 두 여자와 악의 무리들...
✅2번째 추천: 잉잉잉 | 스토리, 개그 | 수업시간에 똥을 싸버린 찌질이 복학생 황준호. 그는 과연 무사히 학교를 졸업할 수 있을 것...
✅3번째 추천: 참치와 돌고래 | 스토리, 드라마 | 모솔에 금사빠인 현호수영장 그남자에게 또 금세 사랑에 빠지다! 과연 현호의 이번 사랑은 이...
✅4번째 추천: 취사병 전설이 되다 | 스토리, 판타지 | 대한민국 대표 흙수저, 강성재. 불안하기만 한 군생활에 한줄기 빛처럼 다가온 전설의 취사병...
✅5번째 추천: 나란의사 그런의사 | 스토리, 드라마 | 한국에 숨겨진 무병장수마을 치웅리.
그곳에 돈밝히는 속물의사 이대환이 병원을 차렸다!...
# paraphrase-multilingual-MiniLM-L12-v2 모델
query_title = "금수저"
recommended_webtoons = recommend_webtoons(query_title, top_n=6)
# 추천된 웹툰에서 입력한 웹툰(query_title) 제외
if recommended_webtoons is not None:
filtered_recommendations = recommended_webtoons[recommended_webtoons["title"] != query_title].head(5)
for i, row in enumerate(filtered_recommendations.itertuples(), start=1):
print(f"✅{i}번째 추천: {row.title} | {row.genre} | {row.description[:50]}...")
# 응답
✅1번째 추천: 도사 가온 | 스토리, 판타지 | 도사가 되고픈 소년 가온과 무명도사의 도술액션 모험판타지!...
✅2번째 추천: 코끼리를 끌어안는 방법 | 스토리, 드라마 | 조금은 특별하고 서툰ㅡ
만나고 부딪히며 아이들은 성장 해 간다.
<심장이뛰다> 백희정...
✅3번째 추천: 이두나! | 스토리, 로맨스 | (구)아이돌, 첫사랑, 소개팅녀까지 한 집에 모였다! <나노리스트> 민송아 작가의 두근두근...
✅4번째 추천: 아침을 지나 밤으로 | 스토리, 판타지 | 사과나무의 대가로 48일간 아이를 빌려가겠습니다'기묘한 편지와 함께 사라진 동생 녹스를 찾...
✅5번째 추천: 평범한 8반 | 스토리, 드라마 | 안 평범한 아이들이 모인 평범한 8반고품격 웰메이드 병맛을 느껴보세요...
결과를 비교해보면 첫 번째 모델이 genre 유사도가 더 높고, description에 금수저와 관련 된 돈, 흙수저 등이 언급된 웹툰을 추천해주는 등 더 나은 성능을 보였다.
두 모델을 사용해보니 실제로 한국어 데이터셋을 벡터DB에 저장하여 사용하게 된다면 한국어 임베딩에 더 적합한 모델을 찾는 것이 우선 순위라 생각되었다. 또, Spotify나 YouTube Music을 처음 가입 할 때, 사용자가 선호하는 장르와 노래, 가수 등을 선택하도록 하는데 그것과 비슷한 절차로 사용자 최적화가 가능하지 않을까 싶어서 생각해본 방안으로 사용자의 쿼리와 클릭 데이터를 저장하여 유사도를 높여갈 수 있을 것 같다는 생각이 들었다.