Blitz es una biblioteca simple y extensible para crear capas de red neuronales bayesianas (basadas en lo que se propone en la incertidumbre de peso en el papel de las redes neuronales) en Pytorch. Mediante el uso de capas y utilidades de bombardeo, puede agregar incertanidad y reunir el costo de complejidad de su modelo de una manera simple que no afecta la interacción entre sus capas, como si estuviera usando Pytorch estándar.
Al usar nuestras clases de muestras de peso de Core, puede extender y mejorar esta biblioteca para agregar incertanidad a un mayor alcance de capas como lo hará de manera bien integrada a Pytorch. También las solicitudes de extracción son bienvenidas.
Para instalar Blitz puede usar el comando PIP:
pip install blitz-bayesian-pytorch
O, a través de conda:
conda install -c conda-forge blitz-bayesian-pytorch
También puede clonarlo y instalarlo localmente:
conda create -n blitz python=3.9
conda activate blitz
git clone https://github.com/piEsposito/blitz-bayesian-deep-learning.git
cd blitz-bayesian-deep-learning
pip install .
Documentación para nuestras capas, peso (y distribución previa) muestreador y utilización:
(Puede verlo por usted mismo ejecutando este ejemplo en su máquina).
Ahora veremos cómo se puede utilizar el aprendizaje profundo bayesiano para la regresión para recopilar el intervalo de confianza sobre nuestro punto de datos en lugar de una predicción del valor continuo pontual. Recopilar un intervalo de confianza para su predicción puede ser incluso una información más útil que una estimación de bajo error.
Sostengo mi argumentación sobre el hecho de que, con un intervalo de confianza bueno/alto, un intervalo de confianza, puede tomar una decisión más confiable que con una estimación muy proximal en algunos contextos: si está tratando de obtener ganancias de una operación comercial, por ejemplo, tener un buen intervalo de confianza puede llevarlo a saber si, al menos, el valor en el que los procedimientos de operación serán más bajos (o más) que algunos determinados X.
Saber si un valor será, seguramente (o con buena probabilidad) en un intervalo determinado puede ayudar a las personas a una decisión sensata más que una estimación muy proximal de que, si es más bajo o superior al valor límite, puede causar pérdida en una transacción. El punto es que, a veces, saber si habrá ganancias puede ser más útil que medirlo.
Para demostrar que crearemos un regresor de la red neuronal bayesiana para el conjunto de datos de juguetes de datos de Boston-House, tratando de crear un intervalo de confianza (CI) para las casas de las cuales el precio que estamos tratando de predecir. Realizaremos algo de escala y el CI será de aproximadamente el 75%. Será interesante ver que aproximadamente el 90% de los IC previstos son más bajos que el límite alto o (inclusive) más alto que el inferior.
A pesar de los módulos conocidos, traeremos de Blitz ATHE variational_estimator Decorator, que nos ayuda a manejar las capas bayesianlineales en el módulo que lo mantiene completamente integrado con el resto de la antorcha y, por supuesto, BayesianLinear , que es nuestra capa que presenta una incertidumbre de peso.
import torch
import torch . nn as nn
import torch . nn . functional as F
import torch . optim as optim
import numpy as np
from blitz . modules import BayesianLinear
from blitz . utils import variational_estimator
from sklearn . datasets import load_boston
from sklearn . preprocessing import StandardScaler
from sklearn . model_selection import train_test_split No hay nada nuevo bajo el sol aquí, estamos importando y escalando los datos para ayudar con la capacitación.
X , y = load_boston ( return_X_y = True )
X = StandardScaler (). fit_transform ( X )
y = StandardScaler (). fit_transform ( np . expand_dims ( y , - 1 ))
X_train , X_test , y_train , y_test = train_test_split ( X ,
y ,
test_size = .25 ,
random_state = 42 )
X_train , y_train = torch . tensor ( X_train ). float (), torch . tensor ( y_train ). float ()
X_test , y_test = torch . tensor ( X_test ). float (), torch . tensor ( y_test ). float ()Podemos crear nuestra clase con la habita de NN.Module, como lo haríamos con cualquier red de antorchas. Nuestro decorador introduce los métodos para manejar las características bayesianas, al calcular el costo de complejidad de las capas bayesianas y hacer muchas fuentes (muestras de diferentes pesos en cada uno) para probar nuestra pérdida.
@ variational_estimator
class BayesianRegressor ( nn . Module ):
def __init__ ( self , input_dim , output_dim ):
super (). __init__ ()
#self.linear = nn.Linear(input_dim, output_dim)
self . blinear1 = BayesianLinear ( input_dim , 512 )
self . blinear2 = BayesianLinear ( 512 , output_dim )
def forward ( self , x ):
x_ = self . blinear1 ( x )
x_ = F . relu ( x_ )
return self . blinear2 ( x_ )Esta función crea un intervalo de confianza para cada predicción en el lote en el que estamos tratando de probar el valor de la etiqueta. Luego podemos medir la precisión de nuestras predicciones buscando cuánto de las distribuciones de prediciton realmente incluyeron la etiqueta correcta para el punto de datos.
def evaluate_regression ( regressor ,
X ,
y ,
samples = 100 ,
std_multiplier = 2 ):
preds = [ regressor ( X ) for i in range ( samples )]
preds = torch . stack ( preds )
means = preds . mean ( axis = 0 )
stds = preds . std ( axis = 0 )
ci_upper = means + ( std_multiplier * stds )
ci_lower = means - ( std_multiplier * stds )
ic_acc = ( ci_lower <= y ) * ( ci_upper >= y )
ic_acc = ic_acc . float (). mean ()
return ic_acc , ( ci_upper >= y ). float (). mean (), ( ci_lower <= y ). float (). mean () Observe aquí que creamos nuestro BayesianRegressor como lo haríamos con otras redes neuronales.
regressor = BayesianRegressor ( 13 , 1 )
optimizer = optim . Adam ( regressor . parameters (), lr = 0.01 )
criterion = torch . nn . MSELoss ()
ds_train = torch . utils . data . TensorDataset ( X_train , y_train )
dataloader_train = torch . utils . data . DataLoader ( ds_train , batch_size = 16 , shuffle = True )
ds_test = torch . utils . data . TensorDataset ( X_test , y_test )
dataloader_test = torch . utils . data . DataLoader ( ds_test , batch_size = 16 , shuffle = True )Hacemos un bucle de entrenamiento que solo difiere de un entrenamiento de antorcha común al probar su pérdida por su método sample_elbo. Todas las demás cosas se pueden hacer normalmente, ya que nuestro propósito con Blitz es aliviar su vida en iterando en sus datos con diferentes NN bayesianos sin problemas.
Aquí está nuestro bucle de entrenamiento muy simple:
iteration = 0
for epoch in range ( 100 ):
for i , ( datapoints , labels ) in enumerate ( dataloader_train ):
optimizer . zero_grad ()
loss = regressor . sample_elbo ( inputs = datapoints ,
labels = labels ,
criterion = criterion ,
sample_nbr = 3 )
loss . backward ()
optimizer . step ()
iteration += 1
if iteration % 100 == 0 :
ic_acc , under_ci_upper , over_ci_lower = evaluate_regression ( regressor ,
X_test ,
y_test ,
samples = 25 ,
std_multiplier = 3 )
print ( "CI acc: {:.2f}, CI upper acc: {:.2f}, CI lower acc: {:.2f}" . format ( ic_acc , under_ci_upper , over_ci_lower ))
print ( "Loss: {:.4f}" . format ( loss ))Una explicación muy rápida de cómo se introduce la incertidumbre en las redes neuronales bayesianas y cómo modelamos su pérdida para mejorar objetivamente la confianza sobre su predicción y reducir la varianza sin abandono.
Como sabemos, en las capas de red neuronales deterministas (no bayesianas), los parámetros capacitables corresponden directamente a los pesos utilizados en su transformación lineal de la anterior (o la entrada, si es el caso). Corresponde a la siguiente ecuación:
(Z corresponde al rendimiento activado de la capa I)
Las capas bayesianas buscan introducir la incertidumbre en sus pesos muestreándolas de una distribución parametrizada por variables capacitables en cada operación de avance.
Esto permite no solo optimizar las métricas de rendimiento del modelo, sino también recopilar la incertidumbre de las predicciones de la red sobre un punto de datos específico (muestreandolo muchas veces y medir la dispersión) y reducir con destino a la mayor cantidad posible de la varianza de la red sobre la predicción, lo que hace posible saber cuánto de incertidumbre todavía tenemos sobre la etiqueta si intentamos modelarlo en la función específica.
Para hacerlo, en cada operación de avance, muestreamos los parámetros de la transformación lineal con las siguientes ecuaciones (donde ρ parametriza la desviación estándar y μ parametriza la media para los parámetros de transformación lineal de las muestras):
Para los pesos:
Donde la W muestreada corresponde a los pesos utilizados en la transformación lineal para la capa ésica en la enésima muestra.
Para los sesgos:
Donde el B muestreado corresponde a los sesgos utilizados en la transformación lineal para la capa ésica en la enésima muestra.
Incluso duro tenemos un multiplicador aleatorio para nuestros pesos y sesgos, es posible optimizarlos, dada una función diferenciable de los pesos muestreados y los parámetros capacitables (en nuestro caso, la pérdida), sumando la derivada de la función en relación con ambos:
Por lo tanto:
y
Se sabe que la pérdida de entretropía (y MSE) son diferenciables. Por lo tanto, si demostramos que existe una función de costo de complejidad que es diferenciable, podemos dejar que nuestro marco tome los derivados y calcule los gradientes en el paso de optimización.
El costo de complejidad se calcula, en la operación de avance, por cada una de las capas bayesianas (con la distribución Apriori de simplificador preferente y su distribución empírica). La suma del costo de complejidad de cada capa se suta a la pérdida.
Como se propone en la incertidumbre de peso en el documento de redes neuronales, podemos recopilar el costo de complejidad de una distribución al llevar la divergencia Kullback-Lebler a una distribución mucho más simple, y al hacer alguna aproximación, podremos diferenciar esta función en relación con sus variables (las distribuciones):
Sea un PDF de distribución de baja entropía establecido a mano, que se supondrá como una distribución "a priori" para los pesos
Sea el PDF de distribución empírica a posteriori para nuestros pesos muestreados, dados sus parámetros.
Por lo tanto, para cada escalar en la matriz de muestreo W:
Al asumir una N muy grande, podríamos aproximar:
y por lo tanto:
Como la esperada (media) de la distribución Q termina escalando los valores, podemos sacarlo de la ecuación (ya que no habrá rastreo marco). Tener un costo de complejidad de la enésima muestra como:
Que es diferenciable en relación con todos sus parámetros.
Por lo tanto, toda la función de costo en la enésima muestra de pesos será:
Podemos estimar la verdadera función de costo completo mediante la muestreo de Monte Carlo (alimentando la alimentación del Netwok X Times y tomando la media de pérdida total) y luego retroceso utilizando nuestro valor estimado. Funciona para un bajo número de experimentos por backprop e incluso para experimentos unitarios.
Llegamos al final de un aprendizaje profundo bayesiano en un tutorial de nuez. Al saber lo que se está haciendo aquí, puede implementar su modelo BNN como desee.
Tal vez pueda optimizar haciendo un paso de optimización por muestra, o utilizando este método Monte-Carlo-ish para reunir la pérdida algunas veces, tome su media y luego optimizador. Tu movimiento.
FYI: Nuestras capas y utilidades bayesianos ayudan a calcular el costo de complejidad a lo largo de las capas en cada operación de avance, así que no le importe demasiado.
Si usa BLiTZ en su investigación, puede citarlo de la siguiente manera:
@misc { esposito2020blitzbdl ,
author = { Piero Esposito } ,
title = { BLiTZ - Bayesian Layers in Torch Zoo (a Bayesian Deep Learing library for Torch) } ,
year = { 2020 } ,
publisher = { GitHub } ,
journal = { GitHub repository } ,
howpublished = { url{https://github.com/piEsposito/blitz-bayesian-deep-learning/} } ,
}