Proxy 工作設計

執行 Agent Platform Neural Architecture Search 工作來搜尋最佳模型之前,請先定義代理任務。Stage1-search 使用的模型訓練規模遠小於完整模型訓練,通常會在兩小時內完成。這種表示法稱為「代理任務」,可大幅降低搜尋成本。搜尋期間的每項試驗都會使用 Proxy 任務設定訓練模型。

以下各節說明套用代理任務設計時涉及的事項:

  • 建立代理任務的方法。
  • 良好代理任務的條件。
  • 如何使用三種代理任務設計工具找出最佳代理任務,在降低搜尋成本的同時維持搜尋品質。

建立 Proxy 任務的方法

建立 Proxy 任務有三種常見方法,包括:

  • 減少訓練步數。
  • 使用子樣本訓練資料集。
  • 使用縮減模型。

減少訓練步數

建立代理任務最簡單的方法,就是減少訓練器的訓練步驟數量,並根據這項部分訓練將分數回報給控制器。

使用子樣本訓練資料集

本節說明如何使用子樣本訓練資料集,進行架構搜尋和增強政策搜尋。

在架構搜尋期間,您可以使用子樣本訓練資料集建立代理任務。不過,進行向下取樣時,請遵循下列準則:

  • 隨機重組 shard 之間的資料。
  • 如果訓練資料不平衡,請進行子樣本處理,平衡資料。

如果您只執行一般架構搜尋,而非僅執行擴增搜尋,請略過本節。使用自動擴增功能搜尋擴增政策。建議您對訓練資料進行子取樣,並執行完整訓練,而不是減少訓練步驟數量。執行完整訓練並大量增強資料,可讓分數更穩定。此外,請使用精簡的訓練資料,降低搜尋成本。

以縮減模型為基礎的代理任務

您也可以縮減模型 (相較於基準模型),建立代理任務。如要將區塊設計搜尋與縮放搜尋分開,這個方法也相當實用。

不過,如果縮減模型並想使用延遲時間限制,請為縮減的模型設定更嚴格的延遲時間限制。提示:您可以縮減基準模型並測量延遲時間,設定更嚴格的延遲時間限制。

與原始基準模型相比,縮減後的模型也可以減少擴增和正規化的數量。

縮減模型範例

如果是以圖片訓練的電腦視覺任務,縮減模型規模有三種常見方法:

  • 減少模型寬度:通道數量。
  • 減少模型深度:層數和區塊重複次數。
  • 稍微縮減訓練圖片大小 (以免消除特徵),或在工作允許的情況下裁剪訓練圖片。

建議閱讀:EfficientNet 論文,深入瞭解如何針對電腦視覺任務調整模型。此外,也會說明這三種資源調度方式之間的關係。

Spinenet 搜尋是另一個與 Agent Platform Neural Architecture Search 搭配使用的模型縮放範例。在第 1 階段搜尋中,會縮減通道數量和圖片大小。

根據組合建立 Proxy 任務

這些方法各自獨立,可以不同程度地結合,建立代理任務。

良好代理任務的條件

代理任務必須符合特定要求,才能向控制器提供穩定的獎勵,並維持搜尋品質。

第 1 階段搜尋與第 2 階段完整訓練之間的排名相關性

使用代理任務進行 Agent Platform 神經架構搜尋時,一項關鍵假設是,如果模型 A 在第 1 階段代理任務訓練中的表現優於模型 B,則模型 A 在第 2 階段完整訓練中的表現也會優於模型 B。如要驗證這項假設,您必須評估搜尋空間中約 10 到 20 個模型的第 1 階段搜尋和第 2 階段完整訓練獎勵之間的排名相關性。這些模型稱為關聯候選模型。

下圖顯示相關性不佳的範例 (相關性分數 = -0.03),因此這項 Proxy 任務不適合用於搜尋:

關聯性不佳。

圖中的每個點都代表一個相關性候選模型。x 軸代表模型的第 2 階段完整訓練分數,y 軸則代表相同模型的第 1 階段代理任務分數。觀察最高點。這個模型提供最高的代理任務分數 (y 軸),但在第 2 階段完整訓練 (x 軸) 期間,表現不如其他模型。相較之下,下圖顯示良好關聯性的範例 (關聯性分數 = 0.67),因此這項 Proxy 任務很適合用於搜尋:

關聯性良好。

如果搜尋涉及延遲時間限制,請一併確認延遲時間值是否具有良好關聯性。

請注意,相關性候選模型的獎勵範圍良好,且獎勵範圍的取樣也相當合理。否則無法評估排名相關性。舉例來說,如果所有相關性候選模型的第 1 階段獎勵都集中在兩個值:0.9 和 0.1,則無法提供足夠的取樣變異。

變異數檢查

代理任務的另一項要求是,在不進行任何變更的情況下,對同一個模型重複執行多次時,準確率或延遲分數不應有大幅變化。如果發生這種情況,就會將雜訊訊號傳回控制器。我們提供測量這項差異的工具。

範例可減少訓練期間的巨大差異。其中一種方法是使用 cosine decay 做為學習率排程。下圖比較三種學習率策略:

不同學習率的分數。

最底部的圖表對應的是固定學習率。如果分數在訓練結束時大幅波動,那麼減少訓練步數的選擇只要稍有變化,最終的代理任務獎勵就會大幅改變。如要讓代理任務獎勵更穩定,建議使用餘弦學習率衰減,如最高圖表中的對應驗證分數所示。請注意,最高圖表在訓練結束時會變得更平滑。中間的圖表顯示與逐步學習率衰減對應的分數。這種方法比固定速率好,但仍不如餘弦衰減平滑,且需要手動調整。

學習率排程如下所示:

學習率。

其他平滑化

如果您使用大量增強,驗證曲線可能不會隨著餘弦衰減而變得足夠平滑。如果大量使用擴增技術,表示訓練資料不足。在這種情況下,不建議使用 Agent Platform Neural Architecture Search,建議改用擴增搜尋。

如果問題並非由大量擴增造成,且您已嘗試餘弦衰減,但仍想進一步提高平滑度,請使用 TensorFlow-2 的指數移動平均,或 PyTorch 的隨機加權平均。如需使用 TensorFlow 2 指數移動平均最佳化器的範例,請參閱這個程式碼指標;如需 PyTorch 的隨機加權平均範例,請參閱這個範例。

如果試驗的準確率/週期圖表如下所示:

未套用平滑處理的準確率/訓練週期圖表

則可套用上述平滑技術 (例如隨機加權平均或指數移動平均),取得更一致的圖表,例如:

套用平滑處理的準確率/週期圖表

記憶體不足 (OOM) 和學習率相關錯誤

架構搜尋空間可生成比基準大得多的模型。您可能已調整基準模型的批次大小,但如果搜尋期間取樣較大的模型,這項設定可能會失敗,導致 OOM 錯誤。在這種情況下,您需要縮減批次大小。

另一種錯誤是 NaN (非數字) 錯誤。建議您降低初始學習率,或加入梯度限幅。

如tutorial-2 所述,如果超過 20% 的搜尋空間模型傳回無效分數,則不會執行完整搜尋。我們的代理任務設計工具提供評估失敗率的方法。

Proxy 任務設計工具

前幾節說明瞭代理任務設計原則。本節提供三種代理任務設計工具,可根據不同的設計方法,自動找出符合所有需求的最佳代理任務。

必要程式碼變更

您必須先稍微修改訓練器程式碼,才能在疊代過程中與 Proxy 工作設計工具互動。tf_vision/train_lib.py 顯示範例。您必須先匯入我們的程式庫:

from google.cloud.visionsolutions.nas.proxy_task import proxy_task_utils

在訓練迴圈開始訓練週期之前,請檢查是否需要提早停止訓練,因為 Proxy 任務設計工具會要求您使用我們的程式庫:

if proxy_task_utils.get_stop_training(
    model_dir,
    end_training_cycle_step=<last-training-step-idx done so far>,
    total_training_steps=<total-training-steps>):
  break

訓練迴圈中的每個訓練週期完成後,更新新的準確率分數、訓練週期開始和結束步驟、訓練週期時間 (以秒為單位),以及訓練步驟總數。

proxy_task_utils.update_trial_training_accuracy_metric(
      model_dir=model_dir,
      accuracy=<latest accuracy value>,
      begin_training_cycle_step=<beginning training step for this cycle>,
      end_training_cycle_step=<end training step for this cycle>,
      training_cycle_time_in_secs=<training cycle time (excluding validation)>,
      total_training_steps=<total-training-steps>)

請注意,訓練循環時間不應包含驗證分數評估時間。請確認訓練器會頻繁計算驗證分數 (評估頻率),以便取得足夠的驗證曲線樣本。如果您使用延遲時間限制,請在計算延遲時間後更新延遲時間指標:

proxy_task_utils.update_trial_training_latency_metric(
          model_dir=model_dir,
          latency=<measured_latency>)

模型選取工具需要載入先前的檢查點,才能進行後續疊代。如要啟用重複使用先前檢查點的功能,請在訓練器中新增旗標,如 tf_vision/cloud_search_main.py 所示:

parser.add_argument(
      "--retrain_use_search_job_checkpoint",
      type=cloud_nas_utils.str_2_bool,
      default=False,
      help="True to use previous NAS search job checkpoint."
  )

訓練模型前,請先載入這個檢查點:

if FLAGS.retrain_use_search_job_checkpoint:
    prev_checkpoint_dir = cloud_nas_utils.get_retrain_search_job_model_dir(
        retrain_search_job_trials=FLAGS.retrain_search_job_trials,
        retrain_search_job_dir=FLAGS.retrain_search_job_dir)
    logging.info("Setting checkpoint to %s.", prev_checkpoint_dir)
    # Now set your checkpoint using 'prev_checkpoint_dir'.

您也需要與訓練器回報的準確度和延遲值相對應的 metric-id。如果訓練器獎勵 (有時是準確度和延遲時間的組合) 與準確度不同,請務必使用訓練器的 other_metrics 回報僅限準確度的指標。舉例來說,以下範例顯示預先建構的訓練器回報的準確率和延遲時間指標:

模型選取指標

變異數評估

修改訓練器程式碼後,第一步是評估訓練器的變異數。如要評估變異數,請修改基準訓練設定,調整下列項目:

  • 減少訓練步驟,只使用一或兩個 GPU 執行約一小時。我們需要一小部分完整訓練樣本。
  • 使用餘弦衰減學習率,並將其步數設為與這些減少的步數相同,使學習率在接近結束時幾乎為零。

變異數測量工具會從搜尋空間中取樣一個模型,確保這個模型可以開始訓練,而不會產生 OOM 或 NAN 錯誤,然後使用您的設定執行這個模型的五個副本約一小時,然後回報訓練分數變異數和流暢度。執行這項工具的總費用,約等於以您的設定執行五個模型約一小時。

執行下列指令,啟動變異數測量工作 (您需要服務帳戶):

DATE="$(date '+%Y%m%d_%H%M%S')"
project_id=<your project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file=<path to your trainer dockerfile>
region=<your job region such as 'us-central1'>
search_space_module=<path to your search space module>
accelerator_type="NVIDIA_TESLA_V100"
num_gpus=2
# Your bucket should be for your project and in the same region as the job.
root_output_dir=<gs://your-bucket>

####### Variance measurement related parameters ######
proxy_task_variance_measurement_docker_id=${USER}_variance_measurement_${DATE}
# Use the service account that you set-up for your project.
service_account=<your service account>
job_name=<your job name>
############################################################

python3 vertex_nas_cli.py build \
--project_id=${project_id} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--trainer_docker_file=${trainer_docker_file} \
--proxy_task_variance_measurement_docker_id=${proxy_task_variance_measurement_docker_id}

# The command below passes 'dummy' arguments for the training docker.
# You need to modify them for your own docker.
python3 vertex_nas_cli.py measure_proxy_task_variance \
--proxy_task_variance_measurement_docker_id=${proxy_task_variance_measurement_docker_id} \
--project_id=${project_id} \
--service_account=${service_account} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--job_name=${job_name} \
--search_space_module=${search_space_module} \
--accelerator_type=${accelerator_type} \
--num_gpus=${num_gpus} \
--root_output_dir=${root_output_dir} \
--search_docker_flags \
dummy_trainer_flag1="dummy_trainer_val"

啟動這項變異數測量工作後,您會取得工作連結。工作名稱開頭應為前置字串 Variance_Measurement。工作 UI 範例如下:

變異數評估工作

variance_measurement_dir 會包含所有輸出內容,您可以點選「View logs」(查看記錄) 連結來查看記錄。這項工作預設會使用雲端中的一個 CPU,在背景中以自訂工作的形式執行,然後啟動及管理子 NAS 工作。

自訂工作與 NAS 工作

在「NAS」NAS工作下方,您會看到名為 Find_workable_model_<your job name> 的工作。這項工作會對搜尋空間進行取樣,找出不會產生任何錯誤的模型。找到這類模型後,變異數測量工作會啟動另一個 NAS 工作 <your job name>,並根據您先前設定的訓練步驟數量,執行這個模型的五個副本。這些模型訓練完成後,變異數測量工作會測量分數變異數和流暢度,並在記錄中回報:

變異數評估記錄

如果變異數偏高,可以探索這裡列出的技術。

選取模型

確認訓練器沒有高變異數後,請按照下列步驟操作:

  • 找出約 10 個相關性候選模型
  • 計算完整訓練分數,做為稍後計算不同代理任務選項的代理任務關聯分數時的參考。

我們的工具會自動且有效率地找出這些相關性候選模型,並確保這些模型在準確度和延遲時間方面都有良好的分數分布,以便為日後的相關性運算奠定良好基礎。為此,工具會執行下列操作:

  • 從搜尋空間隨機取樣 N_begin 個模型。在本範例中,假設 N_begin = 30。訓練時間為完整訓練時間的 1/30。
  • 拒絕 30 個模型中的 5 個,因為這些模型不會增加準確率和延遲時間的分佈。下圖為範例。遭拒的模型會顯示為紅點:

模型選取範例

  • 訓練所選的 25 個模型,訓練時間為完整訓練時間的 1/25,然後根據目前的分數再剔除 5 個模型。請注意,25 個模型的訓練會從先前的查核點繼續。
  • 重複這項程序,直到只剩下 N 個分布良好的模型。
  • 訓練最後 N 個模型,直到完成。

N_begin 的預設設定為 30,可在 proxy_task/proxy_task_model_selection_lib_constants.py 檔案中找到 START_NUM_MODELS。N 的預設設定為 10,可在 proxy_task/proxy_task_model_selection_lib_constants.py 檔案中找到 FINAL_NUM_MODELS。

這項模型選取程序的額外費用計算方式如下:

= (30*1/30 + 25*1/25 + 20*1/20 + 15*1/15 + 10*(remaining-training-time-fraction)) * full-training-time
= (4 + 10*(0.81)) * full-training-time
~= 12 * full-training-time

不過,請保持在 N=10 設定以上。Proxy 任務搜尋工具稍後會同時執行這些 N 模型。因此,請確保您有足夠的 GPU 配額。舉例來說,如果 Proxy 任務使用兩個 GPU 處理一個模型,則配額至少應為 2*N 個 GPU。

模型選取工作應使用與第 2 階段完整訓練工作相同的資料集分區,並使用相同的訓練器設定進行基準完整訓練。

現在可以執行下列指令,啟動模型選取工作 (需要服務帳戶):

DATE="$(date '+%Y%m%d_%H%M%S')"
project_id=<your project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file=<path to your trainer dockerfile>
latency_calculator_docker_id=${USER}_model_selection_${DATE}
latency_calculator_docker_file=${USER}_latency_${DATE}
region=<your job region such as 'us-central1'>
search_space_module=<path to your search space module>
accelerator_type="NVIDIA_TESLA_V100"
num_gpus=2
# Your bucket should be for your project and in the same region as the job.
root_output_dir=<gs://your-bucket>
# Your latency computation device.
target_device_type="CPU"

####### Proxy task model-selection related parameters ######
proxy_task_model_selection_docker_id=${USER}_model_selection_${DATE}
# Use the service account that you set-up for your project.
service_account=<your service account>
job_name=<your job name>
# The value below depends on your accelerator quota. By default
# the model-selection job runs 30 trials. However, depending on
# your quota, you can choose to only run 10 trials in parallel at a time.
# However, lowering this number can increase the overall runtime for the job.
max_parallel_nas_trial=<num parallel trials>
# The value below is the 'metric-id' corresponding to the accuracy ONLY
# metric reported by your trainer. Note that this metric may
# be different from the 'reward'.
accuracy_metric_id=<set accuracy metric id used by your trainer>
latency_metric_id=<set latency metric id used by your trainer>
############################################################

python3 vertex_nas_cli.py build \
--project_id=${project_id} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--trainer_docker_file=${trainer_docker_file} \
--latency_calculator_docker_id=${latency_calculator_docker_id} \
--latency_calculator_docker_file=${latency_calculator_docker_file} \
--proxy_task_model_selection_docker_id=${proxy_task_model_selection_docker_id}

# The command below passes 'dummy' arguments for trainer-docker
# and latency-docker. You need to modify them for your own docker.
python3 vertex_nas_cli.py select_proxy_task_models \
--service_account=${service_account} \
--proxy_task_model_selection_docker_id=${proxy_task_model_selection_docker_id} \
--project_id=${project_id} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--job_name=${job_name} \
--max_parallel_nas_trial=${max_parallel_nas_trial} \
--accuracy_metric_id=${accuracy_metric_id} \
--latency_metric_id=${latency_metric_id} \
--search_space_module=${search_space_module} \
--accelerator_type=${accelerator_type} \
--num_gpus=${num_gpus} \
--root_output_dir=${root_output_dir} \
--latency_calculator_docker_id=${latency_calculator_docker_id} \
--latency_docker_flags \
dummy_latency_flag1="dummy_latency_val" \
--target_device_type=${target_device_type} \
--search_docker_flags \
dummy_trainer_flag1="dummy_trainer_val"

啟動這項模型選取控制器工作後,您會收到工作連結。工作名稱開頭為前置字串 Model_Selection_。工作 UI 範例如下:

模型選取工作

model_selection_dir 包含所有輸出內容。按一下「View logs」連結即可查看記錄。根據預設,這項模型選取控制器工作會使用 Google Cloud 的一個 CPU,在背景中以自訂工作的形式執行,然後為模型選取的每個疊代啟動及管理子 NAS 工作。

自訂工作與 NAS 工作

每個子項 NAS 工作都有名稱,例如 <your_job_name>_iter_3 (疊代 0 除外)。一次只會執行一個疊代。每次疊代時,模型數量 (試驗次數) 都會減少,訓練時間則會增加。在每個疊代結束時,每個 NAS 工作都會儲存 gs://<job-output-dir>/search/filtered_trial_scores.png 檔案,以視覺化方式顯示在這個疊代中遭拒的模型。您也可以執行下列指令:

gcloud storage cat gs://<path to 'model_selection_dir'>/MODEL_SELECTION_STATE.json

其中會顯示模型選取控制器工作的疊代和目前狀態摘要、工作名稱,以及每個疊代的連結:

{
  "start_num_models": 30,
  "final_num_models": 10,
  "num_models_to_remove_per_iter": 5,
  "accuracy_metric_id": "top_1_accuracy_without_latency",
  "latency_metric_id": "latency_milli_seconds",
  "iterations": [
    {
      "num_trials": 30,
      "trials_to_retrain": [
        "27",
        "16",
        ...,
        "14"
      ],
      "search_job_name": "projects/123456/locations/europe-west4/nasJobs/2111217356469436416",
      "search_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/2111217356469436416/cpu?project=my-project",
      "latency_calculator_job_name": "projects/123456/locations/europe-west4/customJobs/6909239809479278592",
      "latency_calculator_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/6909239809479278592/cpu?project=my-project",
      "desired_training_step_pct": 2.0
    },
    ...,
    {
      "num_trials": 15,
      "trials_to_retrain": [
        "14",
        ...,
        "5"
      ],
      "search_job_name": "projects/123456/locations/europe-west4/nasJobs/7045544066951413760",
      "search_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/7045544066951413760/cpu?project=my-project",
      "latency_calculator_job_name": "projects/123456/locations/europe-west4/customJobs/2790768318993137664",
      "latency_calculator_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/2790768318993137664/cpu?project=my-project",
      "desired_training_step_pct": 28.57936507936508
    },
    {
      "num_trials": 10,
      "trials_to_retrain": [],
      "search_job_name": "projects/123456/locations/europe-west4/nasJobs/2742864796394192896",
      "search_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/2742864796394192896/cpu?project=my-project",
      "latency_calculator_job_name": "projects/123456/locations/europe-west4/customJobs/1490864099985195008",
      "latency_calculator_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/1490864099985195008/cpu?project=my-project",
      "desired_training_step_pct": 101.0
    }
  ]
}

最後一個疊代作業會產生最終數量的參考模型,且分數分布良好。這些模型和分數會用於下一個步驟的代理任務搜尋。如果參考模型的最終準確率和延遲分數範圍,看起來比現有基準模型更好或接近,就能初步判斷搜尋空間。如果最終準確度和延遲時間分數範圍明顯低於基準,請重新檢查搜尋空間。

請注意,如果第一次疊代中超過 20% 的試驗失敗,請取消模型選取工作,並找出失敗的根本原因。這可能是搜尋空間或批次大小和學習率設定有問題。

使用地端部署延遲裝置選取模型

如要使用地端部署延遲時間裝置選取模型,請執行 select_proxy_task_models 指令,但不使用延遲時間 Docker 和 latency-docker 旗標,因為您不想在 Google Cloud上啟動延遲時間 Docker。接著,使用教學課程 4 中所述的 run_latency_calculator_local 指令,啟動地端部署延遲時間計算工具工作。請改為傳遞 --search_job_id--controller_job_id 旗標,並附上 執行 select_proxy_task_models 指令後取得的數值模型選取工作 ID。

正在繼續執行模型選取控制器工作

在下列情況下,您必須繼續模型選取控制器工作:

  • 父項模型選取控制器工作終止 (罕見情況)。
  • 您不小心取消模型選取控制器工作。

首先,如果子項 NAS 疊代工作 (「NAS」分頁) 已在執行,請勿取消。接著,如要繼續執行父項模型選取控制器工作,請像之前一樣執行 select_proxy_task_models 指令,但這次要傳遞 --previous_model_selection_dir 旗標,並將其設為先前模型選取控制器工作的輸出目錄。恢復的模型選取控制器工作會從目錄載入先前的狀態,並像之前一樣繼續運作。

找出相關性候選模型及其完整訓練分數後,下一步是使用這些模型評估不同代理任務選擇的相關性分數,並選擇最佳代理任務。我們的代理任務搜尋工具可自動尋找代理任務,並提供下列功能:

  • 最低的 NAS 搜尋成本。
  • 提供代理任務搜尋空間定義後,達到最低相關性要求門檻。

請注意,尋找最佳代理任務時,有三個常見的維度,包括:

  • 減少訓練步數。
  • 減少訓練資料量。
  • 縮小模型。

您可以對這些維度進行取樣,建立離散代理任務搜尋空間,如下所示:

Proxy 任務搜尋空間網格

上述百分比僅為約略建議和範例。在實務上,您可以選擇任何離散選項。請注意,我們並未在上述搜尋空間中加入訓練步驟維度。這是因為 Proxy 任務搜尋工具會根據 Proxy 任務選擇,找出最佳訓練步驟。假設代理任務選擇 [50% training data, 25% model scale]。將訓練步數設為與完整基準訓練相同的數量。評估這項代理任務時,代理任務搜尋工具會啟動關聯候選模型的訓練、監控目前的準確率分數,並持續計算排名關聯分數 (使用參考模型的過去完整訓練分數):

關聯與訓練步數

因此,一旦取得所需的關聯性 (例如 0.65),代理任務搜尋工具就會停止代理任務訓練,或者如果超出搜尋成本配額 (例如每個代理任務 3 小時限制),也會提早停止。因此,您不需要明確搜尋訓練步驟。Proxy 任務搜尋工具會將離散搜尋空間中的每個 Proxy 任務視為網格搜尋進行評估,並提供最佳選項。

以下是 proxy_task/proxy_task_search_spaces.py 檔案中定義的 MnasNet 代理任務搜尋空間定義範例 mnasnet_proxy_task_config_generator,示範如何定義自己的搜尋空間:

# MNasnet training-data size choices.
MNASNET_TRAINING_DATA_PCT_LIST = [25, 50, 75, 95]

# Training data path regex pattern.
_TRAINING_DATA_PATH_REGEX = r"gs://.*/.*"


def update_mnasnet_proxy_training_data(
    baseline_docker_args_map: Dict[str, Any],
    training_data_pct: int) -> Optional[Dict[str, Any]]:
  """Updates MNasnet baseline docker to use a certain training_data_pct."""
  proxy_task_docker_args_map = copy.deepcopy(baseline_docker_args_map)
  # Imagenet training data path looks like:
  # gs://<path to imagenet data>/train-00[0-7]??-of-01024.
  if not re.match(_TRAINING_DATA_PATH_REGEX,
                  baseline_docker_args_map["training_data_path"]):
    raise ValueError(
        "Training data path %s does not match the desired pattern." %
        baseline_docker_args_map["training_data_path"])

  root_path, _ = baseline_docker_args_map["training_data_path"].rsplit("/", 1)
  if training_data_% == 25:
    proxy_task_docker_args_map["training_data_path"] = os.path.join(
        root_path, "train-00[0-1][0-4]?-of-01024*")
  elif training_data_% == 50:
    proxy_task_docker_args_map["training_data_path"] = os.path.join(
        root_path, "train-00[0-4]??-of-01024*")
  elif training_data_% == 75:
    proxy_task_docker_args_map["training_data_path"] = os.path.join(
        root_path, "train-00[0-6][0-4]?-of-01024*")
  elif training_data_% == 95:
    proxy_task_docker_args_map["training_data_path"] = os.path.join(
        root_path, "train-00[0-8][0-4]?-of-01024*")
  else:
    logging.warning("Mnasnet training_data_% %d is not supported.",
                    training_data_pct)
    return None
  proxy_task_docker_args_map["validation_data_path"] = os.path.join(
      root_path, "train-009[0-4]?-of-01024")
  return proxy_task_docker_args_map


def mnasnet_proxy_task_config_generator(
    baseline_docker_args_map: Dict[str, Any]
) -> List[proxy_task_utils.ProxyTaskConfig]:
  """Returns a list of proxy-task configs to be evaluated for MNasnet.

  Args:
    baseline_docker_args_map: A set of baseline training-docker arguments in
      the form of a dictionary of {'key', val}. The different proxy-task
      configs to try can be built by modifying this baseline.

  Returns:
    A list of proxy-task configs to be evaluated for this
    proxy-task search space.
  """
  proxy_task_config_list = []
  # NOTE: Will not search over model-scale for MNasnet.
  for training_data_% in MNASNET_TRAINING_DATA_PCT_LIST:
    proxy_task_docker_args_map = update_mnasnet_proxy_training_data(
        baseline_docker_args_map=baseline_docker_args_map,
        training_data_pct=training_data_pct)
    if not proxy_task_docker_args_map:
      continue
    proxy_task_name = "mnasnet_proxy_training_data_pct_{}".format(
        training_data_pct)
    proxy_task_config_list.append(
        proxy_task_utils.ProxyTaskConfig(
            name=proxy_task_name, docker_args_map=proxy_task_docker_args_map))
  return proxy_task_config_list

在這個範例中,我們建立了一個簡單的搜尋空間,訓練資料百分比為 25、50、75 和 95 (請注意,100% 訓練資料不會用於 stage1-search)。mnasnet_proxy_task_config_generator 函式會採用訓練 Docker 引數的一般基準範本,然後針對每個所需的 Proxy 任務訓練資料大小修改這些引數。接著,系統會傳回 proxy-task-config 清單,並由 proxy-task 搜尋工具依相同順序逐一處理。每個 Proxy 工作設定都有 name 和 docker_args_map,這是 Proxy 工作 Docker 引數的鍵/值對應。

您可以根據自己的需求,自由實作自己的搜尋空間定義,並設計自己的代理任務搜尋空間,甚至可以超過減少訓練資料或減少模型規模的兩個維度。不過,我們不建議明確搜尋訓練步驟,因為這會浪費重複的運算資源。讓 Proxy 任務搜尋工具為您處理這個維度。

第一次搜尋代理任務時,可以嘗試只減少訓練資料 (就像 MnasNet 範例一樣),並略過縮減模型規模,因為模型縮放可能會涉及 image-size、num-filters 或 num-blocks 的多個參數。在多數情況下,減少訓練資料 (以及減少訓練步驟的「隱含」搜尋) 就足以找出合適的代理任務。

將訓練步數設為完整基準訓練使用的步數。第 2 階段完整訓練和第 1 階段代理任務訓練的設定有所不同。如果是 Proxy 任務,請將 batch-size 設為比完整基準訓練設定更低的值,只使用 2 個或 4 個 GPU。一般來說,完整訓練會使用 4 個、8 個或更多 GPU,但 Proxy 工作只會使用 2 個或 4 個 GPU。另一個差異是訓練和驗證分割。以下範例說明 MnasNet 設定的變更,從第 2 階段完整訓練的 4 個 GPU,變更為 2 個 GPU 和不同的驗證分割,用於 Proxy 任務搜尋:

Proxy 工作設定

執行下列指令,啟動 Proxy 任務搜尋控制器工作 (需要服務帳戶):

DATE="$(date '+%Y%m%d_%H%M%S')"
project_id=<your project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file=<path to your trainer dockerfile>
latency_calculator_docker_id=${USER}_model_selection_${DATE}
latency_calculator_docker_file=${USER}_latency_${DATE}
region=<your job region such as 'us-central1'>
search_space_module=<path to your NAS job search space module>
accelerator_type="NVIDIA_TESLA_V100"
num_gpus=2
# Your bucket should be for your project and in the same region as the job.
root_output_dir=<gs://your-bucket>
# Your latency computation device.
target_device_type="CPU"

####### Proxy task search related parameters ######
proxy_task_search_controller_docker_id=${USER}_proxy_task_search_${DATE}
job_name=<your job name>
# Path to your proxy task search space definition. For ex:
# 'proxy_task.proxy_task_search_spaces.mnasnet_proxy_task_config_generator'
proxy_task_config_generator_module=<path to your proxy task config generator module>
# The previous model-slection job provides the candidate-correlation-models
# and their scores.
proxy_task_model_selection_job_id=<Numeric job id of your previous model-selection>
# During proxy-task search, the proxy-task training is stopped
# when the following correlation score is achieved.
desired_accuracy_correlation=0.65
# During proxy-task search, the proxy-task training is stopped
# if the runtime exceeds this limit: 4 hrs.
training_time_hrs_limit=4
# The proxy-task is marked a good candidate only if the latency
# correlation is also above the required threshold.
# Note: This won't be used if you do not have a latency job.
desired_latency_correlation=0.65
# Early stop a proxy-task evaluation if you already have a better candidate.
# If False, evaluate all proxy-taask candidates.
early_stop_proxy_task_if_not_best=False
# Use the service account that you set-up for your project.
service_account=<your service account>
###################################################


python3 vertex_nas_cli.py build \
--project_id=${project_id} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--trainer_docker_file=${trainer_docker_file} \
--latency_calculator_docker_id=${latency_calculator_docker_id} \
--latency_calculator_docker_file=${latency_calculator_docker_file} \
--proxy_task_search_controller_docker_id=${proxy_task_search_controller_docker_id}

# The command below passes 'dummy' arguments for trainer-docker
# and latency-docker. You need to modify them for your own docker.
python3 vertex_nas_cli.py search_proxy_task \
--service_account=${service_account} \
--proxy_task_search_controller_docker_id=${proxy_task_search_controller_docker_id} \
--proxy_task_config_generator_module=${proxy_task_config_generator_module} \
--proxy_task_model_selection_job_id=${proxy_task_model_selection_job_id} \
--proxy_task_model_selection_job_region=${region} \
--desired_accuracy_correlation={$desired_accuracy_correlation}\
--training_time_hrs_limit=${training_time_hrs_limit} \
--desired_latency_correlation=${desired_latency_correlation} \
--early_stop_proxy_task_if_not_best=${early_stop_proxy_task_if_not_best} \
--project_id=${project_id} \
--region=${region} \
--trainer_docker_id=${trainer_docker_id} \
--job_name=${job_name} \
--search_space_module=${search_space_module} \
--accelerator_type=${accelerator_type} \
--num_gpus=${num_gpus} \
--root_output_dir=${root_output_dir} \
--latency_calculator_docker_id=${latency_calculator_docker_id} \
--latency_docker_flags \
dummy_latency_flag1="dummy_latency_val" \
--target_device_type=${target_device_type} \
--search_docker_flags \
dummy_trainer_flag1="dummy_trainer_val"

啟動這項 Proxy 任務搜尋控制器工作後,您會收到工作連結。工作名稱開頭為前置字串 Search_controller_。工作 UI 範例如下:

Proxy 任務搜尋工作

search_controller_dir 會包含所有輸出內容,您可以點選「View logs」連結查看記錄。根據預設,這項工作會使用雲端中的一個 CPU,在背景中以自訂工作的形式執行,然後啟動並管理每個 Proxy 工作評估的子 NAS 工作。

自訂工作與 NAS 工作

每個 Proxy 工作 NAS 工作都有名稱,例如 ProxyTask_<your-job-name>_<proxy-task-name>,其中 <proxy-task-name> 是 Proxy 工作設定產生器模組為每個 Proxy 工作提供的名稱。一次只能執行一項代理任務評估。您也可以執行下列指令:

gcloud storage cat gs://<path to 'search_controller_dir'>/SEARCH_CONTROLLER_STATE.json

這個指令會顯示所有 Proxy 任務評估的摘要,以及搜尋控制器工作的目前狀態、工作名稱和各項評估的連結:

