tiny_dnn 1.0.0
A header only, dependency-free deep learning framework in C++11
Loading...
Searching...
No Matches
util.h
1/*
2 Copyright (c) 2013, Taiga Nomi
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
17 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#pragma once
28#include <vector>
29#include <functional>
30#include <random>
31#include <type_traits>
32#include <limits>
33#include <cassert>
34#include <cstdio>
35#include <cstdarg>
36#include <string>
37#include <sstream>
38
39#include <cereal/cereal.hpp>
40#include <cereal/archives/json.hpp>
41#include <cereal/archives/binary.hpp>
42#include <cereal/types/string.hpp>
43#include <cereal/types/vector.hpp>
44#include <cereal/types/deque.hpp>
45
46#include "tiny_dnn/config.h"
47#include "tiny_dnn/util/macro.h"
48#include "tiny_dnn/util/aligned_allocator.h"
49#include "tiny_dnn/util/nn_error.h"
50#include "tiny_dnn/util/parallel_for.h"
51#include "tiny_dnn/util/random.h"
52
53#if defined(USE_OPENCL) || defined(USE_CUDA)
54#ifdef USE_OPENCL
55#include "third_party/CLCudaAPI/clpp11.h"
56#else
57#include "third_party/CLCudaAPI/cupp11.h"
58#endif
59#endif
60
61namespace tiny_dnn {
62
65typedef serial_size_t label_t;
66
67typedef serial_size_t layer_size_t; // for backward compatibility
68
69typedef std::vector<float_t, aligned_allocator<float_t, 64>> vec_t;
70
71typedef std::vector<vec_t> tensor_t;
72
73enum class net_phase {
74 train,
75 test
76};
77
78enum class padding {
79 valid,
80 same
81};
82
83template<typename T>
84T* reverse_endian(T* p) {
85 std::reverse(reinterpret_cast<char*>(p), reinterpret_cast<char*>(p) + sizeof(T));
86 return p;
87}
88
89inline bool is_little_endian() {
90 int x = 1;
91 return *(char*) &x != 0;
92}
93
94
95template<typename T>
96size_t max_index(const T& vec) {
97 auto begin_iterator = std::begin(vec);
98 return std::max_element(begin_iterator, std::end(vec)) - begin_iterator;
99}
100
101template<typename T, typename U>
102U rescale(T x, T src_min, T src_max, U dst_min, U dst_max) {
103 U value = static_cast<U>(((x - src_min) * (dst_max - dst_min)) / (src_max - src_min) + dst_min);
104 return std::min(dst_max, std::max(value, dst_min));
105}
106
107inline void nop()
108{
109 // do nothing
110}
111
112template <typename T> inline T sqr(T value) { return value*value; }
113
114inline bool isfinite(float_t x) {
115 return x == x;
116}
117
118template <typename Container> inline bool has_infinite(const Container& c) {
119 for (auto v : c)
120 if (!isfinite(v)) return true;
121 return false;
122}
123
124template <typename Container>
125serial_size_t max_size(const Container& c) {
126 typedef typename Container::value_type value_t;
127 const auto max_size = std::max_element(c.begin(), c.end(),
128 [](const value_t& left, const value_t& right) { return left.size() < right.size(); })->size();
129 assert(max_size <= std::numeric_limits<serial_size_t>::max());
130 return static_cast<serial_size_t>(max_size);
131}
132
133inline std::string format_str(const char *fmt, ...) {
134 static char buf[2048];
135
136#ifdef _MSC_VER
137#pragma warning(disable:4996)
138#endif
139 va_list args;
140 va_start(args, fmt);
141 vsnprintf(buf, sizeof(buf), fmt, args);
142 va_end(args);
143#ifdef _MSC_VER
144#pragma warning(default:4996)
145#endif
146 return std::string(buf);
147}
148
149template <typename T>
150struct index3d {
151 index3d(T width, T height, T depth) {
152 reshape(width, height, depth);
153 }
154
155 index3d() : width_(0), height_(0), depth_(0) {}
156
157 void reshape(T width, T height, T depth) {
158 width_ = width;
159 height_ = height;
160 depth_ = depth;
161
162 if ((long long) width * height * depth > std::numeric_limits<T>::max())
163 throw nn_error(
164 format_str("error while constructing layer: layer size too large for tiny-dnn\nWidthxHeightxChannels=%dx%dx%d >= max size of [%s](=%d)",
165 width, height, depth, typeid(T).name(), std::numeric_limits<T>::max()));
166 }
167
168 T get_index(T x, T y, T channel) const {
169 assert(x >= 0 && x < width_);
170 assert(y >= 0 && y < height_);
171 assert(channel >= 0 && channel < depth_);
172 return (height_ * channel + y) * width_ + x;
173 }
174
175 T area() const {
176 return width_ * height_;
177 }
178
179 T size() const {
180 return width_ * height_ * depth_;
181 }
182
183 template <class Archive>
184 void serialize(Archive & ar) {
185 ar(cereal::make_nvp("width", width_));
186 ar(cereal::make_nvp("height", height_));
187 ar(cereal::make_nvp("depth", depth_));
188 }
189
190 T width_;
191 T height_;
192 T depth_;
193};
194
196
197template <typename T>
198bool operator == (const index3d<T>& lhs, const index3d<T>& rhs) {
199 return (lhs.width_ == rhs.width_) && (lhs.height_ == rhs.height_) && (lhs.depth_ == rhs.depth_);
200}
201
202template <typename T>
203bool operator != (const index3d<T>& lhs, const index3d<T>& rhs) {
204 return !(lhs == rhs);
205}
206
207template <typename Stream, typename T>
208Stream& operator << (Stream& s, const index3d<T>& d) {
209 s << d.width_ << "x" << d.height_ << "x" << d.depth_;
210 return s;
211}
212
213template <typename T>
214std::ostream& operator << (std::ostream& s, const index3d<T>& d) {
215 s << d.width_ << "x" << d.height_ << "x" << d.depth_;
216 return s;
217}
218
219template <typename Stream, typename T>
220Stream& operator << (Stream& s, const std::vector<index3d<T>>& d) {
221 s << "[";
222 for (serial_size_t i = 0; i < d.size(); i++) {
223 if (i) s << ",";
224 s << "[" << d[i] << "]";
225 }
226 s << "]";
227 return s;
228}
229
230// equivalent to std::to_string, which android NDK doesn't support
231template <typename T>
232std::string to_string(T value) {
233 std::ostringstream os;
234 os << value;
235 return os.str();
236}
237
238// boilerplate to resolve dependent name
239#define CNN_USE_LAYER_MEMBERS using layer::parallelize_; \
240 using feedforward_layer<Activation>::h_
241
242
243#define CNN_LOG_VECTOR(vec, name)
244/*
245void CNN_LOG_VECTOR(const vec_t& vec, const std::string& name) {
246 std::cout << name << ",";
247
248 if (vec.empty()) {
249 std::cout << "(empty)" << std::endl;
250 }
251 else {
252 for (size_t i = 0; i < vec.size(); i++) {
253 std::cout << vec[i] << ",";
254 }
255 }
256
257 std::cout << std::endl;
258}
259*/
260
261
262template <typename T, typename Pred, typename Sum>
263serial_size_t sumif(const std::vector<T>& vec, Pred p, Sum s) {
264 serial_size_t sum = 0;
265 for (serial_size_t i = 0; i < static_cast<serial_size_t>(vec.size()); i++) {
266 if (p(i)) sum += s(vec[i]);
267 }
268 return sum;
269}
270
271template <typename T, typename Pred>
272std::vector<T> filter(const std::vector<T>& vec, Pred p) {
273 std::vector<T> res;
274 for (size_t i = 0; i < vec.size(); i++) {
275 if (p(i)) res.push_back(vec[i]);
276 }
277 return res;
278}
279
280template <typename Result, typename T, typename Pred>
281std::vector<Result> map_(const std::vector<T>& vec, Pred p) {
282 std::vector<Result> res;
283 for (auto& v : vec) {
284 res.push_back(p(v));
285 }
286 return res;
287}
288
289enum class vector_type : int32_t {
290 // 0x0001XXX : in/out data
291 data = 0x0001000, // input/output data, fed by other layer or input channel
292
293 // 0x0002XXX : trainable parameters, updated for each back propagation
294 weight = 0x0002000,
295 bias = 0x0002001,
296
297 label = 0x0004000,
298 aux = 0x0010000 // layer-specific storage
299};
300
301inline std::string to_string(vector_type vtype) {
302 switch (vtype)
303 {
304 case tiny_dnn::vector_type::data:
305 return "data";
306 case tiny_dnn::vector_type::weight:
307 return "weight";
308 case tiny_dnn::vector_type::bias:
309 return "bias";
310 case tiny_dnn::vector_type::label:
311 return "label";
312 case tiny_dnn::vector_type::aux:
313 return "aux";
314 default:
315 return "unknown";
316 }
317}
318
319inline std::ostream& operator << (std::ostream& os, vector_type vtype) {
320 os << to_string(vtype);
321 return os;
322}
323
324inline vector_type operator & (vector_type lhs, vector_type rhs) {
325 return (vector_type)(static_cast<int32_t>(lhs) & static_cast<int32_t>(rhs));
326}
327
328inline bool is_trainable_weight(vector_type vtype) {
329 return (vtype & vector_type::weight) == vector_type::weight;
330}
331
332inline std::vector<vector_type> std_input_order(bool has_bias) {
333 if (has_bias) {
334 return{ vector_type::data, vector_type::weight, vector_type::bias };
335 }
336 else {
337 return{ vector_type::data, vector_type::weight };
338 }
339}
340
341inline std::vector<vector_type> std_output_order(bool has_activation) {
342 if (has_activation) {
343 return{ vector_type::data, vector_type::aux };
344 }
345 else {
346 return{ vector_type::data };
347 }
348}
349
350inline void fill_tensor(tensor_t& tensor, float_t value) {
351 for (auto& t : tensor) {
352 std::fill(t.begin(), t.end(), value);
353 }
354}
355
356inline void fill_tensor(tensor_t& tensor, float_t value, serial_size_t size) {
357 for (auto& t : tensor) {
358 t.resize(size, value);
359 }
360}
361
362inline serial_size_t conv_out_length(serial_size_t in_length,
363 serial_size_t window_size,
364 serial_size_t stride,
365 padding pad_type) {
366 serial_size_t output_length;
367
368 if (pad_type == padding::same) {
369 output_length = in_length;
370 }
371 else if (pad_type == padding::valid) {
372 output_length = in_length - window_size + 1;
373 }
374 else {
375 throw nn_error("Not recognized pad_type.");
376 }
377 return (output_length + stride - 1) / stride;
378}
379
380// get all platforms (drivers), e.g. NVIDIA
381// https://github.com/CNugteren/CLCudaAPI/blob/master/samples/device_info.cc
382
383inline void printAvailableDevice(const serial_size_t platform_id,
384 const serial_size_t device_id) {
385#if defined(USE_OPENCL) || defined(USE_CUDA)
386 // Initializes the CLCudaAPI platform and device. This initializes the OpenCL/CUDA back-end and
387 // selects a specific device on the platform.
388 auto platform = CLCudaAPI::Platform(platform_id);
389 auto device = CLCudaAPI::Device(platform, device_id);
390
391 // Prints information about the chosen device. Most of these results should stay the same when
392 // switching between the CUDA and OpenCL back-ends.
393 printf("\n## Printing device information...\n");
394 printf(" > Platform ID %zu\n", platform_id);
395 printf(" > Device ID %zu\n", device_id);
396 printf(" > Framework version %s\n", device.Version().c_str());
397 printf(" > Vendor %s\n", device.Vendor().c_str());
398 printf(" > Device name %s\n", device.Name().c_str());
399 printf(" > Device type %s\n", device.Type().c_str());
400 printf(" > Max work-group size %zu\n", device.MaxWorkGroupSize());
401 printf(" > Max thread dimensions %zu\n", device.MaxWorkItemDimensions());
402 printf(" > Max work-group sizes:\n");
403 for (auto i=size_t{0}; i<device.MaxWorkItemDimensions(); ++i) {
404 printf(" - in the %zu-dimension %zu\n", i, device.MaxWorkItemSizes()[i]);
405 }
406 printf(" > Local memory per work-group %zu bytes\n", device.LocalMemSize());
407 printf(" > Device capabilities %s\n", device.Capabilities().c_str());
408 printf(" > Core clock rate %zu MHz\n", device.CoreClock());
409 printf(" > Number of compute units %zu\n", device.ComputeUnits());
410 printf(" > Total memory size %zu bytes\n", device.MemorySize());
411 printf(" > Maximum allocatable memory %zu bytes\n", device.MaxAllocSize());
412 printf(" > Memory clock rate %zu MHz\n", device.MemoryClock());
413 printf(" > Memory bus width %zu bits\n", device.MemoryBusWidth());
414#else
415 nn_warn("TinyDNN was not build with OpenCL or CUDA support.");
416#endif
417}
418
419template<typename T, typename... Args>
420std::unique_ptr<T> make_unique(Args&&... args)
421{
422 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
423}
424
425} // namespace tiny_dnn
Simple image utility class.
Definition image.h:94
error exception class for tiny-dnn
Definition nn_error.h:37
Definition util.h:150