Skip to content

Commit

Permalink
Introduce MLNumber for specifying numeric inputs of any type (#647)
Browse files Browse the repository at this point in the history
For some `MLGraphBuilder` methods the type of a numeric input can vary -
e.g. for `constant()` an explicit `MLOperandDataType` is provided; for
`clamp()` and `pad()` the data type is implied by input operands. In
these cases, specifying the numeric value as either a float/double or
int64 type runs into accuracy or range issues - you can't accurately
represent all int64 values as a double, and you can't represent the full
range of floats as int64. (You also can't represent all int64 values as
an long long either - over 2^53 things get wierd. But that's a
digression.)

- Some methods that took a float or double argument/option but can
  operate on integer data types now take `MLNumber` - a "variant"
  (union) of either a JS Number (equivalent to a double a.k.a. float64)
  or BigInt (for full precision int64/uint64 use)
  - `constant()` (scalar overload) - `MLNumber`
  - `clamp()` (min/max options) - `MLNumber`
  - `pad()` (padding value) - `MLNumber`
  - This fixes #442
- Other methods that took a `float` argument/option now take a `double`.
  These are all ops that only operate on floating point types, so no
  need for `MLNumber` though it would be harmless to use it there to
  allow BigInt inputs. This follows web API best practices, and allows
  full precision conversion to float16 (since float64 to float32 to
  float16 can yield different results than float64 directly to float16)
  - `batchNormalization()`, `instanceNormalization()`,
    `layerNormalization()` - `epsilon` option
  - `elu()`, `gemm()`, `hardSigmoid()`, `leakyRelu()`, `linear()`  -
    `alpha` and `beta` options
  - This fixes #325
- In all of these cases, the input number is cast to the input/output
operand data type when it is used. Casting algorithms are spelled out,
always have "clamp" semantics (i.e. no weird modulus wrapping), and
never fail.
  - For `MLOperand`-vending methods, the conversion can be done eagerly.
  - For `MLActivation`s, the conversion is done at "fusion time"; it's
    notable that the same `MLActivation` instance could be fused with
    multiple ops, and cast differently for each.
  - This fixes #678
- Using a BigInt/numeric union is novel here, but WebIDL experts agree
  it's reasonable (whatwg/webidl/issues/1388). Note that all existing
  WebIDL/JS APIs that are designed to take just a Number or just a
  BigInt will throw if the other thing is passed - there is
  intentionally no silent conversion. So we are in novel territory here
  and should look for implementation and developer feedback.

Fixes #442, #325, #678 

---------

Co-authored-by: Dwayne Robinson <[email protected]>
Co-authored-by: Ningxin Hu <[email protected]>
  • Loading branch information
3 people authored Jul 5, 2024
1 parent 08719e1 commit 9f88ebf
Showing 1 changed file with 143 additions and 20 deletions.
Loading

0 comments on commit 9f88ebf

Please sign in to comment.