code: def eval_fn_video(self, model):
      log_freq = getattr(self.opts, "common.log_freq", DEFAULT_LOG_FREQ)
  
      evaluation_stats = Statistics(
          opts=self.opts,
          metric_names=self.metric_names,
          is_master_node=self.is_master_node,
          is_distributed=self.use_distributed,
          log_writers=self.log_writers,
      )
  
      model.eval()
      if model.training and self.is_master_node:
          logger.warning(
              "Model is in training mode. Switching to evaluation mode"
          )
          model.eval()
  
      num_clips_per_video = getattr(
          self.opts, "sampler.bs.clips_per_video", 1
      )
      voting_fn = getattr(
          self.opts,
          "model.video_classification.clip_out_voting_fn",
          "sum",
      )
      if voting_fn is None:
          voting_fn = "sum"
      voting_fn = voting_fn.lower()
  
      with torch.no_grad():
          epoch_start_time = time.time()
          total_samples = len(self.test_loader)
          processed_samples = 0
  
          for batch_id, batch in enumerate(self.test_loader):
              batch = move_to_device(
                  opts=self.opts, x=batch, device=self.device
              )
  
              samples, targets = batch["samples"], batch["targets"]
              # target_label is Batch*Num_clips
              batch_size_ = get_batch_size(samples)
              batch_size = batch_size_ // num_clips_per_video
              if batch_size_ != (batch_size * num_clips_per_video):
                  logger.log(
                      "Skipping batch. Expected batch size= {}. Got: (bxc:{}x{})".format(
                          batch_size_, batch_size, num_clips_per_video
                      )
                  )
                  continue
  
              with autocast_fn(
                  enabled=self.mixed_precision_training,
                  amp_precision=self.mixed_precision_dtype,
              ):
                  # prediction
                  pred_label = model(samples)
  
              targets = targets.reshape(batch_size, num_clips_per_video)
              # label is the same for all clips in the video
              targets = targets[:, 0]
              pred_label = pred_label.reshape(
                  batch_size, num_clips_per_video, -1
              )
  
              if voting_fn == "sum":
                  pred_label = torch.sum(pred_label, dim=1)
              elif voting_fn == "max":
                  pred_label = torch.max(pred_label, dim=1)
              else:
                  logger.error(
                      "--model.video-classification.clip-out-fusion-fn can be {}. Got: {}".format(
                          SUPPORTED_VIDEO_CLIP_VOTING_FN, voting_fn
                      )
                  )
  
              processed_samples += batch_size
  
              evaluation_stats.update(
                  pred_label=pred_label,
                  target_label=targets,
                  extras={
                      "loss": torch.tensor(
                          0.0, dtype=torch.float, device=self.device
                      )
                  },
                  batch_time=0.0,
                  batch_size=batch_size,
              )
  
              if batch_id % log_freq == 0 and self.is_master_node:
                  evaluation_stats.iter_summary(
                      epoch=0,
                      n_processed_samples=processed_samples,
                      total_samples=total_samples,
                      elapsed_time=epoch_start_time,
                      learning_rate=0.0,
                  )
  
      evaluation_stats.epoch_summary(epoch=0, stage=self.stage_name)
  
file_path: ml-cvnets/engine/evaluation_engine.py
imports: import time
  import torch
  from common import DEFAULT_LOG_FREQ, SUPPORTED_VIDEO_CLIP_VOTING_FN
  from engine.utils import autocast_fn, get_batch_size, get_log_writers
  from metrics.stats import Statistics
  from options.parse_args import parse_validation_metric_names
  from utils import logger
  from utils.common_utils import move_to_device
  from utils.ddp_utils import is_master
label_desc: Use image node_id 3 for calling the Evaluator obj's underlying member method code with example usage: obj.eval_fn_video(model) without return types