@@ -509,6 +509,90 @@ def build_metric_graph(self, eval_config):
509509 ))
510510 return self ._metric_dict
511511
512+ def _resolve_pred_tensor (self , pred_name ):
513+ if pred_name not in self ._prediction_dict :
514+ raise ValueError (
515+ 'summaries pred_name "%s" not found in prediction_dict keys: %s' %
516+ (pred_name , sorted (self ._prediction_dict .keys ())))
517+ pred = tf .to_float (self ._prediction_dict [pred_name ])
518+ if pred_name == 'logits' or pred_name .startswith ('logits_' ):
519+ pred = tf .sigmoid (pred )
520+ # multi-class probs: take positive class when rank-2
521+ if pred .shape .ndims is not None and pred .shape .ndims > 1 :
522+ if pred .shape .ndims == 2 and int (pred .shape [- 1 ]) == 2 :
523+ pred = pred [:, 1 ]
524+ else :
525+ pred = tf .reshape (pred , [- 1 ])
526+ return pred
527+
528+ def _build_feature_mask (self , feature_name , feature_value ):
529+ if feature_name not in self ._feature_dict :
530+ raise ValueError (
531+ 'summaries feature_name "%s" not found in feature_dict keys: %s' %
532+ (feature_name , sorted (self ._feature_dict .keys ())))
533+ feat = self ._feature_dict [feature_name ]
534+ if isinstance (feat , tf .SparseTensor ):
535+ dense = tf .sparse_to_dense (
536+ feat .indices ,
537+ feat .dense_shape ,
538+ feat .values ,
539+ default_value = '' if feat .values .dtype == tf .string else 0 )
540+ feat = tf .reshape (dense , [- 1 ])
541+ else :
542+ feat = tf .reshape (feat , [- 1 ])
543+ if feat .dtype in (tf .float32 , tf .float64 , tf .int32 , tf .int64 ):
544+ try :
545+ target = float (feature_value )
546+ except (TypeError , ValueError ):
547+ target = None
548+ if target is not None :
549+ return tf .equal (tf .to_float (feat ), tf .constant (target , dtype = tf .float32 ))
550+ if feat .dtype != tf .string :
551+ feat = tf .as_string (feat )
552+ return tf .equal (feat , str (feature_value ))
553+
554+ def _masked_mean (self , values , mask ):
555+ values = tf .reshape (tf .to_float (values ), [- 1 ])
556+ masked = tf .boolean_mask (values , mask )
557+ count = tf .size (masked )
558+ return tf .cond (
559+ count > 0 ,
560+ lambda : tf .reduce_mean (masked ),
561+ lambda : tf .constant (0.0 , dtype = tf .float32 ))
562+
563+ def _build_summary_impl (self , summary ):
564+ summary_type = summary .WhichOneof ('summary' )
565+ if summary_type == 'pcoc' :
566+ if self ._labels is None :
567+ return
568+ pred_name = summary .pcoc .pred_name or 'probs'
569+ preds = self ._resolve_pred_tensor (pred_name )
570+ label = tf .to_float (self ._labels [self ._label_name ])
571+ label = tf .reshape (label , [- 1 ])
572+ predicted_ctr = tf .reduce_mean (preds )
573+ observed_ctr = tf .reduce_mean (label )
574+ epsilon = summary .pcoc .epsilon
575+ pcoc = predicted_ctr / (observed_ctr + epsilon )
576+ tf .summary .scalar ('summary/predicted_ctr' , predicted_ctr )
577+ tf .summary .scalar ('summary/observed_ctr' , observed_ctr )
578+ tf .summary .scalar ('summary/pcoc' , pcoc )
579+ elif summary_type == 'scalars' :
580+ cfg = summary .scalars
581+ pred_name = cfg .pred_name or 'probs'
582+ preds = self ._resolve_pred_tensor (pred_name )
583+ if cfg .HasField ('feature_name' ) and cfg .HasField ('feature_value' ):
584+ mask = self ._build_feature_mask (cfg .feature_name , cfg .feature_value )
585+ value = self ._masked_mean (preds , mask )
586+ else :
587+ value = tf .reduce_mean (preds )
588+ tf .summary .scalar ('summary/%s' % cfg .name , value )
589+ elif summary_type is not None :
590+ raise ValueError ('unsupported summary type: %s' % summary_type )
591+
592+ def build_summary_graph (self ):
593+ for summary in self ._base_model_config .summaries_set :
594+ self ._build_summary_impl (summary )
595+
512596 def _get_outputs_impl (self , loss_type , num_class = 1 , suffix = '' ):
513597 binary_loss_set = {
514598 LossType .F1_REWEIGHTED_LOSS ,
0 commit comments