從預處理到部署:如何使用Lore快速構建機器學習模型

機器之心發表於2018-03-13

機器學習的構建和部署通常需要非常多的工作與努力,這對於軟體開發者和入門者造成了很多困難。本文介紹瞭如何使用軟體庫 Lore 快速而高效地構建機器學習模型,並從資料預處理到模型部署等七個步驟介紹構建的經驗。

一般問題

  1. Python 或 SQL 等高階語言編寫程式碼時,模型效能很容易出現瓶頸。

  2. 程式碼複雜性在增長,因為有價值的模型需要通過許多次迭代才能得到。當程式碼以非結構化的方式演化時,難以保證與傳達最初的想法。

  3. 對資料和函式庫的依賴不斷變化,從而導致效能再現受到影響。

  4. 當人們試圖理解最新的論文、軟體包、特徵和問題時,資訊過載使得人們很容易錯過唾手可得的成果,這一問題對於剛入行的人來說更為嚴重。

為了解決這些問題,我們標準化了 Lore 中的機器學習方法,並使用 Lore 開發新的機器學習模型。此外,我們 Instacart 也在產品中執行著十幾個 Lore 模型。

如果您想在沒有上下文的情況下看一下快速的演示,可以從 GitHub 上覆制 my_app。如果您想看到完整工程介紹,請跳至大綱。

$ pip3 install lore
$ git clone https://github.com/montanalow/my_app.git
$ cd my_app 
$ lore install # caching all dependencies locally takes a few minutes the first time
$ lore server & 
$ curl "http://localhost:5000/product_popularity.Keras/predict.json?product_name=Banana&department=produce"

特徵說明

瞭解該專案最好的方法是在十五分鐘內開始我們自己的深度學習專案。如果你想在開始新專案前瞭解本文所述模型的特性,請參閱以下簡要概述:

  • 模型支援使用估計器搜尋超引數,它們將採用幾個不同的策略有效地利用多個 GPU(如果條件允許的話),因此可以分散式地搜尋超引數分佈。

  • 支援使用多個軟體庫的估計器,包括 Keras、XGBoost 和 SciKit Learn 等。這些包都可以通過構建、擬合或預測進行分類,完整地覆蓋了使用者的演算法和架構型別。

  • 資料處理流程避免了資訊在訓練集和測試集間洩露的風險,且一條流程允許許多不同的估計器進行試驗。如果您在實驗過程中超出了可用 RAM,那麼您可以使用基於磁碟處理流程。

  • 轉換標準化的高階特徵工程。例如,使用美國人口普查資料可以將美國人的姓轉換為年齡或性別的統計學特徵;或是從任意格式的電話號字串中提取地域編碼。此外,pandas 包可以支援一般的資料、時間和字串的轉化操作。

  • 編碼器則為您的評估器提供魯棒性的輸入,並能避免常見的缺失和長尾問題。

  • 對流行的(非)關係型資料庫而言,IO 連線在應用程式中以一種標準的方式進行配置和彙集。這種方式對批量資料進行任務管理和讀寫優化,而非傳統的 ORM 單行操作。IO 連線除了用加密的 S3 buckets 分配模型和資料集外,還共享了可配置的查詢快取。

  • 對每個獨立開發中的 APP 而言,依賴項管理都可以將對應包完整地複製到產品中去。因此我們無需瞭解 venv、pyenv、pyvenv、virtualenv、virtualenvwrapper、pipenv 和 conda 依賴項管理工具。

  • 這樣的工作流程可以讓您選擇是使用命令列、python 控制檯、jupyter notebook 或者是其它 IDE。每個環境都可以在產品開發和配置過程中生成可讀的日誌記錄。

15 分鐘開啟機器學習

您只需基礎的 python 知識即可開始。如果您的模型沒有開始進行學習,那您可以用省出來的時間繼續探索機器學習的複雜性。

1. 建立一個新的 app(3 分鐘)

2. 設計一個模型(1 分鐘)

3. 生成架構(2 分鐘)

4. 鋪設流程(5 分鐘)

