https://mooseframework.inl.gov
Loading...
Searching...
No Matches
NEML2ModelHandle.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "NEML2Utils.h"
13
14#ifdef NEML2_ENABLED
15
16#include <memory>
17#include <string>
18#include <map>
19#include <vector>
20#include <utility>
21#include <cstddef>
22#include <filesystem>
23
24#include "neml2/csrc/eager/Model.h"
25#include "neml2/csrc/eager/load_model.h"
26#include "neml2/csrc/dispatchers/factory.h"
27#include "neml2/csrc/dispatchers/DispatchedModel.h"
28#include "neml2/csrc/dispatchers/MPISimpleScheduler.h"
29
46{
47public:
48 virtual ~NEML2ModelHandle() = default;
49
52 virtual const std::vector<std::string> & input_names() const = 0;
53 virtual const std::vector<std::string> & output_names() const = 0;
54 virtual const std::vector<std::vector<int64_t>> & input_base_shapes() const = 0;
55 virtual const std::vector<std::vector<int64_t>> & output_base_shapes() const = 0;
56 virtual const std::map<std::string, std::vector<int64_t>> & parameter_base_shapes() const = 0;
58
63 virtual std::map<std::string, at::Tensor>
64 value(const std::map<std::string, at::Tensor> & inputs) const = 0;
66 virtual std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
67 jacobian(const std::map<std::string, at::Tensor> & inputs) const = 0;
69 virtual std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
70 param_jacobian(const std::map<std::string, at::Tensor> & inputs) const = 0;
72 virtual void set_parameter(const std::string & name, const at::Tensor & value) = 0;
74
76 virtual at::Device device() const = 0;
77};
78
84{
85public:
86 EagerModelHandle(const std::string & input_file,
87 const std::string & model_name,
88 const at::Device & device,
89 const std::vector<std::string> & load)
90 : _m(input_file, model_name, device, load)
91 {
92 }
93
94 const std::vector<std::string> & input_names() const override { return _m.input_names(); }
95 const std::vector<std::string> & output_names() const override { return _m.output_names(); }
96 const std::vector<std::vector<int64_t>> & input_base_shapes() const override
97 {
98 return _m.input_base_shapes();
99 }
100 const std::vector<std::vector<int64_t>> & output_base_shapes() const override
101 {
102 return _m.output_base_shapes();
103 }
104 const std::map<std::string, std::vector<int64_t>> & parameter_base_shapes() const override
105 {
106 return _m.parameter_base_shapes();
107 }
108
109 std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
110 jacobian(const std::map<std::string, at::Tensor> & inputs) const override
111 {
112 return _m.jacobian(inputs);
113 }
114 std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
115 param_jacobian(const std::map<std::string, at::Tensor> & inputs) const override
116 {
117 return _m.param_jacobian(inputs);
118 }
119 void set_parameter(const std::string & name, const at::Tensor & value) override
120 {
121 _m.set_parameter(name, value);
122 }
123 std::map<std::string, at::Tensor>
124 value(const std::map<std::string, at::Tensor> & inputs) const override
125 {
126 return _m.forward(inputs);
127 }
128 at::Device device() const override { return _m.device(); }
129
130private:
131 neml2::eager::Model _m;
132};
133
148{
149public:
150 AOTIModelHandle(const std::string & input,
151 const std::string & model_name,
152 const std::vector<std::string> & devices,
153 const std::vector<std::size_t> & batch_sizes,
154 const void * comm)
155 : _m(load(input, model_name, devices, batch_sizes, comm))
156 {
157 }
158
159 const std::vector<std::string> & input_names() const override { return _m.input_names(); }
160 const std::vector<std::string> & output_names() const override { return _m.output_names(); }
161 const std::vector<std::vector<int64_t>> & input_base_shapes() const override
162 {
163 return _m.input_base_shapes();
164 }
165 const std::vector<std::vector<int64_t>> & output_base_shapes() const override
166 {
167 return _m.output_base_shapes();
168 }
169 const std::map<std::string, std::vector<int64_t>> & parameter_base_shapes() const override
170 {
171 return _m.parameter_base_shapes();
172 }
173
174 std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
175 jacobian(const std::map<std::string, at::Tensor> & inputs) const override
176 {
177 return _m.jacobian(inputs);
178 }
179 std::pair<std::map<std::string, at::Tensor>, neml2::aoti::VariablePairJacobian>
180 param_jacobian(const std::map<std::string, at::Tensor> & inputs) const override
181 {
182 return _m.param_jacobian(inputs);
183 }
184 void set_parameter(const std::string & name, const at::Tensor & value) override
185 {
186 _m.set_parameter(name, value);
187 }
188 std::map<std::string, at::Tensor>
189 value(const std::map<std::string, at::Tensor> & inputs) const override
190 {
191 return _m.forward(inputs);
192 }
193 at::Device device() const override { return _m.device(); }
194
195private:
206 static neml2::aoti::DispatchedModel load(const std::string & input,
207 const std::string & model_name,
208 const std::vector<std::string> & devices,
209 const std::vector<std::size_t> & batch_sizes,
210 const void * comm)
211 {
212 neml2::aoti::MPISimpleScheduler::Config config;
213 config.devices = devices;
214 config.batch_sizes = batch_sizes;
215 config.comm = comm;
216 auto scheduler = std::make_shared<neml2::aoti::MPISimpleScheduler>(config);
217
218 const std::filesystem::path path(input);
219 if (std::filesystem::is_directory(path))
220 return neml2::aoti::DispatchedModel(path, scheduler);
221 if (path.filename() == "metadata.json")
222 return neml2::aoti::DispatchedModel(path.parent_path(), scheduler);
223 return neml2::aoti::load_model(input, model_name, scheduler);
224 }
225
226 neml2::aoti::DispatchedModel _m;
227};
228
247inline std::unique_ptr<NEML2ModelHandle>
249 const std::string & input,
250 const std::string & model,
251 const std::vector<std::string> & devices,
252 const std::vector<std::size_t> & batch_sizes,
253 const void * comm,
254 const std::vector<std::string> & load)
255{
256 if (eager)
257 return std::make_unique<EagerModelHandle>(input, model, at::Device(devices.at(0)), load);
258 return std::make_unique<AOTIModelHandle>(input, model, devices, batch_sizes, comm);
259}
260
261#endif // NEML2_ENABLED
std::unique_ptr< NEML2ModelHandle > makeNEML2ModelHandle(bool eager, const std::string &input, const std::string &model, const std::vector< std::string > &devices, const std::vector< std::size_t > &batch_sizes, const void *comm, const std::vector< std::string > &load)
Construct a NEML2 model handle for the requested runtime.
Handle wrapping the cpp-aoti runtime: a neml2::aoti::DispatchedModel backed by the self-describing ar...
AOTIModelHandle(const std::string &input, const std::string &model_name, const std::vector< std::string > &devices, const std::vector< std::size_t > &batch_sizes, const void *comm)
std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > param_jacobian(const std::map< std::string, at::Tensor > &inputs) const override
Evaluate the model and its parameter Jacobian (d output / d parameter).
const std::vector< std::string > & output_names() const override
std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > jacobian(const std::map< std::string, at::Tensor > &inputs) const override
Evaluate the model and its full input Jacobian.
const std::vector< std::vector< int64_t > > & output_base_shapes() const override
at::Device device() const override
The compute device this rank's workload runs on (for cpp-aoti, the scheduler-assigned device).
static neml2::aoti::DispatchedModel load(const std::string &input, const std::string &model_name, const std::vector< std::string > &devices, const std::vector< std::size_t > &batch_sizes, const void *comm)
Build the MPI scheduler (round-robin device list over the node's ranks) and load the dispatched aoti ...
const std::map< std::string, std::vector< int64_t > > & parameter_base_shapes() const override
void set_parameter(const std::string &name, const at::Tensor &value) override
Replace a (runtime-flexible) model parameter's value.
neml2::aoti::DispatchedModel _m
const std::vector< std::string > & input_names() const override
const std::vector< std::vector< int64_t > > & input_base_shapes() const override
std::map< std::string, at::Tensor > value(const std::map< std::string, at::Tensor > &inputs) const override
Handle wrapping the cpp-eager runtime (embeds CPython; loads from a source .i).
at::Device device() const override
The compute device this rank's workload runs on (for cpp-aoti, the scheduler-assigned device).
neml2::eager::Model _m
const std::map< std::string, std::vector< int64_t > > & parameter_base_shapes() const override
const std::vector< std::string > & input_names() const override
const std::vector< std::string > & output_names() const override
const std::vector< std::vector< int64_t > > & input_base_shapes() const override
std::map< std::string, at::Tensor > value(const std::map< std::string, at::Tensor > &inputs) const override
EagerModelHandle(const std::string &input_file, const std::string &model_name, const at::Device &device, const std::vector< std::string > &load)
std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > param_jacobian(const std::map< std::string, at::Tensor > &inputs) const override
Evaluate the model and its parameter Jacobian (d output / d parameter).
const std::vector< std::vector< int64_t > > & output_base_shapes() const override
std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > jacobian(const std::map< std::string, at::Tensor > &inputs) const override
Evaluate the model and its full input Jacobian.
void set_parameter(const std::string &name, const at::Tensor &value) override
Replace a (runtime-flexible) model parameter's value.
Runtime-agnostic handle over a NEML2 v3 model.
virtual ~NEML2ModelHandle()=default
virtual const std::vector< std::string > & input_names() const =0
virtual std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > jacobian(const std::map< std::string, at::Tensor > &inputs) const =0
Evaluate the model and its full input Jacobian.
virtual at::Device device() const =0
The compute device this rank's workload runs on (for cpp-aoti, the scheduler-assigned device).
virtual const std::vector< std::vector< int64_t > > & output_base_shapes() const =0
virtual void set_parameter(const std::string &name, const at::Tensor &value)=0
Replace a (runtime-flexible) model parameter's value.
virtual std::pair< std::map< std::string, at::Tensor >, neml2::aoti::VariablePairJacobian > param_jacobian(const std::map< std::string, at::Tensor > &inputs) const =0
Evaluate the model and its parameter Jacobian (d output / d parameter).
virtual std::map< std::string, at::Tensor > value(const std::map< std::string, at::Tensor > &inputs) const =0
virtual const std::map< std::string, std::vector< int64_t > > & parameter_base_shapes() const =0
virtual const std::vector< std::vector< int64_t > > & input_base_shapes() const =0
virtual const std::vector< std::string > & output_names() const =0