UNPKG

@tensorflow/tfjs-node

Version:

This repository provides native TensorFlow execution in backend JavaScript applications under the Node.js runtime, accelerated by the TensorFlow C binary under the hood. It provides the same API as [TensorFlow.js](https://js.tensorflow.org/api/latest/).

103 lines (91 loc) 3.57 kB
/** * @license * Copyright 2018 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ import {Shape, util} from '@tensorflow/tfjs'; import {endianness} from 'os'; const INT32_MAX = 2147483648; /** * Node.js-specific tensor type: int64-type scalar. * * This class is created for a specific purpose: to support * writing `step`s to TensorBoard via op-kernel bindings. * `step` is required to have an int64 dtype, but TensorFlow.js * (tfjs-core) doesn't have a built-in int64 dtype. This is * related to a lack of `Int64Array` or `Uint64Array` typed * array in basic JavaScript. * * This class is introduced as a workaround. */ export class Int64Scalar { readonly dtype: string = 'int64'; readonly rank: number = 1; private valueArray_: Int32Array; private static endiannessOkay_: boolean; constructor(readonly value: number) { // The reason why we need to check endianness of the machine here is // negative int64 values and the way in which we represent them // using Int32Arrays in JavaScript. We represent each int64 value with // two consecutive elements of an Int32Array. For positive values, // the high part is simply zero; for negative values, the high part // should be -1. The ordering of the low and high parts assumes // little endian (i.e., least significant digits appear first). // This assumption is checked by the lines below. if (Int64Scalar.endiannessOkay_ == null) { if (endianness() !== 'LE') { throw new Error( `Int64Scalar does not support endianness of this machine: ` + `${endianness()}`); } Int64Scalar.endiannessOkay_ = true; } util.assert( value > -INT32_MAX && value < INT32_MAX - 1, () => `Got a value outside of the bound of values supported for int64 ` + `dtype ([-${INT32_MAX}, ${INT32_MAX - 1}]): ${value}`); util.assert( Number.isInteger(value), () => `Expected value to be an integer, but got ${value}`); // We use two int32 elements to represent a int64 value. This assumes // little endian, which is checked above. const highPart = value >= 0 ? 0 : -1; const lowPart = value % INT32_MAX; this.valueArray_ = new Int32Array([lowPart, highPart]); } get shape(): Shape { return []; } /** Get the Int32Array that represents the int64 value. */ get valueArray(): Int32Array { return this.valueArray_; } } /** * This method encodes a Int32Array as Int64 layout in order to create TF_INT64 * tensor through binding. */ export function encodeInt32ArrayAsInt64(value: Int32Array): Int32Array { if (endianness() !== 'LE') { throw new Error( `Int64Scalar does not support endianness of this machine: ` + `${endianness()}`); } const buffer = new Int32Array(value.length * 2); for (let i = 0; i < value.length; i++) { buffer[i * 2] = value[i]; } return buffer; }