如何用900秒搭建一個深度學習模型?

本文將講解如何用 Python 開源框架迅速配置、搭建、部署和維護深度學習模型。最重要的是,突出了一個「快」字。

截圖來自MIUI論壇

美國遞送日用品業務初創公司 Instacart 近日開源了其 Python 框架 Lore,幫助廣大開發者快速高效的開展機器學習項目。

目前進行機器學習項目往往存在以下幾個常見的問題:

  • 用 Python 或 SQL 語言寫高難度的定製代碼時,很容易出現性能瓶頸問題。
  • 代碼的複雜程度會不斷增加,因為多次迭代後才能產生有價值的模型,而由於代碼以非結構化的方式不斷演變,這就使得每個開發人員的想法很難得到維持和相互溝通。
  • 隨著數據和程序庫的依賴性不斷變化,可重複性會大幅削弱。
  • 當你想跟上最新的論文、程序包、特性時,信息超載會很容易讓我們錯過比較容易實現的小目標,這點對於剛入行的人來說尤其糟糕。

為了解決這些問題,Instacart 在 Lore 上講機器學習進行了標準化處理。其內部有 3 個技術團隊都在用 Lore 研發新的機器學習模型。

有必要看看的一段廢話

如果你想有一個速度超快的 demo,無需 context 就能做出預測,你可以從 GitHub 上克隆my_app,集智君看了看覺得很棒。(github.com/instacart/lo

$ 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"

在正式寫代碼搭模型之前,可以先看看模型有哪些功能:

  1. 模型支持評估器的超參數搜索,並帶有 Data Pipeline 系統,能以不同的方式有效利用多個 GPU,能以水平伸縮的方式保存和分布。
  2. 支持多種程序包中的評估器:Keras,XGBoost,Scikit-learn。
  3. Pipeline 能避免訓練集和測試集之間的信息泄露,其中一個管線允許用不同的評估器進行試驗。
  4. 編碼器能為評估器提供魯棒輸入,並避免一些常見的問題如丟失長尾值等。
  5. 可以在持續集成環境下測試模型,支持持續部署代碼和訓練更新,無需對運維人員增加額外工作量。
  6. 不管你是喜歡用命令行,Python終端,Jupyter Notebook還是IDE,都能支持。

15分鐘教程概覽

在開始機器學習項目之前,需要對 Python 有個基本的了解。然後再花時間逐步了解機器學習。

  • 創建一個新應用(3 分鐘)
  • 設計一個模型(1分鐘)
  • 生成一個腳手架(2分鐘)
  • 實現Pipeline(5分鐘)
  • 測試代碼(1分鐘)
  • 訓練模型(1分鐘)
  • 部署模型(2分鐘)

注意:上面這些時間是在一切順暢的情況下,有些地方需要提前做些準備,比如設計模型這個部分,需要提前準備好,因為沒人真的能在 1 分鐘內設計一個模型···不過,如果你熟練掌握了這些步驟,並備好相關數據,依然能在 15 分鐘內從零開始搭建一個深度學習模型。

搭建深度學習模型

創建一個新應用

Lore 能夠獨立管理每個項目的依賴項,從而避免和你的系統 Python 或其它項目產生衝突。安裝 Lore 程序包:

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

通常我們很難重複別人的項目工作,因為你沒法複製他們的環境。每個 Lore 應用都會有它自己的目錄和 Python 安裝,以及只需用來在 runtime.txt 和 requirements.txt 中指明版本的依賴項。這就能很高效的分享 Lore 應用,讓我們進一步實現機器學習項目的可重複性。

安裝好 Lore 以後,你可以為深度學習項目創建一個新的應用。Lore 在默認狀態下比較簡單,為模塊化設計,因此我們需要指明用 Keras 安裝本項目的深度學習依賴項。

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

設計一個模型

本教程所用的例子是搭建一個模型,預測一件產品根據它的名字和商品板塊在 Instacart 網站上會有多火。全球有不少商家都會找不同的消費者群體測試產品名字,一些零售商也會不斷優化商品在商店中的位置來最大程度的吸引顧客。我們這裡要搭建的一個簡單的 AI 模型會提出類似的建議,幫助商家更好的理解如何在 Instacart 上更好的營銷。

機器學習一個最難的部分就是獲取高質量的數據。幸好,Instacart 已經發布了 3 百萬分匿名購物訂單(instacart.com/datasets/

),可以用為我們項目的數據。然後我們進一步將這個問題細化為搭建一個監督學習回歸模型,根據兩個特徵——商品名字和商品板塊來預測產品的年度銷售狀況。

生成腳手架(scaffold)

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

每個 Lore 模型都包含一個 Pipeline 來載入和編碼數據,以及一個實現具體機器學習演算法的評估器。

Pipeline 先以左側的初始數據開始,將其編碼為右側的理想形式,然後用編碼後的數據訓練評估器,數據在驗證集初期就中止,接著用測試集對評估器進行評估。所有這些都可以序列化為模型庫,只用一行代碼就能再次載入和部署。

實現Pipeline

能高度契合機器學習演算法的原始數據很少見,通常我們要從資料庫中載入出原始數據,或下載一個 CSV 文件,將其編碼為符合演算法的形式,然後拆分為訓練集和測試集兩部分。 lore.pipelines 中的基類以標準的工作流形式封裝了這種邏輯。

Lore.pipeline.holdout.Base 會將我們的數據拆分為訓練集、驗證集測試集,然後針對我們的機器學習演算法對它們進行編碼。我們的子類會定義三個方法:get_data,get_encoders和get_output_encoder。

Instacart 發布的數據分布在多個 CSV 文件中,像資料庫表格一樣。

Pipeline 的 get_data 會下載初始 Instacart 數據,使用 Pandas 將數據添加入帶有數據特徵(product_name, department)的 DataFrame 中,得出總銷量(sales),如下所示:

下面是 get_data 的實現詳情:

# my_app/pipelines/product_popularity.py part 1import osfrom lore.encoders import Token, Unique, Normimport lore.ioimport lore.pipelinesimport lore.envimport pandasclass Holdout(lore.pipelines.holdout.Base): # You can inspect the source data csvs 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)

Pipeline 部分就先到這裡。我們剛開始的評估器會是 lore.estimators.keras.Regression 的一個簡單的子類,lore.estimators.keras.Regression 應用了一種典型的深度學習架構,默認設置也比較合理。

# my_app/estimators/product_popularity.pyimport lore.estimators.kerasclass Keras(lore.estimators.keras.Regression):Pass

終於我們的模型為我們的深度學習架構指定了高級屬性,將它們返回到評估器中,從我們搭建的 Pipeline 中提取數據。

# my_app/models/product_popularity.pyimport lore.models.kerasimport my_app.pipelines.product_popularityimport my_app.estimators.product_popularityclass 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, ) )

測試代碼

當你生成腳手架的時候,就會為模型自動創建一個冒煙測試(smoke test)。第一次運行會花費一些時間,因為要下載 200M 的數據集用來測試。有個比較好的操作方式就是裁減 ./tests/data 中獲取的文件,把它們加入到你的代碼庫中,以去除網路依賴性和加快測試速度。

$ lore test tests.unit.test_product_popularity

訓練模型

訓練我們的模型會獲取 ./data 中的數據,保存 ./models 中的信息。

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

緊跟第二個終端的日誌,看看 Lore 都把時間花在哪了:

$ tail -f logs/development.log

我們也可以嘗試再添加一個隱藏層,看看是否能提高模型的性能。可以編輯模型文件,或直接通過命令行調用輸入任意屬性進行適配,比如--hidden_layers=5。如果用緩存好的數據集,這個過程大概在 30 秒左右。

檢查模型性能

你可以在 Lore 環境下運行 Jupyter notebook,Lore 會安裝一個自定義 Jupyter 內核,它會為 lore notebook 和 lore console 引用你的應用的虛擬環境。

$ lore notebook

瀏覽到 notebooks/product_popularity/features.ipynb,「運行所有」看看模型最終擬合結果的可視化圖:

你可以看到模型的預測結果(藍色)很好地貼合了測試集(金色)的趨勢。在這個例子中,模型很好的預測出了 21 個商品板塊的產品銷售狀況,除了有一處異常值。

你也可以在 notebooks/product_popularity/architecture.ipynb 中運行 notebook,生成的深度學習架構狀況。

商品板塊名稱的 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"

我們模型的結果顯示為「香蕉」添加「有機」兩個字會在「生產」商品板塊增加兩倍銷量,模型預測「青香蕉」比「黃香蕉」的銷量要糟糕的多。

部署模型

通過任何支持 Heroku Buildpacks 的架構都可以部署 Lore 應用。Buildpacks 會在 requirement.txt 和 runtime.txt 中安裝技術說明用來部署。如果你想在雲端實現水平伸縮性,你可以按照 Heroku 上的起始指南操作。

在 ./models/my_app.models.product_popularity/Keras/ 中,你可以看到每次執行 lore fit命令的結果。目錄 ./models/my_app.models.product_popularity/Keras/ 和 ./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 可以很容易的發布應用,代碼如下:

$ 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 應用名稱代替 localhost:5000/ 了,而且能隨時隨地獲取你模型的預測結果。

至此,我們不到 15 分鐘就搭建了一個深度學習模型。本項目的代碼庫地址:

instacart/lore?

github.com圖標

快去動手試一試!


參考資料:

tech.instacart.com/how-


推薦閱讀:

人工智慧驅動一站式全場景交互,華住會引領酒店業未來
2017年 AI安全風險白皮書
2017年你錯過了哪些AI圈大事?最全盤點,值得收藏!
什麼是ANI、AGI、ASI?
道可道之機器學習(1) - 初探人工智慧

TAG:深度學習DeepLearning | 景略集智 | 人工智慧 |