Share via


使用 Visual Studio Code 進行互動式偵錯

適用於:Python SDK azureml v1

了解如何使用 Visual Studio Code (VS Code) 和 debugpy,以互動方式進行 Azure Machine Learning 實驗、管線和部署的偵錯。

在本機執行實驗並進行偵錯

請先使用 Azure Machine Learning 擴充功能來進行機器學習實驗的驗證、執行和偵錯,再將實驗提交至雲端。

必要條件

在本機對實驗進行偵錯

重要

在本機執行實驗之前,請先確定:

  • Docker 正在執行。
  • Visual Studio Code 中的 azureML.CLI Compatibility Mode 設定已如必要條件所指定地設定為 1.0
  1. 在 VS Code 中,開啟 Azure Machine Learning 擴充功能檢視。

  2. 展開包含您工作區的訂用帳戶節點。 如果您還沒有工作區,則可使用擴充功能來建立 Azure Machine Learning 工作區

  3. 展開您的工作區節點。

  4. 以滑鼠右鍵按一下 [實驗] 節點,然後選取 [建立實驗]。 出現提示時,請提供實驗的名稱。

  5. 展開 [實驗] 節點,以滑鼠右鍵按一下您想要執行的實驗,然後選取 [執行實驗]

  6. 從選項清單中選取 [本機]

  7. 第一次只在 Windows 上使用。 當系統提示您允許檔案共用時,請選取 [是]。 當您啟用檔案共用時,其會允許 Docker 將包含您指令碼的目錄掛接到容器。 此外,其也可讓 Docker 將您的執行所得到的記錄和輸出儲存在系統上的暫存目錄中。

  8. 選取 [是] 以對實驗進行偵錯。 否則選取。 選取 [否] 會在本機執行實驗,但不會連結至偵錯工具。

  9. 選取 [建立新的回合組態],以建立您的回合組態。 回合組態會定義您想要執行的指令碼、相依性及使用的資料集。 或者,如果您已經有回合組態,則請從下拉式清單中進行選取。

    1. 選擇您的環境。 您可以從任何已策展的 Azure Machine Learning 進行選擇,也可以建立自己的環境。
    2. 提供要執行的指令碼所具有的名稱。 路徑會相對於 VS Code 中開啟的目錄。
    3. 選擇您是否要使用 Azure Machine Learning 資料集。 您可以使用擴充功能來建立 Azure Machine Learning 資料集
    4. 需要 Debugpy 才能將偵錯工具連結至執行實驗的容器。 若要將 debugpy 新增為相依性,請選取 [新增 Debugpy]。 否則,選取 [Skip] (跳過)。 若未將 debugpy 新增為相依性,則會執行實驗但不將其連結至偵錯工具。
    5. 系統會在編輯器中開啟包含回合組態設定的組態檔。 如果您對設定感到滿意,請選取 [提交實驗]。 或者,您也可以從功能表列開啟命令選擇區 ([檢視] > [命令選擇區]),然後在文字方塊中輸入 AzureML: Submit experiment 命令。
  10. 在提交實驗後,系統便會建立包含您指令碼以及回合組態中所指定組態的 Docker 映像。

    當 Docker 映像建置程序開始進行時,60_control_log.txt 檔案的內容便會串流至 VS Code 中的輸出主控台。

    注意

    系統第一次建立 Docker 映像時可能需要幾分鐘的時間。

  11. 映像建置完成後,就會出現提示讓您啟動偵錯工具。 請在指令碼中設定中斷點,並在準備好開始進行偵錯時,選取 [啟動偵錯工具]。 這麼做會將 VS Code 偵錯工具連結到執行實驗的容器。 或者,也可以在 Azure Machine Learning 擴充功能中,將滑鼠指標停留在目前執行的節點上方,然後選取 [播放] 圖示以啟動偵錯工具。

    重要

    單一實驗不能有多個偵錯工作階段。 但是,您可以使用多個 VS Code 執行個體來對兩個以上的實驗進行偵錯。

至此,您應該已經能夠使用 VS Code 逐步完成程式碼並對其進行偵錯。

