Proxy 工作設計

在執行神經架構搜尋工作以搜尋最佳模型之前,請先定義代理程式工作Stage1-search 會使用完整模型訓練的較小表示法,通常會在兩小時內完成。這類表示法稱為proxy 工作,可大幅降低搜尋成本。搜尋期間的每個試驗都會使用 Proxy 工作設定訓練模型。

以下各節說明套用 Proxy 工作設計時的相關作業:

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

建立 Proxy 工作的方法

建立 Proxy 工作有三種常見做法,包括:

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

減少訓練步驟

建立 Proxy 工作最簡單的方法,就是減少訓練講師的訓練步驟數,並根據這項部分訓練作業回報分數。

使用經過取樣的訓練資料集

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

在架構搜尋期間使用子樣本訓練資料集,即可建立代理程式工作。不過,進行子樣本時,請遵循下列規範:

  • 在分片之間隨機取用資料。
  • 如果訓練資料不平衡,請使用子樣本平衡資料。

如果您並未執行僅限擴充搜尋,而只執行一般架構搜尋,請略過本節。使用「自動擴增」搜尋擴增政策。建議您取樣訓練資料並執行完整訓練,而非減少訓練步驟數。執行完整訓練時,大量增加增強資料,可讓分數更穩定。此外,使用較少的訓練資料,可降低搜尋成本。

以縮小模型為基礎的 Proxy 工作

您也可以根據基準模型縮減模型,以建立代理程式工作。如要將區塊設計搜尋與縮放搜尋分開,這項功能也相當實用。

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

對於縮減的模型,您也可以減少與原始基準模型相比的擴增和規則化量。

縮小模型的範例

對於電腦視覺任務 (您會在其中訓練圖片),有三種常見的縮減模型方式:

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

建議閱讀EfficientNet 論文提供電腦視覺任務的模型資源調度相關洞察。並說明三種縮放方式彼此間的關係。

Spinenet 搜尋是另一個搭配類神經架構搜尋使用的模型縮放功能範例。對於第 1 階段搜尋,它會縮減管道數量和圖片大小。

根據組合建立 Proxy 工作

這些方法可獨立運作,並可在不同程度上結合,以建立 Proxy 工作。

良好的 Proxy 工作需求

代理程式工作必須符合特定規定,才能將穩定的獎勵傳回控制器,並維持搜尋品質。

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

在神經架構搜尋中使用代理任務時,成功搜尋的關鍵假設是,如果模型 A 在第 1 階段代理任務訓練期間的表現優於模型 B,則模型 A 在第 2 階段完整訓練期間的表現也應優於模型 B。為了驗證這項假設,您必須在搜尋空間中,針對約 10 到 20 個模型評估第 1 階段搜尋與第 2 階段完整訓練獎勵之間的排名相關性。這些模型稱為相關係數候選模型

下圖顯示一個關聯度不佳的例子 (correlation-score = -0.03),這會使這個 Proxy 工作成為搜尋的不適當候選項:

關聯性不佳。

圖表中的每個點都代表一個相關候選模型。x 軸代表模型的階段 2 完整訓練分數,y 軸則代表相同模型的階段 1 代理工作分數。觀察最高點。這個模型的代理任務分數 (y 軸) 最高,但在第 2 階段的完整訓練期間 (x 軸) 的表現不如其他模型。相反地,下圖顯示良好的相關性示例 (相關性分數 = 0.67),這會讓這個 Proxy 工作成為搜尋的理想候選項:

相關性良好。

如果搜尋條件包含延遲限制,請一併驗證延遲值的良好關聯。

請注意,相關性候選模型的獎勵範圍良好,且獎勵範圍的取樣也相當不錯。否則,您就無法評估排名相關性。舉例來說,如果所有相關性候選模型的階段 1 獎勵都以 0.9 和 0.1 這兩個值為中心,則無法提供足夠的取樣變化。

變異檢查

代理程式工作另一項必要條件是,在同一個模型中重複執行多次且沒有任何變更時,準確度或延遲分數不得有太大差異。在這種情況下,會傳回雜訊信號給控制器。我們提供工具來評估這項差異

提供範例可在訓練期間減少大幅變化。其中一種方法是使用 cosine decay 做為學習率時間表。下圖比較了三種學習率策略:

