신경망에서 해상도 독립적 인 이미지 표현 (MNIST)

소개



뉴럴 넷으로 화상을 출력할 때, 통상은 해상도마다 전용의 모델을 준비해 학습을 실시하게 됩니다.
이번에는 해상도에 의존하지 않는 형태로, 화상상의 임의의 점으로부터 샘플링을 실시하는 모델에 대해 생각해 보겠습니다.
이미지의 점 $(u, v)$의 값을 $P_{u, v}$로 설정하면,
$$ P_{u, v} = f(u, v, z_1, ..., z_n) $$
되는 함수 $f$를 신경망으로 표현하고 싶습니다. 여기서 $\lbrace z_1, ..., z_n\rbrace$는 이미지를 나타내는 잠재 표현입니다.
이번에는 이 잠재 표현을 VAE의 엔코더부를 이용하여 얻기로 하고, 디코더부가 되는 함수 $f$를 4층의 전체 결합 신경망으로 표현해 보았습니다.

Chainer에 의한 구현 (github)

구현



전체 구성은 일반 VAE와 동일합니다.
차이는 디코더부에서 이렇게 되어 있습니다.

model.py
class SamplingDecoder(chainer.Chain):
    def __init__(self, input_size):
        super().__init__()
        units = [2 + input_size, 256, 256, 256, 1]
        initializer = chainer.initializers.HeNormal()
        with self.init_scope():
            self.linear1 = chainer.links.Linear(units[0], units[1], initialW=initializer)
            self.linear2 = chainer.links.Linear(units[1], units[2], initialW=initializer)
            self.linear3 = chainer.links.Linear(units[2], units[3], initialW=initializer)
            self.linear4 = chainer.links.Linear(units[3], units[4], initialW=initializer)

    def decode(self, z):
        h = z
        h = self.linear1(h)
        h = chainer.functions.relu(h)
        h = self.linear2(h)
        h = chainer.functions.relu(h)
        h = self.linear3(h)
        h = chainer.functions.relu(h)
        h = self.linear4(h)
        return h

    def __call__(self, z, x0_shape):
        xp = self.xp

        # Generate (u, v) coordinates for every samples.
        u = xp.linspace(-1.0, 1.0, x0_shape[2], dtype=xp.float32)
        v = xp.linspace(-1.0, 1.0, x0_shape[3], dtype=xp.float32)
        uv = xp.broadcast_arrays(u[None, None, :, None], v[None, None, None, :])
        uv = xp.concatenate(uv, 1)
        uv = xp.broadcast_to(uv, (z.shape[0], uv.shape[1], uv.shape[2], uv.shape[3]))

        z = z[:, :, None, None]
        z = chainer.functions.broadcast_to(z, (z.shape[0], z.shape[1], uv.shape[2], uv.shape[3]))

        # Combine them.
        uvz = chainer.functions.concat((uv, z))
        uvz = chainer.functions.transpose(uvz, (0, 2, 3, 1))
        uvz = chainer.functions.reshape(uvz, (-1, uvz.shape[3]))

        y = self.decode(uvz)

        y = chainer.functions.reshape(y, (x0_shape[0], x0_shape[2], x0_shape[3], x0_shape[1]))
        y = chainer.functions.transpose(y, (0, 3, 1, 2))
        return y

우선, 화상상에서 출력값을 얻고 싶은 모든 점에 대해 좌표치(u, v)를 생성하고 있습니다. 이것을 잠재 표현 $\lbrace z_1, ..., z_n\rbrace $와 아울러 decode()에 주는 것입니다.
출력에 대한 손실 함수는 베르누이 분포의 음의 로그 우도를 사용합니다.

출력



잠재 표현을 8 차원으로 한 학습 결과입니다.

1 에포크 눈





(위 : 원본 데이터, 아래 : 학습 후 모델에 의한 168x168 렌더링 결과)

50 에포크 눈





(위 : 원본 데이터, 아래 : 학습 후 모델에 의한 168x168 렌더링 결과)

잘 데이터를 재현 할 수있는 것 같습니다.
다만, 통상의 화상 보간 알고리즘에 의한 결과와 크게 변하지 않는 것 같은 생각도 합니다.

좋은 웹페이지 즐겨찾기