如何在15分鐘內建立一個深度學習模型?

Kimi-Dan

用 Python 配置、構建、部署和維護一個開源的深度學習模型的框架。


隨著 Instacart 的發展,我們努力地學到了一些東西。我們開放了 Lore 的源代碼——Lore 是一個可以讓工程師和機器學習維護人員學習機器學習的框架。


機器學習領域的共同感覺



呃,這張紙沒告訴我該如何工作……


共同的問題


1. Python 或 SQL 編寫代碼時,模型性能很容易出現瓶頸。

2. 代碼複雜性在增長,是因為有價值的模型是通過許多次迭代變化得到的。當代碼以非結構化方式進化時,難以保證用戶最初的想法。

3. 對數據庫的依賴的不斷變化導致重複受到影響。

4. 當人們試圖跟緊最新的論文、組件、特徵、問題等時,信息過載使得人們很容易錯過唾手可得的成果……這一問題對於剛入行的人來說更為嚴重。


為了解決這些問題,我們標準化了 Lore 中的機器學習。在 Instacart,我們團隊中有三個人使用 Lore 進行所有新的機器學習開發,我們也在產品中運行著十幾個 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 分配模型和數據集外,還共享了可配置的查詢緩存。

  • 對每個在開發中的獨立的 APP 而言,附屬文件管理都可以 100% 地複製到產品中去。無需手動激活、改變環境變量或是隱藏違反 python 規則的文件。也無需瞭解 venv、pyenv、pyvenv、virtualenv、virtualenvwrapper、pipenv 還有 conda。也沒有人有時間瞭解這麼多。
  • 您的模型可以在連續的集成環境中運行進行測試,測試中還可以繼續部署代碼或升級訓練過程,而這一切的進行都無需增加模型基礎架構團隊的工作量。
  • 這樣的工作流程可以讓您選擇是使用命令行、python 控制檯、jupyter 筆記或者是 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 的模型都包含一條用於加載數據和編碼數據的管道,還包含一個可以實現特定機器學習算法的評估器。模型最有趣的部分在於在已經生成的類別中進行細節實施。


管道從左側的原始數據開始,將原始數據編碼為右側所需格式。評估器可以用編碼數據對模型進行訓練,在驗證集前停止,然後用測試集評估。所有內容都可以被序列化存在模型存儲區,然後用一個單線程再次加載進行部署。



4) 鋪設管道


得到很適合機器學習算法的原始數據是很難的。我們通常會從一個數據集中加載數據或是下載 CSV 文件,將其編碼為適合算法的格式,然後再將其分為訓練集和測試集。lore.pipelines 的基類將這一邏輯封裝起來,成為標準的工作流程。


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


Instacart 公佈的數據分為了多個 csv 文件,如下表所示。



get_down 可以下載 Instacart 的原始數據,使用 pandas 可以將帶有所需特徵(product_name,department)的數據加入 DataFrame,還可將響應量(sales)合併在一起。如下所示:



下述代碼為如何實施 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 their 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) 測試代碼


當搭建框架時模型會自動運行冒煙測試。第一次運行時會花一些時間下載一個 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




檢驗模型特性


您可以在 lore 環境下運行 jupyter 筆記。Lore 將安裝一個可自定義的 jupyter 內核,該內核將為 lore notebook 和 lore console 提供應用程序虛擬環境的參考。


$ lore notebook


瀏覽 notebooks/product_popularity/features.ipynb 或「運行所有」可以瞭解您模型中適配的可視化配件。



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


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


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



縮減為 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 的說明安裝在容器中以供模型部署。如果您想要在雲端橫向擴展,您可以遵循 heroku 的開始指南進行操作。


您可以在 ./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/,您還可以從任何地方獲取預測結果。


或者,您可以從此處進行互動(https://myloreapp.herokuapp.com/product_popularity.Keras/predict.json?product_name=Banana&department=produce)


下一步


我們認為 0.5 版是共同構建 1.0 版的堅實基礎。補丁版是為了避免重大更新,但是次要版本可能會依據用戶需求改變功能。我們會發出警告,以維持現有現有應用程序的升級路徑。


這是一些我們想要在 1.0 版之前添加的特徵:


  • 為模型、評估器和特徵分析提供可視化的 Web 界面

  • 在模型訓練和數據處理過程中集成分佈式計算機的支持,即工作隊列

  • 對不良數據或結構進行測試,而不是僅僅破壞代碼

  • 提供更多的文檔、評估器、編碼器和轉換器

  • Windows 的全面支持


分享到:


相關文章: