code: def pbt_function(config):
      """Toy PBT problem for benchmarking adaptive learning rate.
  
      The goal is to optimize this trainable's accuracy. The accuracy increases
      fastest at the optimal lr, which is a function of the current accuracy.
  
      The optimal lr schedule for this problem is the triangle wave as follows.
      Note that many lr schedules for real models also follow this shape:
  
       best lr
        ^
        |    /\
        |   /  \
        |  /    \
        | /      \
        ------------> accuracy
  
      In this problem, using PBT with a population of 2-4 is sufficient to
      roughly approximate this lr schedule. Higher population sizes will yield
      faster convergence. Training will not converge without PBT.
      """
      lr = config["lr"]
      checkpoint_interval = config.get("checkpoint_interval", 1)
  
      accuracy = 0.0  # end = 1000
  
      # NOTE: See below why step is initialized to 1
      step = 1
      checkpoint = train.get_checkpoint()
      if checkpoint:
          with checkpoint.as_directory() as checkpoint_dir:
              with open(
                  os.path.join(checkpoint_dir, "checkpoint.json"), "r"
              ) as f:
                  checkpoint_dict = json.load(f)
  
          accuracy = checkpoint_dict["acc"]
          last_step = checkpoint_dict["step"]
          # Current step should be 1 more than the last checkpoint step
          step = last_step + 1
  
      # triangle wave:
      #  - start at 0.001 @ t=0,
      #  - peak at 0.01 @ t=midpoint,
      #  - end at 0.001 @ t=midpoint * 2,
      midpoint = 100  # lr starts decreasing after acc > midpoint
      q_tolerance = (
          3  # penalize exceeding lr by more than this multiple
      )
      noise_level = 2  # add gaussian noise to the acc increase
  
      # Let `stop={"done": True}` in the configs below handle trial stopping
      while True:
          if accuracy < midpoint:
              optimal_lr = 0.01 * accuracy / midpoint
          else:
              optimal_lr = (
                  0.01 - 0.01 * (accuracy - midpoint) / midpoint
              )
          optimal_lr = min(0.01, max(0.001, optimal_lr))
  
          # compute accuracy increase
          q_err = max(lr, optimal_lr) / min(lr, optimal_lr)
          if q_err < q_tolerance:
              accuracy += (1.0 / q_err) * random.random()
          elif lr > optimal_lr:
              accuracy -= (q_err - q_tolerance) * random.random()
          accuracy += noise_level * np.random.normal()
          accuracy = max(0, accuracy)
  
          metrics = {
              "mean_accuracy": accuracy,
              "cur_lr": lr,
              "optimal_lr": optimal_lr,  # for debugging
              "q_err": q_err,  # for debugging
              "done": accuracy
              > midpoint * 2,  # this stops the training process
          }
  
          if step % checkpoint_interval == 0:
              # Checkpoint every `checkpoint_interval` steps
              # NOTE: if we initialized `step=0` above, our checkpointing and perturbing
              # would be out of sync by 1 step.
              # Ex: if `checkpoint_interval` = `perturbation_interval` = 3
              # step:                0 (checkpoint)  1     2            3 (checkpoint)
              # training_iteration:  1               2     3 (perturb)  4
              with tempfile.TemporaryDirectory() as tempdir:
                  with open(
                      os.path.join(tempdir, "checkpoint.json"), "w"
                  ) as f:
                      checkpoint_dict = {"acc": accuracy, "step": step}
                      json.dump(checkpoint_dict, f)
                  train.report(
                      metrics,
                      checkpoint=Checkpoint.from_directory(tempdir),
                  )
          else:
              train.report(metrics)
          step += 1
  
file_path: ray/python/ray/tune/examples/pbt_function.py
imports: import argparse
  import json
  import os
  import random
  import tempfile
  import numpy
  import ray
  from ray import train, tune
  from ray.train import Checkpoint
  from ray.tune.schedulers import PopulationBasedTraining
label_desc: Use image node_id 1 for calling a global function with example usage: pbt_function(config) without return types