c

codeye

V1

2022/09/23阅读:44主题:默认主题

贝叶斯网络中的信念传播

贝叶斯网络中的信念传播 贝叶斯网络推理 在这篇文章中,我将使用信仰传播(BP)与一些示例数据。我假定你已经了解了贝叶斯网络(BN)。这篇文章解释了如何计算BN中不同变量的信念,这有助于推理。

照片:Clint Adair on Unsplash 信念传播 我在GitHub上创建了一个包含BP代码的存储库,我将用它来解释这个算法。

首先,设想我们有一个多角树,这是一个没有循环的图。例如,在下面的插图中描述了一个图。我们有4个变量 "雨"、"洒水车"、"福尔摩斯 "和 "华生",其有向边 "雨 "到 "福尔摩斯"、"雨 "到 "华生"、"洒水车 "到 "福尔摩斯"。贝叶斯网络模拟了福尔摩斯和华生是邻居的故事。一天早上,福尔摩斯走到屋外,认识到草地是湿的。要么是下雨了,要么是他忘了关喷水器。于是他去找他的邻居华生,看看他的草是否也湿了。当他看到草确实是湿的时,他非常肯定他没有忘记洒水装置,而是下雨了。于是,信息从华生流向了洒水车。这种信息流是用BNs中的BP来建模的。

在BP中,我们让变量互相交谈,交换它们对彼此的信念。有2种信息:从父母到孩子的信息和从孩子到父母的信息。总的来说,我们只需要使用5个公式来做BP。在我的解释中,我将对某些公式和变量使用不同的名称,因为我发现有些资料很容易引起误解。

  1. 概率(Likelihood 概率持有对儿童的观察信息,例如,不观察霍姆斯的草,湿的可能性是1,不湿的是1。如果观察到了湿草,那么可能性就变成了湿的1,不湿的0。这些单位向量没有被规范化。

似然函数是一个变量儿童的所有传入信息的乘积 似然函数基本上是一个变量的子代发送的所有传入信息的乘积。它返回一个似然向量,包含一个变量的每个可能值的似然值。在 "雨 "的情况下,它的cardinality为2,表示两种状态 "是 "和 "不是"。

如果一个变量没有子节点,因为它是图中的叶子节点,没有被观察到,它的似然向量将是一个单位向量,所有的1代表它所有的可能值,例如,由于我们一开始没有观察到霍姆斯的草,我们把它的似然向量设置为[1,1],分别代表 "不湿 "和 "湿"。

在Python(numpy)代码中,它看起来像这样。

def likelihood(self):
    incoming_children_messages = np.array([
        c.message_to_parent(self) for c in self.children
    ])
    return incoming_children_messages.prod(axis=0)
  1. 优先权

优先权是某些事件的概率,这些事件在开始时已经知道,例如下雨的概率为20%。如果优先权是未知的,下面的公式就是在计算它。这有点复杂,但我要试试。先验是给你各自变量的无条件概率。因此,我们也需要包括条件的。

先验概率函数是所有可能的父值组合的总和乘以各自传入信息的乘积 在我们的例子中也给出了条件概率。在公式中,"P(X|W) "对应于此。此外,我们需要使用来自所有父母的传入信息,这就是公式中的 "j"。索引显示的是信息方向--从父代 "K "到当前变量 "X"。这两部分(条件概率和来自父母的信息)被使用,因为它们都提供了关于变量概率的信息。一方面,我们看到的是给定一些父系数值的概率,另一方面,我们看到这些父系的信息。在没有观察的情况下,这些信息对应于父母的预设值。因此,这里计算的是 "X "的边际,而摆脱了条件变量。

对于每个父母的信息,在条件概率中都存在一个相应的部分。因此,我们可以对每个信息与条件概率表进行点乘,也就是本片段中的self.m。

def priors(self):
     parents_messages = [
         p.message_to_child(self) for p in self.parents
     ]
     return reduce(np.dot, [self.m.transpose()]+parents_messages)
  1. 信念 信念是我们观察到某些事件后的后验概率。它基本上是似然和先验的归一化乘积。信念是可能性和先验的归一化产物 我们利用我们事先知道的概率,并引入从孩子们那里得到的新知识。这样,我们就产生了一个关于我们变量的新信念。如果一个变量既有父母又有子女,那么信念就是更新的概率(后验),包括来自下面和上面的信息。因此,每个传入的信息都被考虑在内。α "是一个归一化常数,因为可能性和先验的乘积总和可以大于1,这是用变量的所有可能状态的总和进行划分的简略形式。

在这个Python片段中,归一化部分变得更加清晰。

def belief(self):
     unnormalized = self.likelihood() * self.priors()
     normalized = unnormalized/unnormalized.sum()
     return normalized
  1. 给父代的信息

为了计算一个变量的可能性,我们需要考虑一个变量的子代的所有传入消息,这些消息在可能性函数中用λ表示。

这个公式相当混乱,但在看一些Python代码时更好理解。一般来说,我们从P(X|U)中把K边际化,而X是发送方(子代),K是接收方(父代),U是X的所有父代,包括K。如果我们想象一个X的条件概率表,对于每个条目,我们采取相应的父代的激活,把各自的传入信息j乘以K本身。然后,我们将该值与X的可能性相乘。最后,我们将所有与K值相同的值相加,剩下的是一个向量,即从X到K的信息。

因此,给父母的信息考虑到所有传入的信息,无论它们是由孩子还是父母发送的(除了收到信息的父母),并考虑到给定父母的某些值的概率。因此,一个具有高概率的变量设置比低概率的变量更容易转发传入的信息。一个传入的消息是由该消息的设置的条件概率来评定的。

我希望Python代码能进一步澄清它。


def message_to_parent(self, parent):
    likelihood = self.likelihood()
    parents_priors = np.array([
        p.message_to_child(self) 
            for p in self.parents if p != parent
    ])
    parent_i = self.parents.index(parent)

    stack = np.vstack([
        np.dot(
            self.m.take(r, axis=parent_i).transpose(),    
            parents_priors.prod(axis=0)
        ) 
        for r in range(parent.cardinality)
    ])
    return np.dot(stack, likelihood)
or given the Holmes example:

message = np.zeros(rain.cardinality)
for r in rain:
  for s in sprinkler:
    for h in holmes:
      message[r] = probas[r, s, h] \
                   * sprinkler_message[s] \
                   * likelihood[h]
  1. 给孩子的信息 为了计算父母发送给子女的信息,存在两种方法。要么是把从其他孩子那里收到的所有信息与当前节点的先验相乘,要么是把当前节点的信念除以相应孩子给父母的信息。

我们认为这个公式叫做Kappa,索引告诉我们信息的方向(从X到K)。

如果我们看一下信念的公式,我们会发现这个公式是可能性和先验的乘积。然而,可能性是所有传入信息的乘积。因此,信念除以来自K的传入信息的结果是所有传入信息的乘积--除了我们除以的那个--和先验。这样,我们就可以解释两种计算Kappa的方式之间的平等。给孩子的信息背后的直觉与给父母的信息相似。你考虑到所有传入的信息(所以要考虑你能得到的所有信息),并将汇总结果发送到下一个节点。

阿尔法又是一个规范化的常数。如果一个父节点只有一个孩子,它不能收集其他孩子的信息,因为没有孩子。因此,它将只返回它的先验。

def message_to_child(self, child):
    children_messages = []
    for c in self.children:
        if c != child:
            children_messages.append(c.message_to_parent(self))
    if len(children_messages) > 0:
        unnormalized = (children_messages * self.get_priors())
        unnormalized = unnormalized.prod(axis=0)
        message = unnormalized/unnormalized.sum()
        return message
    return self.get_priors()

例子 使用我在开头提到的资料库,我们现在可以使用福尔摩斯的例子,计算不同情况下的信念。

为了使用这个库,我们需要把它和NumPy库一起导入。 import numpy as np 从node导入Node 我们导入了资源库的Node类,它代表了BN中的单个节点。在接下来的步骤中,我们实际创建了代表单一概率变量的节点。"福尔摩斯的草是湿的"、"下雨了"、"忘记洒水 "和 "华生的草是湿的"。创建节点时,你必须提供一个名称。之后,你需要设置一些属性,如cardinality和priors或likelihood(如果存在)。

rain = Node("rain")
rain.cardinality = 2
rain.priors = np.array([0.8, 0.2]) # no=0 yes=1

sprinkler = Node("sprinkler")
sprinkler.cardinality = 2
sprinkler.priors = np.array([0.9, 0.1]) # no=0 yes=1

对于没有的子节点,这是直接的。对于其他节点,即有代,但没有可用的priors,我们需要定义一个条件概率表(CPT),该表定义了在父母所有可能的输入下变量的概率。这个CPT在代码中被称为 "m"。

rain = Node("rain")
rain.cardinality = 2
rain.priors = np.array([0.8, 0.2]) #  no=0 yes=1

sprinkler = Node("sprinkler")
sprinkler.cardinality = 2
sprinkler.priors = np.array([0.9, 0.1]) #  no=0 yes=1
For nodes without children, this is straight forward. For other nodes, which do have parents and no priors already available, we need to define a conditional probability table (CPT) which defines the probability of the variable given all possible inputs from the parents. This CPT is called “m” in the code.

m = np.zeros((2, 2, 2)) #  rain, sprinkler, holmes' grass
m[1, 1, 1] = 1
m[0, 1, 1] = 0.9 #  <-- here
m[0, 1, 0] = 0.1
m[1, 0, 1] = 1
m[0, 0, 0] = 1
holmes = Node("holmes")
holmes.cardinality = 2
holmes.m = m
holmes.likelihood = np.array([1, 1])

m = np.zeros((2, 2)) # rain, watson's grass
m[1, 1] = 1
m[0, 1] = 0.2
m[0, 0] = 0.8
watson = Node("watson")
watson.cardinality = 2
watson.m = m
watson.likelihood = np.array([1, 1])

正如你所看到的,"m "在矩阵的前几个维度中获取父类的值,在最后一个维度中获取实际变量的值,例如(代码注释中的 "这里"),如果没有下雨(0)而洒水器被遗忘(1),草地被打湿(1)的概率是0.9。草地被打湿的可能性是1,1,这意味着两种状态的可能性相同。

接下来,我们要连接节点来定义因果关系。节点类有一个叫做 "add_parent "的方法,可以将一个变量连接到一个父变量上。

holmes.add_parent(rain)
holmes.add_parent(sprinkler)
watson.add_parent(rain)

在接下来的步骤中,我们要假装霍姆斯的草是湿的(因此,可能性[0,1])。然后,我们想知道华生的草是否也是湿的(或者说它有多大可能是湿的)。

holmes.likelihood = np.array([0, 1])
holmes.message_to_parent(rain)
holmes.message_to_parent(sprinkler)
watson.get_belief() # array([0.21176471, 0.78823529])

我们看到,Watson的草被打湿的信念确实倾向于被打湿(0.21 vs 0.79)。因此,BN认为Watson的草是湿的,因为在雨节点上有一个连接,这个信念是通过这个节点传播的。

结论 BN的工具集在以下的推理案例中确实有帮助。我对整个因果推理的研究领域感到非常兴奋,并认为在深度学习和一般人工智能方面也会有很大的进展。

分类:

后端

标签:

后端

作者介绍

c
codeye
V1