license /**
 * Utility functions for training and transfer learning of the speech-commands
 * model.
 */ import * as tf from '@tensorflow/tfjs-core' ; param xs param ys param valSplit returns export function balancedTrainValSplit ( xs , ys , valSplit ) { tf . util . assert ( valSplit > 0 && valSplit < 1 , ( ) => `validationSplit is expected to be >0 and <1, ` + `but got ${ valSplit }` ) ; return tf . tidy ( ( ) => { const classIndices = tf . argMax ( ys , - 1 ) . dataSync ( ) ; const indicesByClasses = [ ] ; for ( let i = 0 ; i < classIndices . length ; ++ i ) { const classIndex = classIndices [ i ] ; if ( indicesByClasses [ classIndex ] == null ) { indicesByClasses [ classIndex ] = [ ] ; } indicesByClasses [ classIndex ] . push ( i ) ; } const numClasses = indicesByClasses . length ; const trainIndices = [ ] ; const valIndices = [ ] ; indicesByClasses . map ( classIndices => tf . util . shuffle ( classIndices ) ) ; for ( let i = 0 ; i < numClasses ; ++ i ) { const classIndices = indicesByClasses [ i ] ; const cutoff = Math . round ( classIndices . length * ( 1 - valSplit ) ) ; for ( let j = 0 ; j < classIndices . length ; ++ j ) { if ( j < cutoff ) { trainIndices . push ( classIndices [ j ] ) ; } else { valIndices . push ( classIndices [ j ] ) ; } } } const trainXs = tf . gather ( xs , trainIndices ) ; const trainYs = tf . gather ( ys , trainIndices ) ; const valXs = tf . gather ( xs , valIndices ) ; const valYs = tf . gather ( ys , valIndices ) ; return { trainXs , trainYs , valXs , valYs } ; } ) ; } /**
 * Same as balancedTrainValSplit, but for number arrays or Float32Arrays.
 */ export function balancedTrainValSplitNumArrays ( xs , ys , valSplit ) { tf . util . assert ( valSplit > 0 && valSplit < 1 , ( ) => `validationSplit is expected to be >0 and <1, ` + `but got ${ valSplit }` ) ; const isXsFloat32Array = ! Array . isArray ( xs [ 0 ] ) ; const classIndices = ys ; const indicesByClasses = [ ] ; for ( let i = 0 ; i < classIndices . length ; ++ i ) { const classIndex = classIndices [ i ] ; if ( indicesByClasses [ classIndex ] == null ) { indicesByClasses [ classIndex ] = [ ] ; } indicesByClasses [ classIndex ] . push ( i ) ; } const numClasses = indicesByClasses . length ; const trainIndices = [ ] ; const valIndices = [ ] ; indicesByClasses . map ( classIndices => tf . util . shuffle ( classIndices ) ) ; for ( let i = 0 ; i < numClasses ; ++ i ) { const classIndices = indicesByClasses [ i ] ; const cutoff = Math . round ( classIndices . length * ( 1 - valSplit ) ) ; for ( let j = 0 ; j < classIndices . length ; ++ j ) { if ( j < cutoff ) { trainIndices . push ( classIndices [ j ] ) ; } else { valIndices . push ( classIndices [ j ] ) ; } } } if ( isXsFloat32Array ) { const trainXs = [ ] ; const trainYs = [ ] ; const valXs = [ ] ; const valYs = [ ] ; for ( const index of trainIndices ) { trainXs . push ( xs [ index ] as Float32Array ) ; trainYs . push ( ys [ index ] ) ; } for ( const index of valIndices ) { valXs . push ( xs [ index ] as Float32Array ) ; valYs . push ( ys [ index ] ) ; } return { trainXs , trainYs , valXs , valYs } ; } else { const trainXs = [ ] ; const trainYs = [ ] ; const valXs = [ ] ; const valYs = [ ] ; for ( const index of trainIndices ) { trainXs . push ( xs [ index ] as number [ ] ) ; trainYs . push ( ys [ index ] ) ; } for ( const index of valIndices ) { valXs . push ( xs [ index ] as number [ ] ) ; valYs . push ( ys [ index ] ) ; } return { trainXs , trainYs , valXs , valYs } ; } }