Skip to content
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

[API Proposal]: TensorPrimitives: convert Span<Byte> to Span<Float> and back #103756

Open
vpenades opened this issue Jun 20, 2024 · 6 comments
Open
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Numerics.Tensors
Milestone

Comments

@vpenades
Copy link

vpenades commented Jun 20, 2024

Background and motivation

Working with images and tensors, it is fairly common to convert an array of bytes to an array of floats.

Also, in many cases the conversion requires some normalization or scaling, that is, byte values in the range of 0-255 are converted to float values in the range of 0-1

The usual operation is this:

var src = new byte[100];
var dst = new float[100];

for(int i=0; i < dst.Length; ++i)
{
   dst[i] = (float)src[i] / 255f;
}

Now, I don't know if there's faster way of doing this using SIMD, or any other exotic, platform specific mechanism, but if it doesn't exist now, it may exist in the future, so by using a system function, any current application may benefit from future improvements on the API.

Also, I don't know if this conversion already exists somewhere else in the APIs, I've looked for it without success. But certainly, I would expect such conversions to be available in TensorPrimitives.

My needs are limited to byte-float conversions, but certainly, other types may be included.

API Proposal

static class TensorPrimitives
{
   public static void ConvertToSingle(ReadOnlySpan<byte> src, Span<float> dst);
   public static void ConvertToScaledSingle(ReadOnlySpan<byte> src, Span<float> dst);

   public static void ConvertToByte(ReadOnlySpan<float> src, Span<byte> dst);
   public static void ConvertScaledToByte(ReadOnlySpan<float> src, Span<byte> dst);
}

API Usage

namespace System.Numerics.Tensors

var bytes = byte[100];
var floats = float[199];

TensorPrimitives.ConvertToSingle(bytes,floats); // converts bytes to floats in the range 0-255
TensorPrimitives.ConvertToScaledSingle(bytes,floats); // converts bytes to floats in the range 0-1

TensorPrimitives.ConvertToByte(floats, bytes); // converts floats in the range 0-255 to bytes in the range 0-255
TensorPrimitives.ConvertScaledToByte(floats,bytes); // converts floats in the range 0-1 to bytes in the range 0-255

Alternative Designs

No response

Risks

No response

@vpenades vpenades added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Jun 20, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jun 20, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jun 20, 2024
@huoyaoyuan huoyaoyuan added area-System.Numerics.Tensors and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jun 20, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-numerics-tensors
See info in area-owners.md if you want to be subscribed.

@stephentoub
Copy link
Member

stephentoub commented Jun 20, 2024

Converting between two different types is supported via the generic TensorPrimitives.ConvertTruncating, ConvertSaturating, and ConvertChecked methods. There's no built-in operation that currently combines that with the divide, but it can be done with a second call:

ReadOnlySpan<byte> bytes = RandomNumberGenerator.GetBytes(100);
Span<float> floats = new float[bytes.Length];

TensorPrimitives.ConvertTruncating(bytes, floats);
TensorPrimitives.Divide(floats, 255.0f, floats);

@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Jun 20, 2024
@vpenades
Copy link
Author

vpenades commented Jun 20, 2024

No wonder I could not find these methods.... they're in the Net9 preview packages, is that right?

Anyway, given it's in preview, I would still include a byte to float conversion with divide: it's such a common operation that any future improvement would automatically be used by everybody, that is, imagine that some platform introduces a fast path for this exact operation...

@vpenades vpenades reopened this Jun 20, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jun 20, 2024
@stephentoub
Copy link
Member

they're in the Net9 preview packages, is that right?

Yes

@vpenades
Copy link
Author

vpenades commented Jun 21, 2024

Looking at the code, I don't see that ConvertTruncating has any kind of vectorial acceleration code to convert byte to float. Right now, is there an advantage of using ConvertTruncating, over a plain loop?

@stephentoub
Copy link
Member

Looking at the code, I don't see that ConvertTruncating has any kind of vectorial acceleration code to convert byte to float. Right now, is there an advantage of using ConvertTruncating, over a plain loop?

Not in what's merged, but that's just a matter of adding an additional path for these types, e.g.
#103820

@stephentoub stephentoub added this to the Future milestone Jul 19, 2024
@jeffhandley jeffhandley removed the untriaged New issue has not been triaged by the area owner label Jul 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Numerics.Tensors
Projects
None yet
Development

No branches or pull requests

4 participants