如果您想要在任何一個時間點取消執行,請在執行節點上按一下滑鼠右鍵,然後選取 [取消執行]

和遠端實驗執行類似,您也可以展開執行節點來檢查記錄和輸出。

提示

使用了環境中所定義相同相依性的 Docker 映像,會在兩次執行之間重複使用。 但是,如果您使用新環境或不同環境來執行實驗,則系統會建立新的映像。 由於這些映像會儲存到您的本機儲存體,因此建議您移除舊的或未使用的 Docker 映像。 若要移除系統中的映像,請使用 Docker CLIVS Code Docker 擴充功能

機器學習管線的偵錯和疑難排解

在某些情況下,您可能需要以互動方式來對 ML 管線中使用的 Python 程式碼進行偵錯。 藉由使用 VS Code 和 debugpy,您可以在程式碼在訓練環境中執行時連結程式碼。

必要條件

  • 設定為使用 Azure 虛擬網路Azure Machine Learning 工作區

  • 在管線步驟中使用 Python 指令碼的 Azure Machine Learning 管線。 例如,PythonScriptStep。

  • Azure Machine Learning 計算叢集,位於虛擬網路中供管線用來進行定型

  • 位於虛擬網路中開發環境。 開發環境可為下列其中一種:

    • 虛擬網路中的 Azure 虛擬機器
    • 虛擬網路中 Notebook VM 的計算執行個體
    • 用戶端電腦,具有虛擬網路的私人網路連線能力 (透過 VPN 或 ExpressRoute)。

如需搭配使用 Azure 虛擬網路與 Azure Machine Learning 的詳細資訊,請參閱虛擬網路隔離和隱私權概觀

提示

雖然您可以使用不在虛擬網路後方的 Azure Machine Learning 資源,但還是建議您使用虛擬網路。

運作方式

您的 ML 管線步驟會執行 Python 指令碼。 這些指令碼會經過修改,以便能執行下列動作:

  1. 記錄其執行所在主機的 IP 位址。 您可以使用 IP 位址將偵錯工具連線至指令碼。

  2. 啟動 debugpy 偵錯元件,並等候偵錯工具連線。

  3. 從您的開發環境中,您可以監視定型程序所建立的記錄,以找出指令碼執行所在的 IP 位址。

  4. 您可以使用 launch.json 檔案來告訴 VS Code 要將偵錯工具連線到的 IP 位址。

  5. 您可以連結偵錯工具,並以互動方式逐步執行指令碼。

設定 Python 指令碼

若要啟用偵錯功能,請對您 ML 管線中的步驟所使用的 Python 指令碼進行下列變更:

  1. 新增下列匯入陳述式:

    import argparse
    import os
    import debugpy
    import socket
    from azureml.core import Run
    
  2. 新增下列引數。 這些引數可讓您視需要啟用偵錯工具,並設定用於連結偵錯工具的逾時值:

    parser.add_argument('--remote_debug', action='store_true')
    parser.add_argument('--remote_debug_connection_timeout', type=int,
                        default=300,
                        help=f'Defines how much time the Azure Machine Learning compute target '
                        f'will await a connection from a debugger client (VSCODE).')
    parser.add_argument('--remote_debug_client_ip', type=str,
                        help=f'Defines IP Address of VS Code client')
    parser.add_argument('--remote_debug_port', type=int,
                        default=5678,
                        help=f'Defines Port of VS Code client')
    
  3. 加入下列 陳述式。 這些陳述式會載入目前的執行內容,讓您可以記錄程式碼執行所在節點的 IP 位址:

    global run
    run = Run.get_context()
    
  4. 新增 if 陳述式,以啟動 debugpy 並等候偵錯工具連結。 如果逾時前沒有連結任何偵錯工具,指令碼會繼續正常執行。 請務必要將 listen 函式的 HOSTPORT 值取代為您自己的值。

    if args.remote_debug:
        print(f'Timeout for debug connection: {args.remote_debug_connection_timeout}')
        # Log the IP and port
        try:
            ip = args.remote_debug_client_ip
        except:
            print("Need to supply IP address for VS Code client")
        print(f'ip_address: {ip}')
        debugpy.listen(address=(ip, args.remote_debug_port))
        # Wait for the timeout for debugger to attach
        debugpy.wait_for_client()
        print(f'Debugger attached = {debugpy.is_client_connected()}')
    

