Parris:機器學習演算法自動化訓練工具

思源發表於2018-01-02

Parris 是一個自動化訓練機器學習演算法的工具。如果各位讀者經常需要構建並訓練機器學習模型,且花費很多時間來設定執行伺服器,使用遠端登入服務以監控程式等。那麼這個工具將對大家十分有幫助,甚至我們都不需要使用 SSH 訪問伺服器以完成訓練。機器之心簡要介紹了該工具,更詳細的內容請檢視該 GitHub 專案。

專案地址:https://github.com/jgreenemi/Parris

安裝

我們需要一個 AWS 賬戶,並將 AWS 證照載入到工作站中(通過 $ aws configure 配置),我們還需要構建好的機器學習演算法和資料集。此外,我們還需要一個 S3 儲存體(bucket)或其它儲存位置來儲存演算法的訓練結果。

UNIX/Linux:

$ git clone https://github.com/jgreenemi/parris.git && cd parris
$ virtualenv -p python3 env
$ source env/bin/activate
(env) $ pip --version
pip 9.0.1 from .../env/lib/python3.6/site-packages (python 3.6)
(env) $ pip install -r requirements.txt 

Windows:

$ git clone https://github.com/jgreenemi/parris.git && cd parris
$ virtualenv -p python3.exe env
$ env\Scripts\activate
(env) $ pip --version
pip 9.0.1 from ...\python\python36\lib\site-packages (python 3.6)
(env) $ pip install -r requirements.txt

以上是簡要的安裝過程,後一部分我們將具體討論如何使用 Parris,具體包括從配置環境到登入第一個機器學習訓練堆疊的所有過程。當我們熟悉了這個工具後,我們可以檢視該工具的配置引數,以理解更多的操作選項。引數配置與入門指導將共同幫助讀者全面瞭解這個強大的工具。

此外,目前 FAQ 頁面已經有很多關於該工具的問題。如果該文件沒包含讀者出現的問題,那麼我們可以選擇提交 GitHub Issue,這樣其它讀者就能查閱該問題與解答。

  • 入門指導地址:https://github.com/jgreenemi/Parris/blob/master/docs/GETTING-STARTED.md
  • 引數配置指導地址:https://github.com/jgreenemi/Parris/blob/master/docs/CONFIGURATION.md
  • 常見 FAQ 地址:https://github.com/jgreenemi/Parris/blob/master/docs/FAQ.md

開始使用 Parris


我們將介紹如何只用很簡單的點選操作、命令列和指令碼,就可以開始執行訓練任務。

概覽

Parris 的功能有:

  • 建立一個 Lambda 函式
  • 在呼叫 Lambda 函式的時候執行一個 CloudFormation 堆疊
  • 第一次執行時,在堆疊的 EC2 例項上執行一個 UserData 指令碼,以啟動訓練過程
  • 訓練完成的時候停止 EC2 例項

建立這個工具的目的在於減少訓練機器學習演算法過程中重複乏味的環境配置,同時通過更高效地利用伺服器的運算時數以節省計算成本(伺服器一旦啟動就會立刻開始訓練,並會按照你的配置停止訓練)。

預備工作

請按照 README 中的說明進行設定,我們需要的是一個機器學習演算法、可用的資料集,和一個用於啟動訓練過程的 Bash 指令碼。

我將給出一個示例訓練器指令碼(trainer-script),以幫助你更好地理解使用細節。

關於訓練結果提取的注意事項

訓練器指令碼或演算法本身需要將其訓練結果輸出到外部(如另一個伺服器、一個 S3 bucket,等)。CloudFormation 堆疊在訓練結束之後會立即終止,從而其中的訓練結果也將很快被刪除。畢竟我們並不推薦在該伺服器上儲存任何時段的訓練結果。

0. 準備配置

經過合適的設定之後,使用該工具的主要操作在於編輯 training-config.json 配置檔案以及實際執行訓練過程的 trainer-script.sh 指令碼。由於是第一次進行設定,你還需要設定 lambda-config.json 配置檔案(這個很簡單,只需要寫兩行,每行是一個可選項)。