{
  "proxy_tasks_map": {
    "mnasnet_proxy_training_data_pct_25": {
      "proxy_task_stats": {
        "training_steps": [
          1249,
          2499,
          ...,
          18749
        ],
        "accuracy_correlation_over_step": [
          -0.06666666666666667,
          -0.6,
          ...,
          0.7857142857142856
        ],
        "accuracy_correlation_p_value_over_step": [
          0.8618005952380953,
          0.016666115520282188,
          ...,
          0.005505952380952381
        ],
        "median_accuracy_over_step": [
          0.011478611268103123,
          0.04956454783678055,
          ...,
          0.32932570576667786
        ],
        "median_training_time_hrs_over_step": [
          0.11611097933475001,
          0.22913257125276987,
          ...,
          1.6682701704073444
        ],
        "latency_correlation": 0.9555555555555554,
        "latency_correlation_p_value": 5.5114638447971785e-06,
        "stopping_state": "Met desired correlation",
        "posted_stop_trials_message": true,
        "final_training_time_in_hours": 1.6675102778428197,
        "final_training_steps": 18512
      },
      "proxy_task_name": "mnasnet_proxy_training_data_pct_25",
      "search_job_name": "projects/123456/locations/europe-west4/nasJobs/4173661476642357248",
      "search_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/4173661476642357248/cpu?project=my-project",
      "latency_calculator_job_name": "projects/123456/locations/europe-west4/customJobs/8785347495069745152",
      "latency_calculator_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/8785347495069745152/cpu?project=my-project"
    },
    ...,
    "mnasnet_proxy_training_data_pct_95": {
      "proxy_task_stats": {
        "training_steps": [
          1249,
          ...,
          18749
        ],
        "accuracy_correlation_over_step": [
          -0.3333333333333333,
          ...,
          0.7857142857142856,
          -5.0
        ],
        "accuracy_correlation_p_value_over_step": [
          0.21637345679012346,
          ...,
          0.005505952380952381,
          -5.0
        ],
        "median_accuracy_over_step": [
          0.01120645459741354,
          ...,
          0.38238024711608887,
          -1.0
        ],
        "median_training_time_hrs_over_step": [
          0.11385884770307843,
          ...,
          1.5466042930547819,
          -1.0
        ],
        "latency_correlation": 0.9555555555555554,
        "latency_correlation_p_value": 5.5114638447971785e-06,
        "stopping_state": "Met desired correlation",
        "posted_stop_trials_message": true,
        "final_training_time_in_hours": 1.533235285929564,
        "final_training_steps": 17108
      },
      "proxy_task_name": "mnasnet_proxy_training_data_pct_95",
      "search_job_name": "projects/123456/locations/europe-west4/nasJobs/2341822328209408000",
      "search_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/2341822328209408000/cpu?project=my-project",
      "latency_calculator_job_name": "projects/123456/locations/europe-west4/customJobs/7575005095213924352",
      "latency_calculator_job_link": "https://console.cloud.google.com/agent-platform/locations/europe-west4/training/7575005095213924352/cpu?project=my-project"
    }
  },
  "best_proxy_task_name": "mnasnet_proxy_training_data_pct_75"
}

proxy_tasks_map 會儲存每項代理任務評估的輸出內容,best_proxy_task_name 則會記錄搜尋的最佳代理任務。每個代理任務項目都有額外資料,例如 proxy_task_stats,記錄準確度相關性的進度、p 值、中位數準確度,以及訓練步驟的中位數訓練時間。此外,系統也會記錄延遲時間相關的關聯性 (如適用),以及停止這項工作的原因 (例如超過訓練時間限制) 和停止時的訓練步驟。您也可以執行下列指令,將 search_controller_dir 的內容複製到本機資料夾,以圖表形式查看這些統計資料:

gcloud storage cp gs://<path to 'search_controller_dir'>/* /your/local/dir

並檢查圖表圖片。舉例來說,下圖顯示最佳代理任務的準確度關聯性與訓練時間:

準確度相關性與訓練時間

搜尋完成後,您已找到最佳的 Proxy 任務設定,接下來必須執行下列操作:

  • 將訓練步數設為勝出代理任務的 final_training_steps。
  • 將餘弦衰減步數設為與 final_training_steps 相同,讓學習率在接近結束時幾乎為零。
  • [選用] 在訓練結束時進行一次驗證分數評估,可節省多次評估的費用。

如要使用地端部署延遲時間裝置進行 Proxy 工作搜尋,請執行 search_proxy_task 指令,但不使用延遲時間 Docker 和 latency-docker 旗標,因為您不想在 Google Cloud上啟動延遲時間 Docker。接著,使用教學課程 4 中所述的 run_latency_calculator_local 指令,啟動地端部署延遲時間計算工具工作。請改為傳遞 --search_job_id--controller_job_id 旗標,並附上 執行 search_proxy_task 指令後取得的 proxy-task-search 工作 ID 數字。

在下列情況下,您必須繼續 Proxy 工作搜尋控制器工作:

  • 父項 Proxy 工作搜尋控制器工作終止 (罕見情況)。
  • 您不小心取消了 Proxy 任務搜尋控制器工作。
  • 您想在日後 (甚至多天後) 擴充 Proxy 任務搜尋空間。

首先,如果子項 NAS 疊代工作 (「NAS」分頁) 已在執行,請勿取消。接著,如要繼續執行父項 Proxy 工作搜尋控制器工作,請像之前一樣執行 search_proxy_task 指令,但這次要傳遞 --previous_proxy_task_search_dir 旗標,並將其設為先前 Proxy 工作搜尋控制器工作的輸出目錄。恢復的 Proxy 工作搜尋控制器工作會從目錄載入先前的狀態,並繼續像之前一樣運作。

最終檢查

代理任務的最後兩項檢查包括獎勵範圍,以及儲存資料以供搜尋後分析。

獎勵範圍

回報給控制器的獎勵應介於 [1e-3, 10] 之間。如果不是,您可以人為調整獎勵,以達到這個目標。

儲存資料,以便在搜尋後進行分析

Proxy 任務程式碼應將任何其他指標和資料儲存至 Cloud Storage 位置,以便日後分析搜尋空間。Agent Platform Neural Architecture Search 最多只能記錄五個浮點 other_metrics。任何其他指標都應儲存至 Cloud Storage 位置,以便日後分析。