下列 Python 範例顯示可啟用偵錯功能的簡單 train.py 檔案:

# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license.

import argparse
import os
import debugpy
import socket
from azureml.core import Run

print("In train.py")
print("As a data scientist, this is where I use my training code.")

parser = argparse.ArgumentParser("train")

parser.add_argument("--input_data", type=str, help="input data")
parser.add_argument("--output_train", type=str, help="output_train directory")

# Argument check for remote debugging
parser.add_argument('--remote_debug', action='store_true')
parser.add_argument('--remote_debug_connection_timeout', type=int,
                    default=300,
                    help=f'Defines how much time the Azure Machine Learning compute target '
                    f'will await a connection from a debugger client (VSCODE).')
parser.add_argument('--remote_debug_client_ip', type=str,
                    help=f'Defines IP Address of VS Code client')
parser.add_argument('--remote_debug_port', type=int,
                    default=5678,
                    help=f'Defines Port of VS Code client')

# Get run object, so we can find and log the IP of the host instance
global run
run = Run.get_context()

args = parser.parse_args()

# Start debugger if remote_debug is enabled
if args.remote_debug:
    print(f'Timeout for debug connection: {args.remote_debug_connection_timeout}')
    # Log the IP and port
    ip = socket.gethostbyname(socket.gethostname())
    # try:
    #     ip = args.remote_debug_client_ip
    # except:
    #     print("Need to supply IP address for VS Code client")
    print(f'ip_address: {ip}')
    debugpy.listen(address=(ip, args.remote_debug_port))
    # Wait for the timeout for debugger to attach
    debugpy.wait_for_client()
    print(f'Debugger attached = {debugpy.is_client_connected()}')

print("Argument 1: %s" % args.input_data)
print("Argument 2: %s" % args.output_train)

if not (args.output_train is None):
    os.makedirs(args.output_train, exist_ok=True)
    print("%s created" % args.output_train)

設定 ML 管線

若要提供用來啟動 debugpy 並取得執行內容所需的 Python 套件,請建立環境並設定 pip_packages=['debugpy', 'azureml-sdk==<SDK-VERSION>']。 變更 SDK 版本,使其符合您所使用的版本。 下列程式碼片段會示範如何建立環境:

# Use a RunConfiguration to specify some additional requirements for this step.
from azureml.core.runconfig import RunConfiguration
from azureml.core.conda_dependencies import CondaDependencies
from azureml.core.runconfig import DEFAULT_CPU_IMAGE

# create a new runconfig object
run_config = RunConfiguration()

# enable Docker 
run_config.environment.docker.enabled = True

# set Docker base image to the default CPU-based image
run_config.environment.docker.base_image = DEFAULT_CPU_IMAGE

# use conda_dependencies.yml to create a conda environment in the Docker image for execution
run_config.environment.python.user_managed_dependencies = False

# specify CondaDependencies obj
run_config.environment.python.conda_dependencies = CondaDependencies.create(conda_packages=['scikit-learn'],
                                                                           pip_packages=['debugpy', 'azureml-sdk==<SDK-VERSION>'])

在<設定 Python 指令碼>一節中,我們已在您 ML 管線步驟所使用的指令碼中新增一些引數。 下列程式碼片段會示範如何使用這些引數來為元件啟用偵錯功能,並設定逾時值。 其也會示範如何使用稍早透過設定 runconfig=run_config 所建立的環境:

# Use RunConfig from a pipeline step
step1 = PythonScriptStep(name="train_step",
                         script_name="train.py",
                         arguments=['--remote_debug', '--remote_debug_connection_timeout', 300,'--remote_debug_client_ip','<VS-CODE-CLIENT-IP>','--remote_debug_port',5678],
                         compute_target=aml_compute,
                         source_directory=source_directory,
                         runconfig=run_config,
                         allow_reuse=False)

