30 #include <opm/common/ErrorMacros.hpp> 43 #include <fmt/format.h> 66 resizeI<std::vector<int>>({i});
71 resizeI<std::vector<int>>({i, j});
74 Tensor(
int i,
int j,
int k)
76 resizeI<std::vector<int>>({i, j, k});
79 Tensor(
int i,
int j,
int k,
int l)
81 resizeI<std::vector<int>>({i, j, k, l});
84 template <
typename Sizes>
85 void resizeI(
const Sizes& sizes)
87 if (sizes.size() == 1)
88 dims_ = {(int)sizes[0]};
89 if (sizes.size() == 2)
90 dims_ = {(int)sizes[0], (
int)sizes[1]};
91 if (sizes.size() == 3)
92 dims_ = {(int)sizes[0], (
int)sizes[1], (int)sizes[2]};
93 if (sizes.size() == 4)
94 dims_ = {(int)sizes[0], (
int)sizes[1], (int)sizes[2], (
int)sizes[3]};
96 data_.resize(std::accumulate(begin(dims_), end(dims_), 1.0, std::multiplies<>()));
101 OPM_ERROR_IF(dims_.size() == 0,
"Invalid tensor");
103 int elements = dims_[0];
104 for (
unsigned int i = 1; i < dims_.size(); i++) {
105 elements *= dims_[i];
112 OPM_ERROR_IF(dims_.size() != 1,
"Invalid indexing for tensor");
114 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
115 fmt::format(fmt::runtime(
" Invalid i: " 125 const T& operator()(
int i)
const 127 OPM_ERROR_IF(dims_.size() != 1,
"Invalid indexing for tensor");
129 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
130 fmt::format(fmt::runtime(
" Invalid i: " 140 T& operator()(
int i,
int j)
142 OPM_ERROR_IF(dims_.size() != 2,
"Invalid indexing for tensor");
143 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
144 fmt::format(fmt::runtime(
" Invalid i: " 150 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
151 fmt::format(fmt::runtime(
" Invalid j: " 158 return data_[dims_[1] * i + j];
161 const T& operator()(
int i,
int j)
const 163 OPM_ERROR_IF(dims_.size() != 2,
"Invalid indexing for tensor");
164 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
165 fmt::format(fmt::runtime(
" Invalid i: " 171 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
172 fmt::format(fmt::runtime(
" Invalid j: " 178 return data_[dims_[1] * i + j];
181 T& operator()(
int i,
int j,
int k)
183 OPM_ERROR_IF(dims_.size() != 3,
"Invalid indexing for tensor");
184 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
185 fmt::format(fmt::runtime(
" Invalid i: " 191 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
192 fmt::format(fmt::runtime(
" Invalid j: " 198 OPM_ERROR_IF(!(k < dims_[2] && k >= 0),
199 fmt::format(fmt::runtime(
" Invalid k: " 206 return data_[dims_[2] * (dims_[1] * i + j) + k];
209 const T& operator()(
int i,
int j,
int k)
const 211 OPM_ERROR_IF(dims_.size() != 3,
"Invalid indexing for tensor");
212 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
213 fmt::format(fmt::runtime(
" Invalid i: " 219 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
220 fmt::format(fmt::runtime(
" Invalid j: " 226 OPM_ERROR_IF(!(k < dims_[2] && k >= 0),
227 fmt::format(fmt::runtime(
" Invalid k: " 234 return data_[dims_[2] * (dims_[1] * i + j) + k];
237 T& operator()(
int i,
int j,
int k,
int l)
239 OPM_ERROR_IF(dims_.size() != 4,
"Invalid indexing for tensor");
240 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
241 fmt::format(fmt::runtime(
" Invalid i: " 247 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
248 fmt::format(fmt::runtime(
" Invalid j: " 254 OPM_ERROR_IF(!(k < dims_[2] && k >= 0),
255 fmt::format(fmt::runtime(
" Invalid k: " 261 OPM_ERROR_IF(!(l < dims_[3] && l >= 0),
262 fmt::format(fmt::runtime(
" Invalid l: " 269 return data_[dims_[3] * (dims_[2] * (dims_[1] * i + j) + k) + l];
272 const T& operator()(
int i,
int j,
int k,
int l)
const 274 OPM_ERROR_IF(dims_.size() != 4,
"Invalid indexing for tensor");
275 OPM_ERROR_IF(!(i < dims_[0] && i >= 0),
276 fmt::format(fmt::runtime(
" Invalid i: " 282 OPM_ERROR_IF(!(j < dims_[1] && j >= 0),
283 fmt::format(fmt::runtime(
" Invalid j: " 289 OPM_ERROR_IF(!(k < dims_[2] && k >= 0),
290 fmt::format(fmt::runtime(
" Invalid k: " 296 OPM_ERROR_IF(!(l < dims_[3] && l >= 0),
297 fmt::format(fmt::runtime(
" Invalid l: " 304 return data_[dims_[3] * (dims_[2] * (dims_[1] * i + j) + k) + l];
307 void fill(
const T&
value)
309 std::ranges::fill(data_,
value);
315 OPM_ERROR_IF(dims_.size() != other.dims_.size(),
316 "Cannot add tensors with different dimensions");
318 result.dims_ = dims_;
319 result.data_.resize(data_.size());
321 std::ranges::transform(data_, other.data_, result.data_.begin(),
322 [](
const T& x,
const T& y) {
return x + y; });
330 OPM_ERROR_IF(dims_.size() != other.dims_.size(),
331 "Cannot multiply elements with different dimensions");
334 result.dims_ = dims_;
335 result.data_.resize(data_.size());
337 std::ranges::transform(data_, other.data_, result.data_.begin(),
338 [](
const T& x,
const T& y) {
return x * y; });
346 OPM_ERROR_IF(dims_.size() != 2,
"Invalid tensor dimensions");
347 OPM_ERROR_IF(other.dims_.size() != 2,
"Invalid tensor dimensions");
349 OPM_ERROR_IF(dims_[1] != other.dims_[0],
350 "Cannot multiply with different inner dimensions");
352 Tensor tmp(dims_[0], other.dims_[1]);
354 for (
int i = 0; i < dims_[0]; i++) {
355 for (
int j = 0; j < other.dims_[1]; j++) {
356 for (
int k = 0; k < dims_[1]; k++) {
357 tmp(i, j) += (*this)(i, k) * other(k, j);
367 dims_.swap(other.dims_);
368 data_.swap(other.data_);
371 std::vector<int> dims_;
372 std::vector<T> data_;
381 template <
class Evaluation>
394 virtual bool loadLayer(std::ifstream& file) = 0;
400 enum class ActivationType {
412 template <
class Evaluation>
418 : activation_type_(activation_type)
422 bool loadLayer(std::ifstream& file)
override;
427 ActivationType activation_type_;
433 template <
class Evaluation>
438 float data_max = 1.0f,
439 float feat_inf = 1.0f,
440 float feat_sup = 1.0f);
442 bool loadLayer(std::ifstream& file)
override;
456 template <
class Evaluation>
461 float data_max = 1.0f,
462 float feat_inf = 1.0f,
463 float feat_sup = 1.0f);
465 bool loadLayer(std::ifstream& file)
override;
479 template <
class Evaluation>
485 bool loadLayer(std::ifstream& file)
override;
499 template <
class Evaluation>
503 enum class LayerType { kScaling = 1, kUnScaling = 2, kDense = 3, kActivation = 4 };
508 virtual bool loadModel(
const std::string& filename);
513 std::vector<std::unique_ptr<NNLayer<Evaluation>>> layers_;
527 std::chrono::time_point<std::chrono::high_resolution_clock> start_;
533 template <
typename T>
534 bool readFile(std::ifstream& file, T& data)
536 file.read(reinterpret_cast<char*>(&data),
sizeof(T));
540 template <
typename T>
541 bool readFile(std::ifstream& file, T* data, std::size_t n)
543 file.read(reinterpret_cast<char*>(data),
sizeof(T) * n);
547 template <
class Evaluation>
548 bool NNLayerActivation<Evaluation>::loadLayer(std::ifstream& file)
550 unsigned int activation = 0;
551 OPM_ERROR_IF(!readFile<unsigned int>(file, activation),
"Failed to read activation type");
553 switch (static_cast<ActivationType>(activation)) {
554 case ActivationType::kLinear:
555 activation_type_ = ActivationType::kLinear;
557 case ActivationType::kRelu:
558 activation_type_ = ActivationType::kRelu;
560 case ActivationType::kSoftPlus:
561 activation_type_ = ActivationType::kSoftPlus;
563 case ActivationType::kHardSigmoid:
564 activation_type_ = ActivationType::kHardSigmoid;
566 case ActivationType::kSigmoid:
567 activation_type_ = ActivationType::kSigmoid;
569 case ActivationType::kTanh:
570 activation_type_ = ActivationType::kTanh;
574 fmt::format(fmt::runtime(
"\n Unsupported activation type " 582 template <
class Evaluation>
583 bool NNLayerActivation<Evaluation>::apply(
const Tensor<Evaluation>& in, Tensor<Evaluation>& out)
587 switch (activation_type_) {
588 case ActivationType::kLinear:
590 case ActivationType::kRelu:
591 for (std::size_t i = 0; i < out.data_.size(); i++) {
592 if (out.data_[i] < 0.0) {
597 case ActivationType::kSoftPlus:
598 for (std::size_t i = 0; i < out.data_.size(); i++) {
599 out.data_[i] = log(1.0 + exp(out.data_[i]));
602 case ActivationType::kHardSigmoid:
603 for (std::size_t i = 0; i < out.data_.size(); i++) {
604 constexpr
double sigmoid_scale = 0.2;
605 const Evaluation& x = (out.data_[i] * sigmoid_scale) + 0.5;
616 case ActivationType::kSigmoid:
617 for (std::size_t i = 0; i < out.data_.size(); i++) {
618 const Evaluation& x = out.data_[i];
621 out.data_[i] = 1.0 / (1.0 + exp(-x));
623 const Evaluation& z = exp(x);
624 out.data_[i] = z / (1.0 + z);
628 case ActivationType::kTanh:
629 for (std::size_t i = 0; i < out.data_.size(); i++) {
630 out.data_[i] = sinh(out.data_[i]) / cosh(out.data_[i]);
640 template <
class Evaluation>
641 NNLayerScaling<Evaluation>::NNLayerScaling(
float data_min,
float data_max,
float feat_inf,
float feat_sup)
642 : data_min_(data_min)
643 , data_max_(data_max)
644 , feat_inf_(feat_inf)
645 , feat_sup_(feat_sup)
649 template <
class Evaluation>
650 bool NNLayerScaling<Evaluation>::loadLayer(std::ifstream& file)
652 OPM_ERROR_IF(!readFile<float>(file, data_min_),
"Failed to read data min");
653 OPM_ERROR_IF(!readFile<float>(file, data_max_),
"Failed to read data max");
654 OPM_ERROR_IF(!readFile<float>(file, feat_inf_),
"Failed to read feat inf");
655 OPM_ERROR_IF(!readFile<float>(file, feat_sup_),
"Failed to read feat sup");
659 template <
class Evaluation>
660 bool NNLayerScaling<Evaluation>::apply(
const Tensor<Evaluation>& in, Tensor<Evaluation>& out)
662 out.data_.resize(in.data_.size());
663 out.dims_ = in.dims_;
664 for (std::size_t i = 0; i < out.data_.size(); i++) {
665 auto tempscale = (in.data_[i] - data_min_) / (data_max_ - data_min_);
666 out.data_[i] = tempscale * (feat_sup_ - feat_inf_) + feat_inf_;
672 template <
class Evaluation>
673 NNLayerUnScaling<Evaluation>::NNLayerUnScaling(
674 float data_min,
float data_max,
float feat_inf,
float feat_sup)
675 : data_min_(data_min)
676 , data_max_(data_max)
677 , feat_inf_(feat_inf)
678 , feat_sup_(feat_sup)
682 template <
class Evaluation>
683 bool NNLayerUnScaling<Evaluation>::loadLayer(std::ifstream& file)
685 OPM_ERROR_IF(!readFile<float>(file, data_min_),
"Failed to read data min");
686 OPM_ERROR_IF(!readFile<float>(file, data_max_),
"Failed to read data max");
687 OPM_ERROR_IF(!readFile<float>(file, feat_inf_),
"Failed to read feat inf");
688 OPM_ERROR_IF(!readFile<float>(file, feat_sup_),
"Failed to read feat sup");
693 template <
class Evaluation>
694 bool NNLayerUnScaling<Evaluation>::apply(
const Tensor<Evaluation>& in, Tensor<Evaluation>& out)
696 out.data_.resize(in.data_.size());
697 out.dims_ = in.dims_;
698 for (std::size_t i = 0; i < out.data_.size(); i++) {
699 auto tempscale = (in.data_[i] - feat_inf_) / (feat_sup_ - feat_inf_);
701 out.data_[i] = tempscale * (data_max_ - data_min_) + data_min_;
707 template <
class Evaluation>
708 NNLayerDense<Evaluation>::NNLayerDense(Tensor<float> weights, Tensor<float> biases, ActivationType activation_type)
711 , activation_(activation_type)
715 template <
class Evaluation>
716 bool NNLayerDense<Evaluation>::loadLayer(std::ifstream& file)
718 unsigned int weights_rows = 0;
719 OPM_ERROR_IF(!readFile<unsigned int>(file, weights_rows),
"Expected weight rows");
720 OPM_ERROR_IF(!(weights_rows > 0),
"Invalid weights # rows");
722 unsigned int weights_cols = 0;
723 OPM_ERROR_IF(!readFile<unsigned int>(file, weights_cols),
"Expected weight cols");
724 OPM_ERROR_IF(!(weights_cols > 0),
"Invalid weights shape");
726 unsigned int biases_shape = 0;
727 OPM_ERROR_IF(!readFile<unsigned int>(file, biases_shape),
"Expected biases shape");
728 OPM_ERROR_IF(!(biases_shape > 0),
"Invalid biases shape");
730 weights_.resizeI<std::vector<unsigned int>>({weights_rows, weights_cols});
731 OPM_ERROR_IF(!readFile<float>(file, weights_.data_.data(), weights_rows * weights_cols),
"Expected weights");
733 biases_.resizeI<std::vector<unsigned int>>({biases_shape});
734 OPM_ERROR_IF(!readFile<float>(file, biases_.data_.data(), biases_shape),
"Expected biases");
736 OPM_ERROR_IF(!activation_.loadLayer(file),
"Failed to load activation");
775 template <
class Evaluation>
780 for (
int i = 0; i < weights_.dims_[0]; i++) {
781 for (
int j = 0; j < weights_.dims_[1]; j++) {
782 tmp(j) += (temp_in)(i)*weights_(i, j);
786 for (
int i = 0; i < biases_.dims_[0]; i++) {
787 tmp(i) += biases_(i);
790 OPM_ERROR_IF(!activation_.apply(tmp, out),
"Failed to apply activation");
795 template <
class Evaluation>
798 std::ifstream file(filename.c_str(), std::ios::binary);
799 OPM_ERROR_IF(!file.is_open(),
800 fmt::format(fmt::runtime(
"\n Unable to open file " 804 unsigned int num_layers = 0;
805 OPM_ERROR_IF(!readFile<unsigned int>(file, num_layers),
"Expected number of layers");
807 for (
unsigned int i = 0; i < num_layers; i++) {
808 unsigned int layer_type = 0;
809 OPM_ERROR_IF(!readFile<unsigned int>(file, layer_type),
"Expected layer type");
811 std::unique_ptr<NNLayer<Evaluation>> layer =
nullptr;
813 switch (static_cast<LayerType>(layer_type)) {
814 case LayerType::kScaling:
815 layer = std::make_unique<NNLayerScaling<Evaluation>>();
817 case LayerType::kUnScaling:
818 layer = std::make_unique<NNLayerUnScaling<Evaluation>>();
820 case LayerType::kDense:
821 layer = std::make_unique<NNLayerDense<Evaluation>>();
823 case LayerType::kActivation:
824 layer = std::make_unique<NNLayerActivation<Evaluation>>();
831 fmt::format(fmt::runtime(
"\n Unknown layer type " 834 OPM_ERROR_IF(!layer->loadLayer(file),
835 fmt::format(fmt::runtime(
"\n Failed to load layer " 839 layers_.emplace_back(std::move(layer));
845 template <
class Evaluation>
846 bool NNModel<Evaluation>::apply(
const Tensor<Evaluation>& in, Tensor<Evaluation>& out)
848 Tensor<Evaluation> temp_in(in);
850 for (
unsigned int i = 0; i < layers_.size(); i++) {
856 OPM_ERROR_IF(!(layers_[i]->apply(temp_in, out)),
857 fmt::format(fmt::runtime(
"\n Failed to apply layer " 868 #endif // ML_MODEL_H_ void start()
Start the timer.
Definition: ml_model.cpp:34
Definition: ml_model.hpp:480
Definition: ml_model.hpp:382
bool apply(const Tensor< Evaluation > &in, Tensor< Evaluation > &out) override
Applies the forward pass of a dense (fully connected) neural-network layer.
Definition: ml_model.hpp:776
float stop()
Stop the timer and return elapsed time in milliseconds.
Definition: ml_model.cpp:39
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Definition: ml_model.hpp:413
Definition: ml_model.hpp:434
A number of commonly used algebraic functions for the localized OPM automatic differentiation (AD) fr...
Definition: ml_model.hpp:500
Definition: ml_model.hpp:518
Definition: ml_model.hpp:457
Implements mathematical tensor (Max 4d)
Definition: ml_model.hpp:57