[MachineLearning.Inference] Change internal rank limit and default value
[platform/core/csapi/tizenfx.git] / src / Tizen.MachineLearning.Train / Tizen.MachineLearning.Train / Model.cs
1 /*
2 * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 using static Interop;
17 using System;
18 using System.IO;
19 using Tizen.MachineLearning.Inference;
20 namespace Tizen.MachineLearning.Train
21 {
22     /// <summary>
23     /// Constructs the neural network model
24     /// </summary>
25     /// <remarks>
26     /// Use this class to create neural network model.
27     /// The Model class provides interfaces to construct, complle, run, adding layer
28     /// and etc with neural networks.
29     /// If you want to access only internal storage by using this method,
30     /// you should add privilege %http://tizen.org/privilege/mediastorage. Or, if you
31     /// want to access only external storage by using this method, you should add
32     /// privilege %http://tizen.org/privilege/externalstorage. If you want to access
33     /// both storage, you must add all the privileges.
34     /// </remarks>
35     /// <feature>http://tizen.org/feature/machine_learning.training</feature>
36     /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
37     /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
38     /// <exception cref="UnauthorizedAccessException">Thrown when the application does not have the required privilege.</exception>
39     /// <exception cref="InvalidOperationException">Thrown when the method failed due to the wrong pipeline description or internal error.</exception>
40     /// <since_tizen> 10 </since_tizen>
41     public class Model: IDisposable
42     {
43         private IntPtr handle = IntPtr.Zero;
44         private bool disposed = false;
45
46         /// <summary>
47         /// Constructs the neural network model.
48         /// </summary>
49         /// <since_tizen> 10 </since_tizen>
50         public Model()
51         {
52             NNTrainerError ret = Interop.Model.Construct(out handle);
53             NNTrainer.CheckException(ret, "Failed to create model instance");
54             Log.Info(NNTrainer.Tag, "Created Model");
55         }
56
57         /// <summary>
58         /// Constructs the neural network model with the given configuration file.
59         /// </summary>
60         /// <param name="modelConf">The nntrainer model configuration file.</param>
61         /// <since_tizen> 10 </since_tizen>
62         public Model(string modelConf)
63         {
64             if (string.IsNullOrEmpty(modelConf))
65                 NNTrainer.CheckException(NNTrainerError.InvalidParameter, "modelConf is null");
66
67             NNTrainerError ret = Interop.Model.ConstructWithConf(modelConf, out handle);
68             NNTrainer.CheckException(ret, "Failed to create model instance with modelConf");
69             Log.Info(NNTrainer.Tag, "Created Model with Conf path: "+ modelConf);
70         }
71         /// <summary>
72         /// Destructor of Model
73         /// </summary>
74         /// <since_tizen> 10 </since_tizen>
75         ~Model()
76         {
77             Dispose(false);
78         }
79
80         /// <summary>
81         /// Releases any unmanaged resources used by this object.
82         /// </summary>
83         /// <since_tizen> 10 </since_tizen>
84         public void Dispose()
85         {
86             Dispose(true);
87             GC.SuppressFinalize(this);
88         }
89
90         /// <summary>
91         /// Releases any unmanaged resources used by this object including opened handle.
92         /// </summary>
93         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
94         /// <since_tizen> 10 </since_tizen>
95         protected virtual void Dispose(bool disposing)
96         {
97             if (disposed)
98                 return;
99             if (disposing)
100             {
101                 // release managed object
102             }
103             // release unmanaged object
104             if (handle != IntPtr.Zero)
105             {
106                 // Destroy the neural network model.
107                 NNTrainerError ret = Interop.Model.Destroy(handle);
108                 if (ret != NNTrainerError.None)
109                     Log.Error(NNTrainer.Tag, "Failed to destroy Model instance");
110                 handle = IntPtr.Zero;
111             }
112             disposed = true;
113         }
114
115         /// <summary>
116         /// Compiles and finalizes the neural network model with the hyperparameter.
117         /// </summary>
118         /// <remarks>
119         /// Use this method to initialize neural network model.Various
120         /// hyperparameter can be set before compile the model. Once compiled,
121         /// any modification to the properties of model or layers/dataset/optimizer in
122         /// the model will be restricted. Further, addition of layers or changing the
123         /// optimizer/dataset of the model will not be permitted.
124         /// The input format of hyperparameter must be 'key = value' format.
125         /// <param name="hyperparameter">Hyperparameter for train complie.</param>
126         /// </remarks>
127         /// <since_tizen> 10 </since_tizen>
128         public void Compile(params string[] hyperparameter)
129         {
130             string compileParams = null;
131
132             if (hyperparameter.Length > 0) {
133                 compileParams = string.Join("|", hyperparameter);
134                 Log.Info(NNTrainer.Tag, "Compile hyperparameter:"+ compileParams);
135             }
136
137             NNTrainerError ret = Interop.Model.Compile(handle, compileParams);
138             NNTrainer.CheckException(ret, "Failed to compile model");
139         }
140
141         /// <summary>
142         /// Trains the neural network model with the hyperparameter.
143         /// </summary>
144         /// <remarks>
145         /// Use this method to train the compiled neural network model with
146         /// the passed training hyperparameters. This method will return once the
147         /// training, along with requested validation and testing, is completed.
148         /// The input format of hyperparameter must be 'key = value' format.
149         /// </remarks>
150         /// <param name="hyperparameter">Hyperparameters for train model.</param>
151         /// <since_tizen> 10 </since_tizen>
152         public void Run(params string[] hyperparameter)
153         {
154             string runParams = null;
155
156             if (hyperparameter.Length > 0) {
157                 runParams = string.Join("|", hyperparameter);
158                 Log.Info(NNTrainer.Tag, "Run hyperparameter:"+ runParams);
159             }
160
161             NNTrainerError ret = Interop.Model.Run(handle, runParams);
162             NNTrainer.CheckException(ret, "Failed to run model");
163         }
164
165         /// <summary>
166         /// Gets the summary of the neural network model.
167         /// </summary>
168         /// <param name="verbosity">Verbose level of the summary.</param>
169         /// <returns>On return, a string value. The summary of the current model. Avoid logic to parse and exploit summary if possible.</returns>
170         /// <since_tizen> 10 </since_tizen>
171         public string GetSummary(NNTrainerSummaryType verbosity)
172         {
173             string retSummary;
174             NNTrainerError ret = Interop.Model.GetSummary(handle, verbosity, out string summary);
175             NNTrainer.CheckException(ret, "Failed to get summary");
176
177             retSummary = summary;
178             return retSummary;
179         }
180
181         /// <summary>
182         /// Saves the model.
183         /// </summary>
184         /// <remarks>
185         /// Use this method to save the current model. Format
186         /// describes various formats in which various selections of the
187         /// parameters of the models can be saved. Some formats may save
188         /// parameters required for training. Some other formats may save model
189         /// configurations. Unless stated otherwise, <see cref="Compile"/> has to
190         /// be called upon the a model before calling this method.
191         /// Saved ini, if any, is not guaranteed to be identical to the original
192         /// ini that might have been used to load the model.
193         /// If you want to access only internal storage by using this method,
194         /// you should add privilege %http://tizen.org/privilege/mediastorage. Or, if you
195         /// want to access only external storage by using this method, you should add
196         /// privilege %http://tizen.org/privilege/externalstorage. If you want to access
197         /// both storage, you must add all the privileges.
198         /// </remarks>
199         /// <param name="filePath">File path to save the file.</param>
200         /// <param name="format">Format flag to determine which format should be used to save.</param>
201         /// <since_tizen> 10 </since_tizen>
202         public void Save(string filePath, NNTrainerModelFormat format)
203         {
204             if (string.IsNullOrEmpty(filePath))
205                 NNTrainer.CheckException(NNTrainerError.InvalidParameter, "File path is null");
206             Log.Info(NNTrainer.Tag, "File path: "+ filePath);
207             NNTrainerError ret = Interop.Model.Save(handle, filePath, format);
208             NNTrainer.CheckException(ret, "Failed to save model to path");
209         }
210
211         /// <summary>
212         /// Loads the model.
213         /// </summary>
214         /// <remarks>
215         /// Use this method to load the current model. Format
216         /// describes various formats in which various selections of the
217         /// parameters of the models can be loaded. Some formats may load
218         /// parameters required for training. Some other formats may load model
219         /// configurations. Unless stated otherwise, loading model configuration requires
220         /// a freshly constructed model with new Model() without <see cref="Compile"/>,
221         /// loading model parameter requires Compile() to be called upon the model
222         /// before calling this method.
223         /// If you want to access only internal storage by using this method,
224         /// you should add privilege %http://tizen.org/privilege/mediastorage. Or, if you
225         /// want to access only external storage by using this method, you should add
226         /// privilege %http://tizen.org/privilege/externalstorage. If you want to access
227         /// both storage, you must add all the privileges.
228         /// </remarks>
229         /// <param name="filePath">File path to load the file.</param>
230         /// <param name="format">Format flag to determine which format should be used to load.</param>
231         /// <since_tizen> 10 </since_tizen>
232         public void Load(string filePath, NNTrainerModelFormat format)
233         {
234             if (string.IsNullOrEmpty(filePath))
235                 NNTrainer.CheckException(NNTrainerError.InvalidParameter, "File path is null");
236             Log.Info(NNTrainer.Tag, "File Path: "+ filePath);
237             NNTrainerError ret = Interop.Model.Load(handle, filePath, format);
238             NNTrainer.CheckException(ret, "Failed to load model to path");
239         }
240
241         /// <summary>
242         /// Adds layer in neural network model.
243         /// </summary>
244         /// <remarks>
245         /// Use this method to add a layer to the model. The layer is added to
246         /// the end of the existing layers in the model. This transfers the
247         /// ownership of the layer to the network. No need to destroy the layer once it
248         /// is added to a model. Layer is available until the model is released, so
249         /// Dispose() must never be used.
250         /// </remarks>
251         /// <param name="layer"> The instance of Layer class </param>
252         /// <since_tizen> 10 </since_tizen>
253         public void AddLayer(Layer layer)
254         {
255             if (layer == null) {
256                 Log.Error(NNTrainer.Tag, "layer instance is null");
257                 throw new ArgumentNullException(nameof(layer));
258             }
259
260             //Model has ownership of layer;
261             NNTrainerError ret = Interop.Model.AddLayer(handle, layer.GetHandle());
262             NNTrainer.CheckException(ret, "Failed to add layer");
263             layer.RemoveOwnership();
264
265             Log.Info(NNTrainer.Tag, $"AddLayer:\n{layer.GetHandle()}");
266         }
267
268         /// <summary>
269         /// Gets neural network layer from the model with the given name.
270         /// </summary>
271         /// <remarks>
272         /// Use this method to get already created Neural Network Layer.
273         /// The returned layer must not be deleted as it is owned by the model.
274         /// layerName can be set by SetProperty method of Layer.
275         /// Returned layer instance is different with same layerName, but internally the
276         /// native layer handle is same.
277         /// </remarks>
278         /// <param name="layerName"> Name of the already created layer.</param>
279         /// <returns>layer instance</returns>
280         /// <since_tizen> 10 </since_tizen>
281         public Layer GetLayer(string layerName)
282         {
283             IntPtr layerHandle = IntPtr.Zero;
284              if (string.IsNullOrEmpty(layerName))
285                 NNTrainer.CheckException(NNTrainerError.InvalidParameter, "layerName is null");
286
287             NNTrainerError ret = Interop.Model.GetLayer(handle, layerName, out layerHandle);
288             NNTrainer.CheckException(ret, "Failed to get layer");
289
290             Layer layer = new Layer(layerHandle, false);
291     
292             return layer;
293         }
294
295         /// <summary>
296         /// Sets the optimizer for the neural network model.
297         /// </summary>
298         /// <remarks>
299         /// Use this method to set neural network optimizer. This transfers
300         /// the ownership of the optimizer to the network. No need to destroy the
301         /// optimizer if it is added to a model.
302         /// </remarks>
303         /// <param name="optimizer"> The instance of Optimizer class </param>
304         /// <since_tizen> 10 </since_tizen>
305         public void SetOptimizer(Optimizer optimizer)
306         {
307             if (optimizer == null) {
308                 Log.Error(NNTrainer.Tag, "optimizer instance is null");
309                 throw new ArgumentNullException(nameof(optimizer));
310             }
311
312             NNTrainerError ret = Interop.Model.SetOptimizer(handle, optimizer.GetHandle());
313             NNTrainer.CheckException(ret, "Failed to set optimizer");
314         }
315
316         /// <summary>
317         /// Sets the dataset (data provider) for the neural network model.
318         /// </summary>
319         /// <remarks>
320         /// Use this method to set dataset for running the model. The dataset
321         /// will provide training, validation and test data for the model. This transfers
322         /// the ownership of the dataset to the network. No need to destroy the dataset
323         /// once it is set to a model.
324         /// Unsets the previously set dataset, if any. The previously set
325         /// dataset must be freed using Dispose().
326         /// </remarks>
327         /// <param name="dataset"> The instance of Dataset class </param>
328         /// <since_tizen> 10 </since_tizen>
329         public void SetDataset(Dataset dataset)
330         {
331             if (dataset == null) {
332                 Log.Error(NNTrainer.Tag, "dataset instance is null");
333                 throw new ArgumentNullException(nameof(dataset));
334             }
335
336             NNTrainerError ret = Interop.Model.SetDataset(handle, dataset.GetHandle());
337             NNTrainer.CheckException(ret, "Failed to set dataset");
338         }
339
340         internal static TensorsInfo CreateTensorsInfoFormHandle(IntPtr handle)
341         {
342             const int RankLimit = 16;
343             NNTrainerError ret = NNTrainerError.None;
344             int count;
345
346             ret = Interop.Model.GetTensorsCount(handle, out count);
347             NNTrainer.CheckException(ret, "Failed to get count of Tensors");
348
349             TensorsInfo retInfo = new TensorsInfo();
350             for (int i = 0; i <count; ++i)
351             {
352                 string name;
353                 TensorType type;
354                 uint[] dim = new uint[RankLimit];
355
356                 ret = Interop.Model.GetTensorName(handle, i, out name);
357                 NNTrainer.CheckException(ret, "Failed to get name of Tensors");
358
359                 ret = Interop.Model.GetTensorType(handle, i, out type);
360                 NNTrainer.CheckException(ret, "Failed to get type of Tensors");
361
362                 ret = Interop.Model.GetTensorDimension(handle, i, dim);
363                 NNTrainer.CheckException(ret, "Failed to get dimensionpe of Tensors");
364
365                 Log.Error("MLT", $"count:{count} name:{name} type:{type}");
366                 retInfo.AddTensorInfo(name, type, (int[])(object)dim);
367             }
368             return retInfo;
369         }
370
371         /// <summary>
372         /// Gets output tensors information of the model.
373         /// </summary>
374         /// <remarks>
375         /// Use this method to get output tensors information of the model.
376         /// Model must be compiled before calling this method.
377         /// </remarks>
378         /// <returns>TensorsInfo instance</returns>
379         /// <since_tizen> 10 </since_tizen>
380         public TensorsInfo GetOutputTensorsInfo()
381         {
382             IntPtr tensorsInfoHandle = IntPtr.Zero;
383
384             NNTrainerError ret = Interop.Model.GetOutputTensorsInfo(handle, out tensorsInfoHandle);
385             NNTrainer.CheckException(ret, "Failed to get output tensors info");
386
387             return CreateTensorsInfoFormHandle(tensorsInfoHandle);
388         }
389
390         /// <summary>
391         /// Gets input tensors information of the model.
392         /// </summary>
393         /// <remarks>
394         /// Use this method to get input tensors information of the model.
395         /// Model must be compiled before calling this method.
396         /// </remarks>
397         /// <returns>TensorsInfo instance</returns>
398         /// <since_tizen> 10 </since_tizen>
399         public TensorsInfo GetInputTensorsInfo()
400         {
401             IntPtr tensorsInfoHandle = IntPtr.Zero;
402
403             NNTrainerError ret = Interop.Model.GetInputTensorsInfo(handle, out tensorsInfoHandle);
404             NNTrainer.CheckException(ret, "Failed to get input tensors info");
405
406             return CreateTensorsInfoFormHandle(tensorsInfoHandle);
407         }
408     } 
409 }