diff --git a/include/aidge/aidge.hpp b/include/aidge/aidge.hpp index 9c516575690fbca947496920c7068874bda6bf63..84d77e9f1370977e899331bad27f2ade4b2178f3 100644 --- a/include/aidge/aidge.hpp +++ b/include/aidge/aidge.hpp @@ -64,6 +64,7 @@ #include "aidge/stimuli/Stimulus.hpp" #include "aidge/recipes/Recipes.hpp" +#include "aidge/filler/Filler.hpp" #include "aidge/utils/Attributes.hpp" #include "aidge/utils/StaticAttributes.hpp" diff --git a/include/aidge/filler/Filler.hpp b/include/aidge/filler/Filler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51d01d87f338d1c8eb33b7b3ec6194390bfe13bf --- /dev/null +++ b/include/aidge/filler/Filler.hpp @@ -0,0 +1,63 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#ifndef AIDGE_CORE_FILLER_H_ +#define AIDGE_CORE_FILLER_H_ + +#include <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/data/Tensor.hpp" + +namespace Aidge { + +inline void calculateFanInFanOut(std::shared_ptr<Tensor> tensor, + unsigned int& fanIn, unsigned int& fanOut) { + AIDGE_ASSERT( + tensor->nbDims() == 4, + "Tensor need to have 4 dimensions to compute FanIn and FanOut."); + // Warning: This function suppose NCXX data layout. + // Aidge currently only support NCHW but this maybe not be true in the + // future. + DimSize_t batchSize = tensor->dims()[0]; + DimSize_t channelSize = tensor->dims()[1]; + AIDGE_ASSERT(batchSize != 0, + "Cannot calculate FanIn if tensor batch size is 0."); + AIDGE_ASSERT(channelSize != 0, + "Cannot calculate FanOut if tensor channel size is 0."); + fanIn = static_cast<unsigned int>(tensor->size() / batchSize); + fanOut = static_cast<unsigned int>(tensor->size() / channelSize); +} +enum VarianceNorm { FanIn, Average, FanOut }; + +template <typename T> +void constantFiller(std::shared_ptr<Tensor> tensor, T constantValue); + +template <typename T> +void normalFiller(std::shared_ptr<Tensor> tensor, double mean = 0.0, + double stdDev = 1.0); + +template <typename T> +void uniformFiller(std::shared_ptr<Tensor> tensor, T min, T max); + +template <typename T> +void xavierUniformFiller(std::shared_ptr<Tensor> tensor, T scaling = 1.0, + VarianceNorm varianceNorm = FanIn); +template <typename T> +void xavierNormalFiller(std::shared_ptr<Tensor> tensor, T scaling = 1.0, + VarianceNorm varianceNorm = FanIn); + +template <typename T> +void heFiller(std::shared_ptr<Tensor> tensor, VarianceNorm varianceNorm = FanIn, + T meanNorm = 0.0, T scaling = 1.0); +} // namespace Aidge + +#endif /* AIDGE_CORE_FILLER_H_ */ diff --git a/include/aidge/utils/Random.hpp b/include/aidge/utils/Random.hpp index 704609c0c778c7065a580b86fc67aea7e9d3525d..73cbd1453b3d840d6da2c58eadd5c5f47e9e9070 100644 --- a/include/aidge/utils/Random.hpp +++ b/include/aidge/utils/Random.hpp @@ -9,23 +9,53 @@ * ********************************************************************************/ - #ifndef AIDGE_RANDOM_H_ #define AIDGE_RANDOM_H_ - #include <algorithm> -#include <vector> #include <random> +#include <vector> +namespace Aidge { namespace Random { - void randShuffle(std::vector<unsigned int>& vec) { - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(vec.begin(), vec.end(), g); - } - +/** + * @brief Generator is a class created to handle only one Mersenne Twister + * pseudo-random number generator for the whole Aidge framework. + * + * All of its method are static. You can set a random seed and access the + * generator. + * By default, the random seed is set to 0 but selected randomly. + * + */ +class Generator { + public: + /** + * @brief Set a seed to the pseudo-random number generator. + * + * @return std::mt19937& + */ + static void setSeed(unsigned int seed); + static unsigned int getSeed() { return seed; }; + /** + * @brief Return a Mersenne Twister pseudo-random number generator. + * You can set the seed of this generator using ``setSeed`` method. + * + * @return std::mt19937& + */ + static std::mt19937& get() { return generator; }; + + private: + // Mersenne Twister pseudo-random number generator + static std::mt19937 generator; + static unsigned int seed; +}; + +inline void randShuffle(std::vector<unsigned int>& vec) { + std::shuffle(vec.begin(), vec.end(), Aidge::Random::Generator::get()); } -#endif //AIDGE_RANDOM_H_ \ No newline at end of file +} // namespace Random +} // namespace Aidge + +#endif // AIDGE_RANDOM_H_ diff --git a/python_binding/filler/pybind_Filler.cpp b/python_binding/filler/pybind_Filler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a85c0d6cd6fa0367dfc26328d214c99a4288a3be --- /dev/null +++ b/python_binding/filler/pybind_Filler.cpp @@ -0,0 +1,147 @@ +/******************************************************************************** + * 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 <pybind11/pybind11.h> + +#include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" + +namespace py = pybind11; + +namespace Aidge { + +void init_Filler(py::module &m) { + py::enum_<enum VarianceNorm>(m, "VarianceNorm") + .value("FanIn", VarianceNorm::FanIn) + .value("Average", VarianceNorm::Average) + .value("FanOut", VarianceNorm::FanOut) + .export_values(); + + m.def( + "constant_filler", + [](std::shared_ptr<Tensor> tensor, py::object value) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + constantFiller<double>(tensor, value.cast<double>()); + break; + case DataType::Float32: + constantFiller<float>(tensor, value.cast<float>()); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Constant filler."); + } + }, + py::arg("tensor"), py::arg("value")) + .def( + "normal_filler", + [](std::shared_ptr<Tensor> tensor, double mean, + double stdDev) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + normalFiller<double>(tensor, mean, stdDev); + break; + case DataType::Float32: + normalFiller<float>(tensor, mean, stdDev); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Normal filler."); + } + }, + py::arg("tensor"), py::arg("mean") = 0.0, py::arg("stdDev") = 1.0) + .def( + "uniform_filler", + [](std::shared_ptr<Tensor> tensor, double min, double max) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + uniformFiller<double>(tensor, min, max); + break; + case DataType::Float32: + uniformFiller<float>(tensor, min, max); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Uniform filler."); + } + }, + py::arg("tensor"), py::arg("min"), py::arg("max")) + .def( + "xavier_uniform_filler", + [](std::shared_ptr<Tensor> tensor, py::object scaling, + VarianceNorm varianceNorm) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + xavierUniformFiller<double>( + tensor, scaling.cast<double>(), varianceNorm); + break; + case DataType::Float32: + xavierUniformFiller<float>( + tensor, scaling.cast<float>(), varianceNorm); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Uniform filler."); + } + }, + py::arg("tensor"), py::arg("scaling") = 1.0, + py::arg("varianceNorm") = VarianceNorm::FanIn) + .def( + "xavier_normal_filler", + [](std::shared_ptr<Tensor> tensor, py::object scaling, + VarianceNorm varianceNorm) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + xavierNormalFiller<double>( + tensor, scaling.cast<double>(), varianceNorm); + break; + case DataType::Float32: + xavierNormalFiller<float>(tensor, scaling.cast<float>(), + varianceNorm); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Uniform filler."); + } + }, + py::arg("tensor"), py::arg("scaling") = 1.0, + py::arg("varianceNorm") = VarianceNorm::FanIn) + .def( + "he_filler", + [](std::shared_ptr<Tensor> tensor, VarianceNorm varianceNorm, + py::object meanNorm, py::object scaling) -> void { + switch (tensor->dataType()) { + case DataType::Float64: + heFiller<double>(tensor, varianceNorm, + meanNorm.cast<double>(), + scaling.cast<double>()); + break; + case DataType::Float32: + heFiller<float>(tensor, varianceNorm, + meanNorm.cast<float>(), + scaling.cast<float>()); + break; + default: + AIDGE_THROW_OR_ABORT( + py::value_error, + "Data type is not supported for Uniform filler."); + } + }, + py::arg("tensor"), py::arg("varianceNorm") = VarianceNorm::FanIn, + py::arg("meanNorm") = 0.0, py::arg("scaling") = 1.0) + ; +} +} // namespace Aidge diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp index 52863735ca431e797fab3426d7e61796a8725dd2..5ffa8f6b460b720581fb8196d45ad84e1ef350f2 100644 --- a/python_binding/pybind_core.cpp +++ b/python_binding/pybind_core.cpp @@ -11,12 +11,12 @@ #include <pybind11/pybind11.h> -#include "aidge/backend/cpu/data/TensorImpl.hpp" // This include add Tensor - +#include "aidge/backend/cpu/data/TensorImpl.hpp" // This include add Tensor namespace py = pybind11; namespace Aidge { +void init_Random(py::module&); void init_Data(py::module&); void init_Database(py::module&); void init_DataProvider(py::module&); @@ -71,9 +71,11 @@ void init_Recipes(py::module&); void init_Scheduler(py::module&); void init_TensorUtils(py::module&); +void init_Filler(py::module&); +void init_Aidge(py::module& m) { + init_Random(m); -void init_Aidge(py::module& m){ init_Data(m); init_Database(m); init_DataProvider(m); @@ -129,9 +131,8 @@ void init_Aidge(py::module& m){ init_Recipes(m); init_Scheduler(m); init_TensorUtils(m); + init_Filler(m); } -PYBIND11_MODULE(aidge_core, m) { - init_Aidge(m); -} -} +PYBIND11_MODULE(aidge_core, m) { init_Aidge(m); } +} // namespace Aidge diff --git a/python_binding/utils/pybind_Random.cpp b/python_binding/utils/pybind_Random.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1956d2d1e398cdb81673e7760a92bcde46e2de6 --- /dev/null +++ b/python_binding/utils/pybind_Random.cpp @@ -0,0 +1,24 @@ +/******************************************************************************** + * 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 <pybind11/pybind11.h> +#include "aidge/utils/Random.hpp" + +namespace py = pybind11; + +namespace Aidge { + +void init_Random(py::module &m) { + auto mRand = m.def_submodule("random", "Random module."); + py::class_<Random::Generator>(mRand, "Generator") + .def_static("set_seed", Random::Generator::setSeed); +} +} // namespace Aidge diff --git a/src/data/DataProvider.cpp b/src/data/DataProvider.cpp index 7783ed86cf4ae1d8672cc6a35a97ca9a996457b6..5c3d1d7ef3b3dd8c779cf9cda737f1a2b2f6e01f 100644 --- a/src/data/DataProvider.cpp +++ b/src/data/DataProvider.cpp @@ -41,8 +41,8 @@ Aidge::DataProvider::DataProvider(const Aidge::Database& database, const std::si } // Compute the number of bacthes depending on mDropLast boolean - mNbBatch = (mDropLast) ? - static_cast<std::size_t>(std::floor(mNbItems / mBatchSize)) : + mNbBatch = (mDropLast) ? + static_cast<std::size_t>(std::floor(mNbItems / mBatchSize)) : static_cast<std::size_t>(std::ceil(mNbItems / mBatchSize)); } @@ -98,7 +98,7 @@ std::vector<std::shared_ptr<Aidge::Tensor>> Aidge::DataProvider::readBatch() con void Aidge::DataProvider::setBatches(){ - + mBatches.clear(); mBatches.resize(mNbItems); std::iota(mBatches.begin(), @@ -106,7 +106,7 @@ void Aidge::DataProvider::setBatches(){ 0U); if (mShuffle){ - Random::randShuffle(mBatches); + Aidge::Random::randShuffle(mBatches); } if (mNbItems % mBatchSize !=0){ // The last batch is not full diff --git a/src/filler/ConstantFiller.cpp b/src/filler/ConstantFiller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7db5e4d02b2031e7f5cf6a0203e3c7acbd3b93e --- /dev/null +++ b/src/filler/ConstantFiller.cpp @@ -0,0 +1,40 @@ +/******************************************************************************** + * 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 <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/filler/Filler.hpp" +#include "aidge/data/Tensor.hpp" + + +template<typename T> +void Aidge::constantFiller(std::shared_ptr<Aidge::Tensor> tensor, T constantValue){ + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + std::shared_ptr<Aidge::Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Aidge::Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>(idx, constantValue); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} + + +template void Aidge::constantFiller<float>(std::shared_ptr<Aidge::Tensor>, float); +template void Aidge::constantFiller<double>(std::shared_ptr<Aidge::Tensor>, double); diff --git a/src/filler/HeFiller.cpp b/src/filler/HeFiller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74d681f1a05c15045d27a0fe678aa676d16af077 --- /dev/null +++ b/src/filler/HeFiller.cpp @@ -0,0 +1,59 @@ +/******************************************************************************** + * 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 <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" +#include "aidge/utils/Random.hpp" + +template <typename T> +void Aidge::heFiller(std::shared_ptr<Aidge::Tensor> tensor, + Aidge::VarianceNorm varianceNorm, T meanNorm, T scaling) { + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + unsigned int fanIn, fanOut = 0; + Aidge::calculateFanInFanOut(tensor, fanIn, fanOut); + + const T n((varianceNorm == Aidge::VarianceNorm::FanIn) ? fanIn + : (varianceNorm == Aidge::VarianceNorm::Average) + ? (fanIn + fanOut) / 2.0 + : fanOut); + + const T stdDev(std::sqrt(2.0 / n)); + + const T mean(varianceNorm == Aidge::VarianceNorm::FanIn ? meanNorm / fanIn + : (varianceNorm == Aidge::VarianceNorm::Average) + ? meanNorm / ((fanIn + fanOut) / 2.0) + : meanNorm / fanOut); + + std::normal_distribution<T> normalDist(mean, stdDev); + + std::shared_ptr<Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>(idx, scaling*normalDist(Aidge::Random::Generator::get())); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} + +template void Aidge::heFiller<float>(std::shared_ptr<Aidge::Tensor>, + Aidge::VarianceNorm, float, float); +template void Aidge::heFiller<double>(std::shared_ptr<Aidge::Tensor>, + Aidge::VarianceNorm, double, double); diff --git a/src/filler/NormalFiller.cpp b/src/filler/NormalFiller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f30b32431cf466b10c1b10df8e0e5ccec9f483b6 --- /dev/null +++ b/src/filler/NormalFiller.cpp @@ -0,0 +1,44 @@ +/******************************************************************************** + * 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 <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" +#include "aidge/utils/Random.hpp" + +template <typename T> +void Aidge::normalFiller(std::shared_ptr<Aidge::Tensor> tensor, double mean, + double stdDev) { + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + std::normal_distribution<T> normalDist(mean, stdDev); + + std::shared_ptr<Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>(idx, normalDist(Aidge::Random::Generator::get())); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} + +template void Aidge::normalFiller<float>(std::shared_ptr<Aidge::Tensor>, double, + double); +template void Aidge::normalFiller<double>(std::shared_ptr<Aidge::Tensor>, + double, double); diff --git a/src/filler/UniformFiller.cpp b/src/filler/UniformFiller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a942f59d717fd8d7b541ee28868a7fb9f2e7cd95 --- /dev/null +++ b/src/filler/UniformFiller.cpp @@ -0,0 +1,44 @@ +/******************************************************************************** + * 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 <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" +#include "aidge/utils/Random.hpp" + +template <typename T> +void Aidge::uniformFiller(std::shared_ptr<Aidge::Tensor> tensor, T min, T max) { + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + + std::uniform_real_distribution<T> uniformDist(min, max); + + std::shared_ptr<Aidge::Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Aidge::Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>(idx, uniformDist(Aidge::Random::Generator::get())); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} + +template void Aidge::uniformFiller<float>(std::shared_ptr<Aidge::Tensor>, float, + float); +template void Aidge::uniformFiller<double>(std::shared_ptr<Aidge::Tensor>, + double, double); diff --git a/src/filler/XavierFiller.cpp b/src/filler/XavierFiller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1de15971ca8063e504e270fa6d2275d93270460 --- /dev/null +++ b/src/filler/XavierFiller.cpp @@ -0,0 +1,90 @@ +/******************************************************************************** + * 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 <memory> +#include <random> // normal_distribution, uniform_real_distribution + +#include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" +#include "aidge/utils/Random.hpp" + +template <typename T> +void Aidge::xavierUniformFiller(std::shared_ptr<Aidge::Tensor> tensor, + T scaling, Aidge::VarianceNorm varianceNorm) { + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + unsigned int fanIn, fanOut = 0; + Aidge::calculateFanInFanOut(tensor, fanIn, fanOut); + + const T n((varianceNorm == Aidge::VarianceNorm::FanIn) ? fanIn + : (varianceNorm == Aidge::VarianceNorm::Average) + ? (fanIn + fanOut) / 2.0 + : fanOut); + const T scale(std::sqrt(3.0 / n)); + + std::uniform_real_distribution<T> uniformDist(-scale, scale); + + std::shared_ptr<Aidge::Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Aidge::Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>( + idx, scaling * uniformDist(Aidge::Random::Generator::get())); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} +template <typename T> +void Aidge::xavierNormalFiller(std::shared_ptr<Aidge::Tensor> tensor, T scaling, + Aidge::VarianceNorm varianceNorm) { + AIDGE_ASSERT(tensor->getImpl(), + "Tensor got no implementation, cannot fill it."); + AIDGE_ASSERT(NativeType<T>::type == tensor->dataType(), "Wrong data type"); + + unsigned int fanIn, fanOut = 0; + Aidge::calculateFanInFanOut(tensor, fanIn, fanOut); + + const T n((varianceNorm == Aidge::VarianceNorm::FanIn) ? fanIn + : (varianceNorm == Aidge::VarianceNorm::Average) + ? (fanIn + fanOut) / 2.0 + : fanOut); + const double stdDev(std::sqrt(1.0 / n)); + + std::normal_distribution<T> normalDist(0.0, stdDev); + + std::shared_ptr<Aidge::Tensor> cpyTensor; + // Create cpy only if tensor not on CPU + Aidge::Tensor& tensorWithValues = + tensor->refCastFrom(cpyTensor, tensor->dataType(), "cpu"); + + // Setting values + for (std::size_t idx = 0; idx < tensorWithValues.size(); ++idx) { + tensorWithValues.set<T>( + idx, scaling * normalDist(Aidge::Random::Generator::get())); + } + + // Copy values back to the original tensors (actual copy only if needed) + tensor->copyCastFrom(tensorWithValues); +} + +template void Aidge::xavierUniformFiller<float>(std::shared_ptr<Aidge::Tensor>, + float, Aidge::VarianceNorm); +template void Aidge::xavierUniformFiller<double>(std::shared_ptr<Aidge::Tensor>, + double, Aidge::VarianceNorm); + +template void Aidge::xavierNormalFiller<float>(std::shared_ptr<Aidge::Tensor>, + float, Aidge::VarianceNorm); +template void Aidge::xavierNormalFiller<double>(std::shared_ptr<Aidge::Tensor>, + double, Aidge::VarianceNorm); diff --git a/src/utils/Random.cpp b/src/utils/Random.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c3dc61df54e16d129638c66b4c245d6141e819c --- /dev/null +++ b/src/utils/Random.cpp @@ -0,0 +1,22 @@ +/******************************************************************************** + * 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 "aidge/utils/Random.hpp" + +#include <random> // normal_distribution, uniform_real_distribution + +std::mt19937 Aidge::Random::Generator::generator{std::random_device{}()}; +unsigned int Aidge::Random::Generator::seed = 0; + +void Aidge::Random::Generator::setSeed(unsigned int new_seed) { + seed = new_seed; + generator.seed(seed); +}