DeepSVG: A Hierarchical Generative Network for Vector Graphics Animation

💡 논문 내용이 너무 재밌고 인상깊어서 이전과는 다르게 단순 논문 요약이 아닌 이해하기 위해 발악하며 정리한 내용입니다.

NeurIPS 2020에 Accepted된 논문이다. 더 자세한 내용은 링크 참조하자.

Abstract

Scalable Vector Graphics(SVG)는 rasterized한 image인 .png, .jpg와 다르게 해상도의 변화를 주어도 그에 맞춰서 scale될 수 있다. 그래서 SVG는 이미지 작업에 있어서 유용하게 사용된다. 그러나 SVG는 rasterized image와 달리 deeplearning 분야에 아직까지는 잘 적용되고 있지 못하다. 단순한 pixel 형식이 아니기 때문에 기존 image들 보다는 다루기가 꽤 까다롭기 때문이다.

이 논문에서는 SVG icons을 Deeplearning model에 적용시켜 generation과 interpolation을 할 수 있는 DeepSVG를 소개한다. Interpolation은 보간법이라 하며, 연속적 변수 가운데 그 사이의 변수값에 대한 함수값을 구할 수 있게 하는 것이다. 말이 꽤 어려운데 그림으로 설명하자면,

image

왼쪽과 오른쪽의 svg icon이 각각 있을 때, 그 둘을 적당히 짬뽕시킨 중간 산물들을 만들 수 있다는 것이다.

1. Introduction

Vector Image는 보통 2D shape의 list 형태로 표현된다. 각 2D shape들은 parametric curve로 연결된 2D point들의 sequence으로 encoding된다. sequence로 encoding 되기 때문에 NLP Task랑 비슷하게 접근하면 되지 않을까? 할 수도 있다. 하지만 둘 간의 큰 차이점이 있는데 바로, SVG image는 permutation invariance하다는 것이다.

permutation invariance란, sequence 또는 sequence를 이루는 token 간의 위치가 바뀌어도 output은 동일하다는 것이다. NLP에서 다루는 sequence는 그렇지 않다. I am 13, you are 14. 이라는 문장과 I am 14, you are 13. 이라는 문장의 의미는 다르다.

SVG Image에서 sequence의 위치는 상관이 없다. 결국 그 sequence들이 한번에 모여 2D image를 이루기 때문이다.

논문에서는 Hierarchical Transformer-based architecture를 이용해 vector graphic을 다룬다. Encoder는 각 shape들을 개별적으로 encoding하고 이를 이용해 latent vector \(z\)를 생성한다. Decoder는 \(z\)를 가지고 각 shape들을 predict하게 된다. 각 shape들은 합쳐지면서 하나의 SVG image를 생성한다.

image

model의 중요한 특징은 Decoding을 non-autoregressively하게 한다는 점이다.

위 사진의 (a)는 Encoding 시에 image를 다 때려넣고 Decoding할 때는 하나하나 씩 autoregressive하게 한다. 이들이 제안하는 모델(b)은 Encoding 시에 2D shape마다 각각 encoder에 넣어주고 Decoding시에는 한번에 output이 나오게 된다.

2. DeepSVG

2.1. SVG Dataset and Representation

SVG-Icons8 Dataset. 제대로 된 SVG Dataset이 없었는데 자기들이 56개 카테고리, 총 100,000개 SVG 데이터 만들었다고 얘기하는 거다.

SVG Representation. SVG Image는 path들의 set으로 이루어져 있으며, 각 path는 특정 draw-command의 seqeunce로 이루어진다. 예를 들어 위 사진의 두 개의 말풍선이 있는데, 각 말풍선이 하나의 path이며 각 path는 점으로 split되어 있다. 이렇게 split된 곡선들이 하나의 draw-command가 된다.

Draw-command를 well-defined하였고, representation은 밑의 표를 참고하자.

image

수식으로 Vector graphic image \(V\)를 표현하자면, 다음과 같다.

\[V=\{P_{1},\dots,P_{N_{P}}\}\]

\(P_{i}\)는 path를 의미하며, 이는 또 다음과 같이 표현된다.

\[P_{i} = (S_{i}, f_{i}, v_{i})\]

\(v_{i} \in \{0,1\}\)는 이 path가 visible한 것인지 나타낸다. image에서 visible하지 않다면 왜 있는거지? 싶겠지만 이유는 뒤에서 나온다.

\(f_{i} \in \{0,1,2\}\)는 이 path 내부를 색깔로 칠하는 건지 나타낸다. 각 value는 outline, fill, erase에 mapping된다. erase는 path들이 겹쳤을 때, 용이하게 사용될 수 있을 것이다.

\(S_{i}\)는 command들의 sequence로 표현된다.

\[S_{i}=(C_{i}^{1},\dots,C_{i}^{N_{c}})\]

\(C_{i}^{j}\)는 command로 다음과 같이 표현된다.

\[C_{i}^{j} = (c_{i}^{j},X_{i}^{j})\]

\(c_{i}^{j} \in \{ \text{<SOS>},m,l,c,z,\text{<EOS>}\}\)는 command type을 나타내며, \(X_{i}^{j}=({q_{x_{1}}^{j}}_{,i},{q_{y_{1}}^{j}}_{,i},{q_{x_{2}}^{j}}_{,i},{q_{y_{2}}^{j}}_{,i},{x_{2}^{j}}_{,i},{y_{2}^{j}}_{,i}) \in \mathbb{R}^{6}\)는 argument list이다. 위의 테이블을 보면 최대 argument가 6개라 \(\mathbb{R}^{6}\) space를 사용하게 되는 것이다. 사용하지 않는 argument를 -1로 set한다.

이처럼 효율적인 parallel processing을 위해, \(N_{P}\), \(N_{C}\)를 fixed number로 사용하는데 이러기 위해 visible을 체크해주는 varaible이 있는 것이다! Image에 path가 2개뿐인데, \(N_{P}\)가 10으로 설정되어 있다면, 나머지 8개의 path는 아무 값이나 적어놓고 \(v_{i}\)를 0으로 set해주면 된다. NLP에서 padding 해주는 메커니즘과 동일하다고 보면 된다.

2.2. SVG Embedding

각 \(C_{i}^{j}\)는 dimension \(d_{E}\) space에 embedding 시켜준다. Embedding vector \(e_{i}^{j} \in \mathbb{R}^{d_{E}}\)는 3개 embedding 합으로 이뤄진다.

\[e_{i}^{j} = {e_{cmd}^{j}}_{,i} + {e_{coord}^{j}}_{,i} + {e_{ind}^{j}}_{,i}\]

Command embedding. Command type이 6차원 one-hot vector \(\delta_{c_{i}^{j}}\)로 encoding되어 \(W_{cmd} \in \mathbb{R}^{d_{E}\times 6}\)에 project된다.

\[{e_{cmd}^{j}}_{,i} = W_{cmd} \delta_{c_{i}^{j}}\]

Coordinate embedding. Input 좌표를 8bit로 양자화시킨다.(0~255) 또한 좌표 argument를 사용하지 않는 경우도 추가하여 총 257차원 space로 embedding해준다. 각 좌표는 weight matrix \(W_{X} \in \mathbb{R}^{d_{E} \times 257}\)를 통해 embedding되며, 좌표가 총 6개이므로 concatenate하면 \(6d_{E}\) 차원 vector가 되며, 이를 다시 \(W_{coord} \in \mathbb{R}^{d_{E} \times 6d_{E}}\)를 통해 embedding시킨다.

\[{e_{coord}^{j}}_{,i}=W_{coord}\text{vec}(W_{X}X_{i}^{j})\]

Index embedding. 주어진 sequence에서 command의 위치를 표시하는 vector로 one-hot vector \(\delta_{j} \in \mathbb{R}^{N_{S}}\)를 \(W_{ind} \in \mathbb{R}^{d_{E} \times N_{S}}\)를 통해 embedding시킨다.

\[{e_{ind}^{j}}_{,i}=W_{ind} \delta_{j} \in \mathbb{R}^{d_{E}}\]

2.3 Hierarchical Generative Network

제안하는 Network는 variational auto-encoder(VAE)이다. VAE와 AE의 차이점을 잘 모르고 있었는데, 이 블로그 보고 이해했으니 참고하면 좋다.

Feed-forward prediction. 모든 path에 대해 우리는 \(C_{i}^{j}\)를 predict하게 되며, 이는 non-autoregressively하게 이뤄진다. 우리의 generative model은 다음과 같이 factorized 된다.

\[\begin{aligned} p(\hat{V}|z, \theta)&=\prod_{i=1}^{N_{P}}p(\hat{v_{i}}|z,\theta)p(\hat{f_{i}}|z,\theta)p(\hat{S_{i}}|z,\theta)\\ &=\prod_{i=1}^{N_{P}}p(\hat{v_{i}}|z,\theta)p(\hat{f_{i}}|z,\theta)\prod_{j=1}^{N_{C}}p(\hat{c_{i}^{j}}|z,\theta)p(\hat{X_{i}^{j}}|z,\theta) \end{aligned}\]

식을 보면, 순서 상관없이 다 곱해지니 permutation invariance라는 것을 알 수 있다. \(z\)는 latent vector이다.

image

Encoder. 각 path \(P_{i}\)는 path encoder \(E^{(1)}\)에 의해 encoding된다. output으로 \(({e^{\prime}}_{i}^{j})_{j=1}^{N_{C}}\)이 나오고 이를 average-pool 해주어 \(u_{i}\)를 생성한다. 생성된 \(u_{i}\)들이 encoder \(E^{(2)}\)의 input으로 들어가고 output으로 Gaussian distribution인 \(\hat{\mu}\), \(\hat{\sigma}\)가 나온다. 이 distribution으로 latent vector \(z\)가 도출된다.

Decoder. Decoder \(D^{(2)}\)는 \(z\)를 받아 각 path encoding \(\hat{u_{i}}\), \(\hat{f_{i}}\), \(\hat{v_{i}}\)를 predict한다. Decoder \(D^{(1)}\)는 \(\hat{u_{i}}\)를 \((\hat{C_{i}^{1}},\dots,\hat{C_{i}^{N_{C}}})\)로 decoding한다.

위의 사진의 \(\pi\)는 Permutation Matrix로 ground truth와 predict의 order가 맞지 않을 때, Loss 계산 시 path들을 잘 짝지어 주기 위함이다.

2.4. Training Objective

Training loss는 다음과 같다.

image

\(l\)은 Cross-Entropy loss이며, \(v_{i}\), \(S_{i}\), \(f_{i}\) 각각 loss에서 가중치 \(w\)가 부여된다. 오른쪽 항에 \(v_{i}\)가 붙어있는 이유는 visible한 path에 대해서만 loss를 계산하기 위함이다. 식이 굉장히 직관적이라 좋았다.

Loss를 제대로 계산해주기 위해서는 식에서 \(\hat{i}\)와 \(i\)가 의미하는 path가 동일해야 한다. 즉, \(i=\pi(\hat{i})\)을 만족시켜야 한다. 제대로 permutation을 안해주면 이전 그림에서 큰 말풍선하고 작은 말풍선을 비교해버리는 오류가 발생할 수 있다. \(\pi\)를 어떻게 정의하는 지 논문에서 2가지 방법을 제시한다.

Ordered assignment. \(\pi\)를 특정 기준으로 ground-truth path를 sorting하여 정의한다. 논문에서는 path들의 시작 위치를 기준으로 sorting하여 좋은 결과를 냈다고 한다. Ordered assignment \(\pi_{ord}\)를 사용하면 최종 Loss는 다음과 같다.

\[L(\theta)=w_{KL}KL(p_{\theta}(z)||\mathcal{N}(0,I)) + \sum_{i=1}^{N_{P}}L_{\hat{i},\pi_{ord}(\hat{i})}(\theta)\]

첫번째 항은 \(p_{\theta}\)가 Gaussian distribution을 추종하기 위해 KL divergence를 사용하는 것 같다.(추측임..)

Hungarian assignment. \(\hat{i}\)와 \(i\)가 의미하는 path가 동일할 때, loss가 가장 작을 것이다. 그러니 모든 \(\pi\)에 대해 loss를 계산해보고 loss 값이 minimum인 것으로 계산해주면 된다.

(언뜻봐서는 위의 방법보다 많이 비효율적일 것 같다. 그래서 그런지 결과가 위보다는 좋지 않다.)

\[L(\theta)=w_{KL}KL(p_{\theta}(z)||\mathcal{N}(0,I)) + \min_{\pi \in S_{N_{P}}}\sum_{i=1}^{N_{P}}L_{\hat{i},\pi(\hat{i})}(\theta)\]

Training details. AdamW optimizer를 사용했고, dropout, gradient clipping도 적용하였다. 2개 gpu로 하루 정도 걸렸다고 한다.

3. Experiments

image

사람한테 위의 네개의 모델을 각각 사용해 생성한 interpolation을 보여주고 rank를 매기게 하였다. 표를 보다시피 Ordered assignment를 쓴 DeepSVG가 1등을 가장 많이 차지하였다. 개인적으로 이런 식으로도 evaluation한다는 게 신박했다. 항상 public dataset을 가지고 SOTA랑 비교해야 되는 줄 알았는데..

Quantitative measure를 하기 위해 2가지 metric을 제안한다.

Reconstruction Error. \(RE=d_{Chfr}(V,\hat{V})\)

\[d_{Chfr}(V,\hat{V})=\cfrac{1}{N_{P}}\sum_{i=1}^{N_{P}}\min_{j}\int_{t}\min_{\tau}||P_{i}(t)-\hat{P_{j}}(\tau)||_{2}dt\]

사실 이 식은 제대로 이해못했다.. 바깥의 \(\min_{j}\)부분은 어떤 path끼리가 pair인지 모르니 그냥 다 비교하고 minimum을 계산한다는 의미이다.

Interpolation Smoothless. IS는 다음과 같이 정의된다.

\[IS = \sum_{k=1}^{M}d_{Chfr}(V^{\alpha_{k-1}}, V^{\alpha_{k}}), \alpha_{k}=k/M\]

말그대로 이전 state에서 다음 state로 갈때 smooth하게 넘어가는 지를 \(d_{Chfr}\)로 계산하는 것이다.

두 Measure에서도 모두 Ordered assignment를 쓴 DeepSVG가 우세함을 볼 수 있었다.

image

네 개의 SVG Icon 사이에서 interpolation된 결과를 보면 참 신기하다.

Interpolation이 smooth하게 일어나면 그림을 그려놓고 두 그림을 자연스럽게 연결시켜서 아래와 같이 animation을 만들수도 있다!

image

또한 아래와 같이 latent vector 간의 연산을 통해 feature를 뽑아내어 manipulate할 수 있다.

image

4. Conclusion

Hierarchical Network로 SVG icon interpolation과 manipulation을 성공적으로 수행하였다. 이것은 image vectorisation, style transfer, classification, animation 등 여러 많은 task에 적용될 것으로 기대된다. SVG representation도 잘 되어서 이 모델을 base로 더 많은 연구가 이뤄지면 좋겠다.

References

[1] DeepSVG: A Hierarchical Generative Network for Vector Graphics Animation


Comments

친구가 또 던져줬던 논문이었고 너무 어려워 보여서 안 읽을까 했는데 시간이 좀 여유로워서 읽을 수 있었다. 논문 포스팅을 안한지 3달이 되었고 별로 하기 귀찮아서 얘도 그냥 읽고 넘어가려고 했었는데 주제가 너무 재밌고 그에 반해 한국어로 정리된 포스팅이 없어서 내가 작성해야겠다고 맘먹었다. Image 분야 Task는 항상 raster image를 다뤘었는데 svg 다루는 것을 제안하는 게 너무 신박했다. 정말 처음보는 내용들 투성이라 다 재밌었다. 특히, Loss 계산식이 직관적으로 이해되어서 좋았고 제안한 measure도 그럴듯 했다. 단순한 논문 요약이 아닌 정리라서 거의 3-4시간 걸린 것 같다. 그래도 내용이 재밌어서 즐겁게 할 수 있었다. 정말 저자가 말한대로 아직 explorable한 부분이 많다고 느껴져서 아이디어가 샘솟기를 바라고 있다.