2018년 8월 6일 월요일

내가 왓챠플레이를 만든다면 - 개인별 예고편

내가 왓챠플레이를 만든다면, 특히 예고편을 만든다면 어떤 단계를 거쳐야 할까 좀 더 생각해 보았다.

일단 영상 전체에서 각 장면을 구분해야 된다. 장면이 구분되고 나서야 그 장면이 어떤 성격이고, 사용자 취향에 맞는지 어떤지 판단할 수 있다.
장면을 정의한다면, 영상이란 프레임의 연속이고, 각 프레임마다 분석해서 프레임의 성격이 크게 바뀌는 시점마다 나누었을 때 그 조각들을 장면이라고 할 수 있다.

가장 먼저, 프레임을 나누어야 한다. 간단하게 ffmpeg 명령을 써서 동영상을 이미지 파일로 저장했다. (https://www.wired.com/2014/09/cinema-is-evolving/ 기사에 따르면 영어권 영화에서 한 장면은 평균 12초 길이에서 2.5초 길이로 바뀌었다고 한다. 이미지 파일은 짧게 잡아도 2초당 한 번이면 충분할 것이다)
$ ffmpeg -i 동영상파일 -r 1 (혹은 -vf fps=1/2) -f image2 image-%4d.jpeg
저장된 이미지들을 분석해서 어떤 성격인지 구분하는 건 tensorflow의 이미지 인식 튜토리얼에 있는 classify_image.py를 써보았다.
$ pip3 install tensorflow # tf 미설치 상태라면
$ git clone https://github.com/tensorflow/models
$ cd models/tutorials/image/imagenet/
$ for f in image*.jpeg; do logfile=output.$(basename $f); python3 classify_image.py --image_file=$f > $logfile; done

사실 tensorflow보다 먼저 떠오른 건 Google의 Vision API였지만, 분석할 갯수가 아주 많은데 외부 API를 쓴다는 건 시간과 비용면에서 도저히 선택할 수 없는 방법이어서 접었다. tensorflow는 희미한 개념만 알 뿐 잘 다뤄본 적이 없어서, 아마 결과물의 품질이나 신뢰도가 높지는 않을 거라고 생각하지만, 일단 샘플이니까.

한참 돌아가고 나면 output.* 파일에 아래와 같이 그 이미지의 속성이 분석된 걸 확인할 수 있다.
$ cat output.image-1000.jpeg
sewing machine (score = 0.59451)
restaurant, eating house, eating place, eatery (score = 0.04678)
tank, army tank, armored combat vehicle, armoured combat vehicle (score = 0.02917)
desk (score = 0.02453)
dining table, board (score = 0.01770)
$ cat output.image-1713.jpeg
sock (score = 0.22062)
sandal (score = 0.17339)
clog, geta, patten, sabot (score = 0.15232)
shoe shop, shoe-shop, shoe store (score = 0.01656)
Loafer (score = 0.01599)

개별 파일로 뒀더니 눈에 잘 들어오지 않기도 하고, 2차원으로 가공하기 위한 전 단계로, 한 파일로 합쳤다.

for f in output.*; do N=$(echo $f | sed 's/[^0-9]//g'); cat $f | grep -v "^$" | sed 's/\(.\+\) (score = \(.\+\))/\2\t\1/' | sed "s/^/$N\t/"; done > linear.data


이제 이 값들을 시간순으로 비교해서 연속된 장면인지 아닌지 판단할 차례인데, 어떤 방법을 써야 좋을지 잘 모르겠다. 처음부터 비지도 학습으로 막 계산만 하는 건 적절하지 않으니 초반에는 지도 학습을 위해 프레임이 장면으로 분절되는 걸 사람이 인식할 수 있는 형태로 보여줘야 할 텐데, 그러려면 시각화 방법 중에 어떤 걸 써야 하는 걸까? 아마도 항상 100% 높이를 가지면서 구성요소의 비율을 보여주는 걸 1차원으로 죽 나열하는 게 좋을 것 같다. (percent stack area chart 정도의 명칭인 것 같다) 변곡점이나 분포가 크게 바뀌는 지점을 기준으로 분절을 나누면 되겠지. score가 너무 낮은 건 그 프레임이 어떤 장면인지 파악할 때 영향이 낮게 계산되어야 할 텐데 얼마나 낮아야 낮은 건지도 사람이 개입해야 하는 지점일 것 같다.

시간축과 그 시간마다의 속성 배분을 2차원으로 나열해서 그래프로 그리면 되겠지 싶었다. 문제는 그래프로 그렸을 때 보기 쉽게 하려면 나름대로 연속과 단절이 눈에 띄도록 해야 될 텐데 손으로 직접 짜기엔 마땅히 떠오르는 방법이 없다. 무슨 그래프를 그리면 되는지 정확히 안다면 그런 그래프를 지원하는 도구를 찾으면 되겠지만 그것도 아니고.

어쩌면 word2vec 정도를 가져와서 돌려보면 뭔가 결과가 나올 것 같긴 한데, 이것도 개념만 대충 알고 다뤄본 적은 없어서 잘 모르겠다.
그러고보니 예전에 이런 비슷한 구현체 소식을 들은 것도 같은데 뭐였더라. https://github.com/ryanjay0/miles-deep 이건 것 같다. 포르노 장면마다 무슨 장면인지 구분해주는 물건. 뭘로 학습을 시키면 나오는 모델이려나. 2차 시료인 텍스트를 매개로 구분하는 것보다는 영상 자체를 구분하는 게 훨씬 좋긴 하겠다.
왜 진작 검색을 안해봤나 모르겠네. https://blog.coast.ai/five-video-classification-methods-implemented-in-keras-and-tensorflow-99cad29cc0b5 이런 게 있다. 프레임마다 나눠서 자료를 준비하는 건 같고 그 중에서 학습 자료와 검증 자료를 둬서 모델을 만드는 게 다르다. 가고 있는 방향은 맞다는 얘기라고 생각해도 되려나.