먼저 ➊, ➍를 살펴보면 노드의 수는 각각 64개, 128개로 정했고, 커널 크기는 5로 설정해 5×5 커널이 사용된다는 것을 알 수 있습니다.
discriminator.add(Conv2D(64, =5, =2, = (28,28,1), ="same")) ----- ➊ discriminator.add(Conv2D(128, =5, =2, ="same")) ----- ➍
여기에 strides 옵션이 처음 등장했습니다. strides는 커널 윈도를 몇 칸씩 이동시킬지 정하는 옵션입니다. 특별한 설정이 없으면 커널 윈도는 한 칸씩 움직입니다. strides=2라고 설정했다는 것은 커널 윈도를 두 칸씩 움직이라는 뜻입니다.
strides를 써서 커널 윈도를 여러 칸 움직이게 하는 이유는 무엇일까요? 가로세로 크기가 더 줄어들어 새로운 특징을 뽑아 주는 효과가 생기기 때문입니다. 드롭아웃이나 풀링처럼 새로운 필터를 적용한 효과가 생기는 것입니다. 생성자에서는 출력 수를 28로 맞추어야 하기 때문에 오히려 업샘플링을 통해 가로세로의 수를 늘려 주었지만 판별자는 진짜와 가짜만 구분하면 되기 때문에 그럴 필요가 없습니다. strides나 드롭아웃(➌, ➏) 등 차원을 줄여 주는 기능을 적극적으로 사용하면서 컨볼루션 신경망 본래의 목적을 달성하면 됩니다.
➋, ➎ 는 활성화 함수로 LeakyReLU() 함수를 사용한 것을 보여 줍니다.
➐, ➑ 은 가로×세로의 2차원으로 진행된 과정을 1차원으로 바꾸어 주는 Flatten() 함수와 마지막 활성화 함수로 sigmoid() 함수를 사용하는 과정입니다. 판별의 결과가 진짜(1) 혹은 가짜(0), 둘 중에 하나가 되어야 하므로 sigmoid() 함수를 썼습니다.
➒ 에서는 이제 이진 로스 함수(binary_crossentropy)와 최적화 함수(adam)를 써서 판별자에 필요한 준비를 마무리합니다.
➓ 에서는 앞서 설명한 대로 판별이 끝나고 나면 판별자 자신이 학습되지 않게끔 학습 기능을 꺼 줍니다. discriminator.trainable = False라는 옵션으로 이를 설정할 수 있습니다.