Skip to content
Snippets Groups Projects
Commit 3ca54187 authored by Maxence Naud's avatar Maxence Naud
Browse files

Merge branch 'learning' into 'dev'

[Add] loss function system, MSE loss function, unit-test associated with MSE

See merge request !1
parents e729a198 0ec99fd5
No related branches found
No related tags found
2 merge requests!3Dev - learning - v0.1.0,!1[Add] loss function system, MSE loss function, unit-test associated with MSE
...@@ -52,7 +52,7 @@ public: ...@@ -52,7 +52,7 @@ public:
mReversedDampening.set<float>(0, 1.0f - dampening); mReversedDampening.set<float>(0, 1.0f - dampening);
} }
void update() override { void update() override final {
mLR.setBackend(mParameters[0]->getImpl()->backend()); mLR.setBackend(mParameters[0]->getImpl()->backend());
mLR.set<float>(0, learningRate()); mLR.set<float>(0, learningRate());
if (mParameters[0]->getImpl()->backend() != mMomentum.getImpl()->backend()) { if (mParameters[0]->getImpl()->backend() != mMomentum.getImpl()->backend()) {
...@@ -74,7 +74,7 @@ public: ...@@ -74,7 +74,7 @@ public:
mLRScheduler.update(); mLRScheduler.update();
} }
void setParameters(const std::vector<std::shared_ptr<Tensor>>& parameters) { void setParameters(const std::vector<std::shared_ptr<Tensor>>& parameters) override final {
Optimizer::setParameters(parameters); Optimizer::setParameters(parameters);
mGradientInertia = std::vector<Tensor>(parameters.size()); mGradientInertia = std::vector<Tensor>(parameters.size());
for (std::size_t i = 0; i < parameters.size(); ++i) { for (std::size_t i = 0; i < parameters.size(); ++i) {
......
/********************************************************************************
* 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_LOSS_LOSSLIST_H_
#define AIDGE_CORE_LOSS_LOSSLIST_H_
#include <cstddef> // std::size_t
#include <memory>
#include "aidge/data/Tensor.hpp"
namespace Aidge {
namespace loss {
Tensor MSE(const std::shared_ptr<Tensor>& prediction,
const std::shared_ptr<Tensor>& target);
} // loss
} // namespace Aidge
#endif /* AIDGE_CORE_LOSS_LOSSLIST_H_ */
/********************************************************************************
* 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/loss/LossList.hpp"
#include <memory>
#include <numeric> // std::iota
#include "aidge/data/Tensor.hpp"
#include "aidge/graph/GraphView.hpp"
#include "aidge/graph/OpArgs.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/operator/Pow.hpp"
#include "aidge/backend/cpu/operator/PowImpl.hpp"
#include "aidge/operator/ReduceMean.hpp"
#include "aidge/backend/cpu/operator/ReduceMeanImpl.hpp"
#include "aidge/operator/Sub.hpp"
#include "aidge/backend/cpu/operator/SubImpl.hpp"
#include "aidge/scheduler/Scheduler.hpp"
Aidge::Tensor Aidge::loss::MSE(const std::shared_ptr<Tensor>& prediction, const std::shared_ptr<Tensor>& target) {
AIDGE_ASSERT(prediction->backend() == target->backend(),
"'prediction' and 'target' Tensors must be on the same backend. Found {} and {}.\n",
prediction->backend(),
target->backend());
AIDGE_ASSERT(prediction->dims() == target->dims(),
"'prediction' (shape {}) and 'target' (shape {}) Tensors must have the same dimensions.\n",
prediction->dims(),
target->dims());
AIDGE_ASSERT(prediction->dataType() == target->dataType(),
"'prediction' (shape {}) and 'target' (shape {}) Tensors must have the same dimensions.\n",
prediction->dims(),
target->dims());
// could be accelerated with constexpr constructors
std::vector<int> axes_dims(prediction->nbDims());
std::iota(std::begin(axes_dims), std::end(axes_dims), 0);
auto rm_node = ReduceMean(axes_dims, 1, "mse_res");
const std::shared_ptr<Node> pow_node = Pow();
const std::shared_ptr<Node> pow_exp_node = Producer(std::make_shared<Tensor>(Array1D<int,1>{{2}}));
pow_exp_node->addChild(pow_node, 0, 1);
const std::shared_ptr<Node> sub_node = Sub();
Producer(prediction)->addChild(sub_node, 0, 0);
Producer(target)->addChild(sub_node, 0, 1);
std::shared_ptr<GraphView> gv_local = Sequential({
sub_node,
pow_node,
rm_node
});
gv_local->add({sub_node->getParent(0), sub_node->getParent(1), pow_exp_node});
gv_local->compile(prediction->getImpl()->backend(), prediction->dataType());
gv_local->save("MSEgraph");
SequentialScheduler ss_local{gv_local};
ss_local.forward(false, true);
// TODO: way too complicated to access
const std::shared_ptr<OperatorTensor> res = std::dynamic_pointer_cast<OperatorTensor>(rm_node->getOperator());
return res->getOutput(0)->clone();
}
\ No newline at end of file
/********************************************************************************
* 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 <cmath> //
#include <functional> // std::multiplies, std::plus
#include <memory> // std::make_unique
#include <numeric> // std::accumulate
#include <random> // std::random_device, std::mt19937,
// std::uniform_int_distribution
#include <vector>
#include "aidge/loss/LossList.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/utils/TensorUtils.hpp"
namespace Aidge {
TEST_CASE("[loss/regression] MSE", "[loss][regression][MSE]") {
constexpr std::uint16_t NBTRIALS = 10;
// set random variables
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<std::size_t> dimsDist(1, 5);
std::uniform_int_distribution<std::size_t> nbDimsDist(1, 2);
std::uniform_real_distribution<float> valueDist(0.0f, 1.0f);
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
// Create a random number generator
const std::size_t nb_dims = nbDimsDist(gen);
std::vector<std::size_t> dims(nb_dims);
for (std::size_t i = 0; i < nb_dims; ++i) { dims[i] = dimsDist(gen); }
const std::size_t nb_elements = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>());
// create random predictions
std::unique_ptr<float[]> pred = std::make_unique<float[]>(nb_elements);
for (std::size_t i = 0; i < nb_elements; ++i) {
pred[i] = valueDist(gen);
}
// create random targets
std::unique_ptr<float[]> targ = std::make_unique<float[]>(nb_elements);
for (std::size_t i = 0; i < nb_elements; ++i) {
targ[i] = valueDist(gen);
}
// compute the MSE manually
std::unique_ptr<float[]> tmp_res_manual = std::make_unique<float[]>(nb_elements);
for (std::size_t i = 0; i < nb_elements; ++i) {
tmp_res_manual[i] = std::pow(pred[i] - targ[i],2);
}
std::cout << "Pow output manual:" << std::endl;
std::shared_ptr<Tensor> tmp_tensor = std::make_shared<Tensor>(dims);
tmp_tensor->setBackend("cpu");
tmp_tensor->getImpl()->setRawPtr(tmp_res_manual.get(), nb_elements);
tmp_tensor->print();
const float res_manual = std::accumulate(&tmp_res_manual[0], &tmp_res_manual[nb_elements], 0.0f, std::plus<float>()) / static_cast<float>(nb_elements);
// compute the MSE using Aidge::loss::MSE function
std::cout << "Sub input 0 manual:" << std::endl;
std::shared_ptr<Tensor> pred_tensor = std::make_shared<Tensor>(dims);
pred_tensor->setBackend("cpu");
pred_tensor->getImpl()->setRawPtr(pred.get(), nb_elements);
pred_tensor->print();
std::cout << "Sub input 1 manual:" << std::endl;
std::shared_ptr<Tensor> targ_tensor = std::make_shared<Tensor>(dims);
targ_tensor->setBackend("cpu");
targ_tensor->getImpl()->setRawPtr(targ.get(), nb_elements);
targ_tensor->print();
const Tensor res_function = loss::MSE(pred_tensor, targ_tensor);
// compare results
Tensor res_manual_tensor = Tensor(res_manual);
REQUIRE(approxEq<float>(res_manual, res_function));
}
}
} // namespace Aidge
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment