@@ -69,7 +69,7 @@ extension TestError: CustomStringConvertible
6969///
7070/// - Parameter model: The model on which to select the initialization scheme.
7171///
72- func randomSelectWeightsInitializationScheme( model: Model )
72+ public func randomSelectWeightsInitializationScheme( model: Model )
7373{
7474 let choice = Int . random ( in: 0 ... 4 )
7575 switch choice {
@@ -365,6 +365,153 @@ open class FlowTrainer: Trainer
365365 }
366366}
367367
368+ /// Pipeline that compares gradients of weights computed in the CPU execution context againt the GPU one.
369+ open class FlowPrecisionTrainer : Trainer
370+ {
371+ ///
372+ /// The two models:
373+ /// [model to execute with Float precision, same model to execute with Float16 precision].
374+ ///
375+ public var models : [ Model ] = [ ]
376+
377+ /// Get the model to execute with Float precision.
378+ public var modelFloat : Model
379+ {
380+ get {
381+ return models [ 0 ]
382+ }
383+ }
384+ /// Get the model to execute with Float16 precision.
385+ public var modelFloat16 : Model
386+ {
387+ get {
388+ return models [ 1 ]
389+ }
390+ }
391+
392+ ///
393+ /// Create a model in the two execution contexts: CPU and GPU.
394+ ///
395+ /// - Parameter buildFct: A Function that creates the different layers of the models.
396+ ///
397+ public func build( _ buildFct: ( ModelContext ) -> ( ) )
398+ {
399+ var baseModels = [ BaseModel] ( )
400+
401+ let context = ModelContext ( name: modelName + " Float " , curID: 0 )
402+ buildFct ( context)
403+ baseModels. append ( context. model)
404+
405+ context. model = BaseModel ( name: modelName + " Float16 " )
406+ buildFct ( context)
407+ baseModels. append ( context. model)
408+
409+ var models = [ Model] ( )
410+ for baseModel in baseModels
411+ {
412+ models. append ( Model ( model: baseModel, modelsPrev: [ ] ) )
413+ }
414+ self . models = models
415+ }
416+
417+ /// Initialize the kernel of the models.
418+ public func initialize( )
419+ {
420+ for i in 0 ... 1
421+ {
422+ if i == 0
423+ {
424+ GrAI . Precision. float = true
425+ randomSelectWeightsInitializationScheme ( model: modelFloat)
426+ }
427+
428+ if i > 0
429+ {
430+ models [ i] . weights = models [ i- 1 ] . weights
431+ }
432+
433+ if i == 1
434+ {
435+ GrAI . Precision. float16 = true
436+ }
437+
438+ models [ i] . initialize (
439+ params: optimizerParams,
440+ phase: . Training,
441+ deviceID: DEVICE_ID
442+ )
443+ }
444+ }
445+
446+ ///
447+ /// Run the test.
448+ ///
449+ /// The goal is to compare the gradients of weights computed with Float precision with
450+ /// the gradients of weights computed with Float16 precision.
451+ ///
452+ /// - Parameters:
453+ /// - setData: A function to create/set data to the model.
454+ /// - setLoss: A function to create/set ground truth to the model.
455+ /// - validate: A function that checks whether the relative difference is small enough.
456+ ///
457+ public func run< DataT, LossT> (
458+ setData: ( DataT ? , Model ) -> ( DataT , Int ) ,
459+ setLoss: ( LossT ? , Model ) -> ( LossT ) ,
460+ validate: ( Double ) throws -> ( ) ) throws
461+ {
462+ initialize ( )
463+
464+ var epoch = 0
465+ let nbEpochsMax = 1
466+ while epoch < nbEpochsMax
467+ {
468+ var numLoop = 0
469+ while numLoop < optimizerParams. nbLoops
470+ {
471+ let resultsFloat : [ Double ]
472+ GrAI . Precision. float = true
473+
474+ var ( inputs, batchSize) = setData ( nil , modelFloat)
475+ modelFloat. updateKernel ( batchSize: batchSize)
476+ try ! modelFloat. forward ( )
477+
478+ var gt = setLoss ( nil , modelFloat)
479+ try ! modelFloat. backward ( )
480+ try ! modelFloat. update ( )
481+
482+ resultsFloat = getGradients ( model: modelFloat)
483+
484+ let resultsFloat16 : [ Double ]
485+ GrAI . Precision. float16 = true
486+
487+ ( inputs, batchSize) = setData ( inputs, modelFloat16)
488+ modelFloat16. updateKernel ( batchSize: batchSize)
489+ try ! modelFloat16. forward ( )
490+
491+ gt = setLoss ( gt, modelFloat16)
492+ try ! modelFloat16. backward ( )
493+ try ! modelFloat16. update ( )
494+
495+ resultsFloat16 = getGradients ( model: modelFloat16)
496+
497+ if let gradDiff = checkFlow ( resultsFloat, resultsFloat16)
498+ {
499+ if gradDiff. isNaN
500+ {
501+ fatalError ( " NaN " )
502+ }
503+ try validate ( gradDiff)
504+ }
505+
506+ modelFloat. incStep ( )
507+ modelFloat16. incStep ( )
508+ numLoop += 1
509+ }
510+ epoch += 1
511+ }
512+ }
513+ }
514+
368515/// Compares gradients of weights computed in the CPU execution context againt the GPU one
369516/// after a call to the reset API.
370517open class FlowResetTrainer : FlowTrainer
@@ -831,18 +978,18 @@ open class TransformTrainer: FlowTrainer
831978 // 5. Compare results.
832979
833980 let diffCPU =
834- ( lossCPUNew - lossCPURef) * ( lossCPUNew - lossCPURef) /
835- ( lossCPUNew * lossCPUNew + lossCPURef * lossCPURef)
981+ ( lossCPUNew - lossCPURef) * ( lossCPUNew - lossCPURef) /
982+ ( lossCPUNew * lossCPUNew + lossCPURef * lossCPURef)
836983 let diffGPU =
837- ( lossGPUNew - lossGPURef) * ( lossGPUNew - lossGPURef) /
838- ( lossGPUNew * lossGPUNew + lossGPURef * lossGPURef)
984+ ( lossGPUNew - lossGPURef) * ( lossGPUNew - lossGPURef) /
985+ ( lossGPUNew * lossGPUNew + lossGPURef * lossGPURef)
839986
840987 var warning = " "
841988 let maxDiff = max ( diffCPU, diffGPU)
842989 let maxIndex = diffCPU < diffGPU ? " GPU " : " CPU "
843990 if diffCPU > 0.0000001
844991 {
845- warning = " Load Check Warning " + maxIndex + " : "
992+ warning = " Transform Check Warning " + maxIndex + " : "
846993 }
847994 let strDump = warning + String( maxDiff)
848995 print ( strDump)
0 commit comments