這裡提供的配置是一個使用了我的 GitHub repo 之一的基礎訓練任務示例,以使你更好地理解。除了一些賬戶相關的設定如 IAM role 的 ARN 值和 S3 bucket 名,其它可以按原樣直接執行。

1. 在 training-config 中:

  • 將 subnet-id 改寫為你的 Subnet 之一的 ID(如果這裡不理解,請先在你的 AWS 賬戶上設定 VPC、Subnet、Security Group 和 EC2 Keypair。如果你是第一次使用 AWS,在你的賬戶中會有一些預設的資源)。
  • 將 security-group-id 改寫為你的 VPC 中的一個 Security Group。
  • 將 ec2-keypair-name 改寫為你的一個 EC2 密匙對。
  • 將 instance-type 改寫為 t2.micro 或另一種小型例項型別。由於執行這個堆疊僅僅是為了教學目的,我們希望使用計算成本更低的例項型別,並快速結束任務。t2.micro 是滿足這一目的的最重要的一步。

         可以通過檢視 AWS Simple Monthly Calculator 評估特定例項型別(如 EC2)的計算成本。

  • 所有其它的 training-config 引數可以保持不變,除非必要。可以檢視 CONFIGURATION 文件瞭解各個引數的作用。

2. 在 lambda-config.json 中:

  • 將 lambda-role-arn 更新為你的一個 IAM role 的 ARN 值(如果這裡不理解,可以檢視以下亞馬遜文件)。

Lambda IAM Execution Role 嚮導: http://docs.aws.amazon.com/lambda/latest/dg/with-s3-example-create-iam-role.html

在設定 IAM Role 的時候,你需要將一個或多個 Policy 附加於 Role 上以定義 Lambda 函式可以訪問的一切。以下是我使用的案例,可以使 Lambda 函式啟動一個新的 CloudFormation 堆疊、從 S3 bucket 中獲取物件,以及對 EC2 例項進行大量運算:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:UpdateStack",
                "cloudformation:ValidateTemplate",
                "ec2:DetachVolume",
                "ec2:AttachVolume",
                "ec2:ModifyVolume",
                "ec2:ModifyVolumeAttribute",
                "ec2:DescribeInstances",
                "ec2:TerminateInstances",
                "ec2:DescribeTags",
                "ec2:CreateTags",
                "ec2:DescribeVolumesModifications",
                "ec2:RunInstances",
                "ec2:StopInstances",
                "ec2:DescribeVolumeAttribute",
                "ec2:CreateVolume",
                "ec2:DeleteVolume",
                "ec2:DescribeVolumeStatus",
                "ec2:StartInstances",
                "ec2:DescribeVolumes",
                "ec2:ModifyInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "s3:GetObject"
            ],
            "Resource": "*"
        }
    ]
}

我強烈推薦(雖然不是必要的)使用一個 Policy 以允許將 Lambda 函式寫到一個 CloudWatch logstream 上。當 Lambda 函式出錯的時候,可以通過讀取日誌查詢錯誤。以下是我使用的在一個 Policy 上所有的 CloudWatch Write 許可,這使得視覺化編輯器的設定變得非常簡單:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:DeleteSubscriptionFilter",
                "logs:DeleteLogStream",
                "logs:CreateExportTask",
                "logs:DeleteResourcePolicy",
                "logs:CreateLogStream",
                "logs:DeleteMetricFilter",
                "logs:TagLogGroup",
                "logs:CancelExportTask",
                "logs:DeleteRetentionPolicy",
                "logs:GetLogEvents",
                "logs:AssociateKmsKey",
                "logs:FilterLogEvents",
                "logs:PutDestination",
                "logs:DisassociateKmsKey",
                "logs:UntagLogGroup",
                "logs:DeleteLogGroup",
                "logs:PutDestinationPolicy",
                "logs:TestMetricFilter",
                "logs:DeleteDestination",
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "logs:PutMetricFilter",
                "logs:PutResourcePolicy",
                "logs:PutSubscriptionFilter",
                "logs:PutRetentionPolicy"
            ],
            "Resource": "*"
        }
    ]
}