分數採用不同的學習率。

最底部的圖表對應於固定學習率。當分數在訓練結束時出現大幅變動時,選擇減少訓練步驟的次數時,即使只稍微變動,也可能導致最終代理任務獎勵出現大幅變動。為讓代理任務獎勵更穩定,建議您使用餘弦學習率衰減,如最高圖表中對應的驗證分數所示。請注意,在訓練結束時,最高的圖表會變得更平滑。中間的圖表顯示分數與逐步學習率衰減的對應關係。這比固定速率好,但仍不如餘弦衰減法流暢,且需要手動調整。

學習率時間表如下所示:

學習率。

額外的平滑效果

如果您使用大量的擴增資料,驗證曲線可能無法在餘弦衰減時保持平滑。大量使用擴增功能,表示缺乏訓練資料。在這種情況下,我們不建議使用類神經架構搜尋,建議改用擴增搜尋

如果不是因為過度擴增,且您已嘗試使用餘弦衰減,但仍想讓模型更平滑,請使用 TensorFlow-2 的指數移動平均值或 PyTorch 的隨機加權平均值。請參閱這個程式碼指標,瞭解如何使用 TensorFlow 2 搭配指數移動平均最佳化器的範例,以及 PyTorch 的隨機加權平均範例

如果測試的準確度/週期圖表如下所示:

未套用平滑處理的 Accuray/epoch 圖表

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

套用平滑處理的 Accuray/epoch 圖表

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

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

另一種顯示的錯誤是 NaN (非數字) 錯誤。您應該降低初始學習率,或新增梯度截斷。

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

Proxy 工作設計工具

前面幾節討論了代理程式工作設計的原則。本節提供三種代理程式工作設計工具,可根據不同的設計方法自動找出符合所有需求的最佳代理程式工作。

必要程式碼變更

您必須先稍微修改訓練程式碼,讓程式碼能夠在迭代過程中與代理工作設計工具互動。tf_vision/train_lib.py 為範例。您必須先匯入我們的程式庫:

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

在訓練迴圈開始訓練週期之前,請檢查是否需要提早停止訓練,因為代理程式工作設計工具希望您使用我們的程式庫:

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>)

請注意,訓練週期時間不應包含驗證分數評估的時間。請確認訓練器會經常計算驗證分數 (evaluation-frequency),以便您取得足夠的驗證曲線取樣資料。如果您使用延遲限制,請在計算延遲時間後更新延遲時間指標:

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= project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file= to your trainer dockerfile>
region= job region such as 'us-central1'>
search_space_module= 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=

####### 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= service account>
job_name= 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 會包含所有輸出內容,您可以按一下「查看記錄」連結,查看記錄。根據預設,這項工作會使用雲端上的一個 CPU,以自訂工作的形式在背景執行,然後啟動並管理子項 NAS 工作。

自訂工作與網路附加儲存 (NAS) 工作

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

變異數評估記錄

如果變化幅度很大,您可以參考這裡列出的技巧

多種模型供您選擇

確認訓練資料集變異不大後,請採取下列步驟:

  • 找出約 10 個correlation-candidate-models
  • 計算完整訓練分數,日後在計算不同代理程式工作選項的代理程式工作相關分數時,可做為參考。

我們的工具會自動且有效率找出這些關聯候選模型,並確保這些模型在準確度和延遲方面都有良好的分數分布,以便日後關聯計算有良好的基礎。這項工具會執行以下操作:

  • 隨機從搜尋空間中取樣 N_begin 模型。在本範例中,假設 N_begin = 30。這項工具會以 1/30 的完整訓練時間訓練模型。
  • 拒絕 30 個模型中的五個,因為這些模型無法進一步提升準確度和延遲時間的分配。下圖為這項功能的示例。系統會以紅點標示遭拒絕的模型:

模型選取範例

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

N_begin 的預設設定為 30,可在 proxy_task/proxy_task_model_selection_lib_constants.py 檔案中找到 START_NUM_MODELSN 的預設設定為 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 設定。代理程式搜尋工具稍後會並行執行這些 N 模型。因此,請確保您有足夠的 GPU 配額。舉例來說,如果您的 Proxy 工作會為一個模型使用兩個 GPU,則至少應有 2*N 個 GPU 配額。

針對模型選取工作,請使用與第 2 階段完整訓練工作相同的資料集區隔,並為基準完整訓練使用相同的訓練器設定。

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

DATE="$(date '+%Y%m%d_%H%M%S')"
project_id= project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file= to your trainer dockerfile>
latency_calculator_docker_id=${USER}_model_selection_${DATE}
latency_calculator_docker_file=${USER}_latency_${DATE}
region= job region such as 'us-central1'>
search_space_module= 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=
# 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= service account>
job_name= 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= 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 工作都有一個名稱,例如 _iter_3 (疊代 0 除外)。每次只會執行一個疊代。每次疊代時,模型數量 (試驗次數) 會減少,訓練時間則會增加。在每次疊代結束時,每個 NAS 工作都會儲存 gs:///search/filtered_trial_scores.png 檔案,以視覺化方式顯示在本次疊代中遭到拒絕的模型。您也可以執行下列指令:

gcloud storage cat gs:// 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/vertex-ai/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/vertex-ai/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/vertex-ai/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/vertex-ai/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/vertex-ai/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/vertex-ai/locations/europe-west4/training/1490864099985195008/cpu?project=my-project",
      "desired_training_step_pct": 101.0
    }
  ]
}

最後一個疊代作業會顯示最終的參考模型數量,並提供良好的分數分布。這些模型及其分數會用於下一個步驟的代理工作搜尋。如果參考模型的最終準確度和延遲分數範圍看起來較佳或接近現有基準模型,這表示您可以及早掌握搜尋空間。如果最終準確度和延遲分數範圍明顯低於基準值,請重新檢視搜尋空間。

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

使用本機延遲裝置選取模型

如要使用內部延遲裝置進行模型選取,請在沒有延遲 Docker 和延遲 Docker 標記的情況下執行 select_proxy_task_models 指令,因為您不想在 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 標記,並將其設為先前模型選擇控制器工作的輸出目錄。已暫停的模型選取控制器工作會從目錄載入先前的狀態,並繼續照常運作。

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

  • 最低的 NAS 搜尋費用。
  • 在提供代理程式工作搜尋空間定義後,符合最低相關性需求門檻。

請注意,有三個常見維度可用於搜尋最佳 Proxy 工作,包括:

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

您可以透過取樣這些維度來建立獨立的代理程式工作搜尋空間,如下所示:

Proxy 工作搜尋空間格狀檢視畫面

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

關聯性與訓練步驟

因此,代理任務搜尋工具可在取得所需相關性 (例如 0.65) 後停止代理任務訓練,或是在超出搜尋成本配額 (例如每個代理任務的 3 小時限制) 時提早停止。因此,您不需要明確搜尋訓練步驟。代理程式工作搜尋工具會以格狀搜尋的方式評估個別搜尋空間中的每個代理程式工作,並提供最佳選項。

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

# 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:///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% 訓練資料不會用於第 1 階段搜尋)。mnasnet_proxy_task_config_generator 函式會採用訓練 Docker 引數的常見基準範本,然後針對每個所需的 Proxy 工作訓練資料大小修改這些引數。接著,系統會傳回 proxy-task-config 清單,之後由 proxy-task 搜尋工具依序逐一處理。每個 Proxy-Task 設定都包含 namedocker_args_map,這是 Proxy-Task Docker 引數的鍵/值對應項目。

您可以根據自己的需求自由實作專屬的搜尋空間定義,並設計自己的代理工作搜尋空間,即使是縮減訓練資料或縮減模型規模的兩個維度以上,也能這麼做。不過,不建議明確搜尋訓練步驟,因為這會導致重複運算的浪費。讓代理程式工作搜尋工具處理這個維度。

在第一次執行代理程式搜尋作業時,您可以嘗試只縮減訓練資料 (就像 MnasNet 範例一樣),並略過縮減的模型縮放,因為模型縮放可能涉及 image-sizenum-filtersnum-blocks 的多個參數。在大多數情況下,只要使用減少的訓練資料 (以及在減少的訓練步驟中進行隱含搜尋),就能找到合適的代理任務。

