-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Copy System.Numerics.Tensors sources from dotnet/corefx into onnxruntime #1605
Changes from all commits
66568da
d8d4119
3af74ca
4545d34
11b3507
4c8d56e
74449a3
219bc33
850f449
64cfc7e
579923f
bda3171
0776c04
678edcf
1575be4
6563fb4
1515187
51c7861
573af5f
359bce1
fa01acd
7e54a60
d79654d
74180a5
b00a956
beb104b
b23fa56
02a0485
0505e5a
7080bb7
46f0ff6
7e48d0e
a5f837d
4fb30b9
2422aa3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ | |
using System.Text; | ||
using System.IO; | ||
using Microsoft.ML.OnnxRuntime; | ||
using System.Numerics.Tensors; | ||
using Microsoft.ML.OnnxRuntime.Tensors; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think these couple new types need their own namespace? Would it be OK to just put the Tensor types in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kept it this way, I think it will be easier to switch, of add new api, if System.Numerics.Tensors is available. |
||
|
||
namespace CSharpUsage | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
// This file is copied and adapted from the following git repository - | ||
// https://github.com/dotnet/corefx | ||
// Commit ID: bdd0814360d4c3a58860919f292a306242f27da1 | ||
// Path: /src/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayTensorExtensions.cs | ||
// Original license statement below - | ||
|
||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
using System; | ||
|
||
namespace Microsoft.ML.OnnxRuntime.Tensors | ||
{ | ||
public static class ArrayTensorExtensions | ||
{ | ||
/// <summary> | ||
/// Creates a copy of this single-dimensional array as a DenseTensor<T> | ||
/// </summary> | ||
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam> | ||
/// <param name="array">The array to create a DenseTensor<T> from.</param> | ||
/// <returns>A 1-dimensional DenseTensor<T> with the same length and content as <paramref name="array"/>.</returns> | ||
public static DenseTensor<T> ToTensor<T>(this T[] array) | ||
{ | ||
return new DenseTensor<T>(array); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a copy of this two-dimensional array as a DenseTensor<T> | ||
/// </summary> | ||
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam> | ||
/// <param name="array">The array to create a DenseTensor<T> from.</param> | ||
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): row-major. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): column-major.</param> | ||
/// <returns>A 2-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns> | ||
public static DenseTensor<T> ToTensor<T>(this T[,] array, bool reverseStride = false) | ||
{ | ||
return new DenseTensor<T>(array, reverseStride); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a copy of this three-dimensional array as a DenseTensor<T> | ||
/// </summary> | ||
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam> | ||
/// <param name="array">The array to create a DenseTensor<T> from.</param> | ||
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param> | ||
/// <returns>A 3-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns> | ||
public static DenseTensor<T> ToTensor<T>(this T[,,] array, bool reverseStride = false) | ||
{ | ||
return new DenseTensor<T>(array, reverseStride); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a copy of this n-dimensional array as a DenseTensor<T> | ||
/// </summary> | ||
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam> | ||
/// <param name="array">The array to create a DenseTensor<T> from.</param> | ||
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param> | ||
/// <returns>A n-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns> | ||
public static DenseTensor<T> ToTensor<T>(this Array array, bool reverseStride = false) | ||
{ | ||
return new DenseTensor<T>(array, reverseStride); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
// This file is copied and adapted from the following git repository - | ||
// https://github.com/dotnet/corefx | ||
// Commit ID: bdd0814360d4c3a58860919f292a306242f27da1 | ||
// Path: /src/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayUtilities.cs | ||
// Original license statement below - | ||
|
||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Diagnostics; | ||
using System; | ||
|
||
namespace Microsoft.ML.OnnxRuntime.Tensors | ||
{ | ||
internal static class ArrayUtilities | ||
{ | ||
public const int StackallocMax = 16; | ||
|
||
public static long GetProduct(ReadOnlySpan<int> dimensions, int startIndex = 0) | ||
{ | ||
if (dimensions.Length == 0) | ||
{ | ||
return 0; | ||
} | ||
|
||
long product = 1; | ||
for (int i = startIndex; i < dimensions.Length; i++) | ||
{ | ||
if (dimensions[i] < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException($"{nameof(dimensions)}[{i}]"); | ||
} | ||
|
||
// we use a long which should be much larger than is ever used here, | ||
// but still force checked | ||
checked | ||
{ | ||
product *= dimensions[i]; | ||
} | ||
} | ||
|
||
return product; | ||
} | ||
|
||
public static bool IsAscending(ReadOnlySpan<int> values) | ||
{ | ||
for (int i = 1; i < values.Length; i++) | ||
{ | ||
if (values[i] < values[i - 1]) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public static bool IsDescending(ReadOnlySpan<int> values) | ||
{ | ||
for (int i = 1; i < values.Length; i++) | ||
{ | ||
if (values[i] > values[i - 1]) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the set of strides that can be used to calculate the offset of n-dimensions in a 1-dimensional layout | ||
/// </summary> | ||
/// <param name="dimensions"></param> | ||
/// <param name="reverseStride"></param> | ||
/// <returns></returns> | ||
public static int[] GetStrides(ReadOnlySpan<int> dimensions, bool reverseStride = false) | ||
{ | ||
int[] strides = new int[dimensions.Length]; | ||
|
||
int stride = 1; | ||
if (reverseStride) | ||
{ | ||
for (int i = 0; i < strides.Length; i++) | ||
{ | ||
strides[i] = stride; | ||
stride *= dimensions[i]; | ||
} | ||
} | ||
else | ||
{ | ||
for (int i = strides.Length - 1; i >= 0; i--) | ||
{ | ||
strides[i] = stride; | ||
stride *= dimensions[i]; | ||
} | ||
} | ||
|
||
return strides; | ||
} | ||
|
||
public static void SplitStrides(int[] strides, int[] splitAxes, int[] newStrides, int stridesOffset, int[] splitStrides, int splitStridesOffset) | ||
{ | ||
int newStrideIndex = 0; | ||
for (int i = 0; i < strides.Length; i++) | ||
{ | ||
int stride = strides[i]; | ||
bool isSplit = false; | ||
for (int j = 0; j < splitAxes.Length; j++) | ||
{ | ||
if (splitAxes[j] == i) | ||
{ | ||
splitStrides[splitStridesOffset + j] = stride; | ||
isSplit = true; | ||
break; | ||
} | ||
} | ||
|
||
if (!isSplit) | ||
{ | ||
newStrides[stridesOffset + newStrideIndex++] = stride; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Calculates the 1-d index for n-d indices in layout specified by strides. | ||
/// </summary> | ||
/// <param name="strides"></param> | ||
/// <param name="indices"></param> | ||
/// <param name="startFromDimension"></param> | ||
/// <returns></returns> | ||
public static int GetIndex(int[] strides, ReadOnlySpan<int> indices, int startFromDimension = 0) | ||
{ | ||
Debug.Assert(strides.Length == indices.Length); | ||
|
||
int index = 0; | ||
for (int i = startFromDimension; i < indices.Length; i++) | ||
{ | ||
index += strides[i] * indices[i]; | ||
} | ||
|
||
return index; | ||
} | ||
|
||
/// <summary> | ||
/// Calculates the n-d indices from the 1-d index in a layout specificed by strides | ||
/// </summary> | ||
/// <param name="strides"></param> | ||
/// <param name="reverseStride"></param> | ||
/// <param name="index"></param> | ||
/// <param name="indices"></param> | ||
/// <param name="startFromDimension"></param> | ||
public static void GetIndices(ReadOnlySpan<int> strides, bool reverseStride, int index, int[] indices, int startFromDimension = 0) | ||
{ | ||
Debug.Assert(reverseStride ? IsAscending(strides) : IsDescending(strides), "Index decomposition requires ordered strides"); | ||
Debug.Assert(strides.Length == indices.Length); | ||
|
||
int remainder = index; | ||
for (int i = startFromDimension; i < strides.Length; i++) | ||
{ | ||
// reverse the index for reverseStride so that we divide by largest stride first | ||
var nIndex = reverseStride ? strides.Length - 1 - i : i; | ||
|
||
var stride = strides[nIndex]; | ||
indices[nIndex] = remainder / stride; | ||
remainder %= stride; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Calculates the n-d indices from the 1-d index in a layout specificed by strides | ||
/// </summary> | ||
/// <param name="strides"></param> | ||
/// <param name="reverseStride"></param> | ||
/// <param name="index"></param> | ||
/// <param name="indices"></param> | ||
/// <param name="startFromDimension"></param> | ||
public static void GetIndices(ReadOnlySpan<int> strides, bool reverseStride, int index, Span<int> indices, int startFromDimension = 0) | ||
{ | ||
Debug.Assert(reverseStride ? IsAscending(strides) : IsDescending(strides), "Index decomposition requires ordered strides"); | ||
Debug.Assert(strides.Length == indices.Length); | ||
|
||
int remainder = index; | ||
for (int i = startFromDimension; i < strides.Length; i++) | ||
{ | ||
// reverse the index for reverseStride so that we divide by largest stride first | ||
var nIndex = reverseStride ? strides.Length - 1 - i : i; | ||
|
||
var stride = strides[nIndex]; | ||
indices[nIndex] = remainder / stride; | ||
remainder %= stride; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Takes an 1-d index over n-d sourceStrides and recalculates it assuming same n-d coordinates over a different n-d strides | ||
/// </summary> | ||
public static int TransformIndexByStrides(int index, int[] sourceStrides, bool sourceReverseStride, int[] transformStrides) | ||
{ | ||
Debug.Assert(index >= 0); | ||
Debug.Assert(sourceReverseStride ? IsAscending(sourceStrides) : IsDescending(sourceStrides), "Index decomposition requires ordered strides"); | ||
Debug.Assert(sourceStrides.Length == transformStrides.Length); | ||
|
||
int transformIndex = 0; | ||
int remainder = index; | ||
|
||
for (int i = 0; i < sourceStrides.Length; i++) | ||
{ | ||
// reverse the index for reverseStride so that we divide by largest stride first | ||
var nIndex = sourceReverseStride ? sourceStrides.Length - 1 - i: i; | ||
|
||
var sourceStride = sourceStrides[nIndex]; | ||
var transformStride = transformStrides[nIndex]; | ||
|
||
transformIndex += transformStride * (remainder / sourceStride); | ||
remainder %= sourceStride; | ||
} | ||
|
||
return transformIndex; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An easier way to accomplish this is to set this property in a
Directory.Build.props
file. That way it is only set in 1 spot, when you add a new .csproj you don't need to add it here, and it is set for all targets that are run (not justRestore
).We do it that way in ML.NET here: https://github.com/dotnet/machinelearning/blob/365ccf292789ba1f14d80b13e44daaf951517fff/Directory.Build.props#L53
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just in case you didn't know - Directory.Build.props files are automatically imported to every project under that folder. So if you add the file to the
csharp
directory, all .csproj files under that directory will inherit those properties.In reply to: 313892277 [](ancestors = 313892277)