forked from SciSharp/TensorFlow.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBaseSession.cs
More file actions
472 lines (414 loc) · 22.9 KB
/
BaseSession.cs
File metadata and controls
472 lines (414 loc) · 22.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*****************************************************************************
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
******************************************************************************/
using NumSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using Google.Protobuf;
using static Tensorflow.Binding;
using Tensorflow.Util;
namespace Tensorflow
{
public class BaseSession : DisposableObject
{
protected Graph _graph;
protected bool _opened;
protected bool _closed;
protected int _current_version;
protected byte[] _target;
public Graph graph => _graph;
public BaseSession(string target = "", Graph g = null, ConfigProto config = null, Status status = null)
{
_graph = g ?? ops.get_default_graph();
_graph.as_default();
_target = Encoding.UTF8.GetBytes(target);
using (var opts = new SessionOptions(target, config))
{
lock (Locks.ProcessWide)
{
status = status ?? new Status();
_handle = c_api.TF_NewSession(_graph, opts.Handle, status.Handle);
status.Check(true);
}
}
}
public virtual void run(Operation op, params FeedItem[] feed_dict)
{
_run(op, feed_dict);
}
public virtual NDArray run(Tensor fetche, params FeedItem[] feed_dict)
{
return _run(fetche, feed_dict)[0];
}
public virtual NDArray run(ITensorOrOperation fetche, params FeedItem[] feed_dict)
{
var results = _run(fetche, feed_dict);
return fetche is Tensor ? results[0] : null;
}
public virtual (NDArray, NDArray, NDArray, NDArray, NDArray) run(
(ITensorOrOperation, ITensorOrOperation, ITensorOrOperation, ITensorOrOperation, ITensorOrOperation) fetches,
params FeedItem[] feed_dict)
{
var results = _run(new object[] { fetches.Item1, fetches.Item2, fetches.Item3, fetches.Item4, fetches.Item5 }, feed_dict);
return (results[0], results[1], results[2], results[3], results[4]);
}
public virtual (NDArray, NDArray, NDArray, NDArray) run((ITensorOrOperation, ITensorOrOperation, ITensorOrOperation, ITensorOrOperation) fetches, params FeedItem[] feed_dict)
{
var results = _run(new object[] {fetches.Item1, fetches.Item2, fetches.Item3, fetches.Item4}, feed_dict);
return (results[0], results[1], results[2], results[3]);
}
public virtual (NDArray, NDArray, NDArray) run((ITensorOrOperation, ITensorOrOperation, ITensorOrOperation) fetches, params FeedItem[] feed_dict)
{
var results = _run(new object[] {fetches.Item1, fetches.Item2, fetches.Item3}, feed_dict);
return (results[0], results[1], results[2]);
}
public virtual (NDArray, NDArray) run((ITensorOrOperation, ITensorOrOperation) fetches, params FeedItem[] feed_dict)
{
var results = _run(new object[] {fetches.Item1, fetches.Item2}, feed_dict);
return (results[0], results[1]);
}
public virtual NDArray[] run(object fetches, params FeedItem[] feed_dict)
{
return _run(fetches, feed_dict);
}
public virtual NDArray[] run(object fetches, Hashtable feed_dict = null)
{
var feed_items = feed_dict == null ? new FeedItem[0] : feed_dict.Keys.OfType<object>().Select(key => new FeedItem(key, feed_dict[key])).ToArray();
return _run(fetches, feed_items);
}
private NDArray[] _run(object fetches, FeedItem[] feed_dict = null)
{
var feed_dict_tensor = new Dictionary<object, object>();
//var feed_map = new Dictionary<object, object>();
// Validate and process feed_dict.
if (feed_dict != null)
{
foreach (var subfeed in feed_dict)
{
var subfeed_t = _graph.as_graph_element(subfeed.Key, allow_tensor: true, allow_operation: false);
//var target_dtype = subfeed_t.dtype.as_numpy_typecode(); // subfeed_dtype was never used
feed_dict_tensor[subfeed_t] = subfeed.Value;
//feed_map[subfeed_t.name] = (subfeed_t, subfeed.Value);
}
}
// Create a fetch handler to take care of the structure of fetches.
var fetch_handler = new _FetchHandler(_graph, fetches, feed_dict_tensor);
// Run request and get response.
// We need to keep the returned movers alive for the following _do_run().
// These movers are no longer needed when _do_run() completes, and
// are deleted when `movers` goes out of scope when this _run() ends.
var _ = _update_with_movers();
var final_fetches = fetch_handler.fetches();
var final_targets = fetch_handler.targets();
// We only want to really perform the run if fetches or targets are provided,
// or if the call is a partial run that specifies feeds.
var results = _do_run(final_targets.Select(x => (Operation) x).ToList(), final_fetches, feed_dict_tensor);
return fetch_handler.build_results(this, results);
}
/// <summary>
/// Runs a step based on the given fetches and feeds.
/// </summary>
/// <param name="target_list">A list of operations to be run, but not fetched.</param>
/// <param name="fetch_list"></param>
/// <param name="feed_dict"></param>
/// <returns>
/// A list of numpy ndarrays, corresponding to the elements of
/// `fetch_list`. If the ith element of `fetch_list` contains the
/// name of an operation, the first Tensor output of that operation
/// will be returned for that element.
/// </returns>
private NDArray[] _do_run(List<Operation> target_list, List<Tensor> fetch_list, Dictionary<object, object> feed_dict)
{
var feeds = new KeyValuePair<TF_Output, Tensor>[feed_dict.Count];
int i = 0;
foreach (var x in feed_dict)
{
if (x.Key is Tensor key)
{
switch (x.Value)
{
case Tensor v:
if (v.dtype != key.dtype)
throw new ValueError($"Tensor {v} does not match the expected dtype {key.dtype}, actual dtype: {v.dtype}");
feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), v);
break;
case NDArray v:
feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype));
break;
case IntPtr v:
var tensor = new Tensor(v);
if (tensor.dtype != key.dtype)
throw new ValueError($"Tensor {v} does not match the expected dtype {key.dtype}, actual dtype: {tensor.dtype}");
feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), tensor);
break;
#if _REGEN
// @formatter:off — disable formatter after this line
%types = ["bool", "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"]
%foreach types%
case #1 v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case #1[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
%
// @formatter:on — enable formatter after this line
#else
// @formatter:off — disable formatter after this line
case bool v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case bool[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case sbyte v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case sbyte[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case byte v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case byte[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case short v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case short[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case ushort v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case ushort[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case int v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case int[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case uint v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case uint[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case long v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case long[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case ulong v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case ulong[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case float v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case float[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case double v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case double[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case Complex v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
case Complex[] v: feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break;
// @formatter:on — enable formatter after this line
#endif
case string v:
feeds[i++] = new KeyValuePair<TF_Output, Tensor>(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype));
break;
default:
throw new NotImplementedException($"feed_dict data type {x.Value?.GetType().Name ?? "<null>"}");
}
}
}
var fetches = fetch_list.Select(x => x._as_tf_output()).ToArray();
//var targets = target_list;
return _call_tf_sessionrun(feeds, fetches, target_list);
}
private unsafe NDArray[] _call_tf_sessionrun(KeyValuePair<TF_Output, Tensor>[] feed_dict, TF_Output[] fetch_list, List<Operation> target_list)
{
// Ensure any changes to the graph are reflected in the runtime.
_extend_graph();
var status = tf.Status;
var output_values = fetch_list.Select(x => IntPtr.Zero).ToArray();
c_api.TF_SessionRun(_handle,
run_options: null,
inputs: feed_dict.Select(f => f.Key).ToArray(),
input_values: feed_dict.Select(f => (IntPtr) f.Value).ToArray(),
ninputs: feed_dict.Length,
outputs: fetch_list,
output_values: output_values,
noutputs: fetch_list.Length,
target_opers: target_list.Select(f => (IntPtr) f).ToArray(),
ntargets: target_list.Count,
run_metadata: IntPtr.Zero,
status: status.Handle);
status.Check(true);
var result = new NDArray[fetch_list.Length];
for (int i = 0; i < fetch_list.Length; i++)
result[i] = fetchValue(output_values[i]);
return result;
}
private static unsafe NDArray fetchValue(IntPtr output)
{
NDArray ret;
using (var tensor = new Tensor(output))
{
var ndims = tensor.shape;
var srcAddress = c_api.TF_TensorData(output).ToInt64();
if (ndims.Length == 0)
{
switch (tensor.dtype)
{
case TF_DataType.TF_BOOL:
ret = NDArray.Scalar(*(bool*) srcAddress);
break;
case TF_DataType.TF_STRING:
using (var reader = new CodedInputStream(new IntPtr(srcAddress).Stream(8, (long) tensor.bytesize)))
ret = new NDArray(reader.ReadBytes().ToByteArray());
break;
case TF_DataType.TF_UINT8:
ret = NDArray.Scalar(*(byte*) srcAddress);
break;
case TF_DataType.TF_INT16:
ret = NDArray.Scalar(*(short*) srcAddress);
break;
case TF_DataType.TF_INT32:
ret = NDArray.Scalar(*(int*) srcAddress);
break;
case TF_DataType.TF_INT64:
ret = NDArray.Scalar(*(long*) srcAddress);
break;
case TF_DataType.TF_UINT16:
ret = NDArray.Scalar(*(ushort*) srcAddress);
break;
case TF_DataType.TF_UINT32:
ret = NDArray.Scalar(*(uint*) srcAddress);
break;
case TF_DataType.TF_UINT64:
ret = NDArray.Scalar(*(ulong*) srcAddress);
break;
case TF_DataType.TF_FLOAT:
ret = NDArray.Scalar(*(float*) srcAddress);
break;
case TF_DataType.TF_DOUBLE:
ret = NDArray.Scalar(*(double*) srcAddress);
break;
default:
throw new NotImplementedException("can't fetch output");
}
} else
{
//var size = (long) tensor.size;
//var itemsize = (long) tensor.itemsize;
var bytesize = (long) tensor.bytesize;
var src = (void*) srcAddress;
#if _REGEN
#region Compute
switch (tensor.dtype)
{
%foreach except(supported_dtypes, "Char"),except(supported_dtypes_lowercase, "char"),except(supported_dtypes_TF_DataType,"TF_STRING")%
case TF_DataType.#3:
{
ret = new NDArray(NPTypeCode.#1, ndims, false);
System.Buffer.MemoryCopy(src, #(#3=="TF_STRING"|"(byte*)ret.Unsafe.Address + 8"|"ret.Unsafe.Address"), bytesize, bytesize);
break;
}
%
case TF_DataType.TF_STRING:
{
//TODO:! This is not the way to handle string[], it should be done with TF_DecodeString
using (var reader = new CodedInputStream(new IntPtr(srcAddress).Stream(8, (long)tensor.bytesize)))
ret = NDArray.FromString(reader.ReadString());
break;
}
default:
throw new NotSupportedException();
}
#endregion
#else
#region Compute
switch (tensor.dtype)
{
case TF_DataType.TF_BOOL:
{
ret = new NDArray(NPTypeCode.Boolean, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_UINT8:
{
ret = new NDArray(NPTypeCode.Byte, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_INT16:
{
ret = new NDArray(NPTypeCode.Int16, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_UINT16:
{
ret = new NDArray(NPTypeCode.UInt16, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_INT32:
{
ret = new NDArray(NPTypeCode.Int32, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_UINT32:
{
ret = new NDArray(NPTypeCode.UInt32, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_INT64:
{
ret = new NDArray(NPTypeCode.Int64, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_UINT64:
{
ret = new NDArray(NPTypeCode.UInt64, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_DOUBLE:
{
ret = new NDArray(NPTypeCode.Double, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_FLOAT:
{
ret = new NDArray(NPTypeCode.Single, ndims, false);
System.Buffer.MemoryCopy(src, ret.Unsafe.Address, bytesize, bytesize);
break;
}
case TF_DataType.TF_STRING:
{
throw new NotImplementedException();
//TODO:! This is not the way to handle string[], it should be done with TF_DecodeString
#pragma warning disable CS0162 // Unreachable code detected
using (var reader = new CodedInputStream(new IntPtr(srcAddress).Stream(8, (long) tensor.bytesize)))
#pragma warning restore CS0162 // Unreachable code detected
ret = NDArray.FromString(reader.ReadString());
break;
}
default:
throw new NotSupportedException();
}
#endregion
#endif
}
}
return ret;
}
/// <summary>
/// If a tensor handle that is fed to a device incompatible placeholder,
/// we move the tensor to the right device, generate a new tensor handle,
/// and update feed_dict to use the new handle.
/// </summary>
private List<object> _update_with_movers()
{
return new List<object> { };
}
private void _extend_graph()
{ }
public void close()
{
Dispose();
}
protected override void DisposeUnmanagedResources(IntPtr handle)
{
lock (Locks.ProcessWide)
using (var status = new Status())
{
c_api.TF_DeleteSession(handle, status.Handle);
status.Check(true);
}
}
}
}