license import * as tfc from '@tensorflow/tfjs-core' ; import * as tfl from '@tensorflow/tfjs-layers' ; import * as tfn from '../index' ; const fetch = require ( 'node-fetch' ) ; const OCTET_STREAM_TYPE = 'application/octet-stream' ; const JSON_TYPE = 'application/json' ; const modelTopology1 = { 'class_name' : 'Sequential' , 'keras_version' : '2.1.4' , 'config' : [ { 'class_name' : 'Dense' , 'config' : { 'kernel_initializer' : { 'class_name' : 'VarianceScaling' , 'config' : { 'distribution' : 'uniform' , 'scale' : 1.0 , 'seed' : null , 'mode' : 'fan_avg' } } , 'name' : 'dense' , 'kernel_constraint' : null , 'bias_regularizer' : null , 'bias_constraint' : null , 'dtype' : 'float32' , 'activation' : 'linear' , 'trainable' : true , 'kernel_regularizer' : null , 'bias_initializer' : { 'class_name' : 'Zeros' , 'config' : { } } , 'units' : 1 , 'batch_input_shape' : [ null , 3 ] , 'use_bias' : true , 'activity_regularizer' : null } } ] , 'backend' : 'tensorflow' } ; describe ( 'nodeHTTPRequest-load' , ( ) => { let requestInits ; const setupFakeWeightFiles = ( fileBufferMap ) => { spyOn ( tfc . ENV . platform , 'fetch' ) . and . callFake ( ( path , init ) => { return new Promise ( ( resolve , reject ) => { let contentType = '' ; if ( path . endsWith ( 'model.json' ) ) { contentType = JSON_TYPE ; } else if ( path . endsWith ( 'weightfile0' ) || path . endsWith ( 'weightfile1' ) ) { contentType = OCTET_STREAM_TYPE ; } else { reject ( new Error ( `Invalid path: ${ path }` ) ) ; } requestInits . push ( init ) ; resolve ( new fetch . Response ( fileBufferMap [ path ] , { 'headers' : { 'Content-Type' : contentType } } ) ) ; } ) ; } ) ; } ; beforeEach ( ( ) => { requestInits = [ ] ; } ) ; it ( 'Constructor' , ( ) => { const handler = tfn . io . nodeHTTPRequest ( './foo_model.json' ) ; expect ( handler == null ) . toEqual ( false ) ; expect ( typeof handler . load ) . toEqual ( 'function' ) ; expect ( typeof handler . save ) . toEqual ( 'function' ) ; } ) ; it ( 'Load through NodeHTTPRequest object' , async ( ) => { const weightManifest1 = [ { paths : [ 'weightfile0' ] , weights : [ { name : 'dense/kernel' , shape : [ 3 , 1 ] , dtype : 'float32' , } , { name : 'dense/bias' , shape : [ 1 ] , dtype : 'float32' , } ] } ] ; const floatData = new Float32Array ( [ 1 , 3 , 3 , 7 ] ) ; setupFakeWeightFiles ( { 'http://localhost/model.json' : JSON . stringify ( { modelTopology : modelTopology1 , weightsManifest : weightManifest1 } ) , 'http://localhost/weightfile0' : floatData , } ) ; const handler = tfn . io . nodeHTTPRequest ( 'http://localhost/model.json' , { credentials : 'include' , cache : 'no-cache' } ) ; const modelArtifacts = await handler . load ( ) ; expect ( modelArtifacts . modelTopology ) . toEqual ( modelTopology1 ) ; expect ( modelArtifacts . weightSpecs ) . toEqual ( weightManifest1 [ 0 ] . weights ) ; expect ( new Float32Array ( modelArtifacts . weightData ) ) . toEqual ( floatData ) ; expect ( requestInits ) . toEqual ( [ { credentials : 'include' , cache : 'no-cache' } , { credentials : 'include' , cache : 'no-cache' } ] ) ; } ) ; it ( 'Load through registered handler' , async ( ) => { const weightManifest1 = [ { paths : [ 'weightfile0' ] , weights : [ { name : 'dense/kernel' , shape : [ 3 , 1 ] , dtype : 'float32' , } , { name : 'dense/bias' , shape : [ 1 ] , dtype : 'float32' , } ] } ] ; const floatData = new Float32Array ( [ 1 , 3 , 3 , 7 ] ) ; setupFakeWeightFiles ( { 'https://localhost/model.json' : JSON . stringify ( { modelTopology : modelTopology1 , weightsManifest : weightManifest1 } ) , 'https://localhost/weightfile0' : floatData , } ) ; const model = await tfl . loadLayersModel ( 'https://localhost/model.json' ) ; expect ( model . inputs . length ) . toEqual ( 1 ) ; expect ( model . inputs [ 0 ] . shape ) . toEqual ( [ null , 3 ] ) ; expect ( model . outputs . length ) . toEqual ( 1 ) ; expect ( model . outputs [ 0 ] . shape ) . toEqual ( [ null , 1 ] ) ; } ) ; } ) ;