Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Half type arrays #115

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

Closed
martindevans opened this issue Feb 14, 2023 · 7 comments
Closed

Half type arrays #115

martindevans opened this issue Feb 14, 2023 · 7 comments

Comments

@martindevans
Copy link
Member

martindevans commented Feb 14, 2023

Problem

It isn't possible to create a numpy array from a Half[]

Example

This code:

var x = new[] { (Half)1, (Half)2, (Half)3 };
var y = np.array(x);

Produces this error:

System.ArgumentException: 'Can not convert type of given object to dtype: System.Half[]'

Expected

I expected this to create a new array with dtype == float16

@henon
Copy link
Contributor

henon commented Feb 14, 2023

This is the first time I learn of the new Half type. I can support it of course

@henon
Copy link
Contributor

henon commented Feb 14, 2023

Hmm, that is actually not that easy. Half is only available in .Net 5 and Numpy is still NetStandard 2.0

henon added a commit that referenced this issue Feb 14, 2023
@henon
Copy link
Contributor

henon commented Feb 14, 2023

Here is a workaround for you. You need to do some bit fiddling and you need to know exactly how float16 numbers are represented in binary. Then you can create a byte[] with two bytes per Half and create a numpy array from that like this:

        [TestMethod]
        public async Task F16Workaround()
        {
            // use byte array to create float16 array

            // numbers in float16:
            // 0 01111 0000000000 = 2^0 * (1 + 0/1024) = 1 
            // 1 01111 0000000000 = -1 * 2 ^ 0 * (1 + 0 / 1024) = -1
            // 0 11110 1111111111 = -1^(0) * 2^(15) * (1 + 1023/1024) β‰ˆ 65504
            // see: https://devblogs.microsoft.com/dotnet/introducing-the-half-type/

            // these bytes in binary notation correspond to f16 numbers 1, -1 and 65504 (float16 max value)
            // note, the bytes are in reversed order to the bits shown above
            var bytes = new byte[] { 
                0b00000000, 0b00111100, // 1
                0b00000000, 0b10111100, // -1
                0b11111111, 0b01111011, // 65504
            };
            var floats = np.zeros(new Shape(3), np.float16);
            Console.WriteLine(floats.repr);
            // note, the using prevents a mem-leak with ctypes
            using (var ctypes = floats.PyObject.ctypes) { 
                long ptr = ctypes.data;
                Marshal.Copy(bytes, 0, new IntPtr(ptr), bytes.Length);
            }
            Console.WriteLine(floats.repr);
            Assert.AreEqual("array([ 1.00e+00, -1.00e+00,  6.55e+04], dtype=float16)", floats.repr);
        }

I guess you can probably directly copy the bytes from a Half[] into a byte[] with Marshal.Copy or so.

@martindevans
Copy link
Member Author

Thanks, I'll give that a go tomorrow.

@henon
Copy link
Contributor

henon commented Feb 15, 2023

I'll also see if I can get multi targeting to work so I can support Half natively but it might take some time

@henon
Copy link
Contributor

henon commented Mar 1, 2023

@martindevans Sorry, I didn't have time to look into multi-targeting yet. Did the workaround help you?

@martindevans
Copy link
Member Author

I did test it a couple of weeks ago but in the end I decided to stick with float32, just for simplicity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants