diff --git a/GAN/10.png b/GAN/10.png new file mode 100644 index 0000000..80e7e88 Binary files /dev/null and b/GAN/10.png differ diff --git a/GAN/11.png b/GAN/11.png new file mode 100644 index 0000000..a180803 Binary files /dev/null and b/GAN/11.png differ diff --git a/GAN/12.png b/GAN/12.png new file mode 100644 index 0000000..b135bfe Binary files /dev/null and b/GAN/12.png differ diff --git a/GAN/13.png b/GAN/13.png new file mode 100644 index 0000000..c35c00e Binary files /dev/null and b/GAN/13.png differ diff --git a/GAN/14.png b/GAN/14.png new file mode 100644 index 0000000..6fadab6 Binary files /dev/null and b/GAN/14.png differ diff --git a/GAN/8.png b/GAN/8.png new file mode 100644 index 0000000..1994ea4 Binary files /dev/null and b/GAN/8.png differ diff --git a/GAN/9.png b/GAN/9.png new file mode 100644 index 0000000..1d9984e Binary files /dev/null and b/GAN/9.png differ diff --git a/GAN/GANs.ipynb b/GAN/GANs.ipynb index 27bfcbc..46d42e4 100644 --- a/GAN/GANs.ipynb +++ b/GAN/GANs.ipynb @@ -26,7 +26,7 @@ "### 정보 엔트로피Information Entropy\n", "
\n", "
\n", - "어떤 확률변수 $X$와 확률분포 $P(X=x)$가 있을 때 확률변수값을 예측하기 위해 고려해야할 정보의 양을 나타내기 위한 개념으로 엔트로피를 사용합니다. 예측을 위해 고려해야할 사항이 많다면, 즉, 불확실성이 크다면 엔트로피는 큰것입니다. 시스템의 질서가 너무 잘 잡혀 있어서 쉽게 예측 가능하다면 무질서도가 낮아 엔트로피가 낮은 것입니다. 정보이론에서 이를 어떻게 정의하는지 실례를 들어 간단하게 알아보도록 하겠습니다. \n", + "어떤 확률변수 $X$와 확률분포 $P(X=x)$가 있을 때 '확률 분포에 담긴 불확실성의 한 척도'의 개념으로 엔트로피를 사용합니다. 그 확률 분포를 따르는 확률변수의 값을 예측하기 위해 고려해야할 사항이 많다면, 즉, 불확실성이 크다면 엔트로피는 큰것입니다. 시스템의 질서가 너무 잘 잡혀 있어서 쉽게 예측 가능하다면 무질서도가 낮아 엔트로피가 낮은 것입니다. 정보이론에서 이를 어떻게 정의하는지 실례를 들어 간단하게 알아보도록 하겠습니다. \n", "아래 내용은 칸아카데미 정보엔트로피 강의 [1]를 참고하여 작성하였습니다. \n", "
\n", "어떤 시스템이 1, 2, 3, 4를 출력하는데 숫자 4개가 아래 그림처럼 배치되어 있고, 한번에 해당 숫자에 불 들어온다고 합시다. 1000번정도 시행해 봤더니 1, 2, 3, 4 모두 딱 250번씩 출력했다고 가정합니다. 이 시스템은 1, 2, 3, 4 라는 실수값에 함수값 0.25를 할당하는 확률질량함수 $P(X)$를 확률 분포로 가지는 이산확률변수 $X$ 라고 할수 있습니다. 1001번째 숫자가 출력 되었을 때 이 숫자가 무엇인지 알아내기 위해 우리는 어떤 것을 고려해야 할까요? 다시 말해 어떤 질문들을 던져야 할까요? 가장 쉽게는 1인가요? 2인가요? 3인가요? 라고 3번 묻는다면 그중 한번은 정답을 줄것입니다. 운이 좋다면 한번에 맞추고 운이 나쁘다면 3번이나 질문을 해야 합니다. 하지만 시스템은 정확히 동일한 확률로 숫자를 출력하므로 이렇게 물어 볼 수 있습니다. \n", @@ -141,7 +141,9 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -163,8 +165,8 @@ "random.shuffle(P)\n", "q = q2 = 0\n", "\n", - "#천개만 뽑아서 질문을 한다.\n", - "#H(P)\n", + "#1000개만 뽑아서 질문을 한다.\n", + "#위에서 H(P)를 구할 때 처럼 1또는 2입니까? 를 먼저 질문한다.\n", "for x in P[:1000] :\n", " q2 += 1\n", " if x == 1 or x == 2: \n", @@ -184,11 +186,12 @@ "\n", "print(\"H(P(X)) = {}\".format(q / 1000))\n", "\n", + "#50%, 12.5%, 12.5%, 25%로 샘플을 만들고 \n", "Q = [1]*1000 + [2]*250 + [3]*250 + [4]*500\n", "random.shuffle(Q)\n", "q = q2 = 0\n", "\n", - "#H(Q)\n", + "#위에서 H(Q)를 구할 때 처럼 1번입니까? 4번입니까? 순으로 질문한다.\n", "for x in Q[:1000] :\n", " q2 += 1\n", " if x == 1 :\n", @@ -210,6 +213,7 @@ "\n", "q = q2 = 0\n", "\n", + "#동일한 비율로 숫자가 존재하는 샘플 P를 대상으로 Q방식으로 질문한다.\n", "#H(P,Q)\n", "for x in P[:1000] :\n", " q2 += 1\n", @@ -305,7 +309,9 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -340,7 +346,9 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -491,17 +499,19 @@ "
\n", "GANs를 살짝 맛보기 위해서 정규분포를 근사하는 문제를 풀어보겠습니다. 인터넷에 이미 시도된 몇몇 글 \n", "GANs in 50 lines of code (PyTorch)[4], \n", - "tensorflow-GAN-1d-gaussian-ex-hwalsuklee[5], \n", - "아주 간단한 GAN 구현하기-홍정모[6]을 볼 수 있습니다. 해결해야하는 문제는 임의의 평균과 표준편차를 가지는 정규분포로 부터 획득된 학습데이터만을 가지고(평균과 표준편차는 뭔지 모름) 그 데이터의 분포를 흉내내는 모델을 만드는 것입니다. 쿨벡-라이블러 발산을 코스트로한 예제에서는 추정해야하는 모델이 정규분포라는 것을 알고 또 조정하는 설계변수가 평균과 표준편차라는 것을 알고 그것을 조절해서 최적화를 수행하였습니다. 하지만 GANs는 흉내내야하는 모델의 설계변수등 아무런 정보없이 단지 그 모델로 부터 획득된 데이터만 사용하여 그 모델처럼 동작하는 모델을 만들어내는 것입니다. 기본개념은 위 확률분포 최적화 문제와 같지만 훨씬 일반화된 상태로 문제를 풀어나갑니다. \n", + "tensorflow-GAN-1d-gaussian-ex-이활석[5], \n", + "아주 간단한 GAN 구현하기-홍정모[6]을 볼 수 있습니다. 해결해야하는 문제는 임의의 평균과 표준편차를 가지는 정규분포로 부터 획득된 학습데이터만을 가지고(평균과 표준편차는 뭔지 모름) 그 데이터의 분포를 흉내내는 모델을 만드는 것입니다. 쿨벡-라이블러 발산을 코스트로한 예제에서는 추정해야하는 모델이 정규분포라는 것을 알고 또 조정하는 설계변수가 평균과 표준편차라는 것을 알고 그것을 조절해서 최적화를 수행하였습니다. 하지만 GANs는 흉내내야하는 모델의 설계변수등 아무런 정보없이 단지 그 모델로 부터 획득된 데이터만 사용하여 그 모델처럼 동작하는 모델을 만들어내는 것입니다. 기본개념은 위 확률분포 최적화 문제와 같지만 훨씬 일반화된 상태로 문제를 풀어나갑니다. \n", "\n", - "GANs를 numpy만으로 구현하기에는 코드양이 꽤 되고 GPU의 힘을 빌리지 않고는 훈련시키기에 많은 인내가 필요하므로 케라스를 쓰도록 하겠습니다. 우선 필요한 모듈을 로딩하고 보조 함수를 만듭니다. GAN은 D와 G를 따로 훈련시키는데 Ian Goodfellow의 최초 GANs 논문[6]에 의하면 G를 훈련할 때 D는 훈련하지 않습니다. 케라스에는 모델과 레이어에 trainable이라는 속성을 제공합니다. 이 속성을 false 또는 true로 만드는 보조함수 make_trainable을 정의합니다.[8] (https://github.com/osh/KerasGAN)\n", + "GANs를 numpy만으로 구현하기에는 코드양이 꽤 되고 GPU의 힘을 빌리지 않고는 훈련시키기에 많은 인내가 필요하므로 Keras를 쓰도록 하겠습니다. 우선 필요한 모듈을 로딩하고 보조 함수를 만듭니다. GAN은 D와 G를 따로 훈련시키는데 Goodfellow et al[7]에 의하면 G를 훈련할 때 D는 훈련하지 않습니다. Keras에는 모델과 레이어에 trainable이라는 속성을 제공합니다. 이 속성을 false 또는 true로 만드는 보조함수 make_trainable을 정의합니다.[8] (https://github.com/osh/KerasGAN)\n", "
" ] }, { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stderr", @@ -578,10 +588,9 @@ "metadata": {}, "source": [ "
\n", - "이후 모델을 생성합니다. 생성할 모델은 D와 G 그리고 이 둘이 중첩된 모델 GAN을 생성합니다. \n", - "모델 정의를 위해 우선 GAN에 대한 기초 구조를 이야기 하도록 하겠습니다. \n", - " 어떤 확률변수 $\\boldsymbol{X}$가 있어서 이 변수가 어떤 데이터를 나타낸다고 합시다. 쉬운 예로 28x28 픽셀의 사람 얼굴이라면 요소를 784개 가지는 벡터로 생각할 수 있고 $\\boldsymbol{X}$는 그 벡터를 값으로 가지는 확률 변수가 됩니다. 784개의 요소에 아무값이나 집어 넣은 임의의 벡터 $\\boldsymbol{x}$는 사람 얼굴이 아닐 것입니다. 하지만 어떤 규칙에 의해 784개의 값을 적당히 잘 지정하면 벡터 $\\boldsymbol{x}$는 사람얼굴 처럼 보일 수 도 있습니다. 여기서 어떤 규칙 즉, 확률변수 $\\boldsymbol{X}$가 얼굴로 보이는 $\\boldsymbol{x}$를 가질 확률을 나타내는 확률분포 $p(\\boldsymbol{X})$가 있을 수 있습니다. 존재할 수 있는 모든 길이 784짜리 벡터가 모여있는 공간에는 사람 얼굴처럼 보이는 $\\boldsymbol{x}$도 있고 전혀 아닌 $\\boldsymbol{x}$도 있는데 어떤 확률변수 $\\boldsymbol{X}$가 이들 표본을 가질 때 얼굴을 닮은 $\\boldsymbol{x}$에 대해서 높은 확률을 부여하는 $p(\\boldsymbol{X}=\\boldsymbol{x})$가 존재한는 것입니다. $\\boldsymbol{x}$가 $p(\\boldsymbol{X})$에 따르면 즉, $\\boldsymbol{x} \\sim p(\\boldsymbol{x})$이면 $\\boldsymbol{x}$는 사람 얼굴이 될 것입니다. 문제는 $p(\\boldsymbol{X})$가 무엇인지 전혀 알지 못합니다. 다만 $\\boldsymbol{x} \\sim p(\\boldsymbol{X})$인 $\\boldsymbol{x}$ 여러개는 가질 수 있습니다. 바로 우리가 모은 데이터입니다. 이 데이터를 이용하여 입력된 $\\boldsymbol{x}$가 $p(\\boldsymbol{X})$에서 추출된 것인지 아닌지를 구별하는 D를 만들고, $\\boldsymbol{x}$를 무작위로 만들어 D에게 검사를 받는 G를 만들어 둘을 훈련시키는 네트워크가 GANs입니다. 여기서 $p(\\boldsymbol{X})$가 무엇인지 전혀 알지 못하므로 모아둔 데이터의 분포를 나타내는 $p_{\\text{data}}(\\boldsymbol{X})$를 생각 해볼 수 있습니다. $p_{\\text{data}}(\\boldsymbol{X})$는 $p(\\boldsymbol{X})$와 완전히 같지는 않겠지만 우리가 할 수 있는 최선입니다. 그리고 G도 어떤 규칙으로 데이터를 만들어 낼테니까 G에서 생성되는 데이터의 확률분포 $p_{g}(\\boldsymbol{X})$를 생각해 볼 수 있습니다. 이제 $p_{\\text{data}}(\\boldsymbol{X})$와 최대한 비슷한 $p_{g}(\\boldsymbol{X})$를 만드는것이 우리의 목표입니다. \n", - "우선 D를 훈련 시키기 위한 코스트를 살펴보겠습니다.\n", + "이후 모델을 생성합니다. 생성할 모델은 $D$와 $G$ 그리고 이 둘이 중첩된 모델 GAN을 생성합니다.모델 정의를 위해 우선 GAN에 대한 기초 구조를 이야기 하도록 하겠습니다.
\n", + "어떤 확률변수 $\\boldsymbol{X}$가 있어서 이 변수가 어떤 데이터를 나타낸다고 합시다. 쉬운 예로 28x28 픽셀의 사람 얼굴이라면 요소를 784개 가지는 벡터로 생각할 수 있고 $\\boldsymbol{X}$는 그 벡터를 값으로 가지는 확률 변수가 됩니다. 784개의 요소에 아무값이나 집어 넣은 임의의 벡터 $\\boldsymbol{x}$는 사람 얼굴이 아닐 것입니다. 하지만 어떤 규칙에 의해 784개의 값을 적당히 잘 지정하면 벡터 $\\boldsymbol{x}$는 사람얼굴 처럼 보일 수 도 있습니다. 여기서 어떤 규칙 즉, 확률변수 $\\boldsymbol{X}$가 얼굴로 보이는 $\\boldsymbol{x}$를 가질 확률을 나타내는 확률분포 $p(\\boldsymbol{X})$가 있을 수 있습니다. 존재할 수 있는 모든 길이 784짜리 벡터가 모여있는 공간에는 사람 얼굴처럼 보이는 $\\boldsymbol{x}$도 있고 전혀 아닌 $\\boldsymbol{x}$도 있는데 어떤 확률변수 $\\boldsymbol{X}$가 이들 표본을 가질 때 얼굴을 닮은 $\\boldsymbol{x}$에 대해서 높은 확률을 부여하는 $p(\\boldsymbol{X}=\\boldsymbol{x})$가 존재한는 것입니다. $\\boldsymbol{x}$가 $p(\\boldsymbol{X})$에 따르면 즉, $\\boldsymbol{x} \\sim p(\\boldsymbol{X})$이면 $\\boldsymbol{x}$는 사람 얼굴이 될 것입니다. 문제는 $p(\\boldsymbol{X})$가 무엇인지 전혀 알지 못합니다. 다만 $\\boldsymbol{x} \\sim p(\\boldsymbol{X})$인 $\\boldsymbol{x}$ 여러개는 가질 수 있습니다. 바로 우리가 모은 데이터입니다. 이 데이터를 이용하여 입력된 $\\boldsymbol{x}$가 $p(\\boldsymbol{X})$에서 추출된 것인지 아닌지를 구별하는 D를 만들고, $\\boldsymbol{x}$를 무작위로 만들어 D에게 검사를 받는 G를 만들어 둘을 훈련시키는 네트워크가 GANs입니다. 여기서 $p(\\boldsymbol{X})$가 무엇인지 전혀 알지 못하므로 모아둔 데이터의 분포를 나타내는 $p_{\\text{data}}(\\boldsymbol{X})$를 생각 해볼 수 있습니다. $p_{\\text{data}}(\\boldsymbol{X})$는 $p(\\boldsymbol{X})$와 완전히 같지는 않겠지만 우리가 할 수 있는 최선입니다. 그리고 $G$도 어떤 규칙으로 데이터를 만들어 낼테니까 $G$에서 생성되는 데이터의 확률분포 $p_{g}(\\boldsymbol{X})$를 생각해 볼 수 있습니다. 이제 $p_{\\text{data}}(\\boldsymbol{X})$와 최대한 비슷한 $p_{g}(\\boldsymbol{X})$를 만드는것이 우리의 목표입니다. \n", + "우선 $D$를 훈련 시키기 위한 코스트를 살펴보겠습니다.\n", "

\n", "$$ J^{D} \\left( \\boldsymbol{\\theta}^{(D)} , \\boldsymbol{\\theta}^{(G)} \\right) \n", "= - \\frac{1}{2} \\mathbb{E}_{\\boldsymbol{x} \\sim p_{\\text{data}}} \\log D( \\boldsymbol{x} ) \n", @@ -602,11 +611,11 @@ "\n", "
\n", "\n", - "위 식에서 $\\boldsymbol{\\theta}^{(D)}$는 $D(x)$를 조정하는 매개변수, $\\boldsymbol{\\theta}^{(G)}$는 $G(z)$를 조정하는 매개변수입니다. 먼저 첫번째 항에 대해 이야기하면 $D(\\boldsymbol{x})$는 데이터 $\\boldsymbol{x}$를 입력받아 0~1을 출력하는 함수입니다. $\\boldsymbol{x} \\sim p_{\\text{data}}$는 우리가 모은 데이터의 확률분포에서 추출한 데이터 $\\boldsymbol{x}$라는 뜻으로 그냥 우리의 데이터셋에서 뽑은 데이터라는 뜻입니다. 즉, 진짜 데이터가 되겠습니다. 이 진짜 데이터에 대한 기대값이란 의미이며 또는 $\\boldsymbol{x}$에 대한 평균으로 생각해도 되겠습니다. 두번째 항에서 $G(\\boldsymbol{z})$는 잠재변수latent variable $\\boldsymbol{z}$를 입력받아 우리가 원하는 데이터를 출력하는 함수입니다. 잠재변수는 보통 노이즈인데 우리 예제에서는 균등분포 난수를 사용하겠습니다. 이는 목표로 하는 확률분포가 정규분포인데 G의 입력을 정규분포로 넣어주는 것보다 균등분포로 넣어주는 것이 문제를 더 어렵게 만들기 때문입니다. 이것이 다시 D에 입력되니 결국 0~1의 값이 되고 D가 똑똑하다면 0 근처의 값을 출력해야 합니다. G를 고정시키고(지금 G는 그냥 열심히 가짜 데이터를 만들기만 하면 됨) $\\boldsymbol{\\theta}^{(D)}$에 대해서 위 식을 최소화 시킵니다. 자세한 상황은 아래 그림과 같습니다.\n", - "\n", - " \n", - "\n", - "즉, 아래 식과 같이 그래디언트를 구하고 $\\boldsymbol{\\theta}^{(D)}$를 업데이트 시켜 나가면 D는 점점 똑똑해집니다. 아래 식은 Goodfellow et al[6]의 Algorithm 1에 나와 있는 식입니다. 각 항의 부호가 바뀐것과 기대값 표시가 평균을 구하는 방법으로 바뀐것만 빼면 위 식과 동일한 식입니다. 부호가 바뀌었으므로 이 경우는 $\\boldsymbol{\\theta}^{(D)}$에 대해 최대화 시켜야 합니다.\n", + "위 식에서 $\\boldsymbol{\\theta}^{(D)}$는 $D(x)$를 조정하는 매개변수, $\\boldsymbol{\\theta}^{(G)}$는 $G(z)$를 조정하는 매개변수입니다. 먼저 첫번째 항에 대해 이야기하면 $D(\\boldsymbol{x})$는 데이터 $\\boldsymbol{x}$를 입력받아 0~1을 출력하는 함수입니다. $\\boldsymbol{x} \\sim p_{\\text{data}}$는 우리가 모은 데이터의 확률분포에서 추출한 데이터 $\\boldsymbol{x}$라는 뜻으로 그냥 우리의 데이터셋에서 뽑은 데이터라는 뜻입니다. 즉, 진짜 데이터가 되겠습니다. 이 진짜 데이터에 대한 기대값이란 의미이며 또는 $\\boldsymbol{x}$에 대한 평균으로 생각해도 되겠습니다. 두번째 항에서 $G(\\boldsymbol{z})$는 잠재변수latent variable $\\boldsymbol{z}$를 입력받아 우리가 원하는 데이터를 출력하는 함수입니다. 잠재변수는 보통 노이즈인데 우리 예제에서는 균등분포 난수를 사용하겠습니다. 이는 목표로 하는 확률분포가 정규분포인데 $G$의 입력을 정규분포로 넣어주는 것보다 균등분포로 넣어주는 것이 문제를 더 어렵게 만들기 때문입니다. 이것이 다시 $D$에 입력되니 결국 0~1의 값이 되고 $D$가 똑똑하다면 0 근처의 값을 출력해야 합니다. G를 고정시키고(지금 $G$는 그냥 열심히 가짜 데이터를 만들기만 하면 됨) $\\boldsymbol{\\theta}^{(D)}$에 대해서 위 식을 최소화 시킵니다. 자세한 상황은 아래 그림과 같습니다.\n", + "
\n", + "\n", + "
\n", + "즉, 아래 식과 같이 그래디언트를 구하고 $\\boldsymbol{\\theta}^{(D)}$를 업데이트 시켜 나가면 $D$는 점점 똑똑해집니다. 아래 식은 Goodfellow et al[7]의 Algorithm 1에 나와 있는 식입니다. 각 항의 부호가 바뀐것과 기대값 표시가 평균을 구하는 방법으로 바뀐것만 빼면 위 식과 동일한 식입니다. 부호가 바뀌었으므로 이 경우는 $\\boldsymbol{\\theta}^{(D)}$에 대해 최대화 시켜야 합니다.\n", "

\n", "$$ \n", "\\bigtriangledown_{\\theta^{(D)}} \\frac{1}{m} \\sum_{i=1}^{m} \\left[ \\log D\\left(x^{(i)}\\right) + \\log \\left( 1-D\\left(G(z^{(i)})\\right) \\right)\\right] \n", @@ -631,8 +640,8 @@ "$$ \\bigtriangledown_{\\theta^{(D)}} \\frac{1}{m} \\sum_{i=1}^{2m} \\left[ y^{(i)}\\log D\\left(x^{(i)}\\right) + (1-y^{(i)})\\log \\left( 1-D\\left(G(z^{(i)})\\right) \\right)\\right] \n", "$$\n", "
\n", - "이제 G에 대한 코스트를 살펴보겠습니다. \n", - "G에 대한 코스트는 D에 대한 코스트에 - 부호를 붙여서 그것을 최소화 하면 됩니다.\n", + "이제 $G$에 대한 코스트를 살펴보겠습니다. \n", + "$G$에 대한 코스트는 $D$에 대한 코스트에 - 부호를 붙여서 그것을 최소화 하면 됩니다.\n", "

\n", "$$J^{G} = - J^{D} $$\n", "
\n", @@ -647,15 +656,15 @@ "+ \\frac{1}{2} \\mathbb{E}_{\\boldsymbol{z}} \\log \\left(1-D \\left( G(\\boldsymbol{z}) \\right) \\right)\n", "$$\n", "
\n", - "위 식에서 $\\log D(\\boldsymbol{x})$ 부분은 G와 아무 상관이 없는 항입니다. 따라서 G는 식의 뒷부분인 $\\frac{1}{2} \\mathbb{E}_{z} \\log \\left(1-D(G(\\boldsymbol{z}) \\right)$를 최소화시키면 됩니다. 그런데 전체 식이 D에 대해서 최대화 되었다는 말은 코스트 함수에서 어느정도 평탄한 부분에 도달했다는 말이 됩니다. 그 상태에서 뒷 부분을 코스트로 해서 그래디언트를 계산하고 이를 다시 최소화 시킨다고 했을 때 기울기 값이 크지 않아 최소화 시키기가 힘들 수 있습니다. D는 최대화된 최적점에 가버리고 거기서 G는 다시 낮은 곳으로 가야하는데 기울기가 없어서 꾸물꾸물 거리게 되는 것입니다. 그래서 논문에서는 식을 약간 변형한 형태인 아래 식으로 코스트 함수를 설정하는 것이 효율적이라 합니다.\n", + "위 식에서 $\\log D(\\boldsymbol{x})$ 부분은 $G$와 아무 상관이 없는 항입니다. 따라서 $G$는 식의 뒷부분인 $\\frac{1}{2} \\mathbb{E}_{z} \\log \\left(1-D(G(\\boldsymbol{z}) \\right)$를 최소화시키면 됩니다. 그런데 전체 식이 $D$에 대해서 최대화 되었다는 말은 코스트 함수에서 어느정도 평탄한 부분에 도달했다는 말이 됩니다. 그 상태에서 뒷 부분을 코스트로 해서 그래디언트를 계산하고 이를 다시 최소화 시킨다고 했을 때 기울기 값이 크지 않아 최소화 시키기가 힘들 수 있습니다. $D$는 최대화된 최적점에 가버리고 거기서 $G$는 다시 낮은 곳으로 가야하는데 기울기가 없어서 꾸물꾸물 거리게 되는 것입니다. 그래서 논문에서는 식을 약간 변형한 형태인 아래 식으로 코스트 함수를 설정하는 것이 효율적이라 합니다.\n", "

\n", "$$ J^{G} = -\\frac{1}{2} \\mathbb{E}_{z} \\log \\left(D(G(\\boldsymbol{z}) \\right) $$\n", "
\n", "각 형태에 대한 상황을 그림으로 정리했습니다.\n", - "\n", - " \n", - "\n", - "둘 다 최소화 시키는 코스트로 사용 가능한데 우리 실험에서는 아래와 같이 그래디언트를 구하고 G를 업데이트 하도록하겠습니다.\n", + "
\n", + "\n", + "
\n", + "둘 다 최소화 시키는 코스트로 사용 가능한데 우리 실험에서는 아래와 같이 그래디언트를 구하고 $G$를 업데이트 하도록하겠습니다.\n", "

\n", "$$ \\bigtriangledown_{\\theta^{(G)}} \\left( - \\frac{1}{m}\\sum_{i=1}^{m} \\log D\\left(G(z^{(i)})\\right) \\right)$$\n", "
\n", @@ -667,6 +676,7 @@ "cell_type": "code", "execution_count": 16, "metadata": { + "collapsed": false, "scrolled": false }, "outputs": [ @@ -766,7 +776,9 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -817,20 +829,22 @@ "metadata": {}, "source": [ "
\n", - "G가 토해내는 $p_{g}(\\boldsymbol{x})$는 빨간색으로 표시되는데 한마디로 엉망입니다. 이 G를 훈련시켜서 6을 중심으로 종모양으로 퍼지는 모델을 만드는 것이 목표입니다. 경험적으로 알 수 있는 사실이지만 G의 학습보다는 D의 학습이 더 중요하므로 D를 미리 학습을 한번 시킵니다. Ian Goodfellow의 비유처럼 G는 위폐범인데 D가 위폐를 잘 골라내지 못한다면 G가 적당히 만들어도 D 위폐가 아니라고 판단할 것이고 G는 집중적으로 그 위폐만 만들게 됩니다. 실제로 G가 더 잘 훈련이 되면 우리의 문제에서 G는 거의 모든 값을 6근처의 값으로 집중적으로 만드는 모습을 확인할 수 있습니다. 그래서 왠만하면 D가 G의 결과를 잘 판단하도록 훈련시켜야 합니다. 그의 논문에서 정확히 언급하고 있습니다. \n", + "$G$가 토해내는 $p_{g}(\\boldsymbol{x})$는 빨간색으로 표시되는데 그냥 무작위로 나오고 있습니다. 이 $G$를 훈련시켜서 6을 중심으로 종모양으로 퍼지는 모델을 만드는 것이 목표입니다. 경험적으로 알 수 있는 사실이지만 $G$의 학습보다는 $D$의 학습이 더 중요하므로 $D$를 미리 학습을 한번 시킵니다. Goodfellow의 비유처럼 $G$는 위폐범인데 $D$가 위폐를 잘 골라내지 못한다면 $G$가 적당히 만들어도 $D$는 진짜 지폐라고 판단할 것이고 $G$는 집중적으로 그 위폐만 만들게 됩니다. 실제로 $G$가 더 잘 훈련이 되면 우리의 문제에서 $G$는 거의 모든 값을 6근처의 값으로 집중적으로 만드는 모습을 확인할 수 있습니다. 그래서 왠만하면 $D$가 $G$의 결과를 잘 판단하도록 훈련시켜야 합니다. 그의 논문에서 정확히 언급하고 있습니다. \n", "
\n", "\n", ">\"in particular, G must not be trained too much without updating D, in order to avoid “the Helvetica scenario” in which G collapses too many values of $\\boldsymbol{z}$ to the same value of $\\boldsymbol{x}$ to have enough diversity to model $p_{\\text{data}}$\"\n", "\n", "
\n", - "G가 너무 많은 $\\boldsymbol{z}$ 값을 같은 $\\boldsymbol{x}$값으로 몰리게 해서 $p_{data}$를 묘사하기에 충분한 다양성을 가지지 못하는 문제를 피해야한다는 말인데 어떤 결과를 놓고 이야기하는지 아래에서 실험적으로 확인 해보도록 하겠습니다. 먼저 D를 선학습 시킵니다. (여러번 실험해보면 이 과정이 꼭 필요한것 같지는 않은데 왠지 하면 좀 더 잘되는 느낌은 있습니다.;;)\n", + "$G$가 너무 많은 $\\boldsymbol{z}$ 값을 같은 $\\boldsymbol{x}$값으로 몰리게 해서 $p_{data}$를 묘사하기에 충분한 다양성을 가지지 못하는 문제를 피해야한다는 말입니다. 그래서 먼저 $D$를 선학습 시킵니다. (여러번 실험해보면 이 과정이 꼭 필요한것 같지는 않은데 왠지 하면 좀 더 잘되는 느낌은 있습니다.;;)\n", "
" ] }, { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -925,7 +939,7 @@ "metadata": {}, "source": [ "
\n", - "D가 선학습되어 트레이닝 데이터에 대해 매우 높은 정확도를 보이게 되었습니다. 이제 본 학습에 들어가는데 GANs에서 제안한 대로 D와 G의 업데이트 비율을 조절하면서 학습합니다. 여기서는 D 3번 업데이트하고 G를 한번 업데이트하는 식으로 학습을 진행하였습니다.\n", + "$D$가 선학습되어 트레이닝 데이터에 대해 매우 높은 정확도를 보이게 되었습니다. 이제 본 학습에 들어가는데 GANs에서 제안한 대로 $D$와 $G$의 업데이트 비율을 조절하면서 학습합니다. 여기서는 $D$ 3번 업데이트하고 $G$를 한번 업데이트하는 식으로 학습을 진행하였습니다.\n", "
" ] }, @@ -933,6 +947,7 @@ "cell_type": "code", "execution_count": 19, "metadata": { + "collapsed": false, "scrolled": false }, "outputs": [ @@ -1278,7 +1293,9 @@ { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -1324,16 +1341,30 @@ "
\n", "\n", "
\n", - "논문에서 GANs의 이론적 논의는 D를 고정한 상태에서 G에 대한 코스트함수가 전역적 최소를 가지고 그것이 $p_{data}=p_{g}$일 때이며 상기 알고리즘으로 그 전역 최소에 도달할 수 있는지 보이는 것입니다. 크게 3가지 부분으로 이 문제를 설명합니다. 유재준님의 블로그[12]와 TF-KR의 논문 발표를 참고하여 내용을 정리하였습니다.\n", + "논문에서 GANs의 이론적 논의는 $\\max_{D} V(G,D)$가 G에 대해 전역적 최소를 가지고 그것이 $p_{data}=p_{g}$일 때이며 상기 알고리즘으로 그 전역 최소에 도달할 수 있는지 보이는 것입니다. 크게 3가지 부분으로 이 문제를 설명합니다. 이미 TF-KR의 유재준님께서 이론 부분을 리뷰한 훌륭한 문서들이 존재하는데 [11][12] 여기서는 이 문서들을 참고하고 조금 더 친철하게 내용을 보충하여 설명해보도록 하겠습니다. 각각 알아보기 앞서 우선 한가지 짚어야 할 부분이 있습니다. \n", + "
\n", + "\n", + ">*The generator G implicitly defines a probability distribution $p_g$ as the distribution of the samples $G(z)$ obtained when $z ∼ p_z$.* \n", + "\n", + "\n", + "
\n", + "바로 위 부분인데요. $G$와 $p_g$가 동일한 것이 아니라는 것입니다. $G$는 제너레이터고 $p_g$는 그 제너레이터가 암시적으로 정의하는 확률 분포입니다. 다시말하면 실제로 $G$는 잠재변수 $z$로 부터 생성한 샘플 $G(z)$의 분포를 정의할 뿐이지 $p_g$를 직접적으로 정의 하지 않는다는 것입니다. 우리의 학습 알고리즘이 $G$의 매개변수를 변경하면서 샘플의 분포를 변경하면 암시적으로 $p_g$가 변할 것이고 그것이 $p_{data}$와 비슷하기를 바라는 것입니다. 이 개념을 확실히 새기고 각각 하나씩 살펴보도록 하겠습니다. \n", "
\n", "\n", - "> Proposition 1. *For G fixed, the optimal discriminator D is*\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> Proposition 1. *For G fixed, the optimal discriminator D is*\n", "$$\n", "D^{*}_{G}(\\boldsymbol{x}) = \\frac{p_{data}(\\boldsymbol{x})}{p_{data}(\\boldsymbol{x})+p_{g}(\\boldsymbol{x})}\n", "$$\n", "\n", "
\n", - "Proposition 1은 G가 고정된 상태에서 최적의 D는 위 식으로 주어진다는 것을 이야기 하며 이를 보이기 위해서는 $\\frac{\\partial V(G,D)}{\\partial D(\\boldsymbol{x})}=0$ 또는 ($ V(G,D) = -J^{D}$ 이므로) $\\frac{\\partial J^{D}}{\\partial D(\\boldsymbol{x})}=0$ 인 $D(\\boldsymbol{x})$를 구하면 됩니다.\n", + "Proposition 1은 $G$가 고정된 상태에서 최적의 $D$는 위 식으로 주어진다는 것을 이야기 하며 이를 보이기 위해서는 $\\frac{\\partial V(G,D)}{\\partial D(\\boldsymbol{x})}=0$ 또는 ($ V(G,D) = -J^{D}$ 이므로) $\\frac{\\partial J^{D}}{\\partial D(\\boldsymbol{x})}=0$ 인 $D(\\boldsymbol{x})$를 구하면 됩니다.\n", "

\n", "$$\n", "\\begin{align}\n", @@ -1347,7 +1378,7 @@ "이므로\n", "

\n", "$$\n", - "\\int_{x} \\frac{p_{x \\sim data}(x)\\left( 1-D(x) \\right) - p_{x \\sim g}(x)D(x)}{D(x)\\left(1-D(x) \\right)} dx =0\n", + "\\int_{x} \\frac{p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})\\left( 1-D(\\boldsymbol{x}) \\right) - p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x})D(\\boldsymbol{x})}{D(\\boldsymbol{x})\\left(1-D(\\boldsymbol{x}) \\right)} d\\boldsymbol{x} =0\n", "$$\n", "
\n", "입니다. \n", @@ -1355,22 +1386,22 @@ "

\n", "$$\n", "\\begin{align}\n", - "J^{D} &= -\\int_{x} p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x}) \\log D(x) + p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) \\log (1-D(x)) dx \\\\\n", - "&= \\int_{x} p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x}) \\left(-\\log D(x)\\right) + p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) \\left(-\\log (1-D(x))\\right) dx\n", + "J^{D} &= -\\int_{\\boldsymbol{x}} p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x}) \\log D(\\boldsymbol{x}) + p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) \\log (1-D(\\boldsymbol{x})) d\\boldsymbol{x} \\\\\n", + "&= \\int_{\\boldsymbol{x}} p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x}) \\left(-\\log D(\\boldsymbol{x})\\right) + p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) \\left(-\\log (1-D(\\boldsymbol{x}))\\right) d\\boldsymbol{x}\n", "\\end{align}\n", "$$\n", "
\n", - "$J^{D}$는 위 식과 같은데 위 식에서 $p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})$는 우리가 가진 샘플들에 의해 이미 결정된 확률분포 입니다. 그리고 지금 G가 주어진 상태, 즉, G가 고정된 상태에서 D(x)만 변화 시켜 $J^{D}$의 변화를 보고 있으므로 $p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) $ 역시 고정입니다. 결국 $J^{D}$는 독립변수 $D(x)$에 대한 함수 $-\\log D(x)$와 $-\\log \\left(1-D(x)\\right)$의 조합이므로 $-\\log D(x)$와 $-\\log \\left(1-D(x)\\right)$가 볼록함수임을 보이면 $J^{D}$가 볼록함수임을 보일 수 있습니다. 이를 위해 $D(x)$에 대한 이계미분이 음이 아님을 보이면 되므로\n", + "$J^{D}$는 위 식과 같은데 위 식에서 $p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})$는 우리가 가진 샘플들에 의해 이미 결정된 확률분포 입니다. 그리고 지금 G가 주어진 상태, 즉, G가 고정된 상태에서 $D(x)$만 변화 시켜 $J^{D}$의 변화를 보고 있으므로 $p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) $ 역시 고정입니다. 결국 $J^{D}$는 독립변수 $D(\\boldsymbol{x})$에 대한 함수 $-\\log D(\\boldsymbol{x})$와 $-\\log \\left(1-D(\\boldsymbol{x})\\right)$의 조합이므로 $-\\log D(\\boldsymbol{x})$와 $-\\log \\left(1-D(\\boldsymbol{x})\\right)$가 볼록함수임을 보이면 $J^{D}$가 볼록함수임을 보일 수 있습니다. 이를 위해 $D(\\boldsymbol{x})$에 대한 이계미분이 음이 아님을 보이면 되므로\n", "

\n", "$$\n", - "\\frac{\\partial}{\\partial D(x)}\\left(\\frac{\\partial \\{-\\log D(x)\\}}{\\partial D(x)}\\right) = \\frac{\\partial}{\\partial D(x)}\\left( -\\frac{1}{D(x)} \\right) = \\frac{1}{D^{2}(x)} \n", + "\\frac{\\partial}{\\partial D(\\boldsymbol{x})}\\left(\\frac{\\partial \\{-\\log D(\\boldsymbol{x})\\}}{\\partial D(\\boldsymbol{x})}\\right) = \\frac{\\partial}{\\partial D(\\boldsymbol{x})}\\left( -\\frac{1}{D(\\boldsymbol{x})} \\right) = \\frac{1}{D^{2}(\\boldsymbol{x})} \n", "$$\n", "
\n", "$$\n", - "\\frac{\\partial}{\\partial D(x)}\\left(\\frac{\\partial \\{-\\log (1-D(x))\\}}{\\partial D(x)}\\right) = \\frac{\\partial}{\\partial D(x)}\\left( \\frac{1}{1-D(x)} \\right) = \\frac{1}{ (1-D(x))^2 } \n", + "\\frac{\\partial}{\\partial D(\\boldsymbol{x})}\\left(\\frac{\\partial \\{-\\log (1-D(\\boldsymbol{x}))\\}}{\\partial D(\\boldsymbol{x})}\\right) = \\frac{\\partial}{\\partial D(\\boldsymbol{x})}\\left( \\frac{1}{1-D(\\boldsymbol{x})} \\right) = \\frac{1}{ (1-D(\\boldsymbol{x}))^2 } \n", "$$\n", "
\n", - "이고, 두 결과 모두 $D(x) = 0$를 제외하면 항상 양수이므로 두 함수 모두 볼록 함수이며 이 함수들이 0보다 큰 $p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})$, $p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) $와의 곱의 합으로 나타나는 $J^{D}$ 역시 볼록함수임을 알 수 있습니다. \n", + "이고, 두 결과 모두 $D(\\boldsymbol{x}) = 0$를 제외하면 항상 양수이므로 두 함수 모두 볼록 함수이며 이 함수들이 0보다 큰 $p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})$, $p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}) $와의 곱의 합으로 나타나는 $J^{D}$ 역시 $D(\\boldsymbol{x})$에 대해 볼록함수임을 알 수 있습니다. \n", "따라서\n", "

\n", "$$ p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x}) \\left( 1-D(\\boldsymbol{x}) \\right) - p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x})D(\\boldsymbol{x}) =0 $$\n", @@ -1383,15 +1414,20 @@ "\n", "\n", "마지막으로 $D(\\boldsymbol{x})$는 $p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})$와 $p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x})$가 0이 아닌 집합에 대해서만 정의되면 되므로(어떤 샘플 $\\boldsymbol{x}$가 일어날 확률이 0인 것에 대해서는 참 거짖을 판별할 필요 없음) $Supp(p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})) \\cup Supp(p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}))$ 에서만 정의되면 된다 라고 논문에서 언급합니다. \n", - "논문에서 증명 하기를 $(a,b) \\in \\mathbb{R}^{2} \\backslash \\{0,0\\}$ 인 a, b에 대해서 $a \\log(y) + b \\log(1-y)$라는 함수를 [0,1]에서 y에 대해 미분해서 0인 점을 찾으면 최대값이 $ \\frac{a}{a+b}$에서 나타난다고 하고 이 식에서 a에 해당하는것이 $p_{\\boldsymbol{x} \\sim data}$이고 b에 해당하는 것이 $p_{\\boldsymbol{x} \\sim g}$ 니까 a, b가 0이 아니었듯이 $p_{\\boldsymbol{x} \\sim data}$, $p_{\\boldsymbol{x} \\sim g}$도 0이 아닌 경우에 대해서 생각하기 위해 $Supp(p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})) \\cup Supp(p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}))$ 에서만 정의되면 된다고 언급하고 증명을 마무리한 것으로 생각됩니다.\n", + "논문에서 증명 하기를 $(a,b) \\in \\mathbb{R}^{2} \\backslash \\{0,0\\}$ (집합 (a,b)는 집합 {0,0}을 제외한 실수쌍인 집합)인 a, b에 대해서 $a \\log(y) + b \\log(1-y)$라는 함수를 [0,1]에서 y에 대해 미분해서 0인 점을 찾으면 최대값이 $ \\frac{a}{a+b}$에서 나타난다고 하고 이 식에서 a에 해당하는것이 $p_{\\boldsymbol{x} \\sim data}$이고 b에 해당하는 것이 $p_{\\boldsymbol{x} \\sim g}$ 니까 a, b가 0이 아니었듯이 $p_{\\boldsymbol{x} \\sim data}$, $p_{\\boldsymbol{x} \\sim g}$도 0이 아닌 경우에 대해서 생각하기 위해 $Supp(p_{\\boldsymbol{x} \\sim data}(\\boldsymbol{x})) \\cup Supp(p_{\\boldsymbol{x} \\sim g}(\\boldsymbol{x}))$ 에서만 정의되면 된다고 언급하고 증명을 마무리합니다.\n", "
\n", "\n", - "
\n", - "\n", - ">Theorem 1. *The global minimum of the virtual training criterion $C(G)$ is achieved if and only if $p_g = p_{data}$. At that point, $C(G)$ achieves the value $−log4$*. \n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ">Theorem 1. *The global minimum of the virtual training criterion $C(G)$ is achieved if and only if $p_g = p_{data}$. At that point, $C(G)$ achieves the value $−log4$*. \n", "\n", "
\n", - "위 결과에 의해 $V(G,D)$를 최대화 하는 D를 찾았다고 하면 G에 대한 코스트 C(G)를 아래와 같이 쓸 수 있습니다.\n", + "앞서 정의한 벨류펑션 $V(G,D)$를 D에 대해서 최대화 한 함수를 $G$에 대한 함수로 $C(G)$라 하면 아래와 같이 쓸 수 있습니다. 여기서 $C(G)$를 *virtual training criterion*이라고 표현하는데 $C(G)$는 $G$에 대한 함수인데 존재하는 모든 $G$에 대해서 $D$가 모조리 최대화 되어있는 상태의 함수입니다. 말 그대로 $max_{D} V(G,D)$인 것입니다. 이 함수를 우리가 정식화해서 구할 수 있으면 이 함수를 가지고 경사하강을 하면 될테지만 이런 함수를 미분가능할 정도로 정식화할 수 없기 때문에 $G$에 대한 *\"virtual training criterion\"*이라고 표현했습니다. 자세한 그림은 Proposition 2에서 다시 살펴보도록 하겠습니다. \n", "

\n", "$$\n", "\\begin{align}\n", @@ -1402,13 +1438,13 @@ "\\end{align}\n", "$$\n", "
\n", - "만약 $p_g = p_{data}$ 라면 C(G)는 아래와 같습니다.\n", + "위 식에서 확인할 수 있듯이 $C(G)$는 $C(G)$에 어떤 $G$가 들어와도 $D$는 $D^{*}_{G}$로 이미 최대화가 되어 있는 그런 함수라는 것을 확인할 수 있습니다. 만약 $p_g = p_{data}$ 라면 $C(G)$는 아래와 같습니다.\n", "

\n", "$$\n", "\\mathbb{E}_{\\boldsymbol{x} \\sim p_{\\text{data}}} \\left[ - \\log 2 \\right] + \\mathbb{E}_{\\boldsymbol{x} \\sim p_{\\text{g}}} \\left[ - \\log 2 \\right] = -\\log 4\n", "$$\n", "
\n", - "이제 $-\\log 4$가 C(G)의 전역 최소라는 것을 보이기 위해 아래처럼 $C(G)=V(D^{*}_{G}, G)$에서 위 식을 빼면\n", + "이제 $-\\log 4$가 $C(G)$의 전역 최소라는 것을 보이기 위해 원 논문에서 처럼 $C(G)=V(D^{*}_{G}, G)$에서 위 식을 빼면 ('*that by subtracting this expression from $C(G)=V(D^{*}_{G}, G)$, we obtain*')\n", "

\n", "$$\n", "\\begin{matrix} \n", @@ -1444,8 +1480,96 @@ "\\end{align} \n", "$$\n", "
\n", - "가 됩니다. 마지막 줄은 앞서 살펴보았던 쿨벡-라이블러 발산의 정의를 그대로 이용한 것입니다. 앞서 쿨벡-라이블러 발산은 항상 0보다 크거나 같으며 볼록하다는 것을 확인했습니다. 따라서 위 식으로 부터 $C(G)$는 볼록함수이며 $p_{data}=p_{g}$일 때 전역적 최솟값 $-\\log 4$를 가진다는 것이 증명되었습니다.\n", + "가 됩니다. 마지막 줄은 앞서 살펴보았던 쿨벡-라이블러 발산의 정의를 그대로 이용한 것입니다. 앞서 쿨벡-라이블러 발산은 항상 0보다 크거나 같으며 볼록하다는 것을 확인했습니다. 따라서 위 식으로 부터 $C(G)$는 볼록함수이며 $p_{data}=p_{g}$일 때 전역적 최솟값 $-\\log 4$를 가진다는 것이 증명되었습니다. 여기서 중요한 부분은 $C(G)$가 $G$에 대해 볼록함수라는 사실 보다는 그 볼록함수가 유일한 전역 최적점(*unique global optima*)을 가진다는 것입니다.\n", "\n", + "
\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ">Proposition2. * If G and D have enough capacity,and at each step of Algorithm 1,the discriminator is allowed to reach its optimum given G, and $p_g$ is updated so as to improve the criterion*\n", + "

\n", + "$$\n", + "\\mathbb{E}_{\\boldsymbol{x} \\sim p_{data}} \\left[ \\log D^{*}_{G}(\\boldsymbol{x}) \\right] +\n", + "\\mathbb{E}_{\\boldsymbol{x} \\sim p_{g}} \\left[ \\log (1-D^{*}_{G}(\\boldsymbol{x})) \\right]\n", + "$$\n", + "
\n", + "then $p_g$ converges to $p_{data}$\n", + "\n", + "
\n", + "이제 이 논문에서 이해하기 가장 난해한 부분인 Proposition 2입니다. 내용은 앞서 소개한 알고리즘 $p_g$를 잘 변경시켜서 $p_{data}$에 수렴시킬 것인가? 하는 것입니다. $p_g$를 잘 변경시켜서 $p_{data}$에 수렴시킨다는 말은 Thm 1에서 증명한 바와 같이 $C(G)$함수는 유니크 글로벌 옵티마를 가지는데 그것을 Algorithm 1이 찾을 수 있을 것인가? 하는 말과 동치 입니다. 그리고 그 전제 조건은 \"$G$가 주어졌을 때 최적의 $D$에 도달할 수 있다면\" 입니다.
\n", + "최대한 쉽게 그림과 함께 알아보도록 하겠습니다. 일단 $U(p_{g}, D) = V(G,D)$인 함수 $U$를 생각하도록 하겠습니다. $U$는 $p_g$와 $D$를 변수로 가지는 함수가 됩니다.\n", + "

\n", + "$$\n", + "U(p_{g}, D) = \\int_{\\boldsymbol{x}} p_{data}(\\boldsymbol{x}) \\log (D(\\boldsymbol{x}))+p_{g}(\\boldsymbol{x}) \\log \\left( 1-D(\\boldsymbol{x}) \\right) d\\boldsymbol{x}\n", + "$$\n", + "
\n", + "$U(p_{g}, D)$는 위와 같은데 이는 $p_g$에 대해서 볼록함수입니다. 이는 Integrand를 $p_g$에 대한 함수로 보고 함수의 볼록성 정의를 그대로 이용하여 보여줄 수 있습니다. 또는 간단하게 그냥 $p_g$에 대해 선형이기 때문이라고 생각하여도 됩니다. 상황을 그림으로 대충 그려보기 위해 $U$가 모양이 $p_g$방향으로는 아래로 볼록한 볼록함수이고 $D$방향으로는 임의의 모양을 가지는 움푹한 배수로같은 모양의 함수라 생각해보겠습니다.\n", + "

\n", + "\n", + "
\n", + "앞서 가정한 모양의 $U(p_{g}, D)$가 있다고 했을 때 임의의 구간 $\\mathcal{A}$에 대해서 3개의 $D$를 정해서 그 $D$를 고정시킨 체 $p_g$에 대한 함수를 그려보면 위 그림과 같이 각각 밥그릇 모양의 함수가 나올 것입니다. 물론 구간 $\\mathcal{A}$ 무수히 많은 이런 밥그릇 모양의 함수가 있지만 설명의 편의를 위해 3개만 예를 들도록 하겠습니다. 이 함수들을 $p_g$축 방향에서 보면 아래 왼쪽 그림과 같습니다. \n", + "

\n", + "\n", + "
\n", + "
\n", + "\n", + ">*The subderivatives of a supremum of convex functions include the derivative of the function at the point where the maximum is attained.*\n", + "\n", + "
\n", + "위 문장에서 *supremum of convex functions*이라 함은 위 왼쪽 그림에서 3개의 함수는 모두 convex function인데 그것들의 수프리멈[13]이니까 위 그림에서 오른쪽 그림입니다. 오른쪽 그림은 모든 $p_g$에 대해서 3개 함수중에 max값을 취한 함수입니다. 여기서는 수프리멈이라고 일반화 시켜서 이야기 했지만 이 함수가 Thm 1에서 $C(G)$함수가 됩니다. 구간 $\\mathcal{A}$가 개구간일 경우 특정 $p_g$에서 무수히 많은 $U(p_{g}, D)$에 대해 맥시멈이 없을 수 있기 때문에 엄밀하게 Proposition 2에서는 수프리멈을 사용합니다. 이렇게 $D$에 대해 수프리멈을 찾았으면 이 수프리멈에서 $p_g$에 대해 미니멈을 찾으면 우리가 찾고자 하는 최적점을 찾는 것입니다.(그림에서 별표로 표시) 이 수프리멈은 부분 부분 각각 다른 함수들로 조합되는데 이를 pointwise maximum 또는 pointwise supremum이라 합니다. 이 수프리멈은 볼록함수에 대한 수프리멈이므로 역시 볼록함수입니다.[14] 이는 Thm 1에서 증명한 바이기도 합니다. 또 이 수프리멈은 함수가 조합되는 지점에서 미분 불가능한 점이 생기는데 이 미분불가능 지점에서 subderivative는 무수히 많이 존재합니다.[15] (예로 든 그림은 piecewise 처럼 보이는데 실제로는 pointwise로 거의 쪼각쪼각(?)나는 함수임) 위 그림에서 검은색 동그라미 표시한 지점입니다. 이렇게 정리를 하면 위 문장의 의미를 파악할 수 있습니다. 그림 하나를 더 보면서 이야기하도록 하겠습니다.\n", + "\n", + "

\n", + "\n", + "
\n", + "\n", + "위 그림에서 보면 수프리멈은 구간별로 $ sup_{D} U(p_{g}, D) = U(p_g, D_{k}) $ 이라는 것을 알 수 있습니다. 그림에서 가장 왼쪽 구간은 $U(p_{g}, D_{3}) = sup_{D} U(p_{g}, D)$, 가운데 구간에서는 $U(p_{g}, D_{1}) = sup_{D} U(p_{g}, D)$, 왼쪽 구간에서는 $U(p_{g}, D_{2}) = sup_{D} U(p_{g}, D)$라는 것을 알 수 있습니다. 위에서 말했듯이 함수가 바뀌는 지점이외의 점에서는 유일한 미분값이 존재하고 함수가 바뀌는 지점에서는 무수히 많은 미분값이 subderivative를 이루므로 각 함수 $U(p_{g}, D_{1})$, $U(p_{g}, D_{2})$, $U(p_{g}, D_{3})$의 subderivative를 $sup_{D} U(p_{g}, D)$의 subderivative가 다 포함하게 됩니다. 그래서 어떤 임의의 $p_{g}$에서 맥시멈이 달성된 그 함수의 미분(*the derivative of the function at the point where the maximum is attained.*)은 $sup_{D} U(p_{g}, D)$의 subderivative(*The subderivatives of a supremum of convex functions*)가 다 포함하게 됩니다. 그림으로 다시 특정 예를 들어보겠습니다.\n", + "\n", + "

\n", + "\n", + "
\n", + "\n", + "$\\hat{p}_{g}$에서 맥시멈이 달성된 함수는 $U(p_{g}, D_{3})$입니다. $U(p_{g}, D_{3})$의 미분은 $sup_{D} U(p_{g}, D)$의 subderivative에 다 포함됨은 명백합니다. 이 상황을 논문에서 좀 더 포멀하게 다시 한번 더 이야기합니다.\n", + "
\n", + "\n", + ">In other words, if $f(x) = sup_{\\alpha \\in \\mathcal{A}} f_{\\alpha}(x)$ and $f_{\\alpha}(x)$ is convex in $x$ for every $\\alpha$, then $\\partial f_{\\beta}(x) \\in \\partial f$ if $\\beta = argsup_{\\alpha \\in \\mathcal{A}}f_{\\alpha}(x)$.\n", + "\n", + "
\n", + "위 문장은 노테이션이 주욱 써오던 것을 쓰지 않고 갑자기 일반적인 노테이션으로 바뀌어서 좀 혼란스러울수도 있는데(논문을 구구절절 친절히 쓰기 엄청 귀찮았나 봄;;;) 계속 써오던 노테이션을 [ ]에 넣고 다시 생각해보면 결국 같은 이야기라는 것을 알 수 있습스다. 다시 생각해보면 $x$ [$p_g$]에 대해 볼록함수인 $f_{\\alpha}(x)$ [$U(p_{g},D)$]에 대한 수프리멈을 $f(x)$라 하면 $x$ [$\\hat{p}_g$]에 대해서 수프리멈을 달성하게 하는 아규먼트 $\\beta$ [$D_{3}(x)$]에 대해 $\\partial f_{\\beta}(x)$ [$\\partial U(p_{g}, D_{3})$]은 $\\partial f$에 포함된다 라는 것입니다. 여기서 $\\partial$을 집합 subderivative 라는 의미로 사용했습니다.\n", + "\n", + "
\n", + "\n", + ">*This is equivalent to computing a gradient descent update for $p_g$ at the optimal $D$ given the corresponding $G$.*\n", + "\n", + "
\n", + "수프리멈은 미분 가능한 정도로 정식화 되지 않아 경사하강법 등으로 최솟점을 찾을 수 없는데 수프리멈의 subderivatives가 그 수프리멈을 구성하는 함수의 미분을 포함하기 때문에 수프리멈을 구성하는 각 $U(p_{g}, D^{*})$(여기서 $D^{*}=argsup_{D}U(p_{g}, D)$)에 대해서 경사하강법을 적용하는 것은 수프리멈의 최솟점을 향해 수렴한다는 동일한 결과를 줍니다.\n", + "그리고 다행스럽게도 수프리멈은 Thm 1에서 이미 유니크 전역 최적점(unique global optima)을 가지고 있다고 증명하였으므로(여기서 말하고 있는 수프리멈이 Thm 1에서 $C(G)$) 단계적으로 $U(p_{g}, D^{*})$에 대해서 경사하강법을 적용해서 전역 최적점으로 $p_g$를 수렴 시킬 수 있습니다. \n", + "\n", + "

\n", + "\n", + "
\n", + "\n", + "위 그림에 그 과정을 나타내었습니다. 우선 임의의 $\\hat{p}_{g}$가 있을 때 1번 과정으로 $D$에 대해 최대화 시키고 그 상태에서 2번 과정으로 $p_g$에 대해 최소화를 시킵니다. 업데이트된 $p_g$에서 3번 과정으로 $D$에 대해 최대화 시키고 다시 4번 과정으로 $p_g$에 대해 최소화를 시켜서 수프리멈의 전역 최솟점을 찾을 수 있습니다. 이는 Algorithm 1에서 제안했던 방식과 정확히 일치하는 방식입니다. 이런 방식으로 $p_{g}=p_{data}$가 되는 최적점으로 수렴한다는것을 보인것 입니다. 다만 위 그림처럼 순차적으로 $D$에 대해 최대화, $p_g$에 대해 최소화를 반복하면 어떤 $U(p_{g}, D_{k_{1}})$, $U(p_{g}, D_{k_{2}})$의 최소점 사이를 왔다 갔다 할 수 있습니다. 실제로 그런 현상이 일어나는 것을 위에 실험 결과로 정리했습니다.\n", + "
\n", + "실제로 Algorithm 1은 $p_{g}$를 업데이트하는것이 아니라 $G$의 $\\boldsymbol{\\theta}_{g}$를 업데이트하게 됩니다. 하지만 위 증명은 $p_g$ 도메인에서 되었으므로 앞서 짚었듯이 $G$와 $p_g$간의 암시적 정의 관계때문에 실제로 $\\boldsymbol{\\theta}_{g}$를 업데이트 해서는 $p_g$가 $p_{data}$로 수렴하지 않을 수 있습니다. 하지만 $G$를 MLP(Multi-Layer Perceptrons)으로 구성하면 잘 되니까 합리적인 수준에서 사용할 수 있다할 수 있습니다.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 마무리\n", + "
\n", + "\n", + "
\n", + "어설프나마 end-to-end 방식으로 GANs를 이해할 수 있는 문서를 만들기 위해 주저리 주저리 적어봤습니다. 비전공자로써 내용을 이해하고 정리하는데 많은 어려움이 있었는데 TF-KR에서 많은 도움을 받아서 글을 작성할 수 있었습니다. 오류가 있다면 메일로 지적 부탁드리겠습니다.\n", + "

\n", + "작성자 조준우(metamath@gmail.com)\n", "
" ] }, @@ -1467,7 +1591,10 @@ "[9] NIPS 2016 Tutorial:Generative Adversarial Networks, Ian J. Goodfellow, arXiv:1701.00160v3, 2017
\n", "[10] Generative adversarial networks , 김남주, https://www.slideshare.net/ssuser77ee21/generative-adversarial-networks-70896091
\n", "[11] PR12와 함께하는 GANs, 유재준, https://www.slideshare.net/thinkingfactory/pr12-intro-to-gans-jaejun-yoo
\n", - "[12] 초짜 대학원생 입장에서 이해하는 Generative Adversarial Nets, 유재준, http://jaejunyoo.blogspot.com/2017/01/generative-adversarial-nets-1.html\n", + "[12] 초짜 대학원생 입장에서 이해하는 Generative Adversarial Nets, 유재준, http://jaejunyoo.blogspot.com/2017/01/generative-adversarial-nets-1.html
\n", + "[13] Wasserstein GAN 수학 이해하기 I , 임성빈, https://www.slideshare.net/ssuser7e10e4/wasserstein-gan-i
\n", + "[14] Pointwise maximum, Pointwise supremum, https://cs.uwaterloo.ca/~yuying/Courses/CS870_2012/May15_12.pdf
\n", + "[15] Subderivative, https://en.wikipedia.org/wiki/Subderivative
\n", "
" ] } @@ -1475,7 +1602,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python [default]", "language": "python", "name": "python3" },