diff --git a/doc/Makefile b/doc/Makefile index 8d9461df..abf98509 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -16,6 +16,8 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext +all: html-noplot + help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @@ -48,6 +50,11 @@ html: @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." +html-noplot: + $(SPHINXBUILD) -D plot_gallery=False -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo diff --git a/doc/_static/pystruct.css b/doc/_static/pystruct.css index c16b62a2..9504bf04 100644 --- a/doc/_static/pystruct.css +++ b/doc/_static/pystruct.css @@ -3,5 +3,6 @@ } body .content-container{ - margin-top: 30px + margin-top: 30px; + width: 940px; } diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index d963a2fd..078537ab 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -2,9 +2,9 @@ {% extends "!layout.html" %} {# remove site and page menus #} -{% block sidebartoc %} +{%- block sidebartoc %} {% endblock %} -{% block sidebarrel %} +{%- block sidebarrel %} {% endblock %} {# Include our new CSS file into existing ones. #} @@ -16,5 +16,16 @@
{% block body %}{% endblock %}
+ + {%- endblock %} diff --git a/doc/conf.py b/doc/conf.py index e824b3ec..51b6e782 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -262,8 +262,11 @@ # A list of tuples containting pages to link to. The value should # be in the form [(name, page), ..] - 'navbar_links': [('Examples', 'auto_examples/index'), - ('References', 'references')], + 'navbar_links': [ + ('Introduction', 'intro'), + ('Examples', 'auto_examples/index'), + ('References', 'references'), + ], # Global TOC depth for "site" navbar tab. (Default: 1) # Switching to -1 shows all levels. diff --git a/doc/images/no_image.png b/doc/images/no_image.png index 53ce4358..e6cd8b8c 100644 Binary files a/doc/images/no_image.png and b/doc/images/no_image.png differ diff --git a/doc/index.rst b/doc/index.rst index a8cba89f..d0de1fc5 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,7 +2,13 @@ PyStruct - Structured Learning in Python ======================================== PyStruct aims at being an easy-to-use structured learning and prediction library. Currently it implements only max-margin methods and a perceptron, but other algorithms -might follow. +might follow. The learning algorithms implemented in PyStruct have various names, +which are often used loosely or differently in different communities. +Common names are conditional random fields (CRFs), maximum-margin Markov +random fields (M3N) or structural support vector machines. + +If you are new to structured learning, +have a look at :ref:`intro`. The goal of PyStruct is to provide a well-documented tool for researchers as well as non-experts to make use of structured prediction algorithms. @@ -85,4 +91,4 @@ solver (which should be a faster undergenerating solver, such as QPBO). auto_examples/index references.rst - + intro.rst diff --git a/doc/intro.rst b/doc/intro.rst new file mode 100644 index 00000000..c053ce55 --- /dev/null +++ b/doc/intro.rst @@ -0,0 +1,101 @@ +.. _intro: + +What is structured learning? +============================ + +Structured prediction is a generalization of the standard paradigms of +supervised learning, classification and regression. All of these can be thought +of finding a function that minimizes some loss over a training set. The +differences are in the kind of functions that are used and the losses. + +In classification, the target domain are discrete class labels, and the loss +is usually the 0-1 loss, i.e. counting the misclassifications. In regression, +the target domain is the real numbers, and the loss is usually mean squared +error. +In structured prediction, both the target domain and the loss are +more or less arbitrary. This means the goal is not to predict a label or a +number, but a possibly much more complicated object like a sequence or a +graph. + +What does that mean? +-------------------- + +In structured prediction, we often deal with finite, but large output spaces Y. +This situation could be dealt with using classification with a very large +number of classes. The idea behind structured prediction is that we can do +better than this, by making use of the structure of the output space. + +A (very simplified) example +--------------------------- + +Let's say we want to generate text from spoken sentences. Viewed as a pure +classification problem, we could see each possible sentence as a class. This +has several drawbacks: we have many classes, and to do correct predictions, we +have to have all possible sentences in the training set. That doesn't work +well. Also, we might not care about getting the sentence completely right. + +If we misinterpret a single word, this might be not as bad as +misinterpreting every word. So a 0-1 loss on sentences seems inappropriate. +We could also try to view every word as a separate class and try to predict +each word individually. This seems somehow better, since we could learn to get +most of the word in a sentence right. On the other hand, we lose all context. +So for example the expression "car door" is way more likely than "car boar", +while predicted individually these could be easily confused. +For a similar example, see :ref:`plot_letters.py`. + +Structured prediction tries to overcome these problems by considering the +output (here the sentence) as a whole and using a loss function that is +appropriate for this domain. + +A formalism +----------- +I hope I have convinced you that structured prediction is a useful thing. So +how are we going to formalize this? Having functions that produce arbitrary +objects seem a bit hard to handle. There is one very basic formula at the heart +of structured prediction: + +.. math:: + + y^* = \arg \max_{y \in Y} f(x, y) + +Here x is the input, Y is the set of all possible outputs and f is a +compatibility function that says how well y fits the input x. The prediction +for x is y*, the element of Y that maximizes the compatibility. + +This very simple formula allows us to predict arbitrarily complex outputs, as +long as we can say how compatible a given output is with the input. + +This approach opens up two questions: + +How do we specify f? How do we compute y*? + +As I said above, the output set Y is usually a finite but very large set (all +graphs, all sentences in the English language, all images of a given +resolution). Finding the argmax in the above equation by exhaustive search is +therefore out of the question. So we need to restrict ourselves to f such that +we can do the maximization over y efficiently. The most popular tool for +building such f is using energy functions or conditional random fields (CRFs) +[which are basically the same for finding y*]. + +There are basically three challenges in doing structured learning and prediction: + +* Choosing a parametric form of f +* solving :math:`\arg\max_y f(x, y)` +* learning parameters for f to minimize a loss. + +PyStruct takes :math:`f` to be a linear function of some parameters and a feature function :math:`Psi`. +Then the parametric form is given by the :ref:`models`. +The second problem, computation of the argmax, is done via third party inference solvers. +The interfaces to these are explained at :ref:`inference`. +The last part, the learning is actually the core part of PyStruct. +There are several different algorithms implemented, which you can find under :ref:`learning`. + +There have been many publications and book on this topics. For a nice introduction (in the context of computer vision), I recommend +Sebastian Nowozin, Christoph H. Lampert: + +`Structured Learning and Prediction in Computer Vision `_ + +Two of the founding publications on the topic of learning structured models are: + +* Ben Taskar, Carlos Guestrin, Daphne Koller `Max-Margin Markov Networks `_ +* Tsochantaridis, T. Joachims, T. Hofmann, and Y. Altun `Large Margin Methods for Structured and Interdependent Output Variables `_ diff --git a/doc/references.rst b/doc/references.rst index 3f22fc34..13f6eba8 100644 --- a/doc/references.rst +++ b/doc/references.rst @@ -85,6 +85,7 @@ Conditional Random Fields models.GridCRF models.DirectionalGridCRF +.. _inference: Inference =========== diff --git a/doc/sphinxext/gen_rst.py b/doc/sphinxext/gen_rst.py index e2a2c22d..fa5e70e7 100644 --- a/doc/sphinxext/gen_rst.py +++ b/doc/sphinxext/gen_rst.py @@ -415,7 +415,7 @@ def generate_example_rst(app): .figure { float: left; - margin: 20px; + margin: 16px; top: 0; left: 0; -webkit-border-radius: 10px; /* Saf3-4, iOS 1-3.2, Android <1.6 */ @@ -430,10 +430,7 @@ def generate_example_rst(app): background-repeat: no-repeat; /* --> Thumbnail image size */ width: 150px; - height: 200px; - -webkit-background-size: 150px 100px; /* Saf3-4 */ - -moz-background-size: 150px 100px; /* FF3.6 */ - background-size: 150px 100px; /* Opera, IE9, Saf5, Chrome, FF4 */ + height: 130px; } .figure img { @@ -441,7 +438,6 @@ def generate_example_rst(app): } .figure .caption { - width: 150px; text-align: center !important; } diff --git a/examples/multiclass_comparision_svm_struct.py b/examples/multiclass_comparision_svm_struct.py index 7a473649..44beb584 100644 --- a/examples/multiclass_comparision_svm_struct.py +++ b/examples/multiclass_comparision_svm_struct.py @@ -1,7 +1,7 @@ """ -================================================================== -Comparing PyStruct and SVM-Struct for multi-class classification -================================================================== +================================= +Comparing PyStruct and SVM-Struct +================================= This example compares the performance of pystruct and SVM^struct on a multi-class problem. For the example to work, you need to install SVM^multiclass and diff --git a/pystruct/__init__.py b/pystruct/__init__.py index e69de29b..485f44ac 100644 --- a/pystruct/__init__.py +++ b/pystruct/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.1" diff --git a/setup.py b/setup.py index 6bdc7463..9c4fe62c 100644 --- a/setup.py +++ b/setup.py @@ -8,14 +8,14 @@ os.remove('MANIFEST') setup(name="pystruct", - version="0.1", + version="0.1.1", install_requires=["ad3", "pyqpbo"], packages=['pystruct', 'pystruct.learners', 'pystruct.inference', 'pystruct.models', 'pystruct.utils', 'pystruct.datasets', 'pystruct.tests', 'pystruct.tests.test_learners', 'pystruct.tests.test_models', 'pystruct.tests.test_inference', 'pystruct.tests.test_utils'], - + include_package_data=True, description="Structured Learning and Prediction in Python", author="Andreas Mueller", author_email="t3kcit@gmail.com",