def lifted_multicut_kernighan_lin(graph, costs, lifted_uv_ids, lifted_costs, warmstart=True, time_limit=None, n_threads=1): objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) solver_kl = objective.liftedMulticutKernighanLinFactory().create(objective) if time_limit is None: if warmstart: solver_gaec = objective.liftedMulticutGreedyAdditiveFactory().create(objective) res = solver_gaec.optimize() return solver_kl.optimize(nodeLabels=res) else: return solver_kl.optimize() else: if warmstart: solver_gaec = objective.liftedMulticutGreedyAdditiveFactory().create(objective) visitor1 = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) t0 = time.time() res = solver_gaec.optimize(visitor=visitor1) t0 = time.time() - t0 # time limit is not hard, so t0 might actually be bigger than # our time limit already if t0 > time_limit: return res visitor2 = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit - t0) return solver_kl.optimize(nodeLabels=res, visitor=visitor2) else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver_kl.optimize(visitor=visitor)
def compute_nh(self, graph_depth): # load the graph graph_path = os.path.join(self.tmp_folder, 'graph.n5', 'graph') graph = ndist.loadAsUndirectedGraph(graph_path) # load the node labels node_label_path = os.path.join(self.tmp_folder, 'node_labels.n5') node_label_key = 'node_labels' node_labels = z5py.File(node_label_path)[node_label_key][:] self.assertEqual(len(node_labels), graph.numberOfNodes) # run bfs up to depth 4 to get complete lifted nh lifted_graph = nlmc.liftedMulticutObjective(graph) lifted_graph.insertLiftedEdgesBfs(graph_depth) nh = lifted_graph.liftedUvIds() # filter by nodes which have a node labeling node_ids = np.arange(len(node_labels)) nodes_with_label = node_ids[node_labels != 0] nh_mask = np.in1d(nh, nodes_with_label).reshape(nh.shape) nh_mask = nh_mask.all(axis=1) nh = nh[nh_mask] # need to lexsort - awkward in numpy ... nh = nh[np.lexsort(np.rot90(nh))] return nh
def _to_objective(graph, costs, lifted_uv_ids, lifted_costs): if isinstance(graph, nifty.graph.UndirectedGraph): graph_ = graph else: graph_ = nifty.graph.undirectedGraph(graph.numberOfNodes) graph_.insertEdges(graph.uvIds()) objective = nlmc.liftedMulticutObjective(graph_) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) return objective
def set_up_problem(): path = './exp_data/exp_data.n5' # load the graph and edge probs f = z5py.File(path) ds = f['features'] probs = ds[:, 0] g = ndist.Graph(os.path.join(path, 's0/graph')) graph = nifty.graph.UndirectedGraph(g.numberOfNodes + 1) graph.insertEdges(g.uvIds()) # add lifted edges up to nhood 3 nhood = 2 obj = nlmc.liftedMulticutObjective(graph) obj.insertLiftedEdgesBfs(nhood) lifted_uvs = obj.liftedUvIds() print("Number of lifted edges:") print(len(lifted_uvs)) chunks = (int(1e6), 2) f.create_dataset('s0/lifted_nh', data=lifted_uvs, chunks=chunks, compression='gzip') # set the lifted costs according to the mean prob. of the shortest path print("Calculating costs ...") def find_costs_from_sp(lifted_id): print(lifted_id, "/", len(lifted_uvs)) sp = nifty.graph.ShortestPathDijkstra(graph) u, v = lifted_uvs[lifted_id] edge_path = sp.runSingleSourceSingleTarget(probs, u, v, False) max_prob = np.max(probs[edge_path]) return max_prob # p = find_costs_from_sp(0) # print(p) # return # n_threads = 8 with futures.ThreadPoolExecutor(n_threads) as tp: tasks = [ tp.submit(find_costs_from_sp, i) for i in range(len(lifted_uvs)) ] costs = np.array([t.result() for t in tasks]) assert len(costs) == len(lifted_uvs) costs = probs_to_costs(costs) chunks = (int(1e6), ) f.create_dataset('s0/lifted_costs', data=costs, chunks=chunks, compression='gzip')
def lifted_multicut_fusion_moves(graph, costs, lifted_uv_ids, lifted_costs, time_limit=None, n_threads=1, solver='kernighan-lin'): assert solver in ('kernighan-lin', 'greedy-additive') objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) if time_limit is None: return solver.optimize() else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver.optimize(visitor=visitor)
def lifted_multicut_gaec(graph, costs, lifted_uv_ids, lifted_costs, time_limit=None, n_threads=1): objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) solver = objective.liftedMulticutGreedyAdditiveFactory().create(objective) if time_limit is None: return solver.optimize() else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver.optimize(visitor=visitor)
def make_filtered_lifted_nh(rag, n_labels, uv_ids, lifted_nh): # we can't build the full lifted nh, because the extended fragments # connect short-cut lifted edges. # Hence, we only create the nhood of small - to - snall fragments WITHOUT extended fragments, # small - to - extended and extended to extended # find the extended nodes extended_node_list = np.array(nrag.findZExtendedNodes(rag), dtype='uint32') # filter the initial uv ids to exclude extended nodes edge_mask = np.in1d(uv_ids, extended_node_list).reshape(uv_ids.shape) edge_mask = (edge_mask == 0).all(axis=1) filtered_uv_ids = uv_ids[edge_mask] # get the corresponding lifted nh graph = nifty.graph.undirectedGraph(n_labels) graph.insertEdges(filtered_uv_ids) lifted_objective = nlmc.liftedMulticutObjective(graph) lifted_objective.insertLiftedEdgesBfs(lifted_nh) lifted_uv_ids = lifted_objective.liftedUvIds() # next, get the full lifted nh and post filter it for # small - to - small fragment connections graph = nifty.graph.undirectedGraph(n_labels) graph.insertEdges(uv_ids) lifted_objective = nlmc.liftedMulticutObjective(graph) lifted_objective.insertLiftedEdgesBfs(lifted_nh) additional_lifted_uv_ids = lifted_objective.liftedUvIds() full_lifted = len(additional_lifted_uv_ids) # filter edges that connect to small fragments edge_mask = np.in1d(additional_lifted_uv_ids, extended_node_list).reshape( additional_lifted_uv_ids.shape) edge_mask = np.sum(edge_mask, axis=1) > 1 additional_lifted_uv_ids = additional_lifted_uv_ids[edge_mask] if additional_lifted_uv_ids.size: lifted_uv_ids = np.concatenate( [lifted_uv_ids, additional_lifted_uv_ids], axis=0) print("Filtered number of lifted edges from", len(lifted_uv_ids), "to", full_lifted) return lifted_uv_ids
def run_lmc(graph, local_uv_ids, lifted_uv_ids, local_probs, lifted_probs, local_sizes=None, lifted_sizes=None, weighting_exponent=1., with_ignore_edges=True): if with_ignore_edges: # set the size of ignore edges to 1, to not mess up the weighting ignore_edges = (local_uv_ids == 0).any(axis=1) lifted_ignore_edges = (lifted_uv_ids == 0).any(axis=1) if local_sizes is not None: local_sizes[ignore_edges] = 1 if lifted_sizes is not None: lifted_sizes[lifted_ignore_edges] = 1 # turn probabilities into costs local_costs = cseg.transform_probabilities_to_costs( local_probs, edge_sizes=local_sizes, weighting_exponent=weighting_exponent) lifted_costs = cseg.transform_probabilities_to_costs( lifted_probs, edge_sizes=lifted_sizes, weighting_exponent=weighting_exponent) if with_ignore_edges: # set ignore labels (connecting to node id 0) to be maximally repulsive local_costs[ignore_edges] = -100 lifted_costs[lifted_ignore_edges] = -100 # build the lmc objective lifted_objective = nlmc.liftedMulticutObjective(graph) lifted_objective.setCosts(local_uv_ids, local_costs) lifted_objective.setCosts(lifted_uv_ids, lifted_costs) # compute lifted multicut solver_ga = lifted_objective.liftedMulticutGreedyAdditiveFactory().create( lifted_objective) node_labels = solver_ga.optimize() solver_kl = lifted_objective.liftedMulticutKernighanLinFactory().create( lifted_objective) node_labels = solver_kl.optimize(node_labels) # get indicators for merge ! # and return uv-ids, edge indicators and edge sizes merge_indicator = (node_labels[local_uv_ids[:, 0]] == node_labels[ local_uv_ids[:, 1]]).astype('uint8') return node_labels, merge_indicator
def lifted_multicut(n_nodes, local_uvs, local_costs, lifted_uvs, lifted_costs, time_limit=None): graph = nifty.graph.UndirectedGraph(n_nodes) graph.insertEdges(local_uvs) lifted_obj = nlmc.liftedMulticutObjective(graph) lifted_obj.setCosts(local_uvs, local_costs) lifted_obj.setCosts(lifted_uvs, lifted_costs) # visitor = lifted_obj.verboseVisitor(100) solver_ehc = lifted_obj.liftedMulticutGreedyAdditiveFactory().create(lifted_obj) node_labels = solver_ehc.optimize() solver_kl = lifted_obj.liftedMulticutKernighanLinFactory().create(lifted_obj) node_labels = solver_kl.optimize(node_labels) return node_labels
def lifted_multicut_kernighan_lin(graph, costs, lifted_uv_ids, lifted_costs, time_limit=None, warmstart=True, **kwargs): """ Solve lifted multicut problem with kernighan lin solver. Introduced in "Efficient decomposition of image and mesh graphs by lifted multicuts": http://openaccess.thecvf.com/content_iccv_2015/papers/Keuper_Efficient_Decomposition_of_ICCV_2015_paper.pdf Arguments: graph [nifty.graph] - graph of lifted multicut problem costs [np.ndarray] - edge costs of lifted multicut problem lifted_uv_ids [np.ndarray] - lifted edges lifted_costs [np.ndarray] - lifted edge costs time_limit [float] - time limit for inference (default: None) warmstart [bool] - whether to warmstart with gaec solution (default: True) """ objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) solver_kl = objective.liftedMulticutKernighanLinFactory().create(objective) if time_limit is None: if warmstart: solver_gaec = objective.liftedMulticutGreedyAdditiveFactory().create(objective) res = solver_gaec.optimize() return solver_kl.optimize(nodeLabels=res) else: return solver_kl.optimize() else: if warmstart: solver_gaec = objective.liftedMulticutGreedyAdditiveFactory().create(objective) visitor1 = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) t0 = time.time() res = solver_gaec.optimize(visitor=visitor1) t0 = time.time() - t0 # time limit is not hard, so t0 might actually be bigger than # our time limit already if t0 > time_limit: return res visitor2 = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit - t0) return solver_kl.optimize(nodeLabels=res, visitor=visitor2) else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver_kl.optimize(visitor=visitor)
def lifted_multicut_fusion_moves(graph, costs, lifted_uv_ids, lifted_costs, time_limit=None, warmstart_gaec=True, warmstart_kl=True, **kwargs): """ Solve lifted multicut problem with greedy additive edge contraction solver. Introduced in "An efficient fusion move algorithm for the minimum cost lifted multicut problem": https://hci.iwr.uni-heidelberg.de/sites/default/files/publications/files/1939997197/beier_16_efficient.pdf Arguments: graph [nifty.graph] - graph of lifted multicut problem costs [np.ndarray] - edge costs of lifted multicut problem lifted_uv_ids [np.ndarray] - lifted edges lifted_costs [np.ndarray] - lifted edge costs time_limit [float] - time limit for inference (default: None) warmstart_gaec [bool] - whether to warmstart with gaec solution (default: True) warmstart_kl [bool] - whether to warmstart with kl solution (default: True) """ objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) # TODO keep track of time limits when warmstarting # perform warmstarts node_labels = None if warmstart_gaec: solver_gaec = objective.liftedMulticutGreedyAdditiveFactory().create(objective) node_labels = solver_gaec.optimize() if warmstart_kl: solver_kl = objective.liftedMulticutKernighanLinFactory().create(objective) node_labels = solver_kl.optimize(node_labels) # nifty only supports numberOfThreads=1 # why doesn't nifty expose the internal solver here ? solver = objective.fusionMoveBasedFactory(numberOfThreads=1).create(objective) if time_limit is None: return solver.optimize() if node_labels is None else solver.optimize(node_labels) else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver.optimize(visitor=visitor) if node_labels is None else\ solver.optimize(nodeLabels=node_labels, visitor=visitor)
def compute_energy(name): exp_path = './exp_data/%s.n5' % name f = z5py.File(exp_path) g = ndist.Graph(os.path.join(exp_path, 's0', 'graph')) graph = nifty.graph.undirectedGraph(g.numberOfNodes + 1) graph.insertEdges(g.uvIds()) costs = f['s0/costs'][:] lifted_costs = f['s0/lifted_costs_%s' % name][:] lifted_uvs = f['s0/lifted_nh_%s' % name][:] obj = nlmc.liftedMulticutObjective(graph) obj.setGraphEdgesCosts(costs) obj.setCosts(lifted_uvs, lifted_costs) path = '/g/kreshuk/data/FIB25/cutout.n5' res_key = 'node_labels/%s' % name with z5py.File(path) as f: node_labels = f[res_key][:] e = obj.evalNodeLabels(node_labels) return e
def lifted_multicut_gaec(graph, costs, lifted_uv_ids, lifted_costs, time_limit=None, **kwargs): """ Solve lifted multicut problem with greedy additive edge contraction solver. Introduced in "An efficient fusion move algorithm for the minimum cost lifted multicut problem": https://hci.iwr.uni-heidelberg.de/sites/default/files/publications/files/1939997197/beier_16_efficient.pdf Arguments: graph [nifty.graph] - graph of lifted multicut problem costs [np.ndarray] - edge costs of lifted multicut problem lifted_uv_ids [np.ndarray] - lifted edges lifted_costs [np.ndarray] - lifted edge costs time_limit [float] - time limit for inference (default: None) """ objective = nlmc.liftedMulticutObjective(graph) objective.setGraphEdgesCosts(costs) objective.setCosts(lifted_uv_ids, lifted_costs) solver = objective.liftedMulticutGreedyAdditiveFactory().create(objective) if time_limit is None: return solver.optimize() else: visitor = objective.verboseVisitor(visitNth=1000000, timeLimitTotal=time_limit) return solver.optimize(visitor=visitor)
def __call__(self, local_uvs, lifted_uvs, local_costs, lifted_costs, time_limit=None, **kwargs): n_nodes = int(local_uvs.max()) + 1 graph = nifty.graph.undirectedGraph(n_nodes) graph.insertEdges(local_uvs) objective = nlmc.liftedMulticutObjective(graph) # TODO local vs. lifted weighting ?! objective.setCosts(local_uvs, local_costs) objective.setCosts(lifted_uvs, lifted_costs) # TODO visitors and time limit! # TODO would be nice to have solver chaining in nifty for lmc too solver_ga = objective.liftedMulticutGreedyAdditiveFactory().create( objective) # first solve greedy-agglomerative node_labels = solver_ga.optimize() if self.solver == 'greedy-additive': return node_labels else: solver_kl = objective.liftedMulticutKernighanLinFactory().create( objective) node_labels = solver_kl.optimize(node_labels) if self.solver == 'kernighan-lin': return node_labels elif self.solver == 'fusion-moves': solver_fm = self._get_fusion_moves(objective) node_labels = solver_fm.optimize(node_labels) return node_labels