Commit 368d6d19 authored by Davis King's avatar Davis King

Added CPU version of pooling layer code.

parent 2639a523
......@@ -1023,6 +1023,225 @@ namespace dlib
}
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
pooling::pooling (
) : window_height(0),window_width(0),stride_y(0),stride_x(0),do_max_pooling(true)
{
}
void pooling::
clear(
)
{
window_height = 0;
window_width = 0;
stride_y = 0;
stride_x = 0;
}
void pooling::
setup_max_pooling(
int window_height_,
int window_width_,
int stride_y_,
int stride_x_
)
{
DLIB_CASSERT(window_width_ > 0,"");
DLIB_CASSERT(window_height_ > 0,"");
DLIB_CASSERT(stride_y_ > 0,"");
DLIB_CASSERT(stride_x_ > 0,"");
window_height = window_height_;
window_width = window_width_;
stride_y = stride_y_;
stride_x = stride_x_;
do_max_pooling = true;
}
void pooling::
setup_avg_pooling(
int window_height_,
int window_width_,
int stride_y_,
int stride_x_
)
{
DLIB_CASSERT(window_width_ > 0,"");
DLIB_CASSERT(window_height_ > 0,"");
DLIB_CASSERT(stride_y_ > 0,"");
DLIB_CASSERT(stride_x_ > 0,"");
window_height = window_height_;
window_width = window_width_;
stride_y = stride_y_;
stride_x = stride_x_;
do_max_pooling = false;
}
void pooling::
operator() (
resizable_tensor& dest,
const tensor& src
)
{
DLIB_CASSERT(window_width > 0,"");
DLIB_CASSERT(window_height > 0,"");
DLIB_CASSERT(stride_y > 0,"");
DLIB_CASSERT(stride_x > 0,"");
dest.set_size(
src.num_samples(),
src.k(),
1+(src.nr()-window_height%2)/stride_y,
1+(src.nc()-window_width%2)/stride_x
);
if (src.size() == 0)
{
dest = 0;
return;
}
auto d = dest.host();
auto s = src.host();
if (does_max_pooling())
{
for (long n = 0; n < dest.num_samples(); ++n)
{
for (long k = 0; k < dest.k(); ++k)
{
auto simg = image_plane(src,n,k);
auto dimg = d + (n*dest.k() + k)*dest.nr()*dest.nc();
for (long r = 0; r < dest.nr(); ++r)
{
for (long c = 0; c < dest.nc(); ++c)
{
auto win = centered_rect(c*stride_x,
r*stride_y,
window_width,
window_height);
dimg[r*dest.nc() + c] = max(subm_clipped(simg,win));
}
}
}
}
}
else
{
for (long n = 0; n < dest.num_samples(); ++n)
{
for (long k = 0; k < dest.k(); ++k)
{
auto simg = image_plane(src,n,k);
auto dimg = d + (n*dest.k() + k)*dest.nr()*dest.nc();
for (long r = 0; r < dest.nr(); ++r)
{
for (long c = 0; c < dest.nc(); ++c)
{
auto win = centered_rect(c*stride_x,
r*stride_y,
window_width,
window_height);
dimg[r*dest.nc() + c] = mean(subm_clipped(simg,win));
}
}
}
}
}
}
void pooling::get_gradient(
const tensor& gradient_input,
const tensor& dest,
const tensor& src,
tensor& grad
)
{
DLIB_CASSERT(have_same_dimensions(gradient_input,dest),"");
DLIB_CASSERT(have_same_dimensions(src,grad),"");
if (src.size() == 0)
{
return;
}
auto gi = gradient_input.host();
auto g = grad.host();
auto s = src.host();
if (does_max_pooling())
{
for (long n = 0; n < dest.num_samples(); ++n)
{
for (long k = 0; k < dest.k(); ++k)
{
auto simg = image_plane(src,n,k);
auto gimg = g + (n*grad.k() + k)*grad.nr()*grad.nc();
auto giimg = gi + (n*dest.k() + k)*dest.nr()*dest.nc();
auto imgbox = get_rect(simg);
for (long r = 0; r < dest.nr(); ++r)
{
for (long c = 0; c < dest.nc(); ++c)
{
auto win = centered_rect(c*stride_x,
r*stride_y,
window_width,
window_height).intersect(imgbox);
auto p = max_point(subm(simg,win))+win.tl_corner();
gimg[p.y()*grad.nc()+p.x()] += giimg[r*dest.nc()+c];
}
}
}
}
}
else
{
for (long n = 0; n < dest.num_samples(); ++n)
{
for (long k = 0; k < dest.k(); ++k)
{
auto simg = image_plane(src,n,k);
auto gimg = g + (n*grad.k() + k)*grad.nr()*grad.nc();
auto giimg = gi + (n*dest.k() + k)*dest.nr()*dest.nc();
auto imgbox = get_rect(simg);
for (long r = 0; r < dest.nr(); ++r)
{
for (long c = 0; c < dest.nc(); ++c)
{
auto win = centered_rect(c*stride_x,
r*stride_y,
window_width,
window_height).intersect(imgbox);
const float delta = giimg[r*dest.nc()+c]/win.area();
for (long y = win.top(); y <= win.bottom(); ++y)
{
for (long x = win.left(); x <= win.right(); ++x)
{
gimg[y*grad.nc()+x] += delta;
}
}
}
}
}
}
}
}
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
}
}
......
......@@ -213,6 +213,59 @@ namespace dlib
const tensor& gradient_input
);
// -----------------------------------------------------------------------------------
class pooling
{
public:
pooling(const pooling&) = delete;
pooling& operator=(const pooling&) = delete;
pooling (
);
void clear(
);
void setup_max_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
);
void setup_avg_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
);
bool does_max_pooling(
) const { return do_max_pooling; }
void operator() (
resizable_tensor& dest,
const tensor& src
);
void get_gradient(
const tensor& gradient_input,
const tensor& dest,
const tensor& src,
tensor& grad
);
private:
int window_height;
int window_width;
int stride_y;
int stride_x;
bool do_max_pooling;
};
// -----------------------------------------------------------------------------------
}
......
......@@ -448,101 +448,6 @@ namespace dlib { namespace tt
#endif
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
pooling::
pooling (
)
{
}
void pooling::
clear(
)
{
#ifdef DLIB_USE_CUDA
impl.clear();
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
void pooling::
setup_max_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
)
{
#ifdef DLIB_USE_CUDA
impl.setup_max_pooling(window_height, window_width, stride_y, stride_x);
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
void pooling::
setup_avg_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
)
{
#ifdef DLIB_USE_CUDA
impl.setup_avg_pooling(window_height, window_width, stride_y, stride_x);
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
bool pooling::
does_max_pooling (
) const
{
#ifdef DLIB_USE_CUDA
return impl.does_max_pooling();
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
void pooling::
operator() (
resizable_tensor& dest,
const tensor& src
)
{
#ifdef DLIB_USE_CUDA
impl(dest, src);
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
void pooling::
get_gradient(
const tensor& gradient_input,
const tensor& dest,
const tensor& src,
tensor& grad
)
{
#ifdef DLIB_USE_CUDA
impl.get_gradient(gradient_input, dest, src, grad);
#else
// TODO
DLIB_CASSERT(false,"");
#endif
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
......
......@@ -595,6 +595,9 @@ namespace dlib { namespace tt
class pooling
{
/*!
WHAT THIS OBJECT REPRESENTS
The pooling object is a tool for performing spatial pooling over a tensor.
It can be configured to do either max or average pooling.
!*/
public:
......@@ -602,35 +605,56 @@ namespace dlib { namespace tt
pooling& operator=(const pooling&) = delete;
pooling (
);
) = default;
void clear(
);
) { impl.clear(); }
void setup_max_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
);
) { impl.setup_max_pooling(window_height, window_width, stride_y, stride_x); }
/*!
requires
- window_height > 0
- window_width > 0
- stride_y > 0
- stride_x > 0
ensures
- When you call operator() it will do max pooling with the given
parameters.
!*/
void setup_avg_pooling(
int window_height,
int window_width,
int stride_y,
int stride_x
);
) { impl.setup_avg_pooling(window_height, window_width, stride_y, stride_x); }
/*!
requires
- window_height > 0
- window_width > 0
- stride_y > 0
- stride_x > 0
ensures
- When you call operator() it will do average pooling with the given
parameters.
!*/
bool does_max_pooling(
) const;
) const { return impl.does_max_pooling(); }
void operator() (
resizable_tensor& dest,
const tensor& src
);
) { impl(dest, src); }
/*!
requires
- is_same_object(dest,src) == false
- either setup_max_pooling() or setup_avg_pooling() has been called.
ensures
- #dest.num_samples() == src.num_samples()
- #dest.k() == src.k()
......@@ -656,7 +680,7 @@ namespace dlib { namespace tt
const tensor& dest,
const tensor& src,
tensor& grad
);
) { impl.get_gradient(gradient_input, dest, src, grad); }
/*!
requires
- have_same_dimensions(gradient_input,dest) == true
......@@ -676,7 +700,7 @@ namespace dlib { namespace tt
#ifdef DLIB_USE_CUDA
cuda::pooling impl;
#else
// TODO
cpu::pooling impl;
#endif
};
......
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