最後,我們需要設定 trainer-script.sh,從而切實執行訓練過程。這一部分幾乎完全由你自己編寫,因為你的演算法依賴項和輸出訓練結果的方法和我的示例將是不同的。

1. 在 trainer-script.sh 中:

  • 記住你的訓練指令碼是在一個新的伺服器上執行的,因此關於依賴項、目錄結構等所有設定都需要在訓練開始前搞定。例如,如果你使用的是不同版本的 Python 或者需要複製一個 GitHub repo,確保寫入這些步驟。

一旦完成以上步驟,基本上就可以開始使用這個工具了。如果你沒有在 lambda-config.json 中使用 s3-training-bucket 值,那你就可以進行下一步了。如果你使用 S3 bucket 進行載入配置,你需要在 S3bucket 中載入以下的檔案,命令的結構如下所示(沒有寫特定的目錄或檔名)。

+---your-s3-bucket|   \---trainer-script.sh|   \---training-config.json|   \---lambda-config.json

完成之後,就可以進行下一步了。

1. 準備 Lambda 函式

在開始訓練之前,我們需要一種開啟方式,此時就需要 Lambda 配置。這一步需要你建立一個 AWS Lambda 函式,該函式可用於同一個演算法的多個訓練工作,或者不同演算法的多個訓練工作。

1. 在 Parris 包 root 中,啟用 virtualenv。

2. 使用 $ python setup.py 建立 Lambda 函式

       a. 如果已經有 Lambda 函式,這一步將更新其程式碼包。

3. 如果一切順利,則日誌將輸出配置用的 ARN 值。

2. 登入我們的第一個訓練堆疊

注意,第一步可能需要付費,所以先確保你需要這個工具並在開始前先通讀本文件,尤其是後面的第四步。

1. 開啟 AWS 控制檯並導航到你的 Lambda 函式。

2. 點選頁面頂部的「Test」按鈕,並手動呼叫函式。如果你並沒有配置好的測試,那麼就需要完成以下步驟:

  • 在 Saved Test Events 的 Test 按鈕旁邊的下拉選單,點選「Configure test events」以建立一個新的。
  • 因為 Lambda 函式只有一個活動程式(即在呼叫時登入到一個新的 CloudFormation 堆疊),我們並不需要傳遞任何的引數(即使傳遞到 Lambda 的引數被接收了,那也不會使用)。
  • 建立一個名為 Parris-Test-Event、內容為 {} 的事件作為測試,並點選儲存。
  • 在關閉建立對話方塊後,點選下拉選單中新 Test Event 內的 Test 按鈕,並等待用來更新的執行結果。

3. 當你的函式已經執行,執行結果應該出現「succeeded」,並輸出 {}。

  • 如果函式報錯,那麼需要從執行結果定位錯誤地址。一般而的報錯很可能是因為 Lambda 函式的 IAM 角色中缺少 IAM 許可。

4. 切換到 AWS 控制檯的 CloudFormation 試圖,並檢視是否登入了新的 CloudFormation 棧。這大概只需要 1 到 2 分鐘,但很依賴於我們登入的例項(Instance)。

  • 看不到你的 CloudFormation 棧?確保你在正確的區域。
  • 注意堆疊的名字應該匹配訓練專案的名,即我們在 training-config.json 配置的名字。如果處於某些原因你們並沒有配置訓練專案名,那麼棧的名字應該採用預設名「parris-stack」。

5. 切換到 AWS 控制檯的 EC2 例項檢視,以檢視你登入的新例項。它應該處於「Running」狀態,並執行你的訓練專案。

注意,在該版本的工具中,CloudFormation 棧在完成訓練後並不會終止。相反,EC2 例項將自行關閉。由於例項不再執行,因此我們能節省額外的成本。但若是要刪除它,我們需要導航回控制檯的 CloudFormation 檢視,並點選下拉 Action 中刪除堆疊的選項。

3. 獲取訓練結果

獲取訓練結果主要依賴於如何設定演算法來儲存結果引數。大多數情況下這些結果將儲存至本地資料夾(即伺服器的某處,可能在訓練過程的包中)。但是,由於我們在該指南結束時需要終止該堆疊,因此我們想將它們挪到一個更永久的位置。

4. 終止 CloudFormation 棧

現在你已經建立了 CloudFormation 棧,並確認它按照預期工作,那麼我們可以安全地終止該棧,以節省開銷。

  • 1. 開啟 AWS 管理控制檯,導航至 CloudFormation 檢視。
  • 2. 從列表中選擇你安裝的 CloudFormation 棧。
  • 3. 點選頁面頂部的 Actions 下拉選單,點選 Delete Stack。網頁會詢問是否確認刪除,點選 Delete。
  • 4. 檢視該棧的 Events 標籤(頁面底部)來追蹤程式。你必須重新整理該頁面才能新增新的事件。
  • 5. CloudFormation 棧終止後,將從列表中消失。你可以點選列表左上角,將檢視的 Filter 從 Active 更改至 Deleted,來確認是否已刪除。檢視該棧的當前名稱,狀態為「DELETE_COMPLETE」。那麼此時你不需承擔該訓練資源所需的任何開銷。

一般而言,你應該在每次訓練工作完成時終止 CloudFormation 棧。儘管你可以更新 CloudFormation 棧,但該工具的執行原理是:訓練工作被 EC2 例項上的 UserData 指令碼啟動,該指令碼僅在該例項首次安裝時執行。更新 CloudFormation 棧無法重新安裝該例項(除少數環境),這取決於棧被更新的引數。大多數情況下,該例項可以停止再重新開始,但這不足以重新啟動訓練工作。由於終止和安裝新例項與更新原有的例項相比,不需要額外的開銷,因此演算法訓練最佳實踐是終止棧,然後在需要重新訓練時重新安裝棧。

5. 更新 Lambda 函式

更新 Lambda 函式和在 lambda-function.py 檔案中做出改變一樣簡單,重新執行$ python setup.py。指令碼首先嚐試建立 Lambda 函式,如果建立失敗出現函式中已經存在的錯誤,則指令碼將執行函式程式碼的更新版。

注意 Lambda 函式配置的特定細節(即記憶體)不要被指令碼更新,你需要向指令碼新增額外的邏輯來更新函式後設資料,或刪除原來的函式,使用更新後的後設資料重新建立 Lambda 函式。原因在於 Lambda 函式有多種更新方式,沒有一種方法能夠覆蓋所有場景,所以我提出一種最可能立即得到使用的方式。未來該工具可能包括覆蓋所有場景的額外更新行為。

你可以通過以下方式測試更新行為:

1. 開啟 lambda-function.py,定位至第 272 行 return return-values 語句。

2. 在返回語句上面插入新的一行,如下:

logging.warning('This is a synthetic warning message!')
   
   return return_values

 i. 任意資訊在這裡都可以執行,它可以出現在函式的大多數地方。只要我們更改程式碼,就可以展示更新後的 Lambda 函式。

3. 一旦作出更改,只需再次執行 $ python setup.py,檢視更新 ARN 的日誌記錄輸出。

4. 使用 Test 按鈕再次啟動 Lambda 函式,展開 Execution Result。日誌輸出框應該包括 Lambda 函式通常的日誌輸出,上面的應該是測試資訊。

5. 確保終止 CloudFormation 棧,以節約成本。

6. 更新訓練棧

更新 CloudFormation 棧的功能有限,因為 CloudFormation 棧不強制重啟訓練。因此,不推薦更新 CloudFormation 棧,需要重新訓練時可以刪除再重新安裝 CloudFormation 棧。

7. 在 AWS 管理控制檯之外開始訓練

此時你已經完成了 Parris 的一般步驟!之後的工作更多地是為了更方便地使用該工具。我們的第一個示例是設定一個 IoT 裝置以便根據需求開啟新的訓練工作。更多示例將包括設定常規重新訓練的時間表(即針對你的應用依賴於需要在新資料集上重新訓練的演算法,才能保持有效)。

相關文章