➡️ NLP를 이용한 사진 추천 및 이미지 스와핑
📆 2023.08.23. ~ 2023.10.07.
🗨️ Deep daiv. 오픈세미나 | AI 서비스, 기획부터 배포까지
무한도전 사진들은 무한도전이 종영된 지 5년이 넘었지만 여전히 많은 사람들이 이모티콘 혹은 짤로서 이용하고 있다. 또한 무한도전은 13년 동안이나 방영해서 인지 오늘날의 밈들과 겹치는 내용들도 많이 들어 있어 여전히 회자되고 있는 방송이다. 이러한 무한도전 짤을 나의 얼굴로 변경해 준다면 재미있지 않을까 라는 생각으로부터 프로젝트를 시작하게 되었다.
- [NLP] : 사용자의 문장을 바탕으로 무한도전 사진을 추천하는 추천시스템
- [Computer Vision] : 사용자의 사진과 무한도전 사진을 바꾸어 주는 face swapping
- [Deployment] : 웹사이트 상에 실제 도메인으로 배포
-
이 서비스는 단순 상황에 맞는 짤을 골라주기보다는 사용자의 의도에 맞는 짤을 골라주는 것에 초점을 맞추고 있다.
-
즉, 사용자의 키워드 문장에서의 의도가 이미지에 매칭되게 하도록 하는 것이 목표였기에, 일반적으로 사용되는 OCR 기반 딥러닝 모델을 사용하여 자막추출을 하지 않고 다음과 같이 우리만의 방향을 정해 라벨링을 하였다.
얼굴이 못생겼다고 놀리고 있다. | 생일 축하를 받아 고마워 하고 있다. |
우선, 우리는 BERT의 문장 임베딩의 성능을 우수하게 개선시켜 한국어에 적용시킨 Ko-Sentence-BERT 를 기본적인 모델로 사용하였으며,
사용자에게 입력받은 키워드 문장에서의 임베딩 값과, 미리 입력해놓은 라벨 문장의 임베딩 값을 비교하여 더 유사한 문장과 매칭하도록 하기 위해 KoBERT 모델 중 사전학습된 Ko-Sentence-BERT-SKTBERT 의 라이브러리인 ko-sentence-transformers 를 사용하였다.
from sentence_transformers import SentenceTransformer, models, util
from ko_sentence_transformers.models import KoBertTransformer
그리고 우리는 허깅페이스 허브에 업로드된 모델을 간단히 불러와 이를 질문하는 query 와 임베딩된 corpus 로 나누어 가장 각각의 유사도를 나타내고, 상위 몇개의 문장을 추리는 식으로 추천시스템을 구상하였다.
embedder = SentenceTransformer("jhgan/ko-sbert-nli")
Query: 한 남자가 파스타를 먹는다.
한 남자가 음식을 먹는다. (Score: 0.7417)
한 남자가 빵 한 조각을 먹는다. (Score: 0.6684)
한 남자가 말을 탄다. (Score: 0.1089)
한 남자가 담으로 싸인 땅에서 백마를 타고 있다. (Score: 0.0717)
두 남자가 수레를 숲 속으로 밀었다. (Score: 0.0244)
python 모듈로 다운받아 실행하는 insightface 는, 각자의 task를 수행하는 모델들이 딕셔너리로 저장되어 있는 형태로 buffalo 라는 모델을 통해 face detection, face recognition, face alignment, attributes 까지 모두 한번에 얻을 수 있는 모델이다.
app = FaceAnalysis(name='buffalo_l')
faces= app.get(img)
print(faces[0].keys())
retinaface 모델을 사용해서 face detection을 진행해 bounding box를 얻는다. 이후 얻은 bbox를 이용해 landmark_3d_68, landmark_2d_106, genderage, recognition task를 진행하게 된다.
Face alignment = landmark_3d_68, landmark_2d_106
Face swapping = genderage, recognition task
눈,코,입의 위치는 측면에서 특히 face swap을 진행하기 위해 매우 중요하다.
따라서 insightface에서는 alignment 모델이 따로 존재하며, landmark_3d_68는 3d 상의 좌표를 나타내고, landmark_2d_106는 2d 상의 좌표를 나타낸다. 따라서 insightface에서는 이 2개의 모델을 이용해서 2d상의 106개의 얼굴 좌표가 나오고, 3d 상의 68개의 얼굴좌표가 나오게 된다.
Swapping을 진행할 때는 처음 Face detection 을 통해 얻은 FaceAnalysis 객체에서 source image의 ‘embedding’ 값과, target image의 ‘kps’ 값을 조합하여 눈,코,입의 간단한 5개 키포인트 값을 도출하게 된다.그리고 이 값들이 inswapper 모델을 통과하며 fake_image 를 만든 뒤, gaussian blur를 이용하여 얼굴을 자연스럽게 이어주게 되면 우리가 보는 결과물이 나오는 것이다.
inswapper 모델을 통과한 직후의 사진 | gaussian blur로 평탄화 작업이 된 사진 |
우선 기본적인 프레임워크에는 Django를 이용하였고, 웹서버에는 Nginx를 이용하여 정적 파일들을 빠르게 처리하였고, 이 Web Server 과 Django 를 연결시켜주는 WSGI 는 uWSGI 를 사용하였다.
이미지와 같은 데이터는 Amazon S3 를 통해, 기본적인 도메인 및 서비스는 AWS 의 EC2 서버를 이용하였고, 빠른 배포와 환경설정을 위해 Docker 를 통해 배포하였다.
![](https://private-user-images.githubusercontent.com/92140163/272888573-2b1c7e55-5e4a-463e-a7a2-92dbad234cb8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU5MzgyNzksIm5iZiI6MTcyNTkzNzk3OSwicGF0aCI6Ii85MjE0MDE2My8yNzI4ODg1NzMtMmIxYzdlNTUtNWU0YS00NjNlLWE3YTItOTJkYmFkMjM0Y2I4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTEwVDAzMTI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdiYWNlNTc0NWYxZGJjNDYzYzA2MzM4OWM0MmFmYjM3ZWFlNmI4OTY2ZTQ5YTM2ZWMyZTVkYjY3MmRlNDYwNWMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.xddse9iR1e6ngrK0feBp21UANAjtd5gKjuijyEDyPZM)
![](https://private-user-images.githubusercontent.com/92140163/272888891-21d73bcb-e695-455d-8fe0-a646c47fd8f5.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU5MzgyNzksIm5iZiI6MTcyNTkzNzk3OSwicGF0aCI6Ii85MjE0MDE2My8yNzI4ODg4OTEtMjFkNzNiY2ItZTY5NS00NTVkLThmZTAtYTY0NmM0N2ZkOGY1LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTEwVDAzMTI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0ODFiOWYxMGQyNTM3YzY0OWJhMTg2ZmYwZTIzNmFmMWNhODVmYTc3MDM3NjljOWE4ZTI2NjMwZmJmMmJkZGQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.e3zxLIfOV6xcE_u9P1oZ-ei26yueE_akhtleYVe4vyw)
![](https://private-user-images.githubusercontent.com/92140163/272889008-4dfd4f7f-6693-4b75-b596-323e1a8b9c29.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU5MzgyNzksIm5iZiI6MTcyNTkzNzk3OSwicGF0aCI6Ii85MjE0MDE2My8yNzI4ODkwMDgtNGRmZDRmN2YtNjY5My00Yjc1LWI1OTYtMzIzZTFhOGI5YzI5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTEwVDAzMTI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQwNDZlZjMwN2MwZjllZWFhMjQ4YzEzNWM4NDVlM2RiMzUyOWZjZTU0MThmMGQyOWZmZDU1YjcyYmY1M2VjOTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.QBihpptjrBooITNj9DANgGx8fkVwYhBv6F8d97Wu0Jk)
![](https://private-user-images.githubusercontent.com/92140163/272889129-dd9fcde3-abd3-4e3b-bd93-bbb4736f6649.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU5MzgyNzksIm5iZiI6MTcyNTkzNzk3OSwicGF0aCI6Ii85MjE0MDE2My8yNzI4ODkxMjktZGQ5ZmNkZTMtYWJkMy00ZTNiLWJkOTMtYmJiNDczNmY2NjQ5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTEwVDAzMTI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRlNTU2YmUxN2YyMWY0NTI0OTAxYTNjYzZlMzIwOWVmMmY5N2RiZmZiM2M4MzY1M2E4MjBkZDdkYmZiZjVlNzcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.H0wd6glG0sT76Vaws2XgVwDWFPPwR75qCmoZTBHYMKs)
![](https://private-user-images.githubusercontent.com/92140163/272889184-499f530e-9ac2-4d46-990e-9c6978cd711e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU5MzgyNzksIm5iZiI6MTcyNTkzNzk3OSwicGF0aCI6Ii85MjE0MDE2My8yNzI4ODkxODQtNDk5ZjUzMGUtOWFjMi00ZDQ2LTk5MGUtOWM2OTc4Y2Q3MTFlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTEwVDAzMTI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTM2YjUyNWY0YmU4MGYxNGI2Nzg0NjQ5NDhhNWI1YTcyYjY4ODVjYWI0N2VmOGU2ODliMzEyM2JkYjMxZDNmMTImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.5Io7soy1BdmX2KlqZ6RSq0ZRQvfgCw6M99LFgc0_oOA)