def forward_pass(frcs, bu_msg, graph, pool_shape): """ Forward pass inference using a tree-approximation (cf. Sec S4.2). Parameters ---------- frcs : numpy.ndarray of numpy.int Nx3 array of (feature idx, row, column), where each row represents a single pool center. bu_msg : 3D numpy.ndarray of float The bottom-up messages from the preprocessing layer. Shape is (num_feats, rows, cols) graph : networkx.Graph An undirected graph whose edges describe the pairwise constraints between the pool centers. The tightness of the constraint is in the 'perturb_radius' edge attribute. pool_shape : (int, int) Vertical and horizontal pool shapes. Returns ------- fp_score : float Forward pass score. """ height, width = bu_msg.shape[-2:] # Vertical and horizontal pool shapes vps, hps = pool_shape def _pool_slice(f, r, c): assert (r - vps // 2 >= 0 and r + vps - vps // 2 < height and c - hps // 2 >= 0 and c + hps - hps // 2 < width), \ "Some pools are out of the image boundaries. "\ "Consider increase image padding or reduce pool shapes." return np.s_[f, r - vps // 2:r + vps - vps // 2, c - hps // 2:c + hps - hps // 2] # Find a schedule to compute the max marginal for the most constrained tree tree_schedule = get_tree_schedule(frcs, graph) # If we're sending a message out from x to y, it means x has received all # incoming messages incoming_msgs = {} for source, target, perturb_radius in tree_schedule: msg_in = bu_msg[_pool_slice(*frcs[source])] if source in incoming_msgs: msg_in = msg_in + incoming_msgs[source] del incoming_msgs[source] msg_in = dilate_2d(msg_in, (2 * perturb_radius + 1, 2 * perturb_radius + 1)) if target in incoming_msgs: incoming_msgs[target] += msg_in else: incoming_msgs[target] = msg_in fp_score = np.max(incoming_msgs[tree_schedule[-1, 1]] + bu_msg[_pool_slice(*frcs[tree_schedule[-1, 1]])]) return fp_score
def forward_pass(frcs, bu_msg, graph, pool_shape): """ Forward pass inference using a tree-approximation (cf. Sec S4.2). Parameters ---------- frcs : numpy.ndarray of numpy.int Nx3 array of (feature idx, row, column), where each row represents a single pool center. bu_msg : 3D numpy.ndarray of float The bottom-up messages from the preprocessing layer. Shape is (num_feats, rows, cols) graph : networkx.Graph An undirected graph whose edges describe the pairwise constraints between the pool centers. The tightness of the constraint is in the 'perturb_radius' edge attribute. pool_shape : (int, int) Vertical and horizontal pool shapes. Returns ------- fp_score : float Forward pass score. """ height, width = bu_msg.shape[-2:] # Vertical and horizontal pool shapes vps, hps = pool_shape def _pool_slice(f, r, c): assert (r - vps // 2 >= 0 and r + vps - vps // 2 < height and c - hps // 2 >= 0 and c + hps - hps // 2 < width), \ "Some pools are out of the image boundaries. "\ "Consider increase image padding or reduce pool shapes." return np.s_[f, r - vps // 2: r + vps - vps // 2, c - hps // 2: c + hps - hps // 2] # Find a schedule to compute the max marginal for the most constrained tree tree_schedule = get_tree_schedule(frcs, graph) # If we're sending a message out from x to y, it means x has received all # incoming messages incoming_msgs = {} for source, target, perturb_radius in tree_schedule: msg_in = bu_msg[_pool_slice(*frcs[source])] if source in incoming_msgs: msg_in = msg_in + incoming_msgs[source] del incoming_msgs[source] msg_in = dilate_2d(msg_in, (2 * perturb_radius + 1, 2 * perturb_radius + 1)) if target in incoming_msgs: incoming_msgs[target] += msg_in else: incoming_msgs[target] = msg_in fp_score = np.max(incoming_msgs[tree_schedule[-1, 1]] + bu_msg[_pool_slice(*frcs[tree_schedule[-1, 1]])]) return fp_score
def compute_1pl_message(in_mess, pert_radius): """Compute the outgoing message of a lateral factor given the perturbation radius and input message. Parameters ---------- in_mess : numpy.array Input BP messages to the factor. Each message has shape vps x hps. pert_radius : int Perturbation radius corresponding to the factor. Returns ------- out_mess : numpy.array Output BP message (at the opposite end of the factor from the input message). Shape is (vps, hps). """ pert_diameter = 2 * pert_radius + 1 out_mess = dilate_2d(in_mess, (pert_diameter, pert_diameter)) return out_mess - out_mess.max()
def compute_1pl_message(in_mess, pert_radius): """Compute the outgoing message of a lateral factor given the perturbation radius and input message. Parameters ---------- in_mess : numpy.array Input BP messages to the factor. Each message has shape vps x hps. pert_radius : int Perturbation radius corresponding to the factor. Returns ------- out_mess : numpy.array Output BP message (at the opposite end of the factor from the input message). Shape is (vps, hps). """ pert_diameter = 2 * pert_radius + 1 out_mess = dilate_2d(in_mess, (pert_diameter, pert_diameter)) return out_mess - out_mess.max()