5. 測試程式碼(1 分鐘)

6. 訓練模型(1 分鐘)

7. 部署產品(2 分鐘)

上述時間有些言過其實,只用作部落格宣傳。沒有一個機器學習研究人員可以只用一分鐘就設計出一個模型,但是一旦你開始跟著學,並且將過程中得到的一切都做上筆記,那麼你也可以在 15 分鐘內高效地構建一個自定義的 AI 專案,在你的朋友和同事中一鳴驚人。

1. 建立一個新的 APP

Lore 獨立管理每個專案,這是為了避免與系統中的 python 或其他專案發生衝突。我們可以將 Lore 作為一個標準的 pip 包安裝:

# On Linux
$ pip install lore
# On OS X use homebrew python 2 or 3
$ brew install python3 && pip3 install lore

當你無法複製他人環境時,是很難復現他人的工作。Lore 保護系統中 python 專案的方式可以避免依賴項錯誤和專案衝突。每一個 Lore 的應用程式都有自己的字典和安裝目錄,它特定需要的依賴庫會鎖定在檔案 runtime.txt 和 requirements.txt 中。這使 Lore 的應用程式共享起來更加高效,也讓我們離復現這個機器學習專案更近一步。

在安裝 Lore 之後,我們可以在閱讀本文後建立一個新的深度學習專案的 app。Lore 預設是模組化的,所以我們需要指定——keras 來為這個專案安裝深度學習的依賴項。

$ lore init my_app --python-version=3.6.4 --keras

2. 設計一個模型

為了演示,我們將建立一個預測模型,這個模型將基於產品名字及其所在部門,預測出 Instacart 網站的產品能有多流行。世界各地的製造商零售時會在不同的人群間測試產品名字,看什麼樣的名字能得到最多的關注,我們這個簡單的 AI 專案也可以提供相同的服務。

機器學習中最難的一部分是獲得良好的資料。幸運的是,Instacart 以匿名的方式公佈了 300 萬份雜貨訂單。基於此,我們可以將問題調整為建立一個有監督的迴歸模型,該模型可以基於兩個特點預測年均銷量:產品名稱和產品類別。實際上,該模型的表現並不好,因此後文會繼續討論更加強大的模型。

3. 生成架構

$ cd my_app
$ lore generate scaffold product_popularity --keras --regression --holdout

每一個 Lore 模型都包含一條用於載入資料和編碼資料的流程,還包含一個可以實現特定機器學習演算法的估計器。模型最有趣的部分在於類別生成中的實現細節。

流程從左側的原始資料開始,將原始資料編碼為右側所需格式。估計器可以用編碼資料訓練模型,並根據驗證集的效能確定是否終止訓練,最後再用測試集評估。所有內容都可以被序列化存在模型儲存區,然後用一個單執行緒再次載入進行部署。

從預處理到部署:如何使用Lore快速構建機器學習模型

4. 鋪設流程

得到很適合機器學習演算法的原始資料是很難的。我們通常會從一個資料集中載入資料或是下載 CSV 檔案,將其編碼為適合演算法的格式,然後再將其分割為訓練集和測試集。lore.pipelines 將這一預處理邏輯封裝起來,成為標準的工作流程。

lore.pipelines.holdout.Base 可以將資料分為訓練集、驗證集和測試集,並可以編碼資料,使資料適用於我們的機器學習演算法。我們的子類將定義三種方法:get_data、get_encoders 和 get_output_encoder。

Instacart 公佈的資料分為了多個 csv 檔案,如下表所示。

從預處理到部署:如何使用Lore快速構建機器學習模型

從預處理到部署:如何使用Lore快速構建機器學習模型

從預處理到部署:如何使用Lore快速構建機器學習模型

get_data 可以下載 Instacart 的原始資料,使用 pandas 可以將帶有所需特徵(product_name,department)的資料加入 DataFrame,還可將預測量(sales)合併在一起。如下所示:

從預處理到部署:如何使用Lore快速構建機器學習模型

下列程式碼展示瞭如何實現 get_data :

# my_app/pipelines/product_popularity.py part 1

import os

from lore.encoders import Token, Unique, Norm
import lore.io
import lore.pipelines
import lore.env

import pandas


class Holdout(lore.pipelines.holdout.Base):
    # You can inspect the source data csv's yourself from the command line with:
    # $ wget https://s3.amazonaws.com/instacart-datasets/instacart_online_grocery_shopping_2017_05_01.tar.gz
    # $ tar -xzvf instacart_online_grocery_shopping_2017_05_01.tar.gz

    def get_data(self):
        url = 'https://s3.amazonaws.com/instacart-datasets/instacart_online_grocery_shopping_2017_05_01.tar.gz'

        # Lore will extract and cache files in lore.env.data_dir by default
        lore.io.download(url, cache=True, extract=True)

        # Defined to DRY up paths to 3rd party file hierarchy
        def read_csv(name):
            path = os.path.join(
                lore.env.data_dir,
                'instacart_2017_05_01',
                name + '.csv')
            return pandas.read_csv(path, encoding='utf8')

        # Published order data was split into irrelevant prior/train
        # sets, so we will combine them to re-purpose all the data.
        orders = read_csv('order_products__prior')
        orders = orders.append(read_csv('order_products__train'))

        # count how many times each product_id was ordered
        data = orders.groupby('product_id').size().to_frame('sales')

        # add product names and department ids to ordered product ids
        products = read_csv('products').set_index('product_id')
        data = data.join(products)

        # add department names to the department ids
        departments = read_csv('departments').set_index('department_id')
        data = data.set_index('department_id').join(departments)

        # Only return the columns we need for training
        data = data.reset_index()
        return data[['product_name', 'department', 'sales']]

接下來,我們需要為每一列指定一個編碼器。電腦科學家可能認為編碼器是使機器學習更高效的方法。一些產品的名字太長,所以我們將其名稱限定為前 15 個單詞。

# my_app/pipelines/product_popularity.py part 2

    def get_encoders(self):
        return (
            # An encoder to tokenize product names into max 15 tokens that
            # occur in the corpus at least 10 times. We also want the 
            # estimator to spend 5x as many resources on name vs department
            # since there are so many more words in english than there are
            # grocery store departments.
            Token('product_name', sequence_length=15, minimum_occurrences=10, embed_scale=5),
            # An encoder to translate department names into unique
            # identifiers that occur at least 50 times
            Unique('department', minimum_occurrences=50)
        )

    def get_output_encoder(self):
        # Sales is floating point which we could Pass encode directly to the
        # estimator, but Norm will bring it to small values around 0,
        # which are more amenable to deep learning.
        return Norm('sales')

這就是預處理流程。我們起初用的評估器是 lore.estimators.keras.Regression 的一個簡單子類,可以用預設值實現簡單的深度學習架構。

# my_app/estimators/product_popularity.py

import lore.estimators.keras


class Keras(lore.estimators.keras.Regression):
    pass

最後,我們的模型可以通過將其委託給估計器來改變深度學習架構的高階屬性,還可從我們構建的處理流程中提取資料。

# my_app/models/product_popularity.py

import lore.models.keras

import my_app.pipelines.product_popularity
import my_app.estimators.product_popularity


class Keras(lore.models.keras.Base):
    def __init__(self, pipeline=None, estimator=None):
        super(Keras, self).__init__(
            my_app.pipelines.product_popularity.Holdout(),
            my_app.estimators.product_popularity.Keras(
                hidden_layers=2,
                embed_size=4,
                hidden_width=256,
                batch_size=1024,
                sequence_embedding='lstm',
            )
        )

5. 測試程式碼

當搭建架構時模型會自動執行通煙測試(smoke test),第一次執行時會花一些時間下載一個 200 MB 的資料集進行測試。您還可以對快取在 ./tests/data 中的檔案進行修改,將其移入回收站以加快測試速度。

$ lore test tests.unit.test_product_popularity

6. 訓練模型

