머신러닝&딥러닝/논문리뷰

논문 리뷰: SDE-Net: Equipping Deep Neural Networks with Uncertainty Estimates

Like_Me 2020. 11. 15. 17:05
"SDE-Net: Equipping Deep Neural Networks with Uncertainty Estimates" (2020, ICML) - Lingkai Kong et al.
https://en.wikipedia.org/wiki/Euler%E2%80%93Maruyama_method
 https://arxiv.org/abs/1806.07366
https://en.wikipedia.org/wiki/Euler_method
https://github.com/msurtsukov/neural-ode/blob/master/Neural%20ODEs.ipynb
https://github.com/Lingkai-Kong/SDE-Net

 

  이번 논문은 2018 nips에 올라온 Neural ordinary differential equations(Chen et al.)의 방법에 stochastic 한 과정을 더해 uncertainty를 추가하는 방법을 제시하였다.

 

(이론과 함께 official pytorch 코드(Regression을 수행하는 모델)를 참고하여 tensorflow 코드를 첨부하였습니다.)


Introduction

 

   기존에 uncertainty를 추정하는 방법들은 베이지안 방법이 주를 이루었다. 베이지안 방법은 prior를 도입하여 posterior 분포를 추정하여야 한다. 하지만 DNN의 parameters가 너무 많아 계산이 어렵다. 그래서 non-bayesian 방법들도 나왔는데 가장 유명한 것이 model ensembling 방법이다. 이 방법은 여러 DNNs를 학습시켜 예측의 다른 정도를 가지고 uncertainty를 얻는다. 이러한 방법은 여러 모델을 학습시켜야 하므로 computational cost가 크다. 또 다른 방법들은 aleatoric uncertainty(데이터에 내재된 불확실성)와 epistemic uncertainty(모델이 모르는 불확실성)를 구분하여 측정하지 못하는 문제를 가지고 있다. 

 

이러한 문제들을 SDE-Net을 사용하여 해결한다. SDE-Net은 drift net과 diffusion net을 번갈아 가며 학습시킨다. drift net으로 예측의 정확성을 높이며 aleatoric uncertainty를 측정할 수 있고 , diffusion net으로 epistemic uncertainty를 측정하게 된다.

 

 

Uncertainty에는 2가지 종류가 있다.

Aleatoric Uncertainty

- 데이터에 내재된 노이즈(3과 8을 구분하는 것 등)에 반응한다.

- 데이터가 randomness 한 경우(동전 던지기 등)에 반응한다.

- 데이터가 많아져도 줄어들지 않는다.

- model의 output으로 직접 구한다.

 

Epistemic Uncertainty

- 모델이 모르는 부분(학습되지 않은 데이터)에서 반응한다.

- 데이터를 많이 학습시킬수록 값이 작아진다.

- sampling과 같은 방법으로 구한다.


Neural ordinary differential equations(Chen et al.)

 

  

  논문을 이해하기 위해서는 먼저 Neural ordinary differential equations를 알아야 한다. 이 논문에서는 새로운 optimize방법을 제시하였다. ordinary differential equation을 이용하는 것인데 Euler method가 대표적이다.

 

Euler method는 형태가 알려지지 않은 미지의 곡선을 찾으려고 할 때 사용하는 방법이다. 이 방법은 시작점과 해당 곡선의 미분 방정식을 알고 있다(모든 점에서의 기울기를 구할 수 있다)는 가정을 한다.

 

EX) 아래의 그림과 같이 A0가 시작점(초기값)이라고 가정하여 구해본다. A0에서의 기울기와 $\Delta t$를 곱하여 A0에 더하면 A1의 점을 구할 수 있다. 그렇게 구한 점도 곡선 위에 있다고 가정하고 같은 과정을 반복하면 A4까지 구할 수 있게 된다.

euler method

이는 간단히 $ x_{t+1} = x_{t} + \Delta t \frac {dx} {dt} $ 로 구할 수 있다. $\frac{dx} {dt}$를 $f(x, t)$로 치환하면 다음과 같다.

$$ x_{t+1} = x_{t} + \Delta x f(x,t) $$

Neural Net을 dynamic system으로 생각하여 NN의 각 layer를 연속된 과정이라고 생각하면 ODE를 사용할 수 있다. Resnet의 residual block이 연속되어 존재한다면 다음과 같이 표현할 수 있다.

$$h_{1} = f_{1}(x) + x$$

$$h_{2} = f_{2}(h_{1}) + h_{1}$$

$$h_{3} = f_{3}(h_{2}) + h_{2}$$

$$h_{4} = f_{4}(h_{3}) + h_{3}$$

위의 식을 일반화하여 나타내면 $h_{t+1} = h_{t} + f(h_{t}, \theta_{t})$이다. 만약 Euler method에서 $\Delta x$가 1이라면 위의 residual net의 식과 일치한다. 이는 어떤 하나의 곡선을 찾아나가는 과정으로 이해할 수 있다.

 

논문에서는 Adjoint sensitivity method를 ODE solver로 사용하여 기울기를 구하고 오차를 줄이며 업데이트하는 방식을 사용하였다. (자세한 내용은 논문 참조)

 

Time series model이 좀 더 직관적인데 그 과정은 다음과 같다.

A generative latent function time-series model

1. Enocder에서 posterior의 mean과 sigma를 추정하여 샘플링한다. $(z_{t_{0}}$ ~ $ N(z_{t_{0}} | \mu_{z_{t_{0}}} , \sigma_{z_{t_{0}}} ))$

 

2. ODE Solve를 이용하여 latent space에서의 latent trajectory를 얻는다. ($Z_{t_{0}} \sim Z_{t_{M}}$)

 

3. 다른 Neural Net을 이용하여 latent trajectory를 data space로 mapping 한다. ($\hat{x}(t)$)

 

4. 샘플링된 trajectory를 사용하여 ELBO를 maximize 한다.

 

간단히 말하면 시계열 데이터를 연속인 함수라고 생각하고 그것에 fitting 시켜나가는 것이다.

 

이 방법의 장점은 다음과 같다.

1. Faster testing time than RNN, but slower training time.

2. Time series 예측이 더 정확하다.

3. 새로운 optimizing의 영역을 열었다.

4. 기울기 계산의 메모리가 적게 든다.


Stochastic Differential Equation(SDE) & Brownian motion

 

  ODE는 deterministic 하여 uncertainty를 추정하지 못한다. 따라서 stochastic 한 방법(SDE)을 사용한다. 거기에 더해 brownian motion(액체나 기체 속에서 작은 입자들이 불규칙하게 움직이는 현상) term을 추가하여 epistemic uncertainty를 구한다. brownian motioin term을 추가해 epistemic uncertainty를 구하는 아이디어가 신선한 것 같다. 

 

Euler method에서 t를 $\Delta t$라고 표현하고 $\Delta t \to 0$이라면 위의 ResNet 식을 다음과 같이 표현할 수 있다.

$$ dx_{t} = f(x_{t},t)dt $$

이는 일반 ODE 식이고, brownian motion term을 추가한 SDE 식은 다음과 같다.

$$ dx_{t} = f(x_{t},t)dt + g(x_{t}, t) dW_{t}$$

(f : drift net, g : diffusion net) 

 

$f(x_{t}, t)$는 예측을 잘 해내는 것이 목표이며 $g(x_{t}, t)$는 불확실성을 아는 것이 목표이다. 그러므로 training data가 충분하여 epistemic uncertainty가 낮으면 brownian motion의 variance는 낮을 것이고 training data가 부족하여 epistemic uncertainty가 높다면 brownian motion의 variance가 클 것이다.

 


Euler-Maruyama

 

 

  원리적으로는 high-order numerical solver로 stochastic dynamics를 simulate 할 수 있지만 deep learning의 input data는 보통 high dimension을 가지므로 cost가 굉장하다. 따라서 여기서는 효율적 training을 위해 고정된 step size로 Euler-Maruyama라는 방법을 사용한다.

 

이 방법은 Euler method를 ordinary differential equaion(ODE)에서 stochastic differential equation(SDE)으로 일반화시킨 것이다. 

$ dX_{t} = a(X_{t})dt + b(X_{t})dW_{t} $라는 stochastic differential equation을 가정한다. initial condition $X_{0} = x_{0}$이며 $W_{t}$는 Wiener process, [0, T]에서 일정 시간 간격으로 SDE를 해결하려고 한다. 그러면 solution X에 대한 Euler-Maruyama 근사치는 다음과 같이 정의된 마르코프 체인 Y이다.

$$ Y_{n+1} = Y_{n} + a(Y_{n})\Delta t + b(Y_{n}) \Delta W_{n} $$

($\Delta t = T/N, Y_{0} = x_{0}, \Delta W$ : mean은 0 variance는 $\Delta t$인 i.i.d normal random variables )

 

위의 내용을 코드로 표현한 것과 시뮬레이션 결과는 다음과 같다.(위키피디아 참조)

 

import numpy as np
import matplotlib.pyplot as plt

num_sims = 5  # Display five runs

t_init = 3
t_end = 7
N = 1000  # Compute 1000 grid points
dt = float(t_end - t_init) / N
y_init = 0

c_theta = 0.7
c_mu = 1.5
# sigma 값을 높이면 diffusion이 증가한다.
c_sigma = 1


def mu(y, t):
    """Implement the Ornstein–Uhlenbeck mu."""  # = \theta (\mu-Y_t)
    return c_theta * (c_mu - y)


def sigma(y, t):
    """Implement the Ornstein–Uhlenbeck sigma."""  # = \sigma
    return c_sigma


def dW(delta_t):
    """Sample a random number at each call."""
    return np.random.normal(loc=0.0, scale=np.sqrt(delta_t))


ts = np.arange(t_init, t_end + dt, dt)
ys = np.zeros(N + 1)

ys[0] = y_init

for _ in range(num_sims):
    for i in range(1, ts.size):
        t = (i - 1) * dt
        y = ys[i - 1]
        ys[i] = y + mu(y, t) * dt + sigma(y, t) * dW(dt)
    plt.plot(ts, ys)

plt.xlabel("time (s)")
h = plt.ylabel("y")
plt.show()

sigma = 0.05
sigma = 1

 

실제 training시 사용하는 공식은 다음과 같다.

$$ x_{k+1} = x_{k} + f(x_{k}, t;\theta_{f})\Delta t + g(x_{0};\theta_{g}) \sqrt {\Delta t} Z_{k} $$

($Z_{k} \sim N(0,1), \Delta t = T/N)$

N은 SDE를 해결하는 step 수인데 neural net의 layer depth로 이해할 수 있다. 


SDE-Net : Drift net(f) + Diffusion net(g)

 

 

SDE-Net

  Drift Net f는 좋은 예측 정확도를 학습하는 것에 목표를 둔다. 또한 Aleatoric uncertainty를 측정하는 것을 목표로 한다. Regression문제의 경우 mean과 variance를 출력하여 NLL로 학습시킨다(Simple and Scalable Predictive Uncertainty Estimation Using Deep Ensembles와 같은 방법). Classification은 mean을 출력하여 cross entropy error로 학습시킨다.

 

  Diffusion Net g는 epistemice uncertainty를 구하는 것에 목표를 둔다. In-distribution(ID) data는 Brownian motion의 variance가 작아야 한다. 그래서 system state가 drift term에 의해 결정되며 output variance가 작아야 한다. 반면 Out-of-distribution(OOD) data는 Brownian motion의 variance가 커야 하며 system이 chaotic 해야 한다. 학습을 할 때 binary cross entropy error를 사용하여 fake(OOD)와 true(ID)를 잘 구별하도록 학습시킨다.

 

아래의 코드를 보면 이해가 더 쉽다. SDENet class를 보면 (training_diffusion이 아닌 경우) out이 layer_depth 만큼 반복되며 업데이트되는 것이 보인다(이는 위의 Euler-Maruyama 방법을 사용한 것). 여기서 다른 변수들은 모두 고정이고 random normal variables의 std 값이 diffusion term이 높은지 낮은지에 따라 결정되는 것을 알 수 있다.

diffusion term은 sigmoid를 통과한 값에 sigma_max 값(이는 뒤에서 설명)을 곱해주므로 0~sigma_max의 variance 크기를 갖게 된다. 

 

class Drift(Layer):
    def __init__(self):
        super(Drift, self).__init__(name="drift_net")
        self.fc = Dense(50)  # input : 50
        self.relu = ReLU()

    def call(self, t, x):
        out = self.relu(self.fc(x))
        return out


class Diffusion(Layer):
    def __init__(self):
        super(Diffusion, self).__init__(name="diffusion_net")
        self.relu = ReLU()
        self.fc1 = Dense(100)  # input : 50
        self.fc2 = Dense(1)  # input : 100

    def call(self, t, x):
        out = self.relu(self.fc1(x))
        out = self.fc2(out)
        out = tf.nn.sigmoid(out)
        return out  # batch,1
        

class SDENet(Model):
    def __init__(self, layer_depth):
        super(SDENet, self).__init__(name="SDE_Net")
        self.layer_depth = layer_depth
        self.downsampling_layers = Dense(50)  # batch, 50
        self.drift = Drift()  # batch, 1
        self.diffusion = Diffusion()
        self.fc_layers = Sequential(
            [ReLU(), Dense(2)]
        )  # input : 50, output : mean, variance
        self.deltat = 4.0 / self.layer_depth  # T:4, N:layer_depth
        self.sigma_max = 0.5  # sigma_max : scaling diffusion output

    def call(self, x, training_diffusion=False):
        out = self.downsampling_layers(x)
        if not training_diffusion:
            t = 0
            diffusion_term = self.sigma_max * self.diffusion(t, out)
            for i in range(self.layer_depth):
                t = 4 * (float(i)) / self.layer_depth
                out = (
                    out
                    + self.drift(t, out) * self.deltat
                    + diffusion_term
                    * tf.cast(tf.math.sqrt(self.deltat), "float64")
                    * tf.random.normal(tf.shape(out), dtype="float64")
                )  # Euler-Maruyama method

            final_out = self.fc_layers(out)
            mean = final_out[:, 0]
            # sigma should be greater than 0.
            sigma = tf.math.softplus(final_out[:, 1]) + 1e-3
            return mean, sigma

        else:
            t = 0
            final_out = self.diffusion(t, out)
            return final_out

 


 

 

Objective function for training

 

objective function for training

(L: loss function, $P_{train}$: distribution for training data, $P_{OOD}$: OOD data, T: terminal time of the stochastic process)

 

$ \min_{\theta_{f}}E_{x_{0} \sim P_{train}} E(L(x_{T})) $: training data로 Loss를 minimize 하며 학습시킨다.

$ \min_{\theta_{g}}E_{x_{0} \sim P_{train}} g(x_{0};\theta_{g}) $: training data를 넣었을 때 diffusion net이 low diffusion을 출력하도록 학습시킨다. 

$ \max_{\theta_{g}}E_{\hat {x}_{0} \sim P_{OOD}} g(\tilde {x}_{0};\theta_{g})$: out of distribution data를 넣었을 때 diffusion net이 high diffusion을 출력하도록 학습시킨다. (실제 학습 시에는 fake label을 주어 loss를 minimize 시킴)

 

out of distribution data는 원래 값에 Gaussian noise를 더해준 값이 된다. $\tilde {x}_{0} = x_{0} + \epsilon$

 


Uncertainty Quantification

 

  SDE-Net이 학습된 후, sampling 하여 Uncertainty를 구한다. ($(x_{T})_{m=1}^{M}$)

- 이는 기존의 Ensembling 방법과 비슷해 보인다. 하지만 기존에는 여러 deterministic NNs를 학습시켜야 했지만 SDE는 하나의 NN만 학습시키면 된다,

 

Aleatoric uncertainty : Regression의 경우  FC layer를 통해 출력되는 variance의 sampling 된 mean 값을 통해 구할 수 있다. Classification 문제는 entropy를 통해 구할 수 있다. 

 

Epistemic uncertainty : $x_{T}$에 대한 variance : $Var(x_{T})$ = $\frac {1} {M} \sum_{m=1}^{M} x_{T}^{2} - (\frac {1} {M} \sum_{m=1}^{M} x_{T})^{2}$

 


 

Theoretical Analysis

 

  여기서 제안된 stochastic system의 solution인 $x_{t} (0 \leq t \leq T)$가 존재하고 unique 하다는 증명.

C>0가 존재하면 다음을 만족한다.

$$|| f(x, t;\theta_{f}) - f(y, t;\theta_{f})|| + ||g(x;\theta_{g} - g(y;\theta_{g})|| \leq C||x-y||$$

($x, y \in R^{n}, t \geq 0$)

 

그러면 unique continuous and adapted process $(x_{t}^{x_{0}})_{t \geq 0}$가 존재한다. (t $ \geq 0 $)

$$ x_{t}^{x_{0}} = x_{0} + \int_{0}^{t} f(x_{s}^{x_{0}}, t;\theta_{f})ds + \int_{0}^{t} g(x_{0};\theta_{g})dW_{s} $$

 

위의 정리가 만족하려면 drift net f와 diffusion net  g는 uniformly Lipschitz 여야 한다(Lipschitz condition : 대부분 미분 가능하며 연속성이 보장되고 도함수가 유계인 함수). 이것은 ReLU나 sigmoid, Tanh 같은 Lipshitz nonlinearactivations를 Neural net에 쓰면 된다. 그러나 그냥 optimize를 하면 $g(x_{0};\theta_{g})$가 OOD데이터를 받을 때 infinity 한 값이 나올 수 있다. 따라서 $\sigma_{max}$라는 hyper-parameter를 추가하여 $g(x;\theta_{g})$ output value의 maximum값을 정해준다. 이것은 diffusion layer의 말단에 있는 sigmoid를 통과한 값에 $\sigma_{max}$를 곱해주는 식으로 구현한다.

 


 

Algorithm

 

  학습 Algorithm은 다음과 같다.

algorithm

1. training data를 활용하여 downsampling layer를 통과시켜 $X_{0}^{N_{M}}$를 얻는다.

2. $X_{0}^{N_{0}}$로 Euler-Maruyama method를 활용하여 N번의 step을 통과시킨다.  

3. Fully connected layer를 통과시킨다.

4. Loss를 구하고 down sampling layer와 Fullyconnected layer, drift net을 학습시킨다.

5. out-of-distribution data를 얻어 down sampling layer를 통과시켜 $\tilde {X}_{0}^{N_{M}}$을 얻는다.

6. $X_{0}^{N_{M}}$과 $\tilde{X}_{0}^{N_{M}}$을 diffusion net에 통과시켜 output을 얻는다.

7. 각각 true label과 fake label을 줘서 binary crossentropy로 diffusion net을 학습시킨다. (diffusion net이 ID와 OOD를 구분하게 하는 학습)

 

 위와 같이 drift net과 diffusion net을 번갈아 가며 학습시킨다.

 

코드로 나타내면 아래와 같다. 처음 기울기가 너무 커져 nan값이 나와 clip by norm 처리를 해주었다. 먼저 drift net, fc layer, down sampling layer를 학습시켜 준다. 그다음 diffusion layer를 in-distribution data와 out-of-distribution data로 번갈이 학습시켜 업데이트해준다.

real_label = 0
fake_label = 1

@tf.function
def train_net(x, y):
    with tf.GradientTape(persistent=True) as tape:
        mean, sigma = model(x, training_diffusion=False)
        loss = nll_loss(y, mean, sigma)

    drift_gradient = tape.gradient(loss, model.drift.trainable_variables)
    dsl_gradient = tape.gradient(loss, model.downsampling_layers.trainable_variables)
    fc_gradient = tape.gradient(loss, model.fc_layers.trainable_variables)

    drift_gradient = [(tf.clip_by_norm(grad, 100)) for grad in drift_gradient]
    dsl_gradient = [(tf.clip_by_norm(grad, 100)) for grad in dsl_gradient]
    fc_gradient = [(tf.clip_by_norm(grad, 100)) for grad in fc_gradient]

    optimizer_drift.apply_gradients(
        zip(drift_gradient, model.drift.trainable_variables)
    )
    optimizer_dsl.apply_gradients(
        zip(dsl_gradient, model.downsampling_layers.trainable_variables)
    )
    optimizer_fc.apply_gradients(zip(fc_gradient, model.fc_layers.trainable_variables))



@tf.function
def train_diffusion(real_x):
    with tf.GradientTape(watch_accessed_variables=False) as real_tape_diffusion:
        # only access to diffusion layer's parameters
        real_tape_diffusion.watch(model.diffusion.trainable_variables)
        real_y = tf.fill((real_x.shape[0], 1), real_label)
        real_pred = model(real_x, training_diffusion=True)
        real_loss = mse(real_y, real_pred)

    diffusion_gradient = real_tape_diffusion.gradient(
        real_loss, model.diffusion.trainable_variables
    )

    diffusion_gradient1 = [(tf.clip_by_norm(grad, 100)) for grad in diffusion_gradient]

    with tf.GradientTape(watch_accessed_variables=False) as fake_tape_diffusion:
        fake_tape_diffusion.watch(model.diffusion.trainable_variables)
        # fake std is 2 in official code, but in paper it is 4
        fake_x = (
            tf.cast(
                tf.random.normal((real_x.shape[0], 90), mean=0, stddev=2), "float64"
            )
            + real_x
        )
        fake_y = tf.fill((real_x.shape[0], 1), fake_label)
        fake_pred = model(fake_x, training_diffusion=True)
        fake_loss = mse(fake_y, fake_pred)

    diffusion_gradient = fake_tape_diffusion.gradient(
        fake_loss, model.diffusion.trainable_variables
    )

    diffusion_gradient2 = [(tf.clip_by_norm(grad, 100)) for grad in diffusion_gradient]

    diffusion_gradient = [
        grad1 + grad2 for grad1, grad2 in zip(diffusion_gradient1, diffusion_gradient2)
    ]

    optimizer_diffusion.apply_gradients(
        zip(diffusion_gradient, model.diffusion.trainable_variables)
    )

 


Experiments

 

  SDE-Net과 비교하는 모델들은 다음과 같다.

1) Threshold (Hendrucks & Gimple, 2017)

2) MC-dropout (Gal & Ghahramani, 2016)

3) DeepEnsemble (Lakshminarayanan et al., 2017) -> 5 neural net in ensemble

4) Prior Network (PN) (Malinin & Gales, 2018)

5) Bayes By Backpropagation (BBP) (Blundell et al., 2015)

6) preconditioned Stochastic gradient Langevin dynamics (p-SGLD) (Li et al., 2016)

 

SDE-Net은 10번의 sampling 사용.

 

1. Out of distribution detection

 

- Classfication

table1

MNIST, SVHN으로 각각 training 시키고 OOD를 넣었을 때 성능은 위의 table1과 같다. 단순 accuracy는 DeepEnsemble 모델이 제일 좋지만 parameters가 5배로(model을 5개 학습시킴) 들었음에도 SDE-Net과 차이가 크지 않다. 반면 TNR, AUROC, AUPR 등 모두 SDE-Net이 뛰어난 결과를 가져왔다. 특히 SVHN을 학습시키고 CIFAR를 OOD로 넣었을 때의 결과는 다른 모델들과 상당히 차이가 난다.

 

- Regression

table6

Regression은 Year prediction MSD 데이터에 대해 학습하고 Boston Housing 데이터 셋을 OOD 데이터로 넣었다. 다른 모델들은 OOD 데이터에 정말 취약한 모습으로 보인다. 기본적으로 regression task는 연속적이고 한이 없기 때문에 uncertainty를 알아내기 굉장히 어렵기 때문이다. 하지만 SDE-Net은 상당히 좋은 결과를 내었다. diffusion net이 input data와 OOD데이터를 통해 직접적으로 학습하기 때문에 좋은 성능을 낸 것으로 보인다.

 

 

2. Misclassification Detection

 

table3

Misclassification detection 결과는 DeepEnsemble이 좋다. 하지만 SDE-Net과 별로 차이가 나지 않는 반면 computational cost는 높기 때문에 SDE-Net을 사용하는 것이 더 좋은 선택이 될 수 있다.

 

 

3. Adversarial Sample Detection

 

  DNN은 데이터에 작은 adversarial perturbations를 준 adversarial examples에 굉장히 취약하다. 그래서 adversarial samples를 잘 detect 하는 것이 중요하다. SDE-Net은 따로 adversarial training을 하지는 않았지만 실험을 하였다. 여기서는 Fast Gradient-Sign Method(FGSM)과 Projected Gradient Descent(PGD) 방법으로 실험하였다.

figure 5 - FGSM

먼저 FGSM방법에 대한 결과가 figure 5에 나와있다. adversarial size $\epsilon$에 따른 detection 결과인데 MNIST의 경우 쉬운 task라 대부분의 모델들이 잘 수행하고 있다. 하지만 SVHN은 SDE-Net만 $\epsilon$값이 커지며 100%에 수렴하고 있는 것으로 보인다.

 

figure 6 - PGD

 

 

PGD방법에 대한 결과는 figure 6에 나와있다. MNIST의 경우 SDE-Net이 가장 outperform 한 결과를 내보였다. 하지만 SVHN은 DeepEnsemble을 제외한 나머지는 굉장히 좋지 못한 결과를 보였다. 이는 SVHN의 manifold가 high dimension을 가져 그럴 가능성이 높다고 한다. 그래서 이를 효율적이고 robust 하게 개선하는 것이 further work라고 소개한다.

 

 

4. Active Learning

 

   사람이 많은 데이터를 labeling 하는 것은 cost가 많이 든다. 따라서 '모델이 labeling 된 약간의 데이터를 학습한 다음 labeling이 안된 데이터 중 좋은 데이터를 골라내게 하겠다'라는 아이디어가 active learning이다. 이때 uncertainty가 중요한 역할을 하게 된다. epistemic uncertainty가 높고 aleatoric uncertainty가 낮은 영역의 data를 뽑아내게 하면 학습이 잘 될 것이다. 그렇지 못한다면 overfitting이 되어 성능이 악화될 수도 있다.

 

figure 7 - active learning

 

active learning의 결과는 figure 7에 나와 있다. 처음에 50개의 데이터로 학습하고 각 epoch마다 50개의 데이터를 추가로 선택하여 학습을 진행한다. 총 100 epochs를 진행하였다.

예상대로 SDE-Net이 굉장히 좋은 결과를 내고 있다. uncertainty에 대한 측정이 좋았기 때문에 informative data를 잘 뽑아낸 것이다. 예상외로 MC-dropout도 상당히 좋은 결과를 얻었다. 반면 DeepEnsemble방법은 좋지 못한 결과를 내었다.

cost는 많이 들지만 다른 task에서는 좋은 결과를 내었기 때문에 여기서도 괜찮을 것이라고 예상하였는데 의외였다.

 

 

 


Conclusion

 

- Stochastic Differential Equation과 Brownian motion을 활용하여 Uncertainty를 추정하는 모델을 제시하였다. 

 

- 모델은 drift net과 diffusion net으로 나누어 학습을 하고 각각 accuracy와 epistemic uncertainty를 담당하게 된다.

 

- Euler-Maruyama method를 사용하여 학습을 진행한다.

 

- 모델의 장점은 다음과 같다.

 

  1. 하나의 모델만 사용하여 학습에 대한 cost가 (ensembling 방법보다) 작다.

 

  2. aleatoric uncertainty와 epistemic uncertainty를 구분할 수 있다.

 

  3. prior 분포를 특정할 필요가 없고 posterior 분포를 추정할 필요가 없어 효율적이다.

 

  4. classification과 regression 둘 다 수행 가능하다.

 

  5. OOD(out of distribution) detection, Misclassification Detection, Adversarial Sample Detection, Active Learning 모두에서 좋은 성능을 보인다.

 


pytorch를 활용한 Official code가 Github에 있어 Colab을 이용하여 train 시켜 보았을 때 논문에서 제시한 것과 비슷한 결과를 얻었습니다. 

Tensorflow로 변환한 파일도 따로 만들어 깃헙에 올려두었으나 성능이 torch와는 다르게 나왔습니다. 같은 구조를 만들었다고(learning rate 조정을 하는 부분을 제외하고) 생각하였으나 다른 부분에 문제가 있는 것인지 모르겠습니다.

 

Tensorflow를 활용한 깃헙 파일을 올려두었으니 혹시 문제를 아시는 분은 댓글로 남겨주시면 감사하겠습니다. (참고로 모델은 1 epoch의 훈련만 진행하였습니다.)  

 

그러므로 논문의 결과를 재현하고자 하면 pytorch 코드를 사용하는 것을 추천합니다. pytorch를 사용한 colab 파일 또한 깃헙에 따로 올려두었습니다.

 

official code : github.com/Lingkai-Kong/SDE-Net

깃헙 주소 : github.com/Junghwan-brian/SDE-Net