Вывод принципа байесовской нейронной сети BNN и реализация на Python

глубокое обучение

1. Введение

Байесовские нейронные сети отличаются от обычных нейронных сетей тем, что их весовые параметры являются случайными величинами, а не детерминированными значениями. Как показано ниже:

在这里插入图片描述

То есть, в отличие от традиционных нейронных сетей, которые используют функции потерь, такие как перекрестная энтропия и mse, для соответствия значениям меток, байесовские нейронные сети соответствуют апостериорному распределению.

Преимущество этого заключается в уменьшении переобучения.

2. Модель БНН

В отличие от DNN, BNN может изучать распределение предсказания, не только может давать предсказанное значение, но также можетдают неопределенность прогноза. Это очень важно для многих проблем, таких как: знаменитая проблема исследования и эксплуатации (EE) в машинном обучении, в задачах обучения с подкреплением, нужно ли агенту использовать существующие знания для принятия решений или попробовать что-то неизвестное, экспериментальный дизайн. , байесовская оптимизация используется для настройки гиперпараметров, а следующая точка выбирается на основе оптимального значения текущей модели или путем исследования некоторого пространства с высокой неопределенностью. Например:Обнаружение аномального образца, такие задачи, как обнаружение состязательной выборки, из-за способности количественной оценки неопределенности BNN, он имеет очень сильнуюпрочность.

Вероятностное моделирование: 在这里插入图片描述Здесь сопряженное распределение распределения правдоподобия выбирается таким образом, чтобы апостериорное значение можно было вычислить аналитически. Например, априорное значение бета-распределения и вероятность распределения Бернулли приведут к апостериорному значению, которое подчиняется бета-распределению.在这里插入图片描述

Из-за сопряженного распределения априорное распределение должно быть ограничено. Поэтому мы пытаемся аппроксимировать апостериорное распределение с помощью принятия и вариационного вывода.


Нейронные сети:Использование полностью подключенной сети для соответствия данным эквивалентно использованию нескольких полностью подключенных сетей. Однако нейронная сеть склонна к переобучению и имеет плохую генерализацию, что не может дать уверенности в прогнозируемых результатах.

BNN:Объедините вероятностное моделирование с нейронными сетями и будьте уверены в прогнозируемых результатах.

Априоры используются для описания ключевых параметров и служат входными данными для нейронной сети. Выход нейронной сети используется для описания вероятности определенного распределения вероятностей. Апостериорное распределение вычисляется путем выборки или вариационного вывода. При этом, в отличие от нейронных сетей, вес W является уже не определенной величиной, а распределением вероятностей.


BNN моделируется следующим образом:

Предположим, что сетевые параметры NN равныWW,p(W)p(W)- априорное распределение параметров с учетом наблюдаемых данныхD=X,YD={X,Y},здесьXXвходные данные,YYэто данные этикетки. BNN рассчитывает дать следующее распределение:

То есть наше прогнозируемое значение равно:

P(YX,D)=P(YX,W)P(WD)dW(1)P\left(Y^{\star} | X^{\star}, D\right)=\int P\left(Y^{\star} | X^{\star}, W\right) P(W |Д) д Ш (1)

так как,WWявляется случайной величиной, поэтому наше предсказанное значение также является случайной величиной.

в:

P(WD)=P(W)P(DW)P(D)(2)P(W | D)=\frac{P(W) P(D | W)}{P(D)} (2)

здесьP(WD)P(W|D)это апостериорное распределение,P(DW)P(D|W)функция правдоподобия,P(D)P(D)является предельной вероятностью.

Из формулы (1) видно, что суть использования BNN для вероятностного моделирования и прогнозирования данных состоит в том, чтобы сделать эффективный приблизительный апостериорный вывод, и вариационный вывод VI или выборка являются очень подходящим методом.

Если выборка: Мы выбираем апостериорное распределениеP(WD)P(W \vert \mathcal{D})оценитьP(WD)P(W \vert \mathcal{D}), рассчитанный для каждого образцаf(Xw)f(X \vert w), где f — наша нейронная сеть.

Это наш результат, который представляет собой распределение, а не значение, по которому мы можем оценить неопределенность наших прогнозов.

3. Обучение BNN на основе вариационного вывода

Если вы напрямую выбираете апостериорную вероятностьp(WD)p(W|D)оценитьp(YX,D)p(Y|X, D)Если , существует многомерная проблема апостериорного распределения, и идея вариационного вывода состоит в том, чтобы использовать простое распределение для аппроксимации апостериорного распределения.

выражатьθ=(мю,о)\theta = (\mu, \sigma), каждый весwiw_iиз нормального распределения(мюi,оi)(\mu_i, \sigma_i)средняя выборка.

надеятьсяq(wθ)q(w \vert \theta)иP(wD)P(w \vert \mathcal{D})похожи, и используйте дивергенцию KL для измерения расстояния между двумя распределениями. То есть оптимизировать:

θ*=argminθКЛ[q(wθ)P(wD)]  (3)\theta^* = \underset{\theta}{\mathrm{argmin}} \text{ KL}\left[q(w \vert \theta) \vert \vert P(w \vert \mathcal{D})\right] \; (3)

Дальнейшее происхождение:

θ*=argminθКЛ[q(wθ)P(wD)]=argminθ Eq(wθ)[log[q(wθ)P(wD)]](определение дивергенции KL)=argminθ Eq(wθ)[log[q(wθ)P(D)P(Dw)P(w)]](Теорема Байеса)=argminθ Eq(wθ)[log[q(wθ)P(Dw)P(w)]](УронитьP(D)потому что это не зависитθ)  (4)\begin{array}{l} \theta^* &= \underset{\theta}{\mathrm{argmin}} \text{KL}\left[q(w \vert \theta) \vert \vert P(w \vert \mathcal{D})\right] & \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta) }\left[ \log\left[\frac{ q(w \vert \theta) }{P( w \vert \mathcal{D})}\right]\right] & \text{(определение расхождения KL) } \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac { q(w \vert \theta)P(\mathcal{D})}{P(\mathcal{D} \vertw)P(w)}\right]\right] & \text{(Теорема Байеса)} \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] & \text{(Drop }P(\mathcal{D})\text{ потому что это не зависит от } \theta) \end{array} \;(4)

формула,q(wθ)q(w|\theta)Представляет распределение весовых параметров с учетом параметров нормального распределения;P(Dw)P(D|w)Представляет вероятность наблюдаемых данных после заданных параметров сети;P(w)P(w)Представляет априорные значения весов, которые можно использовать в качестве регуляризации модели.

и использовать

L=Eq(wθ)[log[q(wθ)P(Dw)P(w)]]  (5)\mathcal{L} = - \mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] \;(5)

для представления вариационной нижней границы ELBO, то есть формула (4) эквивалентна максимизации ELBO:

L=ilogq(wiθi)ilogP(wi)jlogP(yjw,xj)  (6)\mathcal{L} = \sum_i \log q(w_i \vert \theta_i) - \sum_i \log P(w_i) - \sum_j \log P(y_j \vert w, x_j) \;(6)

в,D={(x,y)}D =\{ (x, y)\}

Нам нужно вывести математическое ожидание в уравнении (4), но здесь мы используем прием перепараметризации весов:

wi=мюi+оi×ϵi  (7)w_i = \mu_i + \sigma_i \times \epsilon_i \; (7)

в,ϵiN(0,1)\epsilon_i \sim \mathcal{N}(0,1).

Итак, используйтеϵ\epsilonзаменятьwwс последующим:

θEq(ϵ)[log[q(wθ)P(Dw)P(w)]]=Eq(ϵ)[θlog[q(wθ)P(Dw)P(w)]]  (8)\frac{\partial}{\partial \theta}\mathbb{E}_{q(\epsilon)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] =\mathbb{E}_{q(\epsilon)}\left[ \frac{\partial}{\partial \theta}\log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] \; (8)

То есть мы можем передать несколько разныхϵN(0,1)\epsilon \sim \mathcal{N}(0,1), спроситьθlog[q(wθ)P(Dw)P(w)]\frac{\partial}{\partial \theta}\log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]для аппроксимации пары расхождений KLθ\thetaруководство.

Кроме того, кромеwwВ дополнение к повторной выборке, чтобы обеспечитьθ\thetaДиапазон значений параметра включает эту реальную ось, дляо\sigmaДля повторной выборки мы можем сделать,

о=log(1+eр)      (9)\sigma = \log (1 + e^{\rho}) \;\;\; (9)

Потом,θ=(мю,р)\theta = (\mu, \rho),здесьθ\thetaбыло определено как изначальноθ=(мю,о)\theta = (\mu, \sigma)Не то же самое.

4. Практика БНН

алгоритм:

  1. отN(мю,log(1+eр))N(\mu, log(1+e^\rho))пробовать, получитьww;
  2. Рассчитать отдельноlogq(wθ)\log q(w|\theta),logp(w)\log p(w),logp(yw,x)\log p(y|w,x).

Среди них расчетlogp(yw,x)\log p(y|w,x)фактический расчетlogp(yypred)\log p(y|y_{pred}), ypred=w*xy_{pred} = w*x. также получитьL=ilogq(wiθi)ilogP(wi)jlogP(yjw,xj)\mathcal{L} = \sum_i \log q(w_i \vert \theta_i) - \sum_i \log P(w_i) - \sum_j \log P(y_j \vert w, x_j). 3. Неоднократно обновлять параметрыθ=θальфаθL\тета' = \тета -\альфа \набла_\тета \mathcal{L}.

Реализация Питорча:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.distributions import Normal
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt

class Linear_BBB(nn.Module):
    """
        Layer of our BNN.
    """
    def __init__(self, input_features, output_features, prior_var=1.):
        """
            Initialization of our layer : our prior is a normal distribution
            centered in 0 and of variance 20.
        """
        # initialize layers
        super().__init__()
        # set input and output dimensions
        self.input_features = input_features
        self.output_features = output_features

        # initialize mu and rho parameters for the weights of the layer
        self.w_mu = nn.Parameter(torch.zeros(output_features, input_features))
        self.w_rho = nn.Parameter(torch.zeros(output_features, input_features))

        #initialize mu and rho parameters for the layer's bias
        self.b_mu =  nn.Parameter(torch.zeros(output_features))
        self.b_rho = nn.Parameter(torch.zeros(output_features))        

        #initialize weight samples (these will be calculated whenever the layer makes a prediction)
        self.w = None
        self.b = None

        # initialize prior distribution for all of the weights and biases
        self.prior = torch.distributions.Normal(0,prior_var)

    def forward(self, input):
        """
          Optimization process
        """
        # sample weights
        w_epsilon = Normal(0,1).sample(self.w_mu.shape)
        self.w = self.w_mu + torch.log(1+torch.exp(self.w_rho)) * w_epsilon

        # sample bias
        b_epsilon = Normal(0,1).sample(self.b_mu.shape)
        self.b = self.b_mu + torch.log(1+torch.exp(self.b_rho)) * b_epsilon

        # record log prior by evaluating log pdf of prior at sampled weight and bias
        w_log_prior = self.prior.log_prob(self.w)
        b_log_prior = self.prior.log_prob(self.b)
        self.log_prior = torch.sum(w_log_prior) + torch.sum(b_log_prior)

        # record log variational posterior by evaluating log pdf of normal distribution defined by parameters with respect at the sampled values
        self.w_post = Normal(self.w_mu.data, torch.log(1+torch.exp(self.w_rho)))
        self.b_post = Normal(self.b_mu.data, torch.log(1+torch.exp(self.b_rho)))
        self.log_post = self.w_post.log_prob(self.w).sum() + self.b_post.log_prob(self.b).sum()

        return F.linear(input, self.w, self.b)

class MLP_BBB(nn.Module):
    def __init__(self, hidden_units, noise_tol=.1,  prior_var=1.):

        # initialize the network like you would with a standard multilayer perceptron, but using the BBB layer
        super().__init__()
        self.hidden = Linear_BBB(1,hidden_units, prior_var=prior_var)
        self.out = Linear_BBB(hidden_units, 1, prior_var=prior_var)
        self.noise_tol = noise_tol # we will use the noise tolerance to calculate our likelihood

    def forward(self, x):
        # again, this is equivalent to a standard multilayer perceptron
        x = torch.sigmoid(self.hidden(x))
        x = self.out(x)
        return x

    def log_prior(self):
        # calculate the log prior over all the layers
        return self.hidden.log_prior + self.out.log_prior

    def log_post(self):
        # calculate the log posterior over all the layers
        return self.hidden.log_post + self.out.log_post

    def sample_elbo(self, input, target, samples):
        # we calculate the negative elbo, which will be our loss function
        #initialize tensors
        outputs = torch.zeros(samples, target.shape[0])
        log_priors = torch.zeros(samples)
        log_posts = torch.zeros(samples)
        log_likes = torch.zeros(samples)
        # make predictions and calculate prior, posterior, and likelihood for a given number of samples
        for i in range(samples):
            outputs[i] = self(input).reshape(-1) # make predictions
            log_priors[i] = self.log_prior() # get log prior
            log_posts[i] = self.log_post() # get log variational posterior
            log_likes[i] = Normal(outputs[i], self.noise_tol).log_prob(target.reshape(-1)).sum() # calculate the log likelihood
        # calculate monte carlo estimate of prior posterior and likelihood
        log_prior = log_priors.mean()
        log_post = log_posts.mean()
        log_like = log_likes.mean()
        # calculate the negative elbo (which is our loss function)
        loss = log_post - log_prior - log_like
        return loss

def toy_function(x):
    return -x**4 + 3*x**2 + 1

# toy dataset we can start with
x = torch.tensor([-2, -1.8, -1, 1, 1.8, 2]).reshape(-1,1)
y = toy_function(x)

net = MLP_BBB(32, prior_var=10)
optimizer = optim.Adam(net.parameters(), lr=.1)
epochs = 2000
for epoch in range(epochs):  # loop over the dataset multiple times
    optimizer.zero_grad()
    # forward + backward + optimize
    loss = net.sample_elbo(x, y, 1)
    loss.backward()
    optimizer.step()
    if epoch % 10 == 0:
        print('epoch: {}/{}'.format(epoch+1,epochs))
        print('Loss:', loss.item())
print('Finished Training')


# samples is the number of "predictions" we make for 1 x-value.
samples = 100
x_tmp = torch.linspace(-5,5,100).reshape(-1,1)
y_samp = np.zeros((samples,100))
for s in range(samples):
    y_tmp = net(x_tmp).detach().numpy()
    y_samp[s] = y_tmp.reshape(-1)
plt.plot(x_tmp.numpy(), np.mean(y_samp, axis = 0), label='Mean Posterior Predictive')
plt.fill_between(x_tmp.numpy().reshape(-1), np.percentile(y_samp, 2.5, axis = 0), np.percentile(y_samp, 97.5, axis = 0), alpha = 0.25, label='95% Confidence')
plt.legend()
plt.scatter(x, toy_function(x))
plt.title('Posterior Predictive')
plt.show()

Вот среднее значение для 100 повторений и 97,5% больших и 2,5% малых линейных графиков из 100 средних (т.е. 95% достоверность).在这里插入图片描述


Ссылаться на:

  1. вариационный вывод;
  2. Weight Uncertainty in Neural Networks Tutorial;
  3. Bayesian Neural Networks;