將訓練步驟數設為完整基準訓練所使用的數量。階段 2 完整訓練和階段 1 代理程式工作訓練設定之間存在差異。對於 Proxy 工作,您應減少 batch-size 的數量,以便只使用 2 個或 4 個 GPU,一般來說,完整訓練會使用 4 個 GPU、8 個 GPU 或更多,但 Proxy 工作只會使用 2 個 GPU 或 4 個 GPU。另一個差異是訓練和驗證分割。以下是 MnasNet 設定的變更範例,從第 2 階段完整訓練的 4 個 GPU 改為 2 個 GPU,並為代理程式工作搜尋提供不同的驗證分割:

Proxy 工作設定

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

DATE="$(date '+%Y%m%d_%H%M%S')"
project_id= project-id>
# You can choose any unique docker id below.
trainer_docker_id=${USER}_trainer_${DATE}
trainer_docker_file= to your trainer dockerfile>
latency_calculator_docker_id=${USER}_model_selection_${DATE}
latency_calculator_docker_file=${USER}_latency_${DATE}
region= job region such as 'us-central1'>
search_space_module= 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=
# 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= 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= 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= 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= 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-Task Search Controller 工作後,系統會傳送工作連結。工作名稱開頭為前置字串 Search_controller_。以下是工作 UI 範例:

Proxy 工作搜尋工作

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

自訂工作與網路附加儲存 (NAS) 工作

每個 Proxy-task NAS 工作都有一個名稱,例如 ProxyTask__,其中 是 Proxy-task 設定產生器模組為每個 Proxy-task 提供的名稱。一次只能執行一個 Proxy 工作評估。您也可以執行下列指令:

gcloud storage cat gs:// 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/vertex-ai/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/vertex-ai/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/vertex-ai/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/vertex-ai/locations/europe-west4/training/7575005095213924352/cpu?project=my-project"
    }
  },
  "best_proxy_task_name": "mnasnet_proxy_training_data_pct_75"
}

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

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

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

準確率相關係數與訓練時間

搜尋作業已完成,且您已找到最佳的 proxy-task 設定,因此必須執行下列操作:

  • 將訓練步驟數設為勝出者 Proxy 工作項的 final_training_steps
  • 將餘弦衰減步驟設為與 final_training_steps 相同,以便學習率在接近結尾時幾乎為零。
  • [選用] 在訓練結束時執行一次驗證分數評估,可節省多次評估費用。

如要使用內部延遲裝置進行 Proxy 工作搜尋,請在沒有延遲 Docker 和延遲 Docker 標記的情況下執行 search_proxy_task 指令,因為您不想在 Google Cloud上啟動延遲 Docker。接著,請使用第 4 堂教學課程中所述的 run_latency_calculator_local 指令,啟動內部端延遲計算器工作。請不要傳遞 --search_job_id 旗標,而是傳遞 --controller_job_id 旗標,並附上執行 search_proxy_task 指令後取得的代理程式工作搜尋工作 ID 數值。

在下列情況下,您必須恢復代理程式搜尋控制器工作:

  • 父項 Proxy 工作搜尋控制器工作會停止運作 (這種情況很少發生)。
  • 不小心取消了 Proxy-Task Search Controller 工作。
  • 您想在日後 (甚至在多日後) 擴充 Proxy 工作搜尋空間。

首先,如果子項 NAS 迭代工作 (NAS 分頁) 已在執行,請勿取消該工作。接著,如要繼續執行父代理程式工作搜尋控制器工作,請如先前一樣執行 search_proxy_task 指令,但這次要傳遞 --previous_proxy_task_search_dir 標記,並將其設為先前代理程式工作搜尋控制器工作的輸出目錄。已暫停的代理程式工作搜尋控制器工作會從目錄載入先前的狀態,並繼續照常運作。

最終檢查

代理程式工作有兩項最終檢查,包括獎勵範圍和儲存搜尋後分析資料。

獎勵範圍

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

儲存資料以供搜尋後分析

您的 Proxy 工作程式碼應將任何額外指標和資料儲存至 Cloud Storage 位置,這可能有助於日後分析搜尋空間。我們的神經架構搜尋平台最多只支援記錄五個浮點 other_metrics任何額外指標都應儲存至 Cloud Storage 位置,以利日後分析。