import * as tflayers from '@tensorflow/tfjs-layers' ; import { Tensor , tidy , io , ModelPredictConfig } from '@tensorflow/tfjs-core' ; import { random } from 'lodash' ; import { NeuralNetwork } from "./networks" ; import v4 from 'uuid/v4' ; const DEFAULT_MODEL_FIT_CONFIG = { epochs : 10 , stepsPerEpoch : 200 } ; export enum LayerType { DENSE = "DENSE" , CONV2D = "CONV2D" , FLATTEN = "FLATTEN" } /**
 * Simplified layer configuration where you only give your layer, your activation function and the number of units.
 */ export interface LayerConfig { /** Number of neurons of this layer */ units : number ; /** If it is an input layer, the size of the input */ inputShape ? : Array < number > ; /** The activation function ('relu', 'sigmoid', ...) */ activation : string ; useBias ? : boolean ; } const DEFAULT_LAYER_CONFIG = { units : 32 , activation : 'relu' , useBias : false } ; interface ToTfLayerConfig { [ key ] : any ; } /**
 * The Model class is handling everything concerning the neural network
 */ export class Model { model : tflayers . LayersModel ; fitConfig : tflayers . ModelFitArgs ; param { SequentialArgs } config param { ModelFitArgs } fitConfig constructor ( config ? , fitConfig ? ) { this . model = new tflayers . Sequential ( config ) ; this . fitConfig = { ... DEFAULT_MODEL_FIT_CONFIG , ... fitConfig } ; } static async loadFromFile ( file ) { let model = new Model ( ) ; if ( typeof file === "string" ) model . model = await tflayers . loadLayersModel ( file ) ; else model . model = await tflayers . loadLayersModel ( io . browserFiles ( [ file . json , file . weights ] ) ) ; return model ; } param { string } destination param { string } place returns { Promise < void > } async export ( destination , place = 'downloads' ) { await this . model . save ( `${ place }://${ destination }` ) ; } param type param { LayerConfig } config deprecated addLayer ( type , config ) { if ( this . model instanceof tflayers . Sequential ) { let conf = DEFAULT_LAYER_CONFIG ; if ( config . inputShape ) conf . inputShape = config . inputShape ; switch ( type ) { case LayerType . DENSE : conf . units = config . units ; conf . activation = config . activation ; this . model . add ( tflayers . layers . dense ( < any > conf ) ) ; break ; case LayerType . CONV2D : conf . filters = config . units ; conf . activation = config . activation ; conf . useBias = config . useBias ; this . model . add ( tflayers . layers . conv2d ( < any > conf ) ) ; break ; case LayerType . FLATTEN : conf = { } ; this . model . add ( tflayers . layers . flatten ( < any > conf ) ) ; break ; } } else { throw new Error ( "Unable to add a layer to an already created model managed by tensorflowjs" ) ; } } param { ModelCompileArgs } config returns { Model } compile ( config ) { this . model . compile ( config ) ; return this ; } predict ( x , config ? ) { return new Result ( < Tensor > this . model . predict ( x , config ) ) ; } fit ( x , y ) { return this . model . fit ( x , y , this . fitConfig ) ; } randomOutput ( ) { return random ( 0 , this . OutputSize ) ; } get OutputSize ( ) : number { return ( < tflayers . SymbolicTensor > this . model . getOutputAt ( 0 ) ) . shape [ 1 ] ; } get InputSize ( ) : number { return this . model . layers [ 0 ] . batchInputShape [ 1 ] ; } set FitConfig ( fitConfig ) { this . fitConfig = { ... DEFAULT_MODEL_FIT_CONFIG , ... fitConfig } ; } param { NeuralNetwork } network param { ModelFitConfig } fitConfig param { string } name returns { Model } constructor static FromNetwork ( network , fitConfig ? , name = v4 ( ) ) { return new Model ( { name : name , layers : network . createLayers ( ) } , fitConfig ) ; } } /**
 * Just a little wrapper around the result of a request to TensorflowJS. Because every single result is made through WebGL,
 * we need to create async tasks. So we remove the async side by using the dataSync() method to get at the moment the result,
 * instead of returning a Promise.
 */ export class Result { constructor ( private result ) { } private getResultAndDispose ( t ) { this . result . dispose ( ) ; return t . dataSync ( ) ; } returns { number } getHighestValue ( ) { return tidy ( ( ) => this . getResultAndDispose ( this . result . as1D ( ) . max ( ) ) [ 0 ] ) ; } returns { number } getAction ( ) { return tidy ( ( ) => this . getResultAndDispose ( this . result . as1D ( ) . argMax ( ) ) [ 0 ] ) ; } returns { Int32Array | Float32Array | Uint8Array } getValue ( ) { const resTensor = this . result . as1D ( ) ; const result = resTensor . dataSync ( ) ; resTensor . dispose ( ) ; this . result . dispose ( ) ; return result ; } }