🎯要点
🎯空间不确定性和动态相互作用自我认知异类模型 | 🎯精神病神经元算法推理 | 🎯集体信念催化个人行动力数学模型 | 🎯物种基因进化关系网络算法 | 🎯电路噪声低功耗容错解码算法
📜和-积消息传递算法用例
📜MATLAB激光通信和-积消息传递算法(Python图形模型算法)模拟调制
🍪语言内容分比
🍇Python贝叶斯网络消息传递算法
首先,假设我们有一个多叉树,它是没有循环的图。例如,我们有 4 个变量“下雨”、“洒水器”、“福尔摩斯”和“华生”,有向边分别为“下雨”到“福尔摩斯”、“下雨”到“华生”和“洒水器”到“福尔摩斯”。贝叶斯网络模拟了福尔摩斯和华生是邻居的故事。一天早上,福尔摩斯走出家门,发现草地湿了。要么是下雨了,要么是他忘了关洒水器。于是他去找邻居华生,看看他的草地是否也湿了。当他看到草地确实湿了时,他很确定他没有忘了洒水器,而是下雨了。因此,信息从华生流向洒水器。这种信息流由贝叶斯网络中的消息传递算法建模。
可能性包含有关观察的信息,例如,福尔摩斯草地在未观察的情况下的可能性为 1(湿)和 1(不湿)。如果观察到湿草,可能性变为 1(湿)和 0(不湿)。这些单位向量未归一化。
L ( X ) = ∏ K λ ( K → X ) L(X)=\prod_K \lambda_{(K \rightarrow X)} L(X)=K∏λ(K→X)
似然函数基本上是变量子级发送的所有传入消息的乘积。它返回一个似然向量,其中包含变量每个可能值的似然值。对于“下雨”,它的基数为 2,代表“是”和“否”两种状态。
如果某个变量没有子节点(因为它是图中的叶节点且未被观察到),则其似然向量将是一个单位向量,其所有可能值均为 1,例如,由于我们一开始没有观察到福尔摩斯的草,因此我们将其似然向量分别设置为 [1, 1],代表“不湿”和“湿”。
Python伪码表示:
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)
先验是某些事件在开始时就已经知道的概率,例如,下雨的概率为 20%。如果先验未知,则使用以下公式进行计算。先验会给出相应变量的无条件概率。因此,我们还需要包括条件概率。
π ( X ) = ∑ W P ( X ∣ W ) ∏ K ϕ ( K → X ) \pi(X)=\sum_W P(X \mid W) \prod_K \phi_{(K \rightarrow X)} π(X)=W∑P(X∣W)K∏ϕ(K→X)
我们的例子中还给出了条件概率。公式中的“P(X|W)”对应于此。此外,我们需要使用来自所有父方的传入消息,即公式中的“ϕ”。索引显示消息方向 - 从父“K”到当前变量“X”。使用这两个部分(条件概率和来自父的消息)是因为它们都提供有关变量概率的信息。一方面,我们看到给定某些父值的概率,另一方面我们看到这些父的消息。如果没有观察,这些信息对应于父的先验。因此,这里计算“X”的边际并摆脱条件变量。
Python伪码表示:
def priors(self):parents_messages = [p.message_to_child(self) for p in self.parents]return reduce(np.dot, [self.m.transpose()]+parents_messages)
信念是我们观察到某些事件后的后验概率。它基本上是可能性和先验的标准化产物。
β ( X ) = α L ( X ) π ( X ) \beta(X)=\alpha L(X) \pi(X) β(X)=αL(X)π(X)
Python伪码表示:
def belief(self):unnormalized = self.likelihood() * self.priors()normalized = unnormalized/unnormalized.sum()return normalized
为了计算变量的可能性,我们需要考虑来自变量子项的所有传入消息,这些消息由似然函数中的 lambda 表示。
λ ( X → K ) = ∑ x ∈ X L ( x ) ∑ k ∈ K ; k ∈ u P ( x ∣ u ) ∏ i ≠ k ϕ ( Y → X ) i \lambda_{(X \rightarrow K)}=\sum_{x \in X} L(x) \sum_{k \in K ; k \in u} P(x \mid u) \prod_{i \neq k} \phi_{(Y \rightarrow X) i} λ(X→K)=x∈X∑L(x)k∈K;k∈u∑P(x∣u)i=k∏ϕ(Y→X)i
这个公式相当混乱,但看一些 Python 代码会更容易理解。一般来说,我们从 P(X|U) 中边缘化 K,而 X 是发送者(子节点),K 是接收者(父节点),U 是 X 的所有父节点,包括 K。如果我们想象一个 X 的条件概率表,对于每个条目,我们取父节点的相应激活,并将相应的传入消息 ϕ 乘以不包含 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)
计算父方发送给子方的消息有两种方法。要么将从其他子方收到的所有消息与当前节点的先验相乘,要么将当前节点的信念除以相应子方发送给父方的消息。
κ ( X → K ) = α ∏ C \ K λ ( C → X ) π ( X ) = α β ( X ) λ ( K → X ) \kappa_{(X \rightarrow K)}=\alpha \prod_{C \backslash K} \lambda_{(C \rightarrow X)} \pi(X)=\alpha \frac{\beta(X)}{\lambda_{(K \rightarrow X)}} κ(X→K)=αC\K∏λ(C→X)π(X)=αλ(K→X)β(X)
我们认为这个公式称为 Kappa,其索引告诉我们消息的方向(从 X 到 K)。
如果我们看一下信念公式,就会发现这个公式是似然值和先验值的乘积。然而,似然值是所有传入消息的乘积。因此,信念除以来自 K 的传入消息,结果是所有传入消息(除了我们除以的消息)与先验值的乘积。这样,我们就可以解释两种计算 Kappa 的方法之间的相等性。给子方发送消息背后的直觉与给父方发送消息类似。您要考虑所有传入消息,然后将聚合发送到下一个节点。
Python伪码表示:
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 messagereturn self.get_priors()