Skip to content

Commit

Permalink
[record-minmax] Introduce RandomIterator (#14259)
Browse files Browse the repository at this point in the history
* [record-minmax] Introduce RandomIterator

This introduces an iterator for random data.

ONE-DCO-1.0-Signed-off-by: Hyukjin Jeong <[email protected]>

* Update CMakeLists.txt
  • Loading branch information
jinevening authored Oct 28, 2024
1 parent 067baf8 commit b443c68
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 0 deletions.
1 change: 1 addition & 0 deletions compiler/record-minmax/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ endif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" AND FALSE)
# record-minmax is executable, so we do not link it to the test.
# Instead, we use TEST_SOURCES to specify sources uesd for tests.
set(TEST_SOURCES
"src/Utils.cpp"
"src/RecordFunction.cpp"
"src/MinMaxComputer.cpp")

Expand Down
52 changes: 52 additions & 0 deletions compiler/record-minmax/include/RandomIterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2024 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.
*/

#ifndef __RECORD_MINMAX_RANDOM_ITERATOR_H__
#define __RECORD_MINMAX_RANDOM_ITERATOR_H__

#include "DataBuffer.h"
#include "DataSetIterator.h"

#include <luci/IR/Module.h>
#include <luci/IR/CircleNodes.h>

#include <random>
#include <vector>

namespace record_minmax
{

class RandomIterator final : public DataSetIterator
{
public:
RandomIterator(luci::Module *module);

bool hasNext() const override;

std::vector<DataBuffer> next() override;

bool check_type_shape() const override;

private:
std::mt19937 _gen;
std::vector<const luci::CircleInput *> _input_nodes;
uint32_t _curr_idx = 0;
uint32_t _num_data = 0;
};

} // namespace record_minmax

#endif // __RECORD_MINMAX_RANDOM_ITERATOR_H__
36 changes: 36 additions & 0 deletions compiler/record-minmax/include/Utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 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.
*/

#ifndef __RECORD_MINMAX_UTILS_H__
#define __RECORD_MINMAX_UTILS_H__

#include <luci/IR/CircleNodes.h>

#include <vector>
#include <string>

namespace record_minmax
{

// Return total number of elements of the node's output tensor
uint32_t numElements(const luci::CircleNode *node);

// Return the node's output tensor size in bytes
size_t getTensorSize(const luci::CircleNode *node);

} // namespace record_minmax

#endif // __RECORD_MINMAX_UTILS_H__
145 changes: 145 additions & 0 deletions compiler/record-minmax/src/RandomIterator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2024 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 "RandomIterator.h"
#include "DataBuffer.h"
#include "Utils.h"

#include <luci/IR/Module.h>
#include <luci/IR/CircleNodes.h>

#include <vector>
#include <cstring>

namespace
{

std::vector<float> genRandomData(std::mt19937 &gen, uint32_t num_elements, float min, float max)
{
std::uniform_real_distribution<float> dist(min, max);
std::vector<float> input_data(num_elements);

// Write random data
{
auto const generator = [&gen, &dist]() { return static_cast<float>(dist(gen)); };
std::generate(begin(input_data), end(input_data), generator);
}

return input_data;
}

template <typename T>
std::vector<T> genRandomIntData(std::mt19937 &gen, uint32_t num_elements, T min, T max)
{
std::uniform_int_distribution<T> dist(min, max);
std::vector<T> input_data(num_elements);

// Write random data
{
auto const generator = [&gen, &dist]() { return dist(gen); };
std::generate(begin(input_data), end(input_data), generator);
}

return input_data;
}

} // namespace

namespace record_minmax
{

RandomIterator::RandomIterator(luci::Module *module)
{
assert(module); // FIX_CALLER_UNLESS

std::random_device rd;
std::mt19937 _gen(rd());

auto input_nodes = loco::input_nodes(module->graph());
for (auto input_node : input_nodes)
{
const auto cnode = loco::must_cast<const luci::CircleInput *>(input_node);
_input_nodes.emplace_back(cnode);
}

// Hardcoded
_num_data = 3;
}

bool RandomIterator::hasNext() const { return _curr_idx < _num_data; }

std::vector<DataBuffer> RandomIterator::next()
{
std::vector<DataBuffer> res;

for (auto input_node : _input_nodes)
{
DataBuffer buf;

const auto dtype = input_node->dtype();
const auto num_elements = numElements(input_node);

buf.data.resize(getTensorSize(input_node));

switch (dtype)
{
case loco::DataType::FLOAT32:
{
const auto input_data = genRandomData(_gen, num_elements, -5, 5);
const auto data_size = input_data.size() * sizeof(float);
assert(buf.data.size() == data_size);
memcpy(buf.data.data(), input_data.data(), data_size);
break;
}
case loco::DataType::S32:
{
const auto input_data = genRandomIntData<int32_t>(_gen, num_elements, 0, 100);
const auto data_size = input_data.size() * sizeof(int32_t);
assert(buf.data.size() == data_size);
memcpy(buf.data.data(), input_data.data(), data_size);
break;
}
case loco::DataType::S64:
{
const auto input_data = genRandomIntData<int64_t>(_gen, num_elements, 0, 100);
const auto data_size = input_data.size() * sizeof(int64_t);
assert(buf.data.size() == data_size);
memcpy(buf.data.data(), input_data.data(), data_size);
break;
}
case loco::DataType::BOOL:
{
const auto input_data = genRandomIntData<uint8_t>(_gen, num_elements, 0, 1);
const auto data_size = input_data.size() * sizeof(uint8_t);
assert(buf.data.size() == data_size);
memcpy(buf.data.data(), input_data.data(), data_size);
break;
}
default:
throw std::runtime_error("Unsupported datatype");
}

res.emplace_back(buf);
}

_curr_idx++; // move to the next index

return res;
}

bool RandomIterator::check_type_shape() const { return false; }

} // namespace record_minmax
49 changes: 49 additions & 0 deletions compiler/record-minmax/src/Utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 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 "Utils.h"

#include <luci/IR/CircleNodes.h>
#include <luci/IR/DataTypeHelper.h>

namespace record_minmax
{

uint32_t numElements(const luci::CircleNode *node)
{
assert(node); // FIX_CALLER_UNLESS

uint32_t num_elements = 1;
for (uint32_t i = 0; i < node->rank(); i++)
{
if (not node->dim(i).known())
throw std::runtime_error("Unknown dimension found in " + node->name());

num_elements *= node->dim(i).value();
}

return num_elements;
}

size_t getTensorSize(const luci::CircleNode *node)
{
assert(node); // FIX_CALLER_UNLESS

uint32_t elem_size = luci::size(node->dtype());
return numElements(node) * elem_size;
}

} // namespace record_minmax
75 changes: 75 additions & 0 deletions compiler/record-minmax/tests/Utils.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 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 "Utils.h"

#include <luci/IR/CircleNodes.h>

#include <gtest/gtest.h>

using namespace record_minmax;

TEST(UtilsTest, num_elements)
{
luci::CircleAdd node;
node.rank(3);
node.dim(0).set(1);
node.dim(1).set(2);
node.dim(2).set(3);
node.dtype(loco::DataType::FLOAT32);

EXPECT_EQ(6, numElements(&node));
}

TEST(UtilsTest, num_elements_NEG)
{
luci::CircleAdd node;
node.rank(3);
node.dim(0).set(1);
node.dim(1).set(2);
node.dim(2).set(3);
node.dtype(loco::DataType::FLOAT32);

node.dim(0).unset();

EXPECT_ANY_THROW(numElements(&node));
}

TEST(UtilsTest, get_tensor_size)
{
luci::CircleAdd node;
node.rank(3);
node.dim(0).set(1);
node.dim(1).set(2);
node.dim(2).set(3);
node.dtype(loco::DataType::FLOAT32);

EXPECT_EQ(24, getTensorSize(&node));
}

TEST(UtilsTest, get_tensor_size_NEG)
{
luci::CircleAdd node;
node.rank(3);
node.dim(0).set(1);
node.dim(1).set(2);
node.dim(2).set(3);
node.dtype(loco::DataType::FLOAT32);

node.dim(0).unset();

EXPECT_ANY_THROW(getTensorSize(&node));
}

0 comments on commit b443c68

Please sign in to comment.