summaryrefslogtreecommitdiff
path: root/compiler/souschef
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/souschef')
-rw-r--r--compiler/souschef/CMakeLists.txt9
-rw-r--r--compiler/souschef/include/souschef/Data/Explicit.h56
-rw-r--r--compiler/souschef/include/souschef/Data/Gaussian.h63
-rw-r--r--compiler/souschef/include/souschef/DataChef.def19
-rw-r--r--compiler/souschef/include/souschef/Dims.h1
-rw-r--r--compiler/souschef/src/Explicit.cpp98
-rw-r--r--compiler/souschef/src/Gaussian.cpp121
-rw-r--r--compiler/souschef/src/LexicalCast.cpp27
8 files changed, 342 insertions, 52 deletions
diff --git a/compiler/souschef/CMakeLists.txt b/compiler/souschef/CMakeLists.txt
index ca7eddc6f..8dcf4c2b8 100644
--- a/compiler/souschef/CMakeLists.txt
+++ b/compiler/souschef/CMakeLists.txt
@@ -1,13 +1,20 @@
nnas_find_package(Protobuf QUIET)
+nnas_find_package(Fp16Source QUIET)
if(NOT Protobuf_FOUND)
- message(STATUS "Build souschef: FAILED (missing Protobuf")
+ message(STATUS "Build souschef: FAILED (missing Protobuf)")
return()
endif(NOT Protobuf_FOUND)
+if(NOT Fp16Source_FOUND)
+ message(STATUS "Build souschef: FAILED (missing Fp16Source)")
+ return()
+endif(NOT Fp16Source_FOUND)
+
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(souschef STATIC ${SOURCES})
set_target_properties(souschef PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(souschef PRIVATE ${Fp16Source_DIR}/include)
target_include_directories(souschef PUBLIC include)
target_link_libraries(souschef PUBLIC libprotobuf)
diff --git a/compiler/souschef/include/souschef/Data/Explicit.h b/compiler/souschef/include/souschef/Data/Explicit.h
index 6e5ee819e..434d0ec2c 100644
--- a/compiler/souschef/include/souschef/Data/Explicit.h
+++ b/compiler/souschef/include/souschef/Data/Explicit.h
@@ -59,6 +59,27 @@ private:
std::vector<T> _values;
};
+template <> class ExplicitDataChef<std::string> final : public DataChef
+{
+public:
+ ExplicitDataChef()
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::vector<uint8_t> generate(int32_t count) const override;
+
+public:
+ void insert(const std::string &value) { _values.emplace_back(value); }
+
+private:
+ void write_value(std::vector<uint8_t> &res, int32_t value) const;
+
+private:
+ std::vector<std::string> _values;
+};
+
template <typename T> struct ExplicitDataChefFactory : public DataChefFactory
{
std::unique_ptr<DataChef> create(const Arguments &args) const
@@ -75,6 +96,41 @@ template <typename T> struct ExplicitDataChefFactory : public DataChefFactory
}
};
+class ExplicitFloat16DataChef final : public DataChef
+{
+public:
+ ExplicitFloat16DataChef()
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::vector<uint8_t> generate(int32_t count) const override;
+
+public:
+ void insert(const float &value) { _values.emplace_back(value); }
+
+private:
+ // NOTE store values in float but will convert to uint16_t in generate()
+ std::vector<float> _values;
+};
+
+struct ExplicitFloat16DataChefFactory : public DataChefFactory
+{
+ std::unique_ptr<DataChef> create(const Arguments &args) const
+ {
+ std::unique_ptr<ExplicitFloat16DataChef> res{new ExplicitFloat16DataChef};
+
+ for (uint32_t n = 0; n < args.count(); ++n)
+ {
+ auto const value = to_number<float>(args.value(n));
+ res->insert(value);
+ }
+
+ return std::move(res);
+ }
+};
+
} // namespace souschef
#endif // __SOUSCHEF_DATA_EXPLICIT_H__
diff --git a/compiler/souschef/include/souschef/Data/Gaussian.h b/compiler/souschef/include/souschef/Data/Gaussian.h
index 75570e0b8..801bff8e9 100644
--- a/compiler/souschef/include/souschef/Data/Gaussian.h
+++ b/compiler/souschef/include/souschef/Data/Gaussian.h
@@ -41,6 +41,22 @@ private:
float _stddev;
};
+class GaussianFloat16DataChef final : public DataChef
+{
+public:
+ GaussianFloat16DataChef(float mean, float stddev) : _mean{mean}, _stddev{stddev}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::vector<uint8_t> generate(int32_t count) const override;
+
+private:
+ float _mean;
+ float _stddev;
+};
+
class GaussianInt32DataChef final : public DataChef
{
public:
@@ -57,6 +73,22 @@ private:
float _stddev;
};
+class GaussianInt16DataChef final : public DataChef
+{
+public:
+ GaussianInt16DataChef(float mean, float stddev) : _mean{mean}, _stddev{stddev}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::vector<uint8_t> generate(int32_t count) const override;
+
+private:
+ float _mean;
+ float _stddev;
+};
+
class GaussianUint8DataChef final : public DataChef
{
public:
@@ -73,6 +105,22 @@ private:
float _stddev;
};
+class GaussianInt8DataChef final : public DataChef
+{
+public:
+ GaussianInt8DataChef(float mean, float stddev) : _mean{mean}, _stddev{stddev}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::vector<uint8_t> generate(int32_t count) const override;
+
+private:
+ float _mean;
+ float _stddev;
+};
+
struct GaussianFloat32DataChefFactory : public DataChefFactory
{
std::unique_ptr<DataChef> create(const Arguments &args) const;
@@ -83,11 +131,26 @@ struct GaussianInt32DataChefFactory : public DataChefFactory
std::unique_ptr<DataChef> create(const Arguments &args) const;
};
+struct GaussianInt16DataChefFactory : public DataChefFactory
+{
+ std::unique_ptr<DataChef> create(const Arguments &args) const;
+};
+
struct GaussianUint8DataChefFactory : public DataChefFactory
{
std::unique_ptr<DataChef> create(const Arguments &args) const;
};
+struct GaussianFloat16DataChefFactory : public DataChefFactory
+{
+ std::unique_ptr<DataChef> create(const Arguments &args) const;
+};
+
+struct GaussianInt8DataChefFactory : public DataChefFactory
+{
+ std::unique_ptr<DataChef> create(const Arguments &args) const;
+};
+
} // namespace souschef
#endif // __SOUSCHEF_DATA_GAUSSIAN_H__
diff --git a/compiler/souschef/include/souschef/DataChef.def b/compiler/souschef/include/souschef/DataChef.def
deleted file mode 100644
index 28901db18..000000000
--- a/compiler/souschef/include/souschef/DataChef.def
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef DATA_CHEF
-#error "Define DATA_CHEF first"
-#endif // DATA_CHEF
-
-// DATA_CHEF(TYPE, NAME, FACTORY_CLASS)
-// "TYPE" SHOULD BE an enum tag of tflchef::TensorType
-DATA_CHEF(FLOAT32, constant, ConstantDataChefFactory<float>)
-DATA_CHEF(BOOL, constant, ConstantDataChefFactory<bool>)
-DATA_CHEF(UINT8, constant, ConstantDataChefFactory<uint8_t>)
-DATA_CHEF(INT32, constant, ConstantDataChefFactory<int32_t>)
-DATA_CHEF(INT64, constant, ConstantDataChefFactory<int64_t>)
-DATA_CHEF(INT64, explicit, ExplicitDataChefFactory<int64_t>)
-DATA_CHEF(INT32, explicit, ExplicitDataChefFactory<int32_t>)
-DATA_CHEF(UINT8, explicit, ExplicitDataChefFactory<uint8_t>)
-DATA_CHEF(BOOL, explicit, ExplicitDataChefFactory<bool>)
-DATA_CHEF(FLOAT32, explicit, ExplicitDataChefFactory<float>)
-DATA_CHEF(FLOAT32, gaussian, GaussianFloat32DataChefFactory)
-DATA_CHEF(INT32, gaussian, GaussianInt32DataChefFactory)
-DATA_CHEF(UINT8, gaussian, GaussianUint8DataChefFactory)
diff --git a/compiler/souschef/include/souschef/Dims.h b/compiler/souschef/include/souschef/Dims.h
index 52c64dd47..fabbf3f95 100644
--- a/compiler/souschef/include/souschef/Dims.h
+++ b/compiler/souschef/include/souschef/Dims.h
@@ -17,6 +17,7 @@
#ifndef __SOUSCHEF_DIMS_H__
#define __SOUSCHEF_DIMS_H__
+#include <cstdint>
#include <functional>
#include <numeric>
#include <vector>
diff --git a/compiler/souschef/src/Explicit.cpp b/compiler/souschef/src/Explicit.cpp
new file mode 100644
index 000000000..3278ae3c3
--- /dev/null
+++ b/compiler/souschef/src/Explicit.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "souschef/Data/Explicit.h"
+
+#include <string>
+#include <vector>
+
+#include <fp16.h>
+
+namespace souschef
+{
+
+/**
+ * @note This emulates TensorFlow int DynamicBuffer::WriteToBuffer(char** buffer) method
+ * Memory structure:
+ * int32_t count
+ * int32_t offsets[count + 1]
+ * string values[count]
+ * where string is like std::string without ending null byte
+ */
+std::vector<uint8_t> ExplicitDataChef<std::string>::generate(int32_t count) const
+{
+ std::vector<uint8_t> res;
+
+ // write count
+ write_value(res, count);
+
+ // write first item offset
+ int32_t start = sizeof(int32_t) * (count + 2);
+ write_value(res, start);
+
+ // write succeeding items offset (or the end)
+ int32_t offset = start;
+ for (uint32_t n = 0; n < count; ++n)
+ {
+ std::string const value = (n < _values.size()) ? _values.at(n) : std::string{};
+ offset += value.length();
+ write_value(res, offset);
+ }
+
+ for (uint32_t n = 0; n < count; ++n)
+ {
+ std::string const value = (n < _values.size()) ? _values.at(n) : std::string{};
+ const uint8_t *arr = reinterpret_cast<const uint8_t *>(value.c_str());
+
+ for (uint32_t b = 0; b < value.length(); ++b)
+ {
+ res.emplace_back(arr[b]);
+ }
+ }
+
+ return res;
+}
+
+void ExplicitDataChef<std::string>::write_value(std::vector<uint8_t> &res, int32_t value) const
+{
+ const uint8_t *arr = reinterpret_cast<const uint8_t *>(&value);
+
+ for (uint32_t b = 0; b < sizeof(int32_t); ++b)
+ {
+ res.emplace_back(arr[b]);
+ }
+}
+
+std::vector<uint8_t> ExplicitFloat16DataChef::generate(int32_t count) const
+{
+ std::vector<uint8_t> res;
+
+ for (uint32_t n = 0; n < count; ++n)
+ {
+ float const fvalue = (n < _values.size()) ? _values.at(n) : 0.0;
+ uint16_t const value = fp16_ieee_from_fp32_value(fvalue);
+ auto const arr = reinterpret_cast<const uint8_t *>(&value);
+
+ for (uint32_t b = 0; b < sizeof(uint16_t); ++b)
+ {
+ res.emplace_back(arr[b]);
+ }
+ }
+
+ return res;
+}
+
+} // namespace souschef
diff --git a/compiler/souschef/src/Gaussian.cpp b/compiler/souschef/src/Gaussian.cpp
index 4a5083d8e..71ab56792 100644
--- a/compiler/souschef/src/Gaussian.cpp
+++ b/compiler/souschef/src/Gaussian.cpp
@@ -22,26 +22,32 @@
#include <cassert>
#include <stdexcept>
+#include <limits> // std::numeric_limits
+
+#include <fp16.h>
namespace souschef
{
-std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const
+template <typename T>
+static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev,
+ std::minstd_rand::result_type seed)
{
- // TODO Support seed value override
- auto seed = std::chrono::system_clock::now().time_since_epoch().count();
-
std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
- std::normal_distribution<float> dist{_mean, _stddev};
+ std::normal_distribution<float> dist{mean, stddev};
std::vector<uint8_t> res;
+ constexpr float max_cap = std::numeric_limits<T>::max();
+ constexpr float min_cap = std::numeric_limits<T>::lowest();
for (uint32_t n = 0; n < count; ++n)
{
- auto const value = dist(rand);
+ float raw_value = dist(rand);
+ const float capped_value = std::max(min_cap, std::min(max_cap, raw_value));
+ auto const value = static_cast<T>(capped_value);
auto const arr = reinterpret_cast<const uint8_t *>(&value);
- for (uint32_t b = 0; b < sizeof(float); ++b)
+ for (uint32_t b = 0; b < sizeof(T); ++b)
{
res.emplace_back(arr[b]);
}
@@ -50,22 +56,42 @@ std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const
return res;
}
-std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const
+template <typename T>
+static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev)
{
- // TODO Support seed value override
- auto seed = std::chrono::system_clock::now().time_since_epoch().count();
+ auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count();
+
+ // Note this is implementation defined, change if needed.
+ auto seed = static_cast<std::minstd_rand::result_type>(time_stamp);
+
+ return generate_gaussian<T>(count, mean, stddev, seed);
+}
+
+std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const
+{
+ return generate_gaussian<float>(count, _mean, _stddev);
+}
+
+std::vector<uint8_t> GaussianFloat16DataChef::generate(int32_t count) const
+{
+ auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count();
+ auto seed = static_cast<std::minstd_rand::result_type>(time_stamp);
std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
std::normal_distribution<float> dist{_mean, _stddev};
std::vector<uint8_t> res;
+ constexpr float max_cap = 1e9;
+ constexpr float min_cap = -1e9;
for (uint32_t n = 0; n < count; ++n)
{
- auto const value = static_cast<int32_t>(dist(rand));
+ float raw_value = dist(rand);
+ const float capped_value = std::max(min_cap, std::min(max_cap, raw_value));
+ const uint16_t value = fp16_ieee_from_fp32_value(capped_value);
auto const arr = reinterpret_cast<const uint8_t *>(&value);
- for (uint32_t b = 0; b < sizeof(int32_t); ++b)
+ for (uint32_t b = 0; b < sizeof(uint16_t); ++b)
{
res.emplace_back(arr[b]);
}
@@ -74,28 +100,24 @@ std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const
return res;
}
-std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const
+std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const
{
- // TODO Support seed value override
- auto seed = std::chrono::system_clock::now().time_since_epoch().count();
-
- std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
- std::normal_distribution<float> dist{_mean, _stddev};
-
- std::vector<uint8_t> res;
+ return generate_gaussian<int32_t>(count, _mean, _stddev);
+}
- for (uint32_t n = 0; n < count; ++n)
- {
- auto const value = static_cast<uint8_t>(dist(rand)); // uint8_t for data type
- auto const arr = reinterpret_cast<const uint8_t *>(&value); // uint8_t for byte streaming
+std::vector<uint8_t> GaussianInt16DataChef::generate(int32_t count) const
+{
+ return generate_gaussian<int16_t>(count, _mean, _stddev);
+}
- for (uint32_t b = 0; b < sizeof(uint8_t); ++b)
- {
- res.emplace_back(arr[b]);
- }
- }
+std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const
+{
+ return generate_gaussian<uint8_t>(count, _mean, _stddev);
+}
- return res;
+std::vector<uint8_t> GaussianInt8DataChef::generate(int32_t count) const
+{
+ return generate_gaussian<int8_t>(count, _mean, _stddev);
}
std::unique_ptr<DataChef> GaussianFloat32DataChefFactory::create(const Arguments &args) const
@@ -124,6 +146,19 @@ std::unique_ptr<DataChef> GaussianInt32DataChefFactory::create(const Arguments &
return std::unique_ptr<DataChef>{new GaussianInt32DataChef{mean, stddev}};
}
+std::unique_ptr<DataChef> GaussianInt16DataChefFactory::create(const Arguments &args) const
+{
+ if (args.count() != 2)
+ {
+ throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
+ }
+
+ auto const mean = to_number<float>(args.value(0));
+ auto const stddev = to_number<float>(args.value(1));
+
+ return std::unique_ptr<DataChef>{new GaussianInt16DataChef{mean, stddev}};
+}
+
std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments &args) const
{
if (args.count() != 2)
@@ -137,4 +172,30 @@ std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments &
return std::unique_ptr<DataChef>{new GaussianUint8DataChef{mean, stddev}};
}
+std::unique_ptr<DataChef> GaussianInt8DataChefFactory::create(const Arguments &args) const
+{
+ if (args.count() != 2)
+ {
+ throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
+ }
+
+ auto const mean = to_number<float>(args.value(0));
+ auto const stddev = to_number<float>(args.value(1));
+
+ return std::unique_ptr<DataChef>{new GaussianInt8DataChef{mean, stddev}};
+}
+
+std::unique_ptr<DataChef> GaussianFloat16DataChefFactory::create(const Arguments &args) const
+{
+ if (args.count() != 2)
+ {
+ throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
+ }
+
+ auto const mean = to_number<float>(args.value(0));
+ auto const stddev = to_number<float>(args.value(1));
+
+ return std::unique_ptr<DataChef>{new GaussianFloat16DataChef{mean, stddev}};
+}
+
} // namespace souschef
diff --git a/compiler/souschef/src/LexicalCast.cpp b/compiler/souschef/src/LexicalCast.cpp
index 8e3d4cbbb..4468f1ec1 100644
--- a/compiler/souschef/src/LexicalCast.cpp
+++ b/compiler/souschef/src/LexicalCast.cpp
@@ -18,12 +18,25 @@
#include <cassert>
#include <limits>
+#include <stdexcept>
namespace souschef
{
template <> float to_number(const std::string &s) { return std::stof(s); }
template <> int to_number(const std::string &s) { return std::stoi(s); }
+template <> int16_t to_number(const std::string &s)
+{
+ // There are no standard function to parse int16_t or short int
+ // This function simulates behavior similar stoi, stol and stoll
+ int res = std::stol(s);
+ // standard does not specify string in error message, this is arbitrary
+ if (res < std::numeric_limits<int16_t>::min() || res > std::numeric_limits<int16_t>::max())
+ {
+ throw std::out_of_range("to_number<int16_t>");
+ }
+ return res;
+}
template <> int64_t to_number(const std::string &s) { return std::stoll(s); }
template <> uint8_t to_number(const std::string &s)
{
@@ -32,11 +45,21 @@ template <> uint8_t to_number(const std::string &s)
assert(temp <= std::numeric_limits<uint8_t>::max());
return static_cast<uint8_t>(temp);
}
+template <> int8_t to_number(const std::string &s)
+{
+ int temp = std::stoi(s);
+ assert(temp >= std::numeric_limits<int8_t>::min());
+ assert(temp <= std::numeric_limits<int8_t>::max());
+ return static_cast<int8_t>(temp);
+}
template <> bool to_number(const std::string &s)
{
- if (std::stoi(s) || s == "T" || s == "t" || s == "TRUE" || s == "true")
+ if (s == "T" || s == "t" || s == "TRUE" || s == "true" || s == "1")
return true;
- return false;
+ if (s == "F" || s == "f" || s == "FALSE" || s == "false" || s == "0")
+ return false;
+ throw std::invalid_argument("Unsupported boolean argument");
}
+template <> std::string to_number(const std::string &s) { return s; }
} // namespace souschef