Blitz เป็นห้องสมุดที่เรียบง่ายและยืดหยุ่นในการสร้างเลเยอร์เครือข่ายประสาทแบบเบย์ (ขึ้นอยู่กับสิ่งที่เสนอในความไม่แน่นอนของน้ำหนักในกระดาษเครือข่ายประสาท) บน Pytorch ด้วยการใช้เลเยอร์ Blitz และ Utils คุณสามารถเพิ่มความไม่แน่นอนและรวบรวมค่าใช้จ่ายที่ซับซ้อนของแบบจำลองของคุณในวิธีง่ายๆที่ไม่ส่งผลกระทบต่อการทำงานร่วมกันระหว่างเลเยอร์ของคุณราวกับว่าคุณใช้ pytorch มาตรฐาน
ด้วยการใช้คลาสตัวอย่างน้ำหนักหลักของเราคุณสามารถขยายและปรับปรุงไลบรารีนี้เพื่อเพิ่มความไม่แน่นอนให้กับขอบเขตที่ใหญ่กว่าของเลเยอร์ตามที่คุณต้องการในแบบ Pytorch ยินดีต้อนรับคำขอดึง
ในการติดตั้ง Blitz คุณสามารถใช้คำสั่ง PIP:
pip install blitz-bayesian-pytorch
หรือผ่าน conda:
conda install -c conda-forge blitz-bayesian-pytorch
นอกจากนี้คุณยังสามารถ git-clone มันและ pip-install ในพื้นที่:
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 .
เอกสารสำหรับเลเยอร์น้ำหนัก (และการแจกจ่ายก่อน) ของเราตัวอย่างและ UTILS:
(คุณสามารถดูด้วยตัวคุณเองโดยเรียกใช้ตัวอย่างนี้บนเครื่องของคุณ)
ตอนนี้เราจะดูว่าการเรียนรู้แบบเบย์ลึกสามารถใช้สำหรับการถดถอยเพื่อรวบรวมช่วงความมั่นใจผ่าน datapoint ของเราได้อย่างไรมากกว่าการทำนายค่า Pontual ต่อเนื่อง การรวบรวมช่วงความมั่นใจสำหรับการทำนายของคุณอาจเป็นข้อมูลที่มีประโยชน์มากกว่าการประมาณค่าความผิดพลาดต่ำ
ฉันยังคงถกเถียงกันเรื่องความจริงที่ว่าด้วยช่วงเวลาที่ดี/สูงในช่วงความเชื่อมั่นคุณสามารถตัดสินใจที่เชื่อถือได้มากกว่าการประมาณค่าที่ใกล้เคียงกันมากในบางบริบท: หากคุณพยายามที่จะได้รับผลกำไรจากการดำเนินการซื้อขายเช่นการมีช่วงความมั่นใจที่ดีอาจทำให้คุณรู้ว่าอย่างน้อย
การรู้ว่าค่าจะเป็นอย่างแน่นอน (หรือมีความน่าจะเป็นที่ดี) ในช่วงเวลาที่กำหนดสามารถช่วยผู้คนในการตัดสินใจที่สมเหตุสมผลมากกว่าการประมาณค่าใกล้เคียงมากว่าหากต่ำหรือสูงกว่าค่า จำกัด บางอย่างอาจทำให้เกิดการสูญเสียในการทำธุรกรรม ประเด็นก็คือบางครั้งการรู้ว่าจะมีกำไรอาจมีประโยชน์มากกว่าการวัดหรือไม่
เพื่อแสดงให้เห็นว่าเราจะสร้างเครื่องถดถอยเครือข่ายระบบประสาทแบบเบย์สำหรับชุดข้อมูลของเล่น-เฮ้าส์-เฮ้าส์เพื่อสร้างช่วงความมั่นใจ (CI) สำหรับบ้านที่ราคาที่เราพยายามทำนาย เราจะทำการปรับขนาดบางอย่างและ CI จะอยู่ที่ประมาณ 75% มันจะน่าสนใจที่จะเห็นว่าประมาณ 90% ของ CIS ที่คาดการณ์ไว้นั้นต่ำกว่าขีด จำกัด สูงหรือสูงกว่าที่ต่ำกว่า
แม้จะมาจากโมดูลที่รู้จักกัน แต่เราจะนำมาจาก Blitz Athe variational_estimator Decorator ซึ่งช่วยให้เราจัดการกับชั้น bayesianlinear ในโมดูลทำให้มันรวมเข้ากับไฟฉายที่เหลืออย่างสมบูรณ์และแน่นอนว่า BayesianLinear ซึ่งเป็นชั้นของเรา
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 ไม่มีอะไรใหม่ภายใต้ดวงอาทิตย์ที่นี่เรากำลังนำเข้าและปรับขนาดข้อมูลเพื่อช่วยในการฝึกอบรม
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 ()เราสามารถสร้างชั้นเรียนของเราด้วยการสืบค้นจาก nn.module เช่นเดียวกับที่เราทำกับเครือข่ายคบเพลิงใด ๆ มัณฑนากรของเราแนะนำวิธีการจัดการคุณสมบัติแบบเบย์เนื่องจากการคำนวณค่าใช้จ่ายที่ซับซ้อนของชั้นเบย์และทำฟีดไปข้างหน้าจำนวนมาก (การสุ่มตัวอย่างน้ำหนักที่แตกต่างกันในแต่ละอัน) เพื่อลิ้มลองการสูญเสียของเรา
@ 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_ )ฟังก์ชั่นนี้สร้างช่วงความมั่นใจสำหรับการทำนายแต่ละครั้งในชุดที่เราพยายามสุ่มตัวอย่างค่าฉลาก จากนั้นเราสามารถวัดความถูกต้องของการทำนายของเราโดยการค้นหาว่าการแจกแจง prediciton จำนวนเท่าใดนั้นรวมถึงฉลากที่ถูกต้องสำหรับ datapoint
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 () โปรดสังเกตที่นี่ว่าเราสร้าง BayesianRegressor ของเราตามที่เราจะทำกับเครือข่ายประสาทอื่น ๆ
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 )เราทำการฝึกอบรมที่แตกต่างจากการฝึกอบรมคบเพลิงทั่วไปโดยมีการสูญเสียตัวอย่างโดยวิธี sample_elbo สิ่งอื่น ๆ ทั้งหมดสามารถทำได้ตามปกติเนื่องจากจุดประสงค์ของเรากับ Blitz คือการทำให้ชีวิตของคุณหมดอายุในการวนซ้ำข้อมูลของคุณด้วย Bayesian NNS ที่แตกต่างกันโดยไม่มีปัญหา
นี่คือวงฝึกซ้อมที่ง่ายมากของเรา:
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 ))คำอธิบายที่รวดเร็วมากเกี่ยวกับความไม่แน่นอนที่นำมาใช้ในเครือข่ายประสาทเบย์และวิธีที่เราทำแบบจำลองการสูญเสียเพื่อปรับปรุงความเชื่อมั่นในการทำนายและลดความแปรปรวนโดยไม่ออกกลางคัน
อย่างที่เราทราบกันดีว่าในชั้นเครือข่ายประสาทที่กำหนด (ไม่ใช่เบย์) พารามิเตอร์ที่สามารถฝึกอบรมได้ตรงกับน้ำหนักที่ใช้ในการแปลงเชิงเส้นของหนึ่งก่อนหน้า (หรืออินพุตถ้าเป็นกรณี) มันสอดคล้องกับสมการต่อไปนี้:
(Z สอดคล้องกับเอาต์พุตที่เปิดใช้งานของเลเยอร์ I)
เลเยอร์แบบเบย์พยายามที่จะแนะนำความไม่แน่นอนเกี่ยวกับน้ำหนักของมันโดยการสุ่มตัวอย่างจากการกระจาย parametrized โดยตัวแปรที่ฝึกอบรมได้ในการทำงานของ Feedforward แต่ละครั้ง
สิ่งนี้ช่วยให้เราไม่เพียง แต่เพิ่มประสิทธิภาพตัวชี้วัดประสิทธิภาพของแบบจำลอง แต่ยังรวบรวมความไม่แน่นอนของการทำนายเครือข่ายผ่าน datapoint เฉพาะ (โดยการสุ่มตัวอย่างหลายครั้งและการวัดการกระจาย) และลดความแปรปรวนของเครือข่ายให้มากที่สุดเท่าที่จะเป็นไปได้
ในการทำเช่นนั้นในการดำเนินการ feedforward แต่ละครั้งเราจะสุ่มตัวอย่างพารามิเตอร์ของการแปลงเชิงเส้นด้วยสมการต่อไปนี้ (โดยที่ ρ parametrizes ค่าเบี่ยงเบนมาตรฐานและ μ parametrizes ค่าเฉลี่ยสำหรับพารามิเตอร์การแปลงเชิงเส้นตัวอย่าง):
สำหรับน้ำหนัก:
ในกรณีที่ W ตัวอย่างสอดคล้องกับน้ำหนักที่ใช้กับการแปลงเชิงเส้นสำหรับเลเยอร์ ith บนตัวอย่างที่ n
สำหรับอคติ:
โดยที่ตัวอย่าง B สอดคล้องกับอคติที่ใช้กับการแปลงเชิงเส้นสำหรับเลเยอร์ ith บนตัวอย่างที่ n
แม้เราจะมีตัวทวีคูณแบบสุ่มสำหรับน้ำหนักและอคติของเราก็เป็นไปได้ที่จะปรับให้เหมาะสมโดยได้รับฟังก์ชั่นที่แตกต่างกันของพารามิเตอร์น้ำหนักตัวอย่างและพารามิเตอร์ที่สามารถฝึกอบรมได้ (ในกรณีของเราการสูญเสีย) สรุปอนุพันธ์ของฟังก์ชั่น
ดังนั้น:
และ
เป็นที่ทราบกันดีว่าการสูญเสีย crossentropy (และ MSE) นั้นแตกต่างกัน ดังนั้นหากเราพิสูจน์ว่ามีฟังก์ชั่นต้นทุนที่ซับซ้อนที่แตกต่างกันเราสามารถทิ้งไว้ในกรอบของเราใช้อนุพันธ์และคำนวณการไล่ระดับสีในขั้นตอนการเพิ่มประสิทธิภาพ
ค่าใช้จ่ายที่ซับซ้อนถูกคำนวณในการดำเนินการ feedforward โดยแต่ละชั้นแบบเบย์ (ด้วยเลเยอร์การกระจาย apriori ที่กำหนดไว้ล่วงหน้าและการกระจายเชิงประจักษ์) ผลรวมของต้นทุนความซับซ้อนของแต่ละชั้นจะรวมกับการสูญเสีย
ตามที่เสนอในความไม่แน่นอนของน้ำหนักในกระดาษเครือข่ายประสาทเราสามารถรวบรวมต้นทุนความซับซ้อนของการกระจายโดยการใช้ความแตกต่างของ Kullback-Leibler จากมันไปสู่การกระจายที่ง่ายขึ้นมากและโดยการประมาณบางอย่างเราจะสามารถแยกฟังก์ชั่นนี้เมื่อเทียบกับตัวแปร
ปล่อยให้การกระจาย PDF การกระจายต่ำที่กำหนดด้วยมือซึ่งจะถือว่าเป็นการกระจาย "priori" สำหรับน้ำหนัก
ให้เป็น PDF การกระจายเชิงประจักษ์หลังสำหรับน้ำหนักตัวอย่างของเราตามพารามิเตอร์
ดังนั้นสำหรับแต่ละสเกลาร์บนเมทริกซ์ตัวอย่าง W:
โดยสมมติว่ามีขนาดใหญ่มากเราสามารถประมาณ:
และดังนั้น:
ตามที่คาดไว้ (ค่าเฉลี่ย) ของการกระจาย Q จบลงด้วยการปรับสเกลค่าเราสามารถนำออกจากสมการ (เนื่องจากจะไม่มีการติดตามกรอบ) มีค่าใช้จ่ายที่ซับซ้อนของตัวอย่างที่ n เป็น:
ซึ่งแตกต่างเมื่อเทียบกับพารามิเตอร์ทั้งหมด
ดังนั้นฟังก์ชั่นต้นทุนทั้งหมดในตัวอย่างที่ nth ของน้ำหนักจะเป็น:
เราสามารถประเมินฟังก์ชั่นค่าใช้จ่ายเต็มรูปแบบที่แท้จริงโดยการสุ่มตัวอย่าง Monte Carlo (Feedforwarding Netwok X Times และรับค่าเฉลี่ยเกินการสูญเสียเต็ม) จากนั้น backpropagate โดยใช้ค่าโดยประมาณของเรา มันใช้งานได้สำหรับการทดลองจำนวนน้อยต่อ backprop และแม้กระทั่งสำหรับการทดลองรวมกัน
เรามาถึงจุดสิ้นสุดของการเรียนรู้อย่างลึกซึ้งแบบเบย์โดยย่อการสอนสั้น ๆ ด้วยการรู้ว่ากำลังทำอะไรอยู่ที่นี่คุณสามารถใช้โมเดล BNN ของคุณตามที่คุณต้องการ
บางทีคุณสามารถปรับให้เหมาะสมโดยการทำขั้นตอนหนึ่งขั้นตอนต่อตัวอย่างหรือโดยใช้วิธี Monte-Carlo-ish นี้เพื่อรวบรวมการสูญเสียบางครั้งใช้ค่าเฉลี่ยแล้วเพิ่มประสิทธิภาพ การเคลื่อนไหวของคุณ
FYI: เลเยอร์เบย์และ Utils ของเราช่วยในการคำนวณค่าใช้จ่ายที่ซับซ้อนตามเลเยอร์ในการทำงานของฟีดไปข้างหน้าแต่ละครั้งดังนั้นอย่าคิดว่ามันจะมากนัก
หากคุณใช้ BLiTZ ในการวิจัยของคุณคุณสามารถอ้างอิงได้ดังนี้:
@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/} } ,
}