Not updating this repo anymore. Please use dd_mrf_cpp instead, which is a C++ implementation. It is much faster than this one, works on any graph (still need to specify slaves manually, which can be either tree or cycle), and was tested more than Python grid version. Please see accompanying file test_submodular.cpp for usage.
This Python library implements the Dual Decomposition algorithm by Komodakis, Paragios, and Tziritas [1] on a regular
2-D grid by dividing the graph into sub-problems (slaves). The decomposition can be into 1x1 cells of 4 nodes,
or into n_rows + n_cols
trees. The user can choose which decomposition to use.
The Python packages numpy
and joblib
are required. numpy
is used extensively for mathematics and joblib
allows distributing operations over several cores of the machine.
To use, simply include the library in your Python code:
import dd_mrf_grid as ddmrf
Graphs can be built incrementally using the Lattice
class provided by the module.
lat = ddmrf.Lattice(rows, cols, n_labels)
where rows
and cols
signify the number of rows and columns in the grid, and n_labels
is the number of labels
each node takes. n_labels
can be an integer (in which case all nodes can take the same number of labels), or a
Numpy array or list of integers of size rows*cols
to specify how many labels each node must take.
The nodes are indexed in a row-major fashion, starting at the top-left. Thus, the top-left node (also [0,0]
in
the Numpy array) is index 0
, and the index increments along the row first.
Edges can be specified by indicating the two nodes they are between. Nodes are specified by indices, as indicated
above.
To add energies to nodes and edges, use
lat.set_node_energies(i, E_node)
lat.set_edge_energies(i, j, E_edge)
where i
and j
are node indices, and E_node
and E_edge
are, respectively, the node and edge energies. E_node
must have n_labels[i]
elements, while E_edge
must have shape (n_labels[i], n_labels[j])
.
All nodes and edges must be assigned energies before the overall energy can be minimised. To verify whether all energies have been defined, use
lat.check_completeness()
A complete grid can be optimised using
lat.optimise(a_start=1.0, max_iter=1000, strategy='adaptive', decomposition='row_col')
strategy
specifies the strategy of choosing alpha at every iteration (see paper). Accepted values are
'step'
and 'adaptive'
. decomposition
specifies which graph-decomposition to use. Accepted values are
'cell'
and 'row_col'
.
After the algorithm converges, the obtained labelling is stored in lat.labels
.
Primal and dual costs can be plotted with lat.plot_costs()
.
[1] MRF Energy Minimization and Beyond via Dual Decomposition, N. Komodakis, N. Paragios and G. Tziritas, PAMI 2011.