当变分推断(variational inference)遇上神经网络,贝叶斯深度学习以及Pytorch开源代码

如果人脑在执行任务时有特定模式,那么神经网络在增强学习中也应该有特定模式,而不是杂乱无章地更新 — David 9

我们在之前的文章中讨论过,Evolution Strategy遗传算法等传统算法都可以在深度增强学习中发挥作用。其实,人们早就在神经网络中植入各种传统机器学习的方法(包括L2正则法等等)。

在2015年google的论文中就提到结合变分推断(variational inference)启发式更新神经网络的内部参数:

来自:https://arxiv.org/pdf/1505.05424.pdf

其性能效果堪比dropout方法,并且在增强学习中有较好表现。

那么,贝叶斯深度学习或者说变分推断(variational inference)如何应用在神经网络呢?

理论上,对于一般的深度神经网络,Loss如下:

θ 是神经网络的内部参数集。xi, yi 即样本集中的一个样本。上式只是让训练损失最小。

即,要找到一个最好的 θ* ,让  Ln(θ) 最小。

而在贝叶斯学派中,关心的是后验分布:

即,关心在数据D下模型参数θ 的分布。其中 α 是 ℝd 上的θ先验分布(可以理解为从α 中可以抽样得到 θ)。

而实际上,这一理想化的后验分布很难在实际中求解(我们很难穷尽神经网络所有可能的内部参数 θ

实际中我们一般用一个替代分布q(θ|φ)去逼近后验分布p(θ|D), 如果无法知道α 的真正形式,我们就先造一个q(θ|φ)分布,使得变分自由能(variational free energy最小:

其中,θ~q(θ|φ) 代表 θ 从q(θ|φ) 中抽样 , 其中项:

LE(φ) = Eθ ~ q(θ|φ)[Ln(θ)] 可以理解为神经网络θ 的训练损失loss 。 从信息论的角度,是神经网络θ 编码数据D的信息容量, 信息容量越大,loss越小

LC(φ) = KL(q(.|φ)||α) 可理解为替代分布q(θ|φ)真实分布α KL divergence(两个模型的差别度量),KL值越小,模型差别越小(即q(θ|φ)更逼近真实分布α ) 。从信息论的角度,是神经网络θ 自身的信息容量,模型复杂度越大,信息自身容量越大(不一定对编码数据D有用)

既要保证神经网络θ的自身信息容量,又要保证这些信息最大程度地编码数据 D。

我们可以假设 φ = (µ, σ) 是 ℝd x ℝd 之上的参数,q(.|φ) 就是多元高斯分布N(µ, Σ) , 其中Σ = diag(σ12, …, σd2),我们要找到最好的µ* and σ*。

pyvarinf 开源pytorch代码 中给出了具体实现。

如果要定义一个有variational inference 计算功能的神经网络,只需把pytorch 模型变分化(26行):

import pyvarinf
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)
        self.bn1 = nn.BatchNorm2d(10)
        self.bn2 = nn.BatchNorm2d(20)

    def forward(self, x):
        x = self.bn1(F.relu(F.max_pool2d(self.conv1(x), 2)))
        x = self.bn2(F.relu(F.max_pool2d(self.conv2(x), 2)))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x)

model = Net()
var_model = pyvarinf.Variationalize(model)
var_model.cuda()

训练的方法如下:

optimizer = optim.Adam(var_model.parameters(), lr=0.01)

def train(epoch):
    var_model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.cuda(), target.cuda()
        data, target = Variable(data), Variable(target)
        optimizer.zero_grad()
        output = var_model(data)
        loss_error = F.nll_loss(output, target)
  # The model is only sent once, thus the division by
  # the number of datapoints used to train
        loss_prior = var_model.prior_loss() / 60000
        loss = loss_error + loss_prior
        loss.backward()
        optimizer.step()

for epoch in range(1, 500):
    train(epoch)

其中loss = loss_error + loss_prior正是我们之前说的两部分loss值。

loss_errortorch.nn.NLLLoss的log likelihood loss 。

loss_priorpyvarinf 提供的loss接口,用来控制神经网络自身的信息损益。

 

参考文献:

  1. http://blog.csdn.net/u012436149/article/details/55000323
  2. https://www.zhihu.com/question/41765860
  3. https://github.com/ctallec/pyvarinf
  4. http://pdepou.com/
  5. https://arxiv.org/abs/1505.05424

本文采用署名 – 非商业性使用 – 禁止演绎 3.0 中国大陆许可协议进行许可。著作权属于“David 9的博客”原创,如需转载,请联系微信: david9ml,或邮箱:yanchao727@gmail.com

或直接扫二维码:

发布者

David 9

David 9

邮箱:yanchao727@gmail.com 微信: david9ml

发表评论

电子邮件地址不会被公开。 必填项已用*标注