Blitz est une bibliothèque simple et extensible pour créer des couches de réseau neuronal bayésien (basées sur ce qui a proposé l'incertitude de poids dans le papier de réseaux de neurones) sur Pytorch. En utilisant des couches et des utils de blitz, vous pouvez ajouter de l'intercanité et recueillir le coût de complexité de votre modèle d'une manière simple qui n'affecte pas l'interaction entre vos couches, comme si vous utilisiez le pytorch standard.
En utilisant nos classes d'échantillonneur de poids de base, vous pouvez prolonger et améliorer cette bibliothèque pour ajouter l'incertanéité à une plus grande portée de couches comme vous le ferez de manière bien intégrée à Pytorch. Les demandes de traction sont également les bienvenues.
Pour installer Blitz, vous pouvez utiliser la commande PIP:
pip install blitz-bayesian-pytorch
Ou, via conda:
conda install -c conda-forge blitz-bayesian-pytorch
Vous pouvez également le git-clone et l'installer localement:
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 .
Documentation pour nos couches, poids (et distribution antérieure) Échantillonneur et utils:
(Vous pouvez le voir par vous-même en exécutant cet exemple sur votre machine).
Nous allons maintenant voir comment l'apprentissage en profondeur bayésienne peut-il être utilisé pour la régression afin de rassembler l'intervalle de confiance sur notre point de données plutôt qu'une prédiction de valeur continue pontuale. La collecte d'un intervalle de confiance pour votre prédiction peut être même une information plus utile qu'une estimation à faible erre.
Je maintiens mon argumentation sur le fait qu'avec un bon / haut problème un intervalle de confiance, vous pouvez prendre une décision plus fiable qu'avec une estimation très proximale sur certains contextes: si vous essayez de profiter d'une opération de négociation, par exemple, avoir un bon intervalle de confiance peut vous conduire à savoir si, au moins, la valeur sur laquelle les opérations provoquent seront plus faibles (ou plus) que certains déterminés X.
Savoir si une valeur sera, sûrement (ou avec une bonne probabilité) sur un intervalle déterminé peut aider les personnes à décision judicieuse plus qu'une estimation très proximale qui, si elle est inférieure ou supérieure à une valeur limite, peut entraîner une perte sur une transaction. Le fait est que, parfois, savoir s'il y aura des bénéfices peut être plus utile que de le mesurer.
Afin de démontrer que nous créerons un régresseur de réseau neuronal bayésien pour l'ensemble de données de jouets de données Boston-House, essayant de créer un intervalle de confiance (CI) pour les maisons dont le prix que nous essayons de prévoir. Nous effectuerons une mise à l'échelle et l'IC sera d'environ 75%. Il sera intéressant de voir qu'environ 90% des CI prévus sont inférieurs à la limite élevée ou (inclusive) supérieure à celle inférieure.
Malgré les modules connus, nous apporterons de Blitz AThe variational_estimator Decorator, qui nous aide à gérer les couches Bayesianlinear sur le module qui le gardait entièrement intégré au reste de la torche et, bien sûr, BayesianLinear , qui est notre couche qui présente un poids de poids.
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 Rien de nouveau sous le soleil ici, nous importons et évaluons les données pour aider à la formation.
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 ()Nous pouvons créer notre classe avec l'inhréition à partir de nn.module, comme nous le ferions avec n'importe quel réseau de torche. Notre décorateur introduit les méthodes pour gérer les caractéristiques bayésiennes, comme calculant le coût de complexité des couches bayésiennes et faisant de nombreux efforts (échantillonnage de différents poids sur chacun) afin d'échantillonner notre perte.
@ 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_ )Cette fonction crée un intervalle de confiance pour chaque prédiction sur le lot sur lequel nous essayons d'échantillonner la valeur d'étiquette. Nous pouvons ensuite mesurer la précision de nos prévisions en recherchant la quantité de distributions de prédicions incluent réellement l'étiquette correcte pour le point de données.
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 () Remarquez ici que nous créons notre BayesianRegressor comme nous le ferions avec d'autres réseaux de neurones.
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 )Nous faisons une boucle de formation qui ne diffère qu'une formation de torche commune en faisant échantillon sur sa méthode Sample_elbo. Toutes les autres choses peuvent être faites normalement, car notre objectif avec Blitz est de faciliter votre vie en itérant sur vos données avec différents NN bayésien sans problème.
Voici notre boucle de formation très 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 ))Une explication très rapide de la façon dont l'incertitude est introduite dans les réseaux neuronaux bayésiens et comment nous modélisons sa perte afin d'améliorer objectivement la confiance sur sa prédiction et de réduire la variance sans abandon.
Comme nous le savons, sur les couches de réseau neuronal déterministes (non bayésiennes), les paramètres formables correspondent directement aux poids utilisés sur sa transformation linéaire de la précédente (ou à l'entrée, si c'est le cas). Il correspond à l'équation suivante:
(Z correspond à la sortie activée de la couche I)
Les couches bayésiennes cherchent à introduire une incertitude sur ses poids en les échantillonnant à partir d'une distribution paramétrée par des variables entraînables sur chaque opération à action directe.
Cela permet non seulement d'optimiser les métriques de performance du modèle, mais aussi de rassembler l'incertitude des prédictions du réseau par rapport à un point de données spécifique (en l'échantillonnant beaucoup de fois et en mesurant la dispersion) et en réduisant le plus possible la variance du réseau par rapport à la prédiction, ce qui rend possible de savoir quelle quantité d'incertitude que nous avons encore sur l'étiquette si nous essayons de modéliser l'informatique de notre fonction spécifique.
Pour ce faire, sur chaque opération à force alimentaire, nous échantillons les paramètres de la transformation linéaire avec les équations suivantes (où ρ paramétrise l'écart type et μ paramétrise la moyenne des échantillons paramètres de transformation linéaire):
Pour les poids:
Où le w échantillonné correspond aux poids utilisés sur la transformation linéaire pour la ième couche sur l'échantillon nième.
Pour les biais:
Où le B échantillonné correspond aux biais utilisés sur la transformation linéaire pour la ième couche sur l'échantillon nième.
Même difficile, nous avons un multiplicateur aléatoire pour nos poids et nos biais, il est possible de les optimiser en, étant donné une fonction différenciable des poids échantillonnés et entraînables (dans notre cas, la perte), résumant la dérivée de la fonction par rapport à les deux:
Donc:
et
Il est connu que la perte de transentropie (et le MSE) est différenciable. Par conséquent, si nous prouvons qu'il existe une fonction complexité-coût qui est différenciable, nous pouvons le laisser à notre cadre de prendre les dérivés et de calculer les gradients à l'étape d'optimisation.
Le coût de la complexité est calculé, sur le fonctionnement de l'alimentation, par chacune des couches bayésiennes, (avec les couches de distribution d'Apriori de simplification prédéfinie et sa distribution empirique). La somme du coût de complexité de chaque couche est additionnée à la perte.
Comme proposé dans l'incertitude de poids dans le document des réseaux de neurones, nous pouvons recueillir le coût de complexité d'une distribution en prenant la divergence de Kullback-Lebler à lui à une distribution beaucoup plus simple, et en faisant une certaine approximation, nous pourrons différencier cette fonction par rapport à ses variables (les distributions)::
Soit un PDF de distribution à basse entropie définie à la main, qui sera supposée comme une distribution "a priori" pour les poids
Soit le PDF de distribution empirique postérieure pour nos poids échantillonnés, compte tenu de ses paramètres.
Par conséquent, pour chaque scalaire sur la matrice échantillonnée W:
En supposant un très grand N, nous pourrions nous approximer:
Et donc:
Comme la (moyenne) attendue de la distribution Q se termine par la mise à l'échelle des valeurs, nous pouvons le retirer de l'équation (car il n'y aura pas de traçage-cadre). Avoir un coût de complexité de l'échantillon nième comme:
Qui est différenciable par rapport à tous ses paramètres.
Par conséquent, la fonction de coût entière sur le nième échantillon de poids sera:
Nous pouvons estimer la véritable fonction de coût complet par Monte Carlo l'échantillonnage (alimentaire le Netwok X Times et en prenant la moyenne sur une perte complète), puis en un rétablissement en utilisant notre valeur estimée. Il fonctionne pour un faible nombre d'expériences par rétroproppe et même pour des expériences unitaires.
Nous sommes arrivés à la fin d'un apprentissage en profondeur bayésien dans un tutoriel en bref. En sachant ce qui est fait ici, vous pouvez implémenter votre modèle BNN comme vous le souhaitez.
Peut-être que vous pouvez optimiser en faisant une étape d'optimisation par échantillon, ou en utilisant cette méthode Monte-Carlo-ish pour rassembler la perte parfois, prendre sa moyenne puis optimiser. Votre déménagement.
FYI: Nos couches bayésiennes et utilisent des aides à calculer le coût de complexité le long des couches de chaque opération à action directe, donc cela ne vous dérange pas beaucoup.
Si vous utilisez BLiTZ dans vos recherches, vous pouvez le citer comme suit:
@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/} } ,
}