Commit f8b1a3de authored by Davis King's avatar Davis King

Cleanup and added loss spec file.

parent cba82daf
......@@ -3,14 +3,13 @@
#ifndef DLIB_DNn_LOSS_H_
#define DLIB_DNn_LOSS_H_
#include "loss_abstract.h"
#include "core.h"
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class loss_binary_hinge_
......@@ -18,10 +17,8 @@ namespace dlib
public:
const static unsigned int sample_expansion_factor = 1;
typedef double label_type;
typedef float label_type;
// Implementing to_label() is optional. If you don't do it then it just means the
// automatic operator() mapping from tensors to outputs is missing from the net object.
template <
typename SUB_TYPE,
typename label_iterator
......@@ -30,14 +27,6 @@ namespace dlib
const SUB_TYPE& sub,
label_iterator iter
) const
/*!
requires
- SUB_NET implements the SUB_NET interface defined at the top of layers_abstract.h.
- sub.get_output().num_samples() must be a multiple of sample_expansion_factor.
- iter == an iterator pointing to the beginning of a range of
sub.get_output().num_samples()/sample_expansion_factor elements. In
particular, they must be label_type elements.
!*/
{
const tensor& output_tensor = sub.get_output();
DLIB_CASSERT(output_tensor.nr() == 1 &&
......@@ -53,33 +42,14 @@ namespace dlib
}
template <
typename label_iterator,
typename const_label_iterator,
typename SUB_NET
>
double compute_loss (
const tensor& input_tensor,
label_iterator truth, // TODO, this parameter is optional.
const_label_iterator truth,
SUB_NET& sub
) const
/*!
requires
- SUB_NET implements the SUB_NET interface defined at the top of layers_abstract.h.
- input_tensor was given as input to the network sub and the outputs are now
visible in sub.get_output(), sub.sub_net().get_output(), etc.
- input_tensor.num_samples() > 0
- input_tensor.num_samples() must be a multiple of sample_expansion_factor.
- input_tensor.num_samples() == sub.get_output().num_samples() == grad.num_samples()
- truth == an iterator pointing to the beginning of a range of
input_tensor.num_samples()/sample_expansion_factor elements. In particular,
they must be label_type elements.
- sub.get_gradient_input() has the same dimensions as sub.get_output().
- for all valid i:
- *(truth+i/sample_expansion_factor) is the label of the ith sample in
sub.get_output().
ensures
- #sub.get_gradient_input() == the gradient of the loss with respect to
sub.get_output().
!*/
{
const tensor& output_tensor = sub.get_output();
tensor& grad = sub.get_gradient_input();
......@@ -105,11 +75,7 @@ namespace dlib
if (temp > 0)
{
loss += scale*temp;
g[i] = -scale*y;
}
else
{
g[i] = 0;
g[i] += -scale*y;
}
}
return loss;
......@@ -117,8 +83,6 @@ namespace dlib
};
// ----------------------------------------------------------------------------------------
template <typename SUB_NET>
using loss_binary_hinge = add_loss_layer<loss_binary_hinge_, SUB_NET>;
......@@ -128,11 +92,8 @@ namespace dlib
{
public:
//typedef int label_type;
const static unsigned int sample_expansion_factor = 1;
template <
typename SUB_NET
>
......@@ -140,32 +101,12 @@ namespace dlib
const tensor& input_tensor,
SUB_NET& sub
) const
/*!
requires
- SUB_NET implements the SUB_NET interface defined at the top of layers_abstract.h.
- input_tensor was given as input to the network sub and the outputs are now
visible in sub.get_output(), sub.sub_net().get_output(), etc.
- input_tensor.num_samples() must be a multiple of sample_expansion_factor.
- input_tensor.num_samples() == sub.get_output().num_samples() == grad.num_samples()
- truth == an iterator pointing to the beginning of a range of
input_tensor.num_samples()/sample_expansion_factor elements. In particular,
they must be label_type elements.
- sub.get_gradient_input() has the same dimensions as sub.get_output().
- for all valid i:
- *(truth+i/sample_expansion_factor) is the label of the ith sample in
sub.get_output().
ensures
- #sub.get_gradient_input() == the gradient of the loss with respect to
sub.get_output().
!*/
{
return 0;
}
};
// ----------------------------------------------------------------------------------------
template <typename SUB_NET>
using loss_no_label = add_loss_layer<loss_no_label_, SUB_NET>;
......@@ -175,4 +116,3 @@ namespace dlib
#endif // DLIB_DNn_LOSS_H_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_DNn_LOSS_ABSTRACT_H_
#ifdef DLIB_DNn_LOSS_ABSTRACT_H_
#include "core_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class EXAMPLE_LOSS_LAYER_
{
/*!
WHAT THIS OBJECT REPRESENTS
A loss layer is the final layer in a deep neural network. It computes the
task loss. That is, it computes a number that tells us how well the
network is performing on some task, such as predicting a binary label.
You can use one of the loss layers that comes with dlib (defined below).
But importantly, you are able to define your own loss layers to suit your
needs. You do this by creating a class that defines an interface matching
the one described by this EXAMPLE_LOSS_LAYER_ class. Note that there is no
dlib::EXAMPLE_LOSS_LAYER_ type. It is shown here purely to document the
interface that a loss layer object must implement.
A loss layer can optionally provide a to_label() method that converts the
output of a network into a user defined type. If to_label() is not
provided then the operator() methods of add_loss_layer will not be
available, but otherwise everything will function as normal.
Finally, note that there are two broad flavors of loss layer, supervised
and unsupervised. The EXAMPLE_LOSS_LAYER_ as shown here is a supervised
layer. To make an unsupervised loss you simply leave out the label_type
typedef, to_label(), and the truth iterator argument to compute_loss().
!*/
public:
// sample_expansion_factor must be > 0
const static unsigned int sample_expansion_factor;
typedef whatever_type_you_use_for_labels label_type;
// Implementing to_label() is optional.
template <
typename SUB_TYPE,
typename label_iterator
>
void to_label (
const SUB_TYPE& sub,
label_iterator iter
) const;
/*!
requires
- SUB_NET implements the SUB_NET interface defined at the top of
layers_abstract.h.
- sub.get_output().num_samples()%sample_expansion_factor == 0
- All outputs in each layer of sub have the same number of samples. That
is, for all valid i:
- sub.get_output().num_samples() == layer<i>(sub).get_output().num_samples()
- iter == an iterator pointing to the beginning of a range of
sub.get_output().num_samples()/sample_expansion_factor elements.
Moreover, they must be label_type elements.
ensures
- Converts the output of the provided network to label_type objects and
stores the results into the range indicated by iter. In particular, for
all valid i and j, it will be the case that:
*(truth+i/sample_expansion_factor) is the output corresponding to the
ith sample in layer<j>(sub).get_output().
!*/
template <
typename const_label_iterator,
typename SUB_NET
>
double compute_loss (
const tensor& input_tensor,
const_label_iterator truth,
SUB_NET& sub
) const;
/*!
requires
- SUB_NET implements the SUB_NET interface defined at the top of
layers_abstract.h.
- input_tensor was given as input to the network sub and the outputs are
now visible in layer<i>(sub).get_output(), for all valid i.
- input_tensor.num_samples() > 0
- input_tensor.num_samples()%sample_expansion_factor == 0.
- for all valid i:
- layer<i>(sub).get_output().num_samples() == input_tensor.num_samples().
- layer<i>(sub).get_gradient_input() has the same dimensions as layer<i>(sub).get_output().
- truth == an iterator pointing to the beginning of a range of
input_tensor.num_samples()/sample_expansion_factor elements. In
particular, they must be label_type elements.
- for all valid i and j:
- *(truth+i/sample_expansion_factor) is the label of the ith sample in
layer<j>(sub).get_output().
ensures
- This function computes the loss function that describes how well the output
of sub matches the expected labels given by truth. Let's write the loss
function as L(input_tensor, truth, sub).
- Then compute_loss() computes the gradient of L() with respect to the
outputs in sub. Specifically, compute_loss() adds the gradients into sub
by performing the following tensor additions, for all valid i:
- layer<i>(sub).get_gradient_input() += the gradient of
L(input_tensor,truth,sub) with respect to layer<i>(sub).get_output().
- returns L(input_tensor,truth,sub)
!*/
};
// For each loss layer you define, always define an add_loss_layer template so that
// layers can be easily composed. Moreover, the convention is that the layer class
// ends with an _ while the add_loss_layer template has the same name but without the
// trailing _.
template <typename SUB_NET>
using EXAMPLE_LOSS_LAYER = add_loss_layer<EXAMPLE_LOSS_LAYER_, SUB_NET>;
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class loss_binary_hinge_
{
/*!
WHAT THIS OBJECT REPRESENTS
You use this loss to perform binary classification with the hinge loss.
Therefore, the possible outputs/labels when using this loss are +1 and -1.
!*/
public:
const static unsigned int sample_expansion_factor = 1;
typedef float label_type;
template <
typename SUB_TYPE,
typename label_iterator
>
void to_label (
const SUB_TYPE& sub,
label_iterator iter
) const;
/*!
This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except
it has the additional calling requirements that:
- sub.get_output().nr() == 1
- sub.get_output().nc() == 1
- sub.get_output().k() == 1
!*/
template <
typename const_label_iterator,
typename SUB_NET
>
double compute_loss (
const tensor& input_tensor,
const_label_iterator truth,
SUB_NET& sub
) const;
/*!
This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except
it has the additional calling requirements that:
- sub.get_output().nr() == 1
- sub.get_output().nc() == 1
- sub.get_output().k() == 1
- all values pointed to by truth are +1 or -1.
!*/
};
template <typename SUB_NET>
using loss_binary_hinge = add_loss_layer<loss_binary_hinge_, SUB_NET>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_DNn_LOSS_ABSTRACT_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment