Gaussian Process Practice (3) Beware Boundaries

  • Gaussian Process 연습입니다.
  • scikit-learn을 비롯한 예제를 재구성하여 연습합니다.
  • 주의사항을 알려드립니다. Gaussian Process는 경계조건에 매우 취약합니다.

1. Gaussian Process의 한계

scikit-learn: Gaussian Process Regression: basic introductory example

  • Gaussian Process는 적은 데이터로도 꽤 믿을만한 결과를 출력합니다.

  • 심지어 신뢰 구간까지 알 수 있어서 매우 정직해 보입니다.

  • 하지만 치명적인 단점이 있습니다.

  • 지난 글과 같은 예제를 사용합니다.

  • 모든 것이 정상으로 보입니다.

  • 합리적인 범위의 평균값(GP prediction (mean))과 신뢰 구간(95% CI)을 보이고 있습니다.

  • 하지만 오른쪽 끄트머리를 보면, 조금 미심쩍습니다.

  • 참값이 신뢰 구간의 바닥에 겨우 걸려있습니다.

    개그콘서트, "불편한 진실"

  • 극단적인 경우를 살펴봅니다.

  • X 값의 범위로 참값의 좌우에 50씩을 보태 -50 ~ 60을 입력합니다.

  • 평균이 0, 95% 신뢰구간이 무려 10에 가까운 커다란 밴드가 생겼습니다.

  • 다항회귀를 해도 이렇지는 않을 것 같습니다.


  • Gaussian Process의 원리에 답이 있습니다.

  • Gaussian 분포를 prior로 놓기 때문에 평균이 0입니다.

  • 학습 데이터(evidence)가 반영된 구간 안쪽은 그나마 괜찮지만 바깥쪽이 문제입니다.

  • 안쪽에서 학습을 시켜봐야 바깥쪽의 중심값이 0이라고 가정되어 있기 때문에 저런 일이 벌어집니다.

2. 비교

  • 조금 더 확실하게 확인합니다.

  • 위의 예제에 offset = $\pm 5$를 해서 새로운 참값을 만듭니다.

  • 그리고, 여기서 같은 X 좌표의 데이터들을 학습용으로 추출합니다.


  • 여기에 똑같은 RBF 커널을 적용한 Gaussian Process를 적용하면 아래와 같은 결과가 나옵니다.

  • 좌우 그림에서 파란 선으로 표시한 평균값의 양 끝이 향하는 방향이 반대입니다.

  • offset=+5인 왼쪽 그림은 양 끝이 아래를 향하고 있고,

  • offset=-5인 오른쪽 그림은 양 끝이 기를 쓰고 고개를 들려고 하고 있습니다.

  • 모두 0을 향하고 있습니다.


  • 양 끝만 영향을 받는 것이 아닙니다.

  • X = 6~8 사이 구간도 offset에 따라 달라집니다.

  • 0에서 먼 왼쪽 그림은 신뢰 구간이 비교적 얇은 반면 오른쪽은 두텁고 mean 값도 참값과 더 벌어져 있습니다.

3. Solution

  • 해결 방법은 생각보다 간단합니다.

  • 외삽(extrapolation)이 문제라면 외삽을 하지 않으면 됩니다.

  • 학습 데이터에 데이터 범위의 양 끝을 추가하면 모든 범위가 내삽이 됩니다.

    1
    2
    3
    4
    # sample including ends
    training_indices += [0, 999]
    Xp_train1, Xm_train1 = Xp[training_indices], Xm[training_indices]
    yp_train1, ym_train1 = yp[training_indices], ym[training_indices]
  • 그리고 같은 학습을 시키면 offset에 관계 없이 동일한 결과를 얻을 수 있습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    kernel = 1*RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2))

    fig, axs = plt.subplots(ncols=2, figsize=(6, 3), constrained_layout=True, sharex=True, sharey=True)

    for ax, X, y, X_train, y_train, title in zip(axs, [Xp, Xm], [yp, ym],
    [Xp_train1, Xm_train1], [yp_train1, ym_train1],
    ["offset = +5", "offset = -5"]):
    # Gaussian Process
    gpr = GaussianProcessRegressor(kernel, n_restarts_optimizer=9, random_state=0)
    gpr.fit(X_train, y_train)

    # prediction
    y_pred_mean, y_pred_std = gpr.predict(X, return_std=True)

    ax.plot(X, y, c="0.5", label="true")
    ax.scatter(X_train, y_train, label="sample")
    ax.plot(X.ravel(), y_pred_mean, c="b", label="GP prediction (mean)")
    ax.fill_between(X.ravel(), y_pred_mean-1.96*y_pred_std, y_pred_mean+1.96*y_pred_std, alpha=0.5, fc="cornflowerblue", label="95% CI")
    ax.axhline(0, c="g", lw=1)
    ax.set_title(title, pad=12)


    axs[0].legend(loc="lower right")


4. 결론

  • 머신 러닝 기법들이 모두 그렇지만 외삽은 주의해야 합니다.
  • Gaussian Process는 prior의 존재로 인해 외삽에 더 취약할 수 있으니 각별히 주의해야 합니다.
  • 본 글에 사용된 코드는 여기에서 다운받으실 수 있습니다.


도움이 되셨나요? 카페인을 투입하시면 다음 포스팅으로 변환됩니다

Share