Beatmup
pooling2d.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2020, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "pooling2d.h"
20 #include "deserialized_model.h"
21 
22 using namespace Beatmup;
23 using namespace NNets;
24 
25 
26 static const char *UNIFORM_INPUT = "features";
27 
28 
30  const std::string& name,
31  const Operator op,
32  const int size,
33  const int stride,
34  const Size::Padding padding
35 ):
38  size(size, size, 1), stride(stride <= 0 ? this->size : Size(stride, stride, 1)),
39  op(op), padding(padding),
40  ready(false), program(nullptr)
41 {
42  if (op == Operator::AVERAGE)
43  InvalidArgument::check(padding == Size::Padding::VALID, "Average 2D pooling only supports valid padding");
44  OutOfRange::checkMin(size, 2, "Pooling size must be at least 2, %d got");
45 }
46 
47 
49  // delete the old program
50  if (program)
51  bank.release(gpu, program);
52 
54 
55  code.printf("uniform sampler2D %s[1];", UNIFORM_INPUT);
57 
58  // main
59  code.line("void main() {");
60 
61  // declare neighborhood, inline sampling
62  SpatialFilteringMixin::declare(code, "lowp vec4", true);
63 
64  // declare the result variable
65  switch (op) {
66  case Operator::MAX:
67  code("lowp");
68  break;
69  case Operator::AVERAGE:
70  code("mediump");
71  break;
72  }
73  code.line(" vec4 r;");
74 
75  // compute pooling
76  switch (op) {
77  case Operator::MAX:
78  for (int i = 0; i < size.volume(); ++i) {
79  code(i == 0 ? "r = (" : "r = max(r, ");
81  code.line(");");
82  }
83  code.line("gl_FragColor = r;");
84  break;
85  case Operator::AVERAGE:
86  code("r = ");
87  for (int i = 0; i < size.volume(); ++i) {
88  if (i > 0)
89  code(" + ");
91  }
92  code.line(";");
93  code.printf("gl_FragColor = %0.10f * r;", 1.0f / size.volume());
94  break;
95  }
96 
97  // store the result
98  code("}");
99 
100  // init program
101  program = bank(gpu, code);
102 
103  ready = true;
104 }
105 
106 
108  if (!ready)
109  throw NotReady(this);
110  RuntimeError::check(input, "Input is not provided to a Pooling2D operation.");
111  RuntimeError::check(output, "Output is not provided to Pooling2D operation " + getName());
112  RuntimeError::check(input.getDepth() == output.getDepth(), "Input / output depth mismatch.");
113 
114  // prepare deltas
115  program->enable(gpu);
118 
119  // setup texture coordinates
124  );
125 
126  // for each output channel
127  const IntPoint origin = input.getChannelOrigin(0);
128  Storage::Binder bind(gpu);
129  for (int channel = 0; channel < input.getDepth(); channel += 4) {
130  // bind things to program
131  bind.begin(*program, output, channel);
132  bind(input, UNIFORM_INPUT, channel);
133 
134  // setup
136 
137  // run
138  program->blend();
139  }
140 }
141 
142 
144  return (padding == Size::Padding::SAME) ? std::max(size[0], size[1]) / 2 : 0;
145 }
146 
147 
148 void Pooling2D::getSampledChannels(int index, int& min, int& max) const {
149  min = max = (index == 0 ? 4 : 0);
150 }
151 
152 
153 Size Pooling2D::getOutputSize(int outputIndex) const {
154  if (outputIndex == 0) {
155  RuntimeError::check(input, "Input is not provided to a Pooling2D operation.");
157  RuntimeError::check(result.volume() > 0, "Invalid (zero or negative) output size got in " + getName());
158  return result;
159  }
160  return Size::EMPTY;
161 }
162 
163 
164 void Pooling2D::setInput(Storage::View&& view, int inputIndex) {
165  OutOfRange::check(inputIndex, 0, 0, "Input index out of range: %d");
166  RuntimeError::check(view.getStorage().getPadding() >= getInputPadding(inputIndex), "The storage has insufficient padding");
167  this->input = std::move(view);
168 }
169 
170 
171 void Pooling2D::setOutput(Storage::View&& storage, int outputIndex) {
172  OutOfRange::check(outputIndex, 0, 0, "Output index out of range: %d");
173  this->output = std::move(storage);
174 }
175 
176 
177 std::map<std::string, std::string> Pooling2D::serialize() const {
178  return {
179  { "_name", getName() },
180  { "_type", "pooling2d" },
181  { "operator", std::to_string(op) },
182  { "size", std::to_string(size[0]) },
183  { "stride", std::to_string(stride[0]) },
184  { "padding", std::to_string(padding) }
185  };
186 }
187 
188 
190  static class Pooling2DDeserializer : public AbstractOperation::Deserializer {
191  public:
192  Pooling2DDeserializer() : Deserializer("pooling2d") {}
193  AbstractOperation* deserialize(Context& context, const Listing::Block& block) {
194  /** \page NNetsOpsSerialization
195  \section Pooling2D
196  \code{yaml}
197  - _name: arbitrary operation name
198  _type: pooling2d # fixed string
199  operator: max # "max" or "average"
200  size: 3 # pooling size
201  stride: 2 # stride (defaults to 1)
202  padding: valid # paddling, string, "valid" or "same" (defaults to "valid")
203  \endcode
204  */
205  return new Pooling2D(
206  block["_name"],
207  Pooling2D::operatorFromString(block["operator"]),
208  block.get<int>("size"),
209  block.get<int>("stride", 1),
210  paddingFromString(block.get<std::string>("padding", std::to_string(Size::Padding::VALID)))
211  );
212  }
213  } john;
214 
215  return true;
216 }
217 
218 
220  this->input = Storage::View();
221  this->output = Storage::View();
222 }
223 
224 
225 unsigned long Pooling2D::countTexelFetches() const {
226  return getOutputSize(0).volume() * size.volume() / 4;
227 }
228 
229 
231  const std::string lc = StringUtils::lowercase(str);
232  if (lc == "average")
233  return Operator::AVERAGE;
234  if (lc == "max")
235  return Operator::MAX;
236  throw InvalidArgument("Invalid pooling operator: " + str);
237  return Operator::AVERAGE;
238 }
239 
240 
242  switch (op) {
243  case Pooling2D::Operator::AVERAGE: return "average";
244  case Pooling2D::Operator::MAX: return "max";
245  }
246  Insanity::insanity("Invalid pooling operator");
247  return "";
248 }
A key-value pair set storing pieces of arbitrary data (chunks) under string keys.
Definition: chunkfile.h:36
Basic class: task and memory management, any kind of static data.
Definition: context.h:59
static const CustomPoint ZERO
Definition: geometry.h:122
void enable(const GraphicPipeline &gpu)
Definition: program.cpp:250
Stores linked GLSL programs and their associated fragment shader codes.
Definition: program_bank.h:31
void release(GraphicPipeline &gpu, GL::RenderingProgram *program)
Marks a program as unused any more.
void blend(bool onScreen)
Definition: program.cpp:548
static const char * DECLARE_TEXTURE_COORDINATES_IN_FRAG
Declaring texture coordinates in fragment shader.
Internal low-level GPU control API.
Definition: pipeline.h:33
void setTextureCoordinates(const Rectangle &coords)
Specifies texture coordinates for the next rendering pass.
Definition: pipeline.cpp:966
static void insanity(const char *message)
Definition: exception.h:136
static void check(const bool condition, const std::string &message)
Definition: exception.h:75
Set of key-value pairs.
Definition: listing.h:46
T get(const std::string &key) const
Returns a value by key casted to a given type.
Enables construction of an operation from its serialized representation.
Definition: operation.h:248
Abstract neural net operation (layer).
Definition: operation.h:46
std::string getName() const
Definition: operation.h:242
Operator
Pooling operator specification.
Definition: pooling2d.h:45
Storage::View input
Definition: pooling2d.h:54
void setOutput(Storage::View &&storage, int outputIndex=0)
Definition: pooling2d.cpp:171
void getSampledChannels(int index, int &min, int &max) const
Retrieves range of input features channels sampled at the same time for a specific input.
Definition: pooling2d.cpp:148
Size getOutputSize(int outputIndex=0) const
Returns full size of a specific operation output.
Definition: pooling2d.cpp:153
std::map< std::string, std::string > serialize() const
Returns a serialized representation of th operation;.
Definition: pooling2d.cpp:177
Storage::View output
Definition: pooling2d.h:54
void setInput(Storage::View &&storage, int inputIndex=0)
Definition: pooling2d.cpp:164
Pooling2D(const std::string &name, const Operator op, const int size, const int stride=1, const Size::Padding padding=Size::Padding::VALID)
2D pooling layer.
Definition: pooling2d.cpp:29
void disconnect()
Assigns empty inputs and outputs.
Definition: pooling2d.cpp:219
int getInputPadding(int index=0) const
Retrieves minimum required size of zero padding for a given input.
Definition: pooling2d.cpp:143
const Size::Padding padding
Definition: pooling2d.h:53
const Operator op
Definition: pooling2d.h:52
static Operator operatorFromString(const std::string &str)
Returns a pooling operator from string.
Definition: pooling2d.cpp:230
void execute(TaskThread &thread, GraphicPipeline &gpu)
Executes the operation.
Definition: pooling2d.cpp:107
GL::RenderingProgram * program
Definition: pooling2d.h:56
static bool initDeserializer()
Sets up deserialization of the operation.
void prepare(GraphicPipeline &gpu, ChunkCollection &data, GL::ProgramBank &bank)
Compiles GLSL shaders.
Definition: pooling2d.cpp:48
unsigned long countTexelFetches() const
Counts (approximate) number of texels fetches.
Definition: pooling2d.cpp:225
Operation 3D input/output size.
Definition: storage.h:37
Padding
Zero padding specification.
Definition: storage.h:45
@ SAME
operation output size matches its input size for unit strides
int volume() const
Definition: storage.h:79
static const Size EMPTY
Definition: storage.h:50
Size transform(Size kernel, Size stride, Padding padding, int depth=0) const
Computes operation output size in function of operation kernel, padding, stride and depth,...
Definition: storage.cpp:58
Generates GLSL fragment shader code sampling a local neighborhood around the current texture coordina...
Definition: operation.h:272
void sampleInline(StringBuilder &code, const char *inputName, const int inputIndex, const IntPoint &position, const Point &shift, const char *suffix="")
Definition: operation.cpp:174
void setup(const int width, const int height)
Prepares the spatial filtering operation execution.
Definition: operation.cpp:197
void writeHeader(StringBuilder &code, bool useUniformShift)
Writes out the very GLSL fragment shader header required for spatial neighborhood sampling.
Definition: operation.cpp:110
void declare(StringBuilder &code, const char *datatype, bool inlineSampling=false)
Declares GLSL fragment shader main(..) code part required for spatial neighborhood sampling.
Definition: operation.cpp:119
void setupProgram(GL::Program &program)
Prepares a given program for spatial filtering.
Definition: operation.cpp:217
IntRectangle getSamplingArea(const IntPoint &size, const IntPoint &stride, const Size::Padding padding) const
Implements common padding policies by computing a rectangular area of positions the sampling kernel t...
Definition: operation.cpp:223
void setUniformShift(GL::Program &program, const IntPoint &shift, const IntPoint &inputSize)
Applies an offset to the sampling position at runtime.
Definition: operation.cpp:209
Binding of different input/output storages/texture handlers to a GLSL program.
Definition: storage.h:419
Maps a 3D tensor onto a storage.
Definition: storage.h:308
int getTextureHeight() const
Returns height in pixels of all the textures.
Definition: storage.h:375
IntPoint getChannelOrigin(int channel) const
Returns origin in pixels of a given channel within the texture containing it.
Definition: storage.cpp:509
IntPoint getTextureSize() const
Definition: storage.h:377
IntPoint getSpatialSize() const
Returns the spatial size (width and height) of the storage in pixels.
Definition: storage.h:389
int getTextureWidth() const
Returns width in pixels of all the textures.
Definition: storage.h:370
friend class View
Definition: storage.h:135
static void checkMin(const datatype value, const datatype min, const char *message)
Definition: exception.h:92
static void check(const datatype value, const datatype min, const datatype max, const char *message)
Definition: exception.h:86
static void check(const bool condition, const std::string &message)
Definition: exception.h:64
StringBuilder & line(const std::string &append)
StringBuilder & printf(const char *format,...)
StringBuilder including a string container.
Thread executing tasks.
Definition: parallelism.h:154
Size::Padding paddingFromString(const std::string &str)
Returns a zero padding value from a string.
Definition: storage.cpp:703
std::string lowercase(const std::string &str)
Converts a string to lower case (latin letters only).
CustomPoint< int > IntPoint
Definition: geometry.h:629
std::string to_string(Beatmup::NNets::ActivationFunction function)
CustomPoint< numeric > min(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:724
CustomPoint< numeric > max(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:728
static const char * UNIFORM_INPUT
Definition: pooling2d.cpp:26
return(jlong) new Beatmup jlong jstring name
jlong jint index
Beatmup::IntPoint result
jlong jobject size
bitmap bind(jenv, jobj)
jlong jint op
JNIEnv jobject jstring str