當管線執行時,每個步驟都會建立子執行。 如果啟用了偵錯功能,修改過的指令碼會在子執行的 70_driver_log.txt 中記錄類似下列文字的資訊:

Timeout for debug connection: 300
ip_address: 10.3.0.5

儲存 ip_address 值。 此資訊用於下一節。

提示

您也可以從執行記錄中找到此管線步驟子執行的 IP 位址。 如需如何檢視此資訊的詳細資訊,請參閱監視 Azure Machine Learning 實驗執行和計量

設定開發環境

  1. 若要在 VS Code 開發環境上安裝 debugpy,請使用下列命令:

    python -m pip install --upgrade debugpy
    

    如需搭配 VS Code 使用 debugpy 的詳細資訊,請參閱遠端偵錯

  2. 若要設定 VS Code 以便與執行偵錯工具的 Azure Machine Learning 計算進行通訊,請建立新的偵錯組態:

    1. 從 VS Code 選取 [偵錯] 功能表,然後選取 [開啟組態]。 隨即開啟名為 launch.json 的檔案。

    2. 在 launch.json 檔案中,尋找包含 "configurations": [ 的那一行,並在其後插入下列文字。 將 "host": "<IP-ADDRESS>" 項目變更為上一節中您的記錄所傳回的 IP 位址。 將 "localRoot": "${workspaceFolder}/code/step" 項目變更為要進行偵錯的指令碼複本所在的本機目錄:

      {
          "name": "Azure Machine Learning Compute: remote debug",
          "type": "python",
          "request": "attach",
          "port": 5678,
          "host": "<IP-ADDRESS>",
          "redirectOutput": true,
          "pathMappings": [
              {
                  "localRoot": "${workspaceFolder}/code/step1",
                  "remoteRoot": "."
              }
          ]
      }
      

      重要

      如果組態區段中已經有其他項目,請在您插入的程式碼後面新增逗號 (,)。

      提示

      最佳做法 (尤其是對管線來說) 是將指令碼的資源存放在不同目錄,讓程式碼只與每個步驟有所關聯。 在此範例中,localRoot 範例值會參考 /code/step1

      如果您要對多個指令碼進行偵錯,請在不同目錄中為每個指令碼建立個別的組態區段。

    3. 儲存 launch.json檔案。

連線偵錯工具

  1. 開啟 VS Code 並開啟指令碼的本機複本。

  2. 設定要讓指令碼在您連結之後停止執行的中斷點。

  3. 當子程序正在執行指令碼,且 Timeout for debug connection 顯示在記錄中時,請使用 F5 鍵或選取 [偵錯]。 出現提示時,請選取 [Azure Machine Learning 計算:遠端偵錯] 組態。 您也可以從提要欄位選取 [偵錯] 圖示、從 [偵錯] 下拉式功能表選取 [Azure Machine Learning:遠端偵錯] 項目,然後使用綠色箭號來連結偵錯工具。

    至此,VS Code 會連線到計算節點上的 debugpy,並在您先前設定的中斷點停止執行。 您現在可以在程式碼執行時逐步執行、檢視變數等。

    注意

    如果記錄顯示的項目指出 Debugger attached = False,則表示已超過逾時時間,指令碼會在沒有偵錯工具的情況下繼續執行。 請重新提交管線,並在 Timeout for debug connection 訊息出現後,以及在超過逾時時間之前,連線到偵錯工具。

針對部署進行偵錯和疑難排解

在某些情況下,您可能需要以互動方式來對模型部署中包含的 Python 程式碼進行偵錯。 例如,如果輸入指令碼失敗,而其他記錄無法判斷原因。 藉由使用 VS Code 和 debugpy,您可以連結至在 Docker 容器內執行的程式碼。

提示

如果您要在本機使用受控線上端點和部署,請參閱在 Visual Studio Code 中於本機對受控線上端點進行偵錯 (預覽)

重要

使用 Model.deploy()LocalWebservice.deploy_configuration 在本機部署模型時,無法使用這種偵錯方法。 相反地,您必須使用 Model.package() 方法來建立映像。

本機 Web 服務部署需要在您的本機系統上執行正常的 Docker 安裝。 如需使用 Docker 的詳細資訊,請參閱 Docker Azure 文件。 在使用計算執行個體時,Docker 便已安裝完成。

設定開發環境

  1. 若要在本機 VS Code 開發環境上安裝 debugpy,請使用下列命令:

    python -m pip install --upgrade debugpy
    

    如需搭配 VS Code 使用 debugpy 的詳細資訊,請參閱遠端偵錯

  2. 若要設定 VS Code 以與 Docker 映像通訊,請建立新的偵錯組態:

    1. 從 VS Code 選取 [執行] 擴充功能中的 [偵錯] 功能表,然後選取 [開啟組態]。 隨即開啟名為 launch.json 的檔案。

    2. launch.json 檔案中,尋找 "configurations" 項目 (包含 "configurations": [ 的那一行),並在其後插入下列文字。

      {
          "name": "Azure Machine Learning Deployment: Docker Debug",
          "type": "python",
          "request": "attach",
          "connect": {
              "port": 5678,
              "host": "0.0.0.0",
          },
          "pathMappings": [
              {
                  "localRoot": "${workspaceFolder}",
                  "remoteRoot": "/var/azureml-app"
              }
          ]
      }
      

      插入之後,launch.json 檔案應會如下所示:

      {
      // Use IntelliSense to learn about possible attributes.
      // Hover to view descriptions of existing attributes.
      // For more information, visit: https://go.microsoft.com/fwlink/linkid=830387
      "version": "0.2.0",
      "configurations": [
          {
              "name": "Python: Current File",
              "type": "python",
              "request": "launch",
              "program": "${file}",
              "console": "integratedTerminal"
          },
          {
              "name": "Azure Machine Learning Deployment: Docker Debug",
              "type": "python",
              "request": "attach",
              "connect": {
                  "port": 5678,
                  "host": "0.0.0.0"
                  },
              "pathMappings": [
                  {
                      "localRoot": "${workspaceFolder}",
                      "remoteRoot": "/var/azureml-app"
                  }
              ]
          }
          ]
      }
      

      重要

      如果組態區段中已經有其他項目,請在您插入的程式碼後面新增逗號 ( , )。

      本節會使用連接埠 5678 連結至 Docker 容器。

    3. 儲存 launch.json檔案。

建立包含 debugpy 的映像

  1. 修改部署的 Conda 環境,使其包含 debugpy。 以下範例示範如何使用 pip_packages 參數新增:

    from azureml.core.conda_dependencies import CondaDependencies 
    
    
    # Usually a good idea to choose specific version numbers
    # so training is made on same packages as scoring
    myenv = CondaDependencies.create(conda_packages=['numpy==1.15.4',
                                'scikit-learn==0.19.1', 'pandas==0.23.4'],
                                 pip_packages = ['azureml-defaults==1.0.83', 'debugpy'])
    
    with open("myenv.yml","w") as f:
        f.write(myenv.serialize_to_string())
    
  2. 若要在服務啟動時啟動 debugpy 並等候連線,請將下列內容新增至 score.py 檔案的頂端:

    import debugpy
    # Allows other computers to attach to debugpy on this IP address and port.
    debugpy.listen(('0.0.0.0', 5678))
    # Wait 30 seconds for a debugger to attach. If none attaches, the script continues as normal.
    debugpy.wait_for_client()
    print("Debugger attached...")
    
  3. 建立以環境定義為基礎的映像,並將映像提取到本機登錄。

    注意

    這個範例假設 ws 指向您的 Azure Machine Learning 工作區,而且該 model 是要部署的模型。 myenv.yml 檔案包含在步驟 1 中建立的 Conda 相依性。

    from azureml.core.conda_dependencies import CondaDependencies
    from azureml.core.model import InferenceConfig
    from azureml.core.environment import Environment
    
    
    myenv = Environment.from_conda_specification(name="env", file_path="myenv.yml")
    myenv.docker.base_image = None
    myenv.docker.base_dockerfile = "FROM mcr.microsoft.com/azureml/openmpi3.1.2-ubuntu18.04:latest"
    inference_config = InferenceConfig(entry_script="score.py", environment=myenv)
    package = Model.package(ws, [model], inference_config)
    package.wait_for_creation(show_output=True)  # Or show_output=False to hide the Docker build logs.
    package.pull()
    

    建立並下載映像後 (此程序可能需要 10 分鐘以上的時間),映像路徑 (包括存放庫、名稱和標籤,在此案例中也是其訊息摘要) 最後會顯示在類似下列內容的訊息中:

    Status: Downloaded newer image for myregistry.azurecr.io/package@sha256:<image-digest>
    
  4. 為了能更輕鬆地在本機使用映像,您可以使用下列命令來為此映像新增標籤。 將下列命令中的 myimagepath 取代為上一個步驟中的位置值。

    docker tag myimagepath debug:1
    

    在其餘的步驟中,您可以將本機映像參照為 debug:1,而不是完整的映像路徑值。

服務偵錯

提示

如果您在 score.py 檔案中設定 debugpy 連線的逾時時間,則必須在逾時時間到期之前,將 VS Code 連線到偵錯工作階段。 啟動 VS Code 並開啟 score.py 的本機複本,然後設定中斷點,並在使用本節中的步驟之前做好準備。

如需有關偵錯和設定中斷點的詳細資訊,請參閱偵錯

  1. 若要使用映像啟動 Docker 容器,請使用下列命令:

    docker run -it --name debug -p 8000:5001 -p 5678:5678 -v <my_local_path_to_score.py>:/var/azureml-app/score.py debug:1 /bin/bash
    

    此命令會將您在本機的 score.py 連結到容器中的對應項目。 因此,在編輯器中所做的任何變更都會自動反映在容器中

  2. 為了獲得更好的體驗,您可以使用新的 VS Code 介面進入容器。 從 VS Code 提要欄位中選取 Docker 擴充功能,尋找您建立的本機容器,在本文件中,這個容器是 debug:1。 以滑鼠右鍵按一下此容器並選取 "Attach Visual Studio Code",系統便會自動開啟新的 VS Code 介面,而且此介面會顯示您建立的容器內。

    The container VS Code interface

  3. 在容器內,於殼層中執行下列命令

    runsvdir /var/runit
    

    然後,您就會在容器內的殼層中看到下列輸出:

    The container run console output

  4. 若要將 VS Code 連結至容器內的 debugpy,請開啟 VS Code 並使用 F5 鍵,或選取 [偵錯]。 出現提示時,請選取 [Azure Machine Learning 部署:Docker 偵錯] 組態。 您也可以從提要欄位選取 [執行] 擴充功能、從 [偵錯] 下拉式功能表選取 [Azure Machine Learning 部署:Docker 偵錯] 項目,然後使用綠色箭號來連結偵錯工具。

    The debug icon, start debugging button, and configuration selector

    在選取綠色箭號並連結偵錯工具後,您會在容器的 VS Code 介面中看到一些新資訊:

    The container debugger attached information

    此外,在您的主要 VS Code 介面中,您可以看到如下內容:

    The VS Code breakpoint in score.py

現在,連結到容器的本機 score.py 已在您設定的中斷點停止執行了。 此時,VS Code 會連線到 Docker 容器內的 debugpy,並在您先前設定的中斷點停止 Docker 容器。 您現在可以在程式碼執行時逐步執行、檢視變數等。

如需使用 VS Code 來偵錯 Python 的詳細資訊,請參閱偵錯您的 Python 程式碼

停止容器

若要停止容器,請使用下列命令:

docker stop debug

下一步

現在,您已設定好 VS Code Remote,接下來可以從 VS Code 使用計算執行個體作為遠端計算,以互動方式對程式碼進行偵錯。

深入了解疑難排解: