Skip to content
Snippets Groups Projects

Scheduler backprop

Merged Maxence Naud requested to merge scheduler_backprop into dev
7 files
+ 81
70
Compare changes
  • Side-by-side
  • Inline
Files
7
+ 192
0
 
/********************************************************************************
 
* Copyright (c) 2023 CEA-List
 
*
 
* This program and the accompanying materials are made available under the
 
* terms of the Eclipse Public License 2.0 which is available at
 
* http://www.eclipse.org/legal/epl-2.0.
 
*
 
* SPDX-License-Identifier: EPL-2.0
 
*
 
********************************************************************************/
 
 
#include <catch2/catch_test_macros.hpp>
 
#include <cstddef> // std::size_t
 
#include <cstdint> // std::uint16_t
 
#include <chrono>
 
#include <iostream>
 
#include <memory>
 
#include <numeric> // std::accumulate
 
#include <random> // std::random_device, std::mt19937, std::uniform_real_distribution
 
 
#include "aidge/data/Tensor.hpp"
 
#include "aidge/backend/cpu/data/TensorImpl.hpp"
 
#include "aidge/operator/Add.hpp"
 
#include "aidge/backend/cpu/operator/AddImpl.hpp"
 
 
namespace Aidge {
 
 
TEST_CASE("Test addition of Tensors","[TensorImpl][Add]") {
 
constexpr std::uint16_t NBTRIALS = 10;
 
// Create a random number generator
 
std::random_device rd;
 
std::mt19937 gen(rd());
 
std::uniform_real_distribution<float> valueDist(0.1f, 1.1f); // Random float distribution between 0 and 1
 
std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), std::size_t(10));
 
std::uniform_int_distribution<int> boolDist(0,1);
 
 
// Create MatMul Operator
 
std::shared_ptr<Node> mySub = Add(2);
 
auto op = std::static_pointer_cast<OperatorTensor>(mySub-> getOperator());
 
op->setDataType(DataType::Float32);
 
op->setBackend("cpu");
 
 
// Create 2 input Tensors
 
std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>();
 
op->associateInput(0,T0);
 
T0->setDataType(DataType::Float32);
 
T0->setBackend("cpu");
 
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>();
 
op -> associateInput(1,T1);
 
T1->setDataType(DataType::Float32);
 
T1->setBackend("cpu");
 
 
// Create results Tensor
 
Tensor Tres{};
 
Tres.setDataType(DataType::Float32);
 
Tres.setBackend("cpu");
 
 
// To measure execution time of 'MatMul_Op::forward()' member function call
 
std::chrono::time_point<std::chrono::system_clock> start;
 
std::chrono::time_point<std::chrono::system_clock> end;
 
std::chrono::duration<double, std::micro> duration{};
 
 
std::size_t number_of_operation = 0;
 
 
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
 
// generate 2 random Tensors
 
// handle dimensions, replace some dimensions with '1' to get broadcasting
 
constexpr std::size_t nbDims = 4;
 
std::vector<std::size_t> dims;
 
for (std::size_t i = 0; i < nbDims; ++i) {
 
dims.push_back(dimSizeDist(gen));
 
}
 
std::vector<std::size_t> dims0 = dims;
 
std::vector<std::size_t> dims1 = dims;
 
std::vector<std::size_t> dimsOut = dims;
 
for (std::size_t i = 0; i < nbDims; ++i) {
 
if (boolDist(gen)) {
 
dims0[i] = 1;
 
}
 
if (boolDist(gen)) {
 
dims1[i] = 1;
 
}
 
dimsOut[i] = (dims0[i] == 1) ? dims1[i] : dims0[i];
 
}
 
 
// create arrays and fill them with random values
 
float* array0 = new float[dims0[0]*dims0[1]*dims0[2]*dims0[3]];
 
float* array1 = new float[dims1[0]*dims1[1]*dims1[2]*dims1[3]];
 
float* result = new float[dimsOut[0]*dimsOut[1]*dimsOut[2]*dimsOut[3]];
 
 
for (std::size_t i = 0; i < dims0[0]*dims0[1]*dims0[2]*dims0[3]; ++i) {
 
array0[i] = valueDist(gen);
 
}
 
for (std::size_t i = 0; i < dims1[0]*dims1[1]*dims1[2]*dims1[3]; ++i) {
 
array1[i] = valueDist(gen);
 
}
 
 
// compute true result
 
const std::size_t strides0[nbDims] = {dims0[1]*dims0[2]*dims0[3], dims0[2]*dims0[3], dims0[3], 1};
 
const std::size_t strides1[nbDims] = {dims1[1]*dims1[2]*dims1[3], dims1[2]*dims1[3], dims1[3], 1};
 
for (std::size_t a = 0; a < dimsOut[0]; ++a) {
 
for (std::size_t b = 0; b < dimsOut[1]; ++b) {
 
const std::size_t idx0_0 = strides0[0] * ((dims0[0] > 1) ? a : 0)
 
+ strides0[1] * ((dims0[1] > 1) ? b : 0);
 
const std::size_t idx1_0 = strides1[0] * ((dims1[0] > 1) ? a : 0)
 
+ strides1[1] * ((dims1[1] > 1) ? b : 0);
 
for (std::size_t c = 0; c < dimsOut[2]; ++c) {
 
const std::size_t idx_out = dimsOut[3] * (c + dimsOut[2] * (b + dimsOut[1] * a));
 
for (std::size_t d = 0; d < dimsOut[3]; ++d) {
 
std::size_t idx0 = idx0_0
 
+ strides0[2] * ((dims0[2] > 1) ? c : 0)
 
+ ((dims0[3] > 1) ? d : 0);
 
std::size_t idx1 = idx1_0
 
+ strides1[2] * ((dims1[2] > 1) ? c : 0)
 
+ ((dims1[3] > 1) ? d : 0);
 
result[idx_out + d] = array0[idx0] + array1[idx1];
 
// std::cout << "(" << idx0 << ", " << idx1 << ") -> " << array0[idx0] << " - " << array1[idx1] << " -> " << idx_out + d << std::endl;
 
}
 
}
 
}
 
}
 
 
// conversion to Aidge::Tensors
 
// input0
 
T0->resize(dims0);
 
T0->getImpl() -> setRawPtr(array0, dims0[0]*dims0[1]*dims0[2]*dims0[3]);
 
 
// input1
 
T1->resize(dims1);
 
T1->getImpl() -> setRawPtr(array1, dims1[0]*dims1[1]*dims1[2]*dims1[3]);
 
 
// results
 
Tres.resize(dimsOut);
 
Tres.getImpl() -> setRawPtr(result, dimsOut[0]*dimsOut[1]*dimsOut[2]*dimsOut[3]);
 
 
Tensor T2 = *T0 + *T1;
 
REQUIRE(T2 == Tres);
 
 
// no implementation
 
Tensor T3(T1->dims());
 
REQUIRE_THROWS(*T0 + T3);
 
 
// // wrong backend
 
// static Registrar<Add_Op> registrarAddImpl_custom("custom", [](const Add_Op& op) { return std::make_unique<AddImpl_cpu>(op); } );
 
// static Registrar<Tensor> registrarTensorImpl_custom_Int32({"custom", DataType::Int32},
 
// [] (DeviceIdx_t device, std::vector<DimSize_t> dims) {
 
// return std::make_shared<TensorImpl_cpu<int>>(device, dims);
 
// }
 
// );
 
// T1.setBackend("custom");
 
// REQUIRE_THROWS(T0 + T1);
 
 
// wrong datatype
 
Tensor T4(T1->dims());
 
T4.setDataType(DataType::Float64);
 
REQUIRE_THROWS(*T0 + T4);
 
}
 
}
 
 
TEST_CASE("Test substraction of Tensors","[TensorImpl][Sub]") {
 
Tensor T0 = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
 
Tensor T1 = Array3D<int, 2, 2, 2>{{{{7, 1}, {3, 7}}, {{54, 0}, {7, 12}}}};
 
Tensor T2 = T0 - T1;
 
T2.print();
 
REQUIRE(T2 == Tensor(Array3D<int, 2, 2, 2>{{{{-6,1},{0,-3}},{{-49,6},{0,-4}}}}));
 
 
Tensor T3(T1.dims());
 
REQUIRE_THROWS(T0 - T3);
 
}
 
 
TEST_CASE("Test multiplication of Tensors","[TensorImpl][Mul]") {
 
Tensor T0 = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
 
Tensor T1 = Array3D<int, 2, 2, 2>{{{{7, 2}, {3, 7}}, {{5, 6}, {7, 8}}}};
 
Tensor T2 = T0 * T1;
 
T2.print();
 
REQUIRE(T2 == Tensor(Array3D<int, 2, 2, 2>{{{{7,4},{9,28}},{{25,36},{49,64}}}}));
 
 
Tensor T3(T1.dims());
 
REQUIRE_THROWS(T0 * T3);
 
}
 
 
TEST_CASE("Test division of Tensors","[TensorImpl][Div]") {
 
Tensor T0 = Array3D<int, 2, 2, 2>{{{{7,4},{9,28}},{{25,36},{49,64}}}};
 
Tensor T1 = Array3D<int, 2, 2, 2>{{{{7, 2}, {3, 7}}, {{5, 6}, {7, 8}}}};
 
Tensor T2 = T0 / T1;
 
T2.print();
 
REQUIRE(T2 == Tensor(Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}}));
 
 
Tensor T3(T1.dims());
 
REQUIRE_THROWS(T0 / T3);
 
}
 
} // namespace Aidge
Loading