訓練模型需要 ./data 中的快取資料,並將工作儲存在 ./models 中。

$ lore fit my_app.models.product_popularity.Keras --test --score

查閱終端日誌可以瞭解 Lore 的時間都花在了哪裡。

$ tail -f logs/development.log

嘗試新增更多隱藏層以瞭解這一操作是否有助於提高您模型的效能。您可以編輯模型檔案或者直接通過命令列呼叫合適的屬性,如 --hidden_layers=5。

從預處理到部署:如何使用Lore快速構建機器學習模型

檢驗模型特性

您可以在 lore 環境下執行 jupyter notebooks。Lore 將安裝一個可自定義的 jupyter 核心,該核心將為 lore notebook 和 lore console 提供應用程式虛擬環境。

$ lore notebook

瀏覽 notebooks/product_popularity/features.ipynb 或「執行所有」可以瞭解您模型的視覺化分析。

從預處理到部署:如何使用Lore快速構建機器學習模型

「生產」類被編碼到「20」,這是很大的銷售量了。

彙總特定特徵時您就可以瞭解到模型的預測結果(藍色)和測試結果(黃色)有多一致。在本例中,有 21 類重合程度相當高。「生產」類是例外,模型沒有充分說明其逸出值。

您還可以通過執行 notebooks/product_popularity/architecture.ipynb 中的筆記了解生成的深層學習架構。

從預處理到部署:如何使用Lore快速構建機器學習模型

縮減為 15 個字元的名字通過左邊的 LSTM 執行,類名輸入到右邊的嵌入中,然後一起通過隱藏層。

釋出模型服務

Lore 的應用程式可以作為 HTTP API 在本地執行。預設情況下模型會通過 HTTP GET 端點公開其「預測」方法。

$ lore server &
$ curl "http://localhost:5000/product_popularity.Keras/predict.json?product_name=Banana&department=produce"
$ curl "http://localhost:5000/product_popularity.Keras/predict.json?product_name=Organic%20Banana&department=produce"
$ curl "http://localhost:5000/product_popularity.Keras/predict.json?product_name=Green%20Banana&department=produce"
$ curl "http://localhost:5000/product_popularity.Keras/predict.json?product_name=Brown%20Banana&department=produce"

結果表明,在「香蕉」中加入「有機」,將會在「生產」類賣出超過兩倍的水果。預測得出,「綠香蕉」比「棕香蕉」銷量更差。如果您需要果汁的記錄,則應該選擇「有機黃香蕉」。

7. 部署產品

Lore 的應用程式可以通過任何支援 Heroku buildpack 的基礎架構進行部署。Buildpacks 將 runtime.txt 和 requirements.txt 的依賴項在容器中安裝以供模型部署。

您可以在 ./models/my_app.models.product_popularity/Keras/ 中瞭解每一次執行 lore fit 指令的結果。這個字典和 ./data/ 都預設在 .gitignore 中,您的程式碼隨時可以重建路徑。您可以在釋出前檢查要釋出的模型版本,這是一個簡單的部署策略:

$ git init .
$ git add .
$ git add -f models/my_app.models.product_popularity/Keras/1 # or your preferred fitting number to deploy
$ git commit -m "My first lore app!"

Heroku 使釋出一個應用程式變得非常簡單,您可以點選連結瀏覽其入門介紹:https://devcenter.heroku.com/articles/getting-started-with-python#introduction

下面是「太長不看」版:

$ heroku login
$ heroku create
$ heroku config:set LORE_PROJECT=my_app
$ heroku config:set LORE_ENV=production
$ git push heroku master
$ heroku open

$ curl “`heroku info -s | grep web_url | cut -d= -f2`product_popularity.Keras/predict.json?product_name=Banana&department=produce”

現在您可以用 heroku 應用的名字替代 http://localhost:5000/,並在任何地方獲取預測結果。從預處理到部署:如何使用Lore快速構建機器學習模型

原文連結:https://tech.instacart.com/how-to-build-a-deep-learning-model-in-15-minutes-a3684c6f71e

相關文章