GitHub Actions的機器學習推理上線,推進測試部署高度自動化

在看到最近新推出的GitHub Actions後,我的第一個想法是創建一個簡單的示例項目,在這個項目中,我們“部署”一個使用了這個新特性的機器學習模型。當然,這不是一個“真正的部署”,但是可用此模型在存儲庫中測試你的模型,而不需要任何額外的編碼。

GitHub Actions是一個用於構建、測試和部署的自動化工具。舉個例子快速瞭解下它是什麼:每次你創建一個Pull Request(帶有某個標籤)時,都會觸發新的應用程序構建,然後它可以向高級開發人員發送消息,讓他們快速查看代碼。

項目地址:
https://github.com/gaborvecsei/Machine-Learning-Inference-With-GitHub-Actions

我們將創建什麼?

在存儲庫上創建一個自定義操作和自動化工作流,你可以在其中使用經過訓練的模型,並在某個問題有了新評論時觸發它。你還可以找到模型訓練和推理代碼。我想要超級硬核,所以我選擇了Iris數據集和隨機森林分類器。這個樹集成模型經過訓練,可以根據萼片和花瓣的長度和寬度來識別花朵。

這個模型的訓練是在Jupyter Notebook上完成的。這些代碼訓練並序列化我們將用於預測的模型。當問題收到評論時,GitHub Actions工作流將被觸發。如果評論包含前綴/predict,那麼我們就開始解析評論,然後我們做一個預測並構造一個回覆。最後一步,該消息由機器人在相同的問題下發回給用戶。爲了把事情做得更好,整個自定義操作將在Docker容器中運行。

我們將找出工作流中的步驟,併爲某些步驟創建單獨的操作。一個工作流可以包含多個操作,但是在這個項目中,我們將使用單個操作。

創建一個操作

第一步,我們應該在名爲action.yaml的根文件夾中創建操作。在這裏,我們可以描述inputs、outputs和運行環境。

name: 'Prediction GitHub Action Test'
description: 'This is a sample with which you can run inference on a ML model with a toy dataset'
inputs:
  issue_comment_body:
    required: true
    description: 'This is the Github issue comment message'
  issue_number:
    required: true
    description: 'Number of the Github issue'
  issue_user:
    required: true
	description: 'This user send the comment'
outputs:
   issue_comment_reply:
	 description: 'Reply to the request'
runs:
   using: 'docker'
   image: 'Dockerfile'
    args:    
        - ${{ inputs.issue_comment_body }}
	    - ${{ inputs.issue_number }}
	    - ${{ inputs.issue_user }}  

從上到下,你可以看到定義好的3個輸入和1個輸出。最後,runs鍵描述了我們的代碼將要在其中運行的環境。這是一個Docker容器,其輸入將作爲參數傳入。因此,容器的入口點應該按照定義的順序接受這3個參數。

容器

如果我們仔細查看Dockerfile,就可以看到我們的運行環境是如何構建的。首先,我們安裝所有Python需要的東西。然後複製entrypoint.sh並使其可執行,這樣它就可以在容器內運行了。最後,序列化的sklearn模型文件被複制到容器中,這樣,我們就可以使用它來進行預測。(在真實的場景中,不應該將模型文件存儲在存儲庫中。這只是爲了可以快速演示。)

FROM python:3.6

# Install python requirements
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

# Setup Docker entrypoint script
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Copy the trained model
COPY random_forest_model.pkl /random_forest_model.pkl

ENTRYPOINT ["/entrypoint.sh"]

定義工作流

沒有工作流就不能使用操作。它定義了你希望在管道中採取的不同步驟。

name: Demo
on: [issue_comment]

jobs:
    my_first_job:
        runs-on: ubuntu-latest
        name: Just a simple demo job
        steps:
            - name: Checkout
              uses: actions/checkout@master
            - name: See full payload (for debugging)
              env:
                  PAYLOAD: ${{ toJSON(github.event) }}
              run: echo "FULL PAYLOAD:\n${PAYLOAD}\n"
            - name: Run the container and make a prediction
              if: startsWith(github.event.comment.body, '/predict')
              uses: ./
              id: make_prediction
              with:
                  issue_comment_body: ${{ github.event.comment.body }}
                  issue_number: ${{ github.event.issue.number }}
                  issue_user: ${{ github.event.comment.user.login }}
            - name: Print the output from the container(for debugging)
              run: echo "The reply message is ${{steps.make_prediction.outputs.issue_comment_reply}}"
            - name: Send reply to issue for user
              env:
                GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
              run: bash issue_comment.sh "steps.makeprediction.outputs.issuecommentreply""{{ github.event.issue.number }}"

首先,on: [issue_comment]定義了我希望在接收到某個問題的評論(任何人提出的任何問題)時觸發這個流。然後,我通過runs-on: ubuntu-latest定義了運行的VM類型(它可以是自託管的,也可以是由GitHub提供的)。接下來是有趣的部分,我之前提到的步驟。

  • 簽出步驟:在這個步驟中,我們將移到存儲庫中所需的分支上(這也是一個github操作)。
  • 查看有效負載:我在這裏把它用於調試。在問題下收到評論後,它顯示整個有效負載,包括這個容器、評論、問題編號、留下評論的用戶等等。
  • 做出預測:這是我們的自定義動作。代碼行if: startsWith(github.event.comment.body,’/predict’)確保只有在出現有效的預測請求時才運行這個步驟(包含前綴/predict)。你可以看到,輸入是在with關鍵字下定義的,而值是通過它們的鍵(如github.event.comment.body)從負載中添加的。
  • 打印應答:構造的應答被回顯到日誌。它使用前面的步驟中定義的輸出:steps.make_prediction.output .issue_comment_reply。
  • 發送應答:創建的應答中包含預測,將使用腳本issue_comments .sh作爲應答發送。

每個步驟都在指定的運行器ubuntu-latest上運行,但是我們的操作在創建的容器中運行。此容器是在工作流被觸發時構建的。(我本來可以緩存它,這樣每次流運行時就可以使用以前構建的映像,但是我還是懶得將它添加到這個示例中)。

做出預測

有一件事我沒有談到:預測是如何做出的?你可以通過查看main.py腳本輕鬆地解決這個問題。
model = load_model("/random_forest_model.pkl")

try:
    sepal_length, sepal_width, petal_length, petal_width = parse_comment_input(args.issue_comment_body)
    predicted_class_id = make_prediction(model, sepal_length, sepal_width, petal_length, petal_width)
    predicted_class_name = map_class_id_to_name(predicted_class_id)
    reply_message = f"Hey @{args.issue_user}!<br>This was your input: {args.issue_comment_body}.<br>The prediction: **{predicted_class_name}**"
except Exception as e:
    reply_message = f"Hey @{args.issue_user}! There was a problem with your input. The error: {e}"

print(f"::set-output name=issue_comment_reply::{reply_message}")

看到上面的內容,可能你就會覺得這太簡單了:輸入、數據集、模型、模式存儲、如何處理請求等等。例如,對於圖像輸入,你可以從一個base64字符串解碼,然後通過存儲在GitLFS中的深度學習模型運行它。那麼,就動手實際操作下吧。

原文鏈接:
https://www.gaborvecsei.com/Machine-Learning-Inference-with-GitHub-Actions/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章