[MachineLearning.Inference] Add Inference APIs for Machine Learning (#940)
[platform/core/csapi/tizenfx.git] / src / Tizen.MachineLearning.Inference / Tizen.MachineLearning.Inference / TensorsInfo.cs
1 /*
2 * Copyright (c) 2019 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
17 using System;
18 using System.Collections.Generic;
19 using Log = Tizen.Log;
20
21 namespace Tizen.MachineLearning.Inference
22 {
23     /// <summary>
24     /// The TensorsInfo class manages each Tensor information such as Name, Type and Dimension.
25     /// </summary>
26     /// <since_tizen> 6 </since_tizen>
27     public class TensorsInfo : IDisposable
28     {
29         private List<TensorInfo> _infoList;
30         private IntPtr _handle = IntPtr.Zero;
31         private bool _disposed = false;
32
33         /// <summary>
34         /// Get the number of Tensor information which is added.
35         /// </summary>
36         /// <since_tizen> 6 </since_tizen>
37         public int Count => _infoList.Count;
38
39         /// <summary>
40         /// Creates a TensorsInfo instance.
41         /// </summary>
42         /// <since_tizen> 6 </since_tizen>
43         public TensorsInfo()
44         {
45             Log.Info(NNStreamer.TAG, "TensorsInfo is created");
46             _infoList = new List<TensorInfo>();
47         }
48
49         /// <summary>
50         /// Destroys the TensorsInfo resource.
51         /// </summary>
52         /// <since_tizen> 6 </since_tizen>
53         ~TensorsInfo()
54         {
55             Dispose(false);
56         }
57
58         /// <summary>
59         /// Add a Tensor information to the TensorsInfo instance. Note that we support up to 16 tensors in TensorsInfo.
60         /// </summary>
61         /// <param name="type">Data element type of Tensor.</param>
62         /// <param name="dimension">Dimension of Tensor. Note that we support up to 4th ranks.</param>
63         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
64         /// <exception cref="IndexOutOfRangeException">Thrown when the number of Tensor already exceeds the size limits (i.e. Tensor.SlzeLimit)</exception>
65         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
66         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
67         /// <since_tizen> 6 </since_tizen>
68         public void AddTensorInfo(TensorType type, int[] dimension)
69         {
70             AddTensorInfo(null, type, dimension);
71         }
72
73         /// <summary>
74         /// Add a Tensor information to the TensorsInfo instance. Note that we support up to 16 tensors in TensorsInfo.
75         /// </summary>
76         /// <param name="name">Name of Tensor.</param>
77         /// <param name="type">Data element type of Tensor.</param>
78         /// <param name="dimension">Dimension of Tensor. Note that we support up to 4th ranks.</param>
79         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
80         /// <exception cref="IndexOutOfRangeException">Thrown when the number of Tensor already exceeds the size limits (i.e. Tensor.SlzeLimit)</exception>
81         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
82         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
83         /// <since_tizen> 6 </since_tizen>
84         public void AddTensorInfo(string name, TensorType type, int[] dimension)
85         {
86             int idx = _infoList.Count;
87             if (idx >= Tensor.SizeLimit) {
88                 throw new IndexOutOfRangeException("Max size of the tensors is " + Tensor.SizeLimit);
89             }
90             _infoList.Add(new TensorInfo(name, type, dimension));
91
92             if (_handle != IntPtr.Zero)
93             {
94                 NNStreamerError ret = NNStreamerError.None;
95
96                 /* Set the number of tensors */
97                 ret = Interop.Util.SetTensorsCount(_handle, _infoList.Count);
98                 NNStreamer.CheckException(ret, "unable to set the number of tensors");
99
100                 /* Set the type and dimension of Tensor */
101                 ret = Interop.Util.SetTensorType(_handle, idx, type);
102                 NNStreamer.CheckException(ret, "fail to set TensorsInfo type");
103
104                 ret = Interop.Util.SetTensorDimension(_handle, idx, dimension);
105                 NNStreamer.CheckException(ret, "fail to set TensorsInfo dimension");
106             }
107         }
108
109         /// <summary>
110         /// Sets the tensor name with given index.
111         /// </summary>
112         /// <param name="idx">The index of the tensor to be updated.</param>
113         /// <param name="name">The tensor name to be set.</param>
114         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
115         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
116         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
117         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
118         /// <since_tizen> 6 </since_tizen>
119         public void SetTensorName(int idx, string name)
120         {
121             CheckIndexBoundary(idx);
122             _infoList[idx].Name = name;
123
124             if (_handle != IntPtr.Zero)
125             {
126                 NNStreamerError ret = NNStreamerError.None;
127                 ret = Interop.Util.SetTensorName(_handle, idx, name);
128                 NNStreamer.CheckException(ret, "unable to set the name of tensor: " + idx.ToString());
129             }
130         }
131
132         /// <summary>
133         /// Gets the tensor name with given index.
134         /// </summary>
135         /// <param name="idx">The index of the tensor.</param>
136         /// <returns>The tensor name.</returns>
137         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
138         /// <since_tizen> 6 </since_tizen>
139         public string GetTensorName(int idx)
140         {
141             CheckIndexBoundary(idx);
142             return _infoList[idx].Name;
143         }
144
145         /// <summary>
146         /// Sets the tensor type with given index and its type.
147         /// </summary>
148         /// <param name="idx">The index of the tensor to be updated.</param>
149         /// <param name="type">The tensor type to be set.</param>
150         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
151         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
152         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
153         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
154         /// <since_tizen> 6 </since_tizen>
155         public void SetTensorType(int idx, TensorType type)
156         {
157             CheckIndexBoundary(idx);
158             _infoList[idx].Type = type;
159
160             if (_handle != IntPtr.Zero)
161             {
162                 NNStreamerError ret = NNStreamerError.None;
163                 ret = Interop.Util.SetTensorType(_handle, idx, type);
164                 NNStreamer.CheckException(ret, "unable to set the type of tensor: " + idx.ToString());
165             }
166         }
167
168         /// <summary>
169         /// Gets the tensor type with given index.
170         /// </summary>
171         /// <param name="idx">The index of the tensor.</param>
172         /// <returns>The tensor type</returns>
173         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
174         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
175         /// <since_tizen> 6 </since_tizen>
176         public TensorType GetTensorType(int idx)
177         {
178             CheckIndexBoundary(idx);
179             return _infoList[idx].Type;
180         }
181
182         /// <summary>
183         /// Sets the tensor dimension with given index and dimension.
184         /// </summary>
185         /// <param name="idx">The index of the tensor to be updated.</param>
186         /// <param name="dimension">The tensor dimension to be set.</param>
187         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
188         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
189         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
190         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
191         /// <since_tizen> 6 </since_tizen>
192         public void SetDimension(int idx, int[] dimension)
193         {
194             CheckIndexBoundary(idx);
195             _infoList[idx].SetDimension(dimension);
196
197             if (_handle != IntPtr.Zero)
198             {
199                 NNStreamerError ret = NNStreamerError.None;
200                 ret = Interop.Util.SetTensorDimension(_handle, idx, dimension);
201                 NNStreamer.CheckException(ret, "unable to set the dimension of tensor: " + idx.ToString());
202             }
203         }
204
205         /// <summary>
206         /// Gets the tensor dimension with given index.
207         /// </summary>
208         /// <param name="idx">The index of the tensor.</param>
209         /// <returns>The tensor dimension.</returns>
210         /// <exception cref="IndexOutOfRangeException">Thrown when the index is greater than the number of Tensor.</exception>
211         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
212         /// <since_tizen> 6 </since_tizen>
213         public int[] GetDimension(int idx)
214         {
215             CheckIndexBoundary(idx);
216             return _infoList[idx].Dimension;
217         }
218
219         /// <summary>
220         /// Creates a TensorsData instance based on informations of TensorsInfo
221         /// </summary>
222         /// <returns>TensorsData instance</returns>
223         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
224         /// <exception cref="ArgumentException">Thrown when the method failed due to TensorsInfo's information is invalid.</exception>
225         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
226         /// <since_tizen> 6 </since_tizen>
227         public TensorsData GetTensorsData()
228         {
229             IntPtr tensorsData_h;
230             TensorsData retTensorData;
231             NNStreamerError ret = NNStreamerError.None;
232
233             if (_handle == IntPtr.Zero)
234             {
235                 Log.Info(NNStreamer.TAG, "_handle is IntPtr.Zero\n" + "  GetTensorsInfoHandle() is called");
236                 GetTensorsInfoHandle();
237             }
238
239             ret = Interop.Util.CreateTensorsData(_handle, out tensorsData_h);
240             NNStreamer.CheckException(ret, "unable to create the tensorsData object");
241             Log.Info(NNStreamer.TAG, "success to CreateTensorsData()\n");
242
243             retTensorData = TensorsData.CreateFromNativeHandle(tensorsData_h);
244
245             return retTensorData;
246         }
247
248         internal IntPtr GetTensorsInfoHandle()
249         {
250             NNStreamerError ret = NNStreamerError.None;
251             IntPtr ret_handle;
252             int idx;
253
254             /* Already created */
255             if (_handle != IntPtr.Zero)
256                 return _handle;
257
258             /* Check required parameters */
259             int num = _infoList.Count;
260             if (num <= 0 || num > Tensor.SizeLimit)
261                 ret = NNStreamerError.InvalidParameter;
262             NNStreamer.CheckException(ret, "number of Tensor in TensorsInfo is invalid: " + _infoList.Count);
263
264             /* Create TensorsInfo object */
265             ret = Interop.Util.CreateTensorsInfo(out ret_handle);
266             NNStreamer.CheckException(ret, "fail to create TensorsInfo object");
267
268             /* Set the number of tensors */
269             ret = Interop.Util.SetTensorsCount(ret_handle, _infoList.Count);
270             NNStreamer.CheckException(ret, "unable to set the number of tensors");
271
272             /* Set each Tensor info */
273             idx = 0;
274             foreach (TensorInfo t in _infoList)
275             {
276                 ret = Interop.Util.SetTensorType(ret_handle, idx, t.Type);
277                 NNStreamer.CheckException(ret, "fail to set the type of tensor" + idx.ToString());
278
279                 ret = Interop.Util.SetTensorDimension(ret_handle, idx, t.Dimension);
280                 NNStreamer.CheckException(ret, "fail to set the dimension of tensor: " + idx.ToString());
281
282                 idx += 1;
283             }
284
285             _handle = ret_handle;
286             return ret_handle;
287         }
288
289         /// <summary>
290         /// Releases any unmanaged resources used by this object.
291         /// </summary>
292         /// <since_tizen> 6 </since_tizen>
293         public void Dispose()
294         {
295             Dispose(true);
296             GC.SuppressFinalize(this);
297         }
298
299         /// <summary>
300         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
301         /// </summary>
302         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
303         protected virtual void Dispose(bool disposing)
304         {
305             if (_disposed)
306                 return;
307
308             if (disposing)
309             {
310                 // release managed objects
311                 _infoList.Clear();
312             }
313
314             // release unmanaged objects
315             if (_handle != IntPtr.Zero)
316             {
317                 NNStreamerError ret = NNStreamerError.None;
318                 ret = Interop.Util.DestroyTensorsInfo(_handle);
319                 if (ret != NNStreamerError.None)
320                 {
321                     Log.Error(NNStreamer.TAG, "failed to destroy TensorsInfo object");
322                 }
323             }
324             _disposed = true;
325         }
326         
327         private void CheckIndexBoundary(int idx)
328         {
329             if (idx < 0 || idx >= _infoList.Count) {
330                 throw new IndexOutOfRangeException("Invalid index [" + idx + "] of the tensors");
331             }
332         }
333
334         private class TensorInfo
335         {
336             public TensorInfo(TensorType type, int[] dimension)
337             {
338                 Type = type;
339                 SetDimension(dimension);
340             }
341
342             public TensorInfo(string name, TensorType type, int[] dimension)
343             {
344                 Name = name;
345                 Type = type;
346                 SetDimension(dimension);
347             }
348
349             public void SetDimension(int[] dimension)
350             {
351                 if (dimension == null) {
352                     throw new ArgumentException("Max size of the tensor rank is" + Tensor.RankLimit);
353                 }
354
355                 if (dimension.Length > Tensor.RankLimit) {
356                     throw new ArgumentException("Max size of the tensor rank is" + Tensor.RankLimit);
357                 }
358                 Dimension = (int[])dimension.Clone();
359             }
360
361             public string Name { get; set; } = null;
362
363             public TensorType Type { get; set; } = TensorType.Int32;
364
365             public int[] Dimension { get; private set; } = new int[Tensor.RankLimit];
366         }
367     }
368 }