// m_ij(x_j) = sum_xi {phi(i)*phi(i,j)*prod_{u \in N(i)\j} {m_uj(xi)}} // m_ij(x_j) = max_xi {phi(i)*phi(i,j)*prod_{u \in N(i)\j} {m_uj(xi)}} void InferenceEngineBP::sendMessage(BPNode* xi, BPNode* xj, dVector* phi_i, dMatrix** phi_ij, dVector** msg) { // potential(i) -> Vi dVector Vi(phi_i[xi->id]); // potential(i,j) -> Mij dMatrix Mij; if( xi->id < xj->id ) Mij.set( phi_ij[xi->id][xj->id] ); else { Mij.set( phi_ij[xj->id][xi->id] ); Mij.transpose(); } // prod_{u \in N(i)\j} {m_ui(xi)} -> Vi std::list<BPNode*>::iterator it; for(it=xi->neighbors.begin(); it!=xi->neighbors.end(); it++) { if( xj->equal(*it) ) continue; Vi.add( msg[(*it)->id][xi->id] ); } if( isSumProduct ) logMultiply( Vi, Mij, msg[xi->id][xj->id] ); else logMultiplyMaxProd( Vi, Mij, msg[xi->id][xj->id] ); }
// m_ij(x_j) = sum_xi {potential(i)*potential(i,j)*prod_{u \in N(i)\j} {m_ui(xi)}} void InferenceEngineLoopyBP::sendMessage(int xi, int xj, int nbNodes, const Beliefs potentials, std::vector<dVector>& messages, iMatrix adjMat, int adjMatMax, bool bMaxProd) { int max_hi=-1; // for Viterbi decoding // potential(i) dVector Vi(potentials.belStates[xi]); // potential(i,j) dMatrix Mij(potentials.belEdges[adjMat(xi,xj)-1]); if( xi>xj ) Mij.transpose(); // prod_{u \in N(i)\j} {m_ui(xi)}} int msg_idx; for( int xu=0; xu<nbNodes; xu++ ) { if( !adjMat(xu,xi) || xu==xj ) continue; msg_idx = (xu>xi) ? adjMatMax+adjMat(xu,xi)-1 : adjMat(xu,xi)-1; Vi.add(messages[msg_idx]); } // m_ij(xj) = Vi \dot Mij msg_idx = (xi>xj) ? adjMatMax+adjMat(xi,xj)-1 : adjMat(xi,xj)-1; if( bMaxProd ) max_hi = logMultiplyMaxProd(Vi, Mij, messages[msg_idx]); else logMultiply(Vi, Mij, messages[msg_idx]); // Normalize messages to avoid numerical over/under-flow // Make \sum_{xj} m_ij(xj)=1. Other methods could also be used. double min = messages[msg_idx].min(); if( min < 0 ) messages[msg_idx].add(-min); messages[msg_idx].multiply(1/messages[msg_idx].sum()); }
// b_i(xi) = potential(i) * prod_{u \in N(i)}{m_ui} // b_ij(xi,xj) = potential(i) * potential(j) * potential(i,j) // * prod_{u \in N(i)\j}{m_ui} * prod_{u \in N(j)\i}{m_uj} void InferenceEngineBP::updateBeliefs(Beliefs& b, dVector* phi_i, dMatrix** phi_ij, dVector** msg, DataSequence* X, Model* m, iMatrix adjMat) { int xi, xj, xu, nbNodes, seqLength; dVector Vi, Vj; dMatrix Mij; nbNodes = adjMat.getHeight(); seqLength = X->length(); // b_i(xi) = potential(i) * prod_{u \in N(i)}{m_ui} for(xi=0; xi<nbNodes; xi++) { b.belStates[xi].set( phi_i[xi] ); for(int xu=0; xu<nbNodes; xu++) { if( !adjMat(xu,xi) ) continue; b.belStates[xi].add( msg[xu][xi] ); } } // b_ij(xi,xj) = potential(i) * potential(j) * potential(i,j) // * prod_{u \in N(i)\j}{m_ui} * prod_{u \in N(j)\i}{m_uj} for(xi=0; xi<nbNodes; xi++) { for(xj=xi+1; xj<nbNodes; xj++) { // xj starts from xi+1 because b_ij==b_ji if( !adjMat(xi,xj) ) continue; // potential(i) * prod_{u \in N(i)\j){m_ui} Vi.set( phi_i[xi] ); for(xu=0; xu<nbNodes; xu++ ) { if( !adjMat(xu,xi) || xu==xj ) continue; Vi.add( msg[xu][xi] ); } // potential(j) * prod_{u \in N(j)\i){m_uj} Vj.set( phi_i[xj] ); for(xu=0; xu<nbNodes; xu++ ) { if( !adjMat(xu,xj) || xu==xi ) continue; Vj.add( msg[xu][xj] ); } // (Vi*Vj*Mij) * potential(i,j) Mij.create(Vj.getLength(), Vi.getLength()); logMultiply(Vi, Vj, Mij); Mij.add( phi_ij[xi][xj] ); if( m->isMultiViewMode() ) b.belEdges[adjMat(xi,xj)-1].set(Mij); else b.belEdges[xi].set(Mij); } } // Normalize beliefs and compute partition unsigned int i; double logZ = 0; // marginals are consistent across nodes logZ = b.belStates[0].logSumExp(); for(i=0; i<b.belStates.size(); i++) { b.belStates[i].add(-logZ); b.belStates[i].eltExp(); } for(i=0; i<b.belEdges.size(); i++) { b.belEdges[i].add(-logZ); b.belEdges[i].eltExp(); } b.partition = logZ; }
// b_i(xi) = potential(i) * prod_{u \in N(i)}{m_ui} // b_ij(xi,xj) = potential(i) * potential(j) * potential(i,j) // * prod_{u \in N(i)\j}{m_ui} * prod_{u \in N(j)\i}{m_uj} void InferenceEngineLoopyBP::updateBeliefs(int nbNodes, Beliefs& beliefs, const Beliefs potentials, const std::vector<dVector> messages, iMatrix adjMat, int adjMatMax) { int msg_idx; dVector Vi, Vj; dMatrix Mij; // b_i(xi) = potential(i) * prod_{u \in N(i)}{m_ui} for(int xi=0; xi<nbNodes; xi++) { beliefs.belStates[xi].set(potentials.belStates[xi]); for(int xu=0; xu<nbNodes; xu++) { if( !adjMat(xu,xi) ) continue; msg_idx = (xu>xi) ? adjMatMax+adjMat(xu,xi)-1 : adjMat(xu,xi)-1; beliefs.belStates[xi].add(messages[msg_idx]); } } // b_ij(xi,xj) = potential(i) * potential(j) * potential(i,j) // * prod_{u \in N(i)\j}{m_ui} * prod_{u \in N(j)\i}{m_uj} for(int xi=0; xi<nbNodes; xi++) { for(int xj=xi+1; xj<nbNodes; xj++ ) { // xj starts from xi+1 because b_ij==b_ji if( !adjMat(xi,xj) ) continue; // potential(i) * prod_{u \in N(i)\j){m_ui} Vi.set(potentials.belStates[xi]); for(int xu=0; xu<nbNodes; xu++ ) { if( !adjMat(xu,xi) || xu==xj ) continue; msg_idx = (xu>xi) ? adjMatMax+adjMat(xu,xi)-1 : adjMat(xu,xi)-1; Vi.add(messages[msg_idx]); } // potential(j) * prod_{u \in N(j)\i){m_uj} Vj.set(potentials.belStates[xj]); for(int xu=0; xu<nbNodes; xu++ ) { if( !adjMat(xu,xj) || xu==xi ) continue; msg_idx = (xu>xj) ? adjMatMax+adjMat(xu,xj)-1 : adjMat(xu,xj)-1; Vj.add(messages[msg_idx]); } // potential(i,j) * Vi*Vj*Mij Mij.create( Vj.getLength(), Vi.getLength() ); logMultiply(Vi,Vj,Mij); Mij.add(potentials.belEdges[adjMat(xi,xj)-1]); beliefs.belEdges[adjMat(xi,xj)-1].set(Mij); } } // Normalize beliefs and compute partition double logZ = 0; beliefs.partition = 0; for(unsigned int i=0; i<beliefs.belStates.size(); i++) { logZ = beliefs.belStates[i].logSumExp(); beliefs.belStates[i].add(-logZ); beliefs.belStates[i].eltExp(); beliefs.partition += logZ; } for(unsigned int i=0; i<beliefs.belEdges.size(); i++) { logZ = beliefs.belEdges[i].logSumExp(); beliefs.belEdges[i].add(-logZ); beliefs.belEdges[i].eltExp(); beliefs.partition += logZ; } }