Skip to content

Commit d290881

Browse files
KsenijaScodemzs
authored andcommitted
Tensor extensions (#4260)
* Add TensorTypeExtensions * Upgrade performance by replacing ToArray method * Fix failing tests * Remove unused code * Remove duplicate file TensorTypeExtensions * Remove comented code * Add exceptions * Add copyright header * Rename ToSpan to CopyTo * Use Utils.EnsureSize method * Use CopyTo method to copy the values to span * Fix Destination too short error * Call CopyTo inside ToArray method to ensure code reuse * No need to assign values span to dst * Use checked keyword around cast to len * Set keepOld to false instead of true in Utils.EnsureSize * Add assert to ensure that imageArray and featurizedImage are the same size * Cast tensor.size to int instead of long * Remove FetchData since it's no longer used * Add checked keyword around cast
1 parent 4088620 commit d290881

File tree

5 files changed

+82
-27
lines changed

5 files changed

+82
-27
lines changed

src/Microsoft.ML.Dnn/DnnRetrainTransform.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,14 +379,18 @@ private void TrainCore(DnnRetrainEstimator.Options options, IDataView input, IDa
379379
ITensorValueGetter[] srcTensorGetters,
380380
Runner runner)
381381
{
382-
float loss = 0;
383-
float metric = 0;
382+
float loss = 0.0f;
383+
float metric = 0.0f;
384384
for (int i = 0; i < inputs.Length; i++)
385385
runner.AddInput(inputs[i], srcTensorGetters[i].GetBufferedBatchTensor());
386386

387387
Tensor[] tensor = runner.Run();
388-
loss = tensor.Length > 0 && tensor[0] != IntPtr.Zero ? (float)tensor[0].ToArray<float>()[0] : 0.0f;
389-
metric = tensor.Length > 1 && tensor[1] != IntPtr.Zero ? (float)tensor[1].ToArray<float>()[0] : 0.0f;
388+
if (tensor.Length > 0 && tensor[0] != IntPtr.Zero)
389+
tensor[0].ToScalar<float>(ref loss);
390+
391+
if (tensor.Length > 1 && tensor[1] != IntPtr.Zero)
392+
tensor[1].ToScalar<float>(ref metric);
393+
390394
return (loss, metric);
391395
}
392396

@@ -871,7 +875,7 @@ private Delegate MakeGetter<T>(DataViewRow input, int iinfo, ITensorValueGetter[
871875
UpdateCacheIfNeeded(input.Position, srcTensorGetters, activeOutputColNames, outputCache);
872876

873877
var tensor = outputCache.Outputs[_parent._outputs[iinfo]];
874-
dst = tensor.ToArray<T>()[0];
878+
tensor.ToScalar<T>(ref dst);
875879
};
876880
return valuegetter;
877881
}
@@ -903,7 +907,7 @@ private Delegate MakeGetter<T>(DataViewRow input, int iinfo, ITensorValueGetter[
903907

904908
var editor = VBufferEditor.Create(ref dst, (int)tensorSize);
905909

906-
DnnUtils.FetchData<T>(tensor.ToArray<T>(), editor.Values);
910+
tensor.CopyTo<T>(editor.Values);
907911
dst = editor.Commit();
908912
};
909913
return valuegetter;

src/Microsoft.ML.Dnn/DnnUtils.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,6 @@ internal static Session GetSession(IHostEnvironment env, string modelPath, bool
277277
return LoadTFSessionByModelFilePath(env, modelPath, metaGraph);
278278
}
279279

280-
internal static unsafe void FetchData<T>(T[] data, Span<T> result)
281-
{
282-
var dataCopy = new T[data.Length];
283-
Array.Copy(data, dataCopy, data.Length);
284-
var dataSpan = new Span<T>(dataCopy, 0, result.Length);
285-
dataSpan.CopyTo(result);
286-
}
287-
288280
internal static unsafe void FetchStringData<T>(Tensor tensor, Span<T> result)
289281
{
290282
if (tensor == null)

src/Microsoft.ML.Dnn/ImageClassificationTransform.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,18 @@ private void CacheFeaturizedImagesToDisk(IDataView input, string labelColumnName
235235
ImageClassificationMetrics metrics = new ImageClassificationMetrics();
236236
metrics.Bottleneck = new BottleneckMetrics();
237237
metrics.Bottleneck.DatasetUsed = dataset;
238+
float[] imageArray = null;
238239
while (cursor.MoveNext())
239240
{
240241
labelGetter(ref label);
241242
imagePathGetter(ref imagePath);
242243
var imagePathStr = imagePath.ToString();
243244
var imageTensor = imageProcessor.ProcessImage(imagePathStr);
244245
runner.AddInput(imageTensor, 0);
245-
var featurizedImage = runner.Run()[0]; // Reuse memory?
246-
writer.WriteLine(label - 1 + "," + string.Join(",", featurizedImage.ToArray<float>()));
246+
var featurizedImage = runner.Run()[0]; // Reuse memory
247+
featurizedImage.ToArray<float>(ref imageArray);
248+
Host.Assert((int)featurizedImage.size == imageArray.Length);
249+
writer.WriteLine(label - 1 + "," + string.Join(",", imageArray));
247250
featurizedImage.Dispose();
248251
imageTensor.Dispose();
249252
metrics.Bottleneck.Index++;
@@ -338,6 +341,8 @@ private void TrainAndEvaluateClassificationLayer(string trainBottleneckFilePath,
338341

339342
ImageClassificationMetrics metrics = new ImageClassificationMetrics();
340343
metrics.Train = new TrainMetrics();
344+
float accuracy = 0;
345+
float crossentropy = 0;
341346
for (int epoch = 0; epoch < epochs; epoch += 1)
342347
{
343348
metrics.Train.Accuracy = 0;
@@ -378,8 +383,10 @@ private void TrainAndEvaluateClassificationLayer(string trainBottleneckFilePath,
378383
.AddInput(new Tensor(labelBatchPtr, labelTensorShape, TF_DataType.TF_INT64, labelBatchSizeInBytes), 1)
379384
.Run();
380385

381-
metrics.Train.Accuracy += outputTensors[0].ToArray<float>()[0];
382-
metrics.Train.CrossEntropy += outputTensors[1].ToArray<float>()[0];
386+
outputTensors[0].ToScalar<float>(ref accuracy);
387+
outputTensors[1].ToScalar<float>(ref crossentropy);
388+
metrics.Train.Accuracy += accuracy;
389+
metrics.Train.CrossEntropy += crossentropy;
383390

384391
outputTensors[0].Dispose();
385392
outputTensors[1].Dispose();
@@ -429,7 +436,8 @@ private void TrainAndEvaluateClassificationLayer(string trainBottleneckFilePath,
429436
.AddInput(new Tensor(labelBatchPtr, labelTensorShape, TF_DataType.TF_INT64, labelBatchSizeInBytes), 1)
430437
.Run();
431438

432-
metrics.Train.Accuracy += outputTensors[0].ToArray<float>()[0];
439+
outputTensors[0].ToScalar<float>(ref accuracy);
440+
metrics.Train.Accuracy += accuracy;
433441
metrics.Train.BatchProcessedCount += 1;
434442
batchIndex = 0;
435443

@@ -799,8 +807,10 @@ private class OutputCache
799807
private ReadOnlyMemory<char> _imagePath;
800808
private Runner _runner;
801809
private ImageProcessor _imageProcessor;
802-
public UInt32 PredictedLabel { get; set; }
803-
public float[] ClassProbabilities { get; set; }
810+
private long _predictedLabel;
811+
public UInt32 PredictedLabel => (uint)_predictedLabel;
812+
private float[] _classProbability;
813+
public float[] ClassProbabilities => _classProbability;
804814
private DataViewRow _inputRow;
805815

806816
public OutputCache(DataViewRow input, ImageClassificationTransformer transformer)
@@ -826,8 +836,8 @@ public void UpdateCacheIfNeeded()
826836
_imagePathGetter(ref _imagePath);
827837
var processedTensor = _imageProcessor.ProcessImage(_imagePath.ToString());
828838
var outputTensor = _runner.AddInput(processedTensor, 0).Run();
829-
ClassProbabilities = outputTensor[0].ToArray<float>();
830-
PredictedLabel = (UInt32)outputTensor[1].ToArray<long>()[0];
839+
outputTensor[0].ToArray<float>(ref _classProbability);
840+
outputTensor[1].ToScalar<long>(ref _predictedLabel);
831841
outputTensor[0].Dispose();
832842
outputTensor[1].Dispose();
833843
processedTensor.Dispose();
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using Microsoft.ML.Internal.Utilities;
7+
using NumSharp.Backends;
8+
using NumSharp.Backends.Unmanaged;
9+
using NumSharp.Utilities;
10+
using Tensorflow;
11+
12+
namespace Microsoft.ML.Transforms
13+
{
14+
[BestFriend]
15+
internal static class TensorTypeExtensions
16+
{
17+
public static void ToScalar<T>(this Tensor tensor, ref T dst) where T : unmanaged
18+
{
19+
if (typeof(T).as_dtype() != tensor.dtype)
20+
throw new NotSupportedException();
21+
22+
unsafe
23+
{
24+
dst = *(T*)tensor.buffer;
25+
}
26+
27+
}
28+
29+
public static void CopyTo<T>(this Tensor tensor, Span<T> values) where T: unmanaged
30+
{
31+
if (typeof(T).as_dtype() != tensor.dtype)
32+
throw new NotSupportedException();
33+
34+
unsafe
35+
{
36+
var len = checked((int)tensor.size);
37+
var src = (T*)tensor.buffer;
38+
var span = new Span<T>(src, len);
39+
span.CopyTo(values);
40+
}
41+
}
42+
43+
public static void ToArray<T>(this Tensor tensor, ref T[] array) where T : unmanaged
44+
{
45+
Utils.EnsureSize(ref array, (int)tensor.size, (int)tensor.size, false);
46+
var span = new Span<T>(array);
47+
48+
CopyTo(tensor, span);
49+
}
50+
}
51+
}

src/Microsoft.ML.TensorFlow/TensorflowTransform.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -593,15 +593,13 @@ protected override Delegate MakeGetter(DataViewRow input, int iinfo, Func<int, b
593593
private Delegate MakeGetter<T>(DataViewRow input, int iinfo, ITensorValueGetter[] srcTensorGetters, string[] activeOutputColNames, OutputCache outputCache) where T : unmanaged
594594
{
595595
Host.AssertValue(input);
596-
597596
if (_parent.OutputTypes[iinfo].IsStandardScalar())
598597
{
599598
ValueGetter<T> valuegetter = (ref T dst) =>
600599
{
601600
UpdateCacheIfNeeded(input.Position, srcTensorGetters, activeOutputColNames, outputCache);
602-
603601
var tensor = outputCache.Outputs[_parent.Outputs[iinfo]];
604-
dst = tensor.ToArray<T>()[0];
602+
tensor.ToScalar<T>(ref dst);
605603
};
606604
return valuegetter;
607605
}
@@ -633,7 +631,7 @@ private Delegate MakeGetter<T>(DataViewRow input, int iinfo, ITensorValueGetter[
633631

634632
var editor = VBufferEditor.Create(ref dst, (int)tensorSize);
635633

636-
DnnUtils.FetchData<T>(tensor.ToArray<T>(), editor.Values);
634+
tensor.CopyTo<T>(editor.Values);
637635
dst = editor.Commit();
638636
};
639637
return valuegetter;

0 commit comments

Comments
 (0)