基於Hadoop分佈式集羣YARN模式下的TensorFlowOnSpark平臺搭建

1. 介紹

  在過去幾年中,神經網絡已經有了很壯觀的進展,如今他們幾乎已是圖像識別和自動翻譯領域中最強者[1]。爲了從海量數據中得到洞察力,須要部署分佈式深度學習。現有的DL框架一般須要爲深度學習設置單獨的集羣,迫使咱們爲機器學習流程建立多個程序(見Figure 1)。擁有獨立的集羣須要咱們在它們之間傳遞大型數據集,從而引發沒必要要的系統複雜性和端到端的學習延遲。html

  TensorFlow是Google公司剛剛發佈不久一款用於數值計算和神經網絡的深度學習框架。java

  TensorFlowOnSpark是yahoo今年剛開源的一個項目,目的就是充分發掘TensorFlow在現有的大數據集羣上進行高效深度學習的能力,利用TensorFlowOnSpark,數據科學家和工程師們能夠直接利用運行於CPU/GPU架構上的Spark或者Hadoop作分佈式模型訓練。該庫支持把現有的TensorFlow程序切換到新的API,同時實現了模型訓練的性能提高。node

  在開源公告裏,雅虎說明了TensorFlowOnSpark想解決的問題,好比在深度神經網絡訓練中管理Spark數據管線以外的其餘集羣帶來的運維負載,以網絡I/O爲瓶頸的數據集在訓練集羣的傳入和傳出,使人討厭的系統複雜性,以及端到端的總體學習時延。TensorFlowOnSpark的工做和雅虎以前開源的CaffeOnSpark類似。現有的對TensorFlow和Spark的集成所作的努力,有DataBricks的TensorFrame,以及Amp Lab 的SparkNet,這些對於雅虎來講都是在正確方向上的邁進,可是在容許TensorFlow進程之間直接通訊方面仍是有所欠缺。雅虎的目標之一,是讓TensorFlowOnSpark成爲一個徹底對Spark兼容的API,在一個Spark處理工做流裏,其集成能力能跟SparkSQL、MLib以及其餘Spark核心庫同樣好。
  在架構上,它把給定TensorFlow算法和TensorFlow core放在一個Spark Executor中,並讓TensorFlow任務可以經過TensorFlow的文件閱讀器和QueueRunners直接獲取HDFS數據,這是一種有着更少網絡I/O以及「把計算帶給數據」的方案。TensorFlowOnSpark在語義上就支持對執行器的端口預留和監聽,對數據和控制函數的消息輪詢,TensorFlow主函數的啓動,數據注入,直接從HDFS讀取數據的閱讀器和queue-runner機制,經過feed_dict向TensorFlow注入Spark RDD,以及關機。
  除了TensorFlowOnSpark,yahoo還在他們本身的分支上擴展了TensorFlow核心C++引擎以在Infiniband裏使用RDMA,這個需求在TensorFlow主項目裏被提出過還產生了相關討論。雅虎的Andy Feng注意到,使用RDMA而不是gRPC來作進程間通訊,在不一樣的網絡裏會帶來百分之十到百分之兩百不等的訓練速度的提高[2]python

2.TensorFlowOnSpark核心技術點

  • 輕鬆遷移全部現有的TensorFlow程序,<10行代碼更改; 
  • 支持全部TensorFlow功能:同步/異步訓練,模型/數據並行,推理和TensorBoard; 
  • 服務器到服務器的直接通訊在可用時實現更快的學習; 
  • 容許數據集在HDFS和由Spark推進的其餘來源或由TensorFlow拖動; 
  • 輕鬆集成您現有的數據處理流水線和機器學習算法(例如,MLlib,CaffeOnSpark); 
  • 輕鬆部署在雲或內部部署:CPU和GPU,以太網和Infiniband[3]

3.基於Hadoop分佈式羣YARN模式的搭建

  官方指導連接:https://github.com/yahoo/TensorFlowOnSpark/wiki/GetStarted_YARN,這篇文章過於簡略,不少地方都沒有說明白,初學者會繞不少彎路,也許是由於這個項目剛剛開源不久,不少指導性的說明都沒有。簡言之,官網的 Instructions 略坑,搭建成功與否靠人品。git

  如下是本人實踐成功的步驟:github

3.1 環境準備

  已經安裝了 Spark 的 Hadoop 分佈式集羣環境(安裝於 Ubuntu Server 系統),下表顯示了個人集羣環境( Spark 已經開啓):算法

安裝了 Spark 的 Hadoop 分佈式集羣環境
主機名 ip 用途
master 192.168.0.20

ResourceManagerapache

NameNodebootstrap

SecondaryNameNodevim

Master

node1 192.168.0.21

DataNode

NodeManager

Worker

node2 192.168.0.22

DataNode

NodeManager

Worker

  這裏給你們推薦一個超詳細的關於部署 Hadoop 徹底分佈式集羣的博客:http://blog.csdn.net/dream_an/article/details/52946840[4]

3.2 在 Master 節點上進行:

(1) 安裝 Python 2.7

  這一步的是在本地文件夾裏下載安裝 Python ,目的是在進行任務分發的時候可以把這個 Python 和其餘依賴環境(這裏指的是包含 TensorFlow)同時分發給對應的 Spark executor ,因此這一步不是單純的只安裝 Python 。

#下載解壓 Python 2.7
export PYTHON_ROOT=~/Python curl -O https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz tar -xvf Python-2.7.12.tgz rm Python-2.7.12.tgz

#在編譯 Python 以前,須要完成如下工做,不然編譯產生的 python 會出現沒有 zlib 、沒有 SSL 模塊等錯誤
#安裝 ruby , zlib , ssl 相關包
sudo apt install ruby
sudo apt install zlib1g,zlib1g.dev
sudo apt install libssl-dev

#進入剛纔解壓的 Python 目錄,修改 Modules/Setup.dist文件,該文件是用於產生 Python 相關配置文件的
cd Python-2.7.12
sudo vim Modules/Setup.dist
#去掉 ssl , zlib 相關的註釋:
#與 ssl 相關:
#SSL=/usr/local/ssl
#_ssl _ssl.c \
# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
# -L$(SSL)/lib -lssl -lcrypto
#與 zlib 相關:
#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz

#編譯 Python 到本地文件夾 ${PYTHON_ROOT}
pushd Python-2.7.12
./configure --prefix="${PYTHON_ROOT}" --enable-unicode=ucs4
#./configure 這一步若是提示 "no acceptable C compiler" , 須要安裝 gcc : sudo apt install gcc
make
make install
popd
rm -rf Python-2.7.12

#安裝 pip
pushd "${PYTHON_ROOT}"
curl -O https://bootstrap.pypa.io/get-pip.py
bin/python get-pip.py
rm get-pip.py

#安裝 pydoop
${PYTHON_ROOT}/bin/pip install pydoop
#這裏安裝 pydoop,如果提示錯誤:LocalModeNotSupported,直接下載資源包經過 setup 安裝:
#資源包下載:https://pypi.python.org/pypi/pydoop
#tar -xvf pydoop-1.2.0.tar.gz
#cd pydoop-1.2.0
#python setup.py build
#python setup.py install

#安裝 TensorFlow
${PYTHON_ROOT}/bin/pip install tensorflow
#這裏安裝 tensorflow ,不須要從源碼進行編譯安裝,除非你須要 RDMA 這個特性
popd

(2) 安裝 TensorFlowOnSpark

git clone https://github.com/yahoo/TensorFlowOnSpark.git
git clone https://github.com/yahoo/tensorflow.git
#從 yahoo 下載的 TensorFlowOnSpark 資源包裏面 tensorflow 是空的文件夾,git 上該文件夾鏈接到了 yahoo/tensorflow ,這裏須要咱們將 tensorflow 拷貝到 TensorFlowO#nSpark 下面:
sudo rm -rf TensorFlowOnSpark/tensorflow/
sudo mv tensorflow/ TensorFlowOnSpark/
#上面 tensorflow 和 TensorFlowOnSpark 文件目錄根據本身的實際狀況修改,個人是在根目錄下面,因此如上

(3) 安裝編譯 Hadoop InputFormat/OutputFormat for TFRecords

#安裝如下依賴工具:
sudo apt install autoconf,automake,libtool,curl,make,g++,unzip,maven

#先安裝 protobuf
# git 上有詳細說明:github上有詳細的安裝說明:https://github.com/google/protobuf/blob/master/src/README.md
#也能夠參考連接:http://www.itdadao.com/articles/c15a1006495p0.html

 #編譯 TensorFlow 的 protos:
 git clone https://github.com/tensorflow/ecosystem.git
 cd ecosystem/hadoop
 protoc --proto_path=/opt/TensorFlowOnSpark/tensorflow/ --java_out=src/main/java/ /opt/TensorFlowOnSpark/tensorflow/tensorflow/core/example/{example,
 feature}.proto
 mvn clean package
 mvn install

 #將上一步產生的 jar 包上傳到 HDFS
 cd target
 hadoop fs -put tensorflow-hadoop-1.0-SNAPSHOT.jar

(4) 爲 Spark 準備 Python with TensorFlow 壓縮包

pushd "${PYTHON_ROOT}"
zip -r Python.zip *
popd
#將該壓縮包上傳到 HDFS
hadoop fs -put ${PYTHON_ROOT}/Python.zip

(5) 爲 Spark 準備 TensorFlowOnSpark 壓縮包

pushd TensorFlowOnSpark/src
zip -r ../tfspark.zip *
popd

環境基本搭建完成。

4. 測試[5]

1)準備數據

下載、壓縮mnist數據集 

mkdir ${HOME}/mnist
pushd ${HOME}/mnist >/dev/null
curl -O "http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz"
curl -O "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz"
curl -O "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz"
curl -O "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"
zip -r mnist.zip *
popd >/dev/null

2)feed_dic方式運行,步驟以下

# step 1 設置環境變量
export PYTHON_ROOT=~/Python
export LD_LIBRARY_PATH=${PATH}
export PYSPARK_PYTHON=${PYTHON_ROOT}/bin/python
export SPARK_YARN_USER_ENV="PYSPARK_PYTHON=Python/bin/python"
export PATH=${PYTHON_ROOT}/bin/:$PATH
export QUEUE=default

# step 2 上傳文件到hdfs 
hdfs dfs -rm /user/${USER}/mnist/mnist.zip
hdfs dfs -put ${HOME}/MLdata/mnist/mnist.zip /user/${USER}/mnist/mnist.zip

# step 3 將圖像文件(images)和標籤(labels)轉換爲CSV文件
hdfs dfs -rm -r /user/${USER}/mnist/csv
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 4 \
--executor-memory 4G \
--archives hdfs:///user/${USER}/Python.zip#Python,hdfs:///user/${USER}/mnist/mnist.zip#mnist \
TensorFlowOnSpark/examples/mnist/mnist_data_setup.py \
--output mnist/csv \
--format csv


# step 4 訓練(train)
hadoop fs -rm -r mnist_model
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 3 \
--executor-memory 8G \
--py-files ${HOME}/TensorFlowOnSpark/tfspark.zip,${HOME}/TensorFlowOnSpark/examples/mnist/spark/mnist_dist.py \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.yarn.executor.memoryOverhead=6144 \
--archives hdfs:///user/${USER}/Python.zip#Python \
--conf spark.executorEnv.LD_LIBRARY_PATH="$JAVA_HOME/jre/lib/amd64/server" \
${HOME}/TensorFlowOnSpark/examples/mnist/spark/mnist_spark.py \
--images mnist/csv/train/images \
--labels mnist/csv/train/labels \
--mode train \
--model mnist_model


# step 5 推斷(inference)
hadoop fs -rm -r predictions
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 3 \
--executor-memory 8G \
--py-files ${HOME}/TensorFlowOnSpark/tfspark.zip,${HOME}/TensorFlowOnSpark/examples/mnist/spark/mnist_dist.py \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.yarn.executor.memoryOverhead=6144 \
--archives hdfs:///user/${USER}/Python.zip#Python \
--conf spark.executorEnv.LD_LIBRARY_PATH="$JAVA_HOME/jre/lib/amd64/server" \
${HOME}/TensorFlowOnSpark/examples/mnist/spark/mnist_spark.py \
--images mnist/csv/test/images \
--labels mnist/csv/test/labels \
--mode inference \
--model mnist_model \
--output predictions


# step 6 查看結果(可能有多個文件)
hdfs dfs -ls predictions
hdfs dfs -cat predictions/part-00001
hdfs dfs -cat predictions/part-00002
hdfs dfs -cat predictions/part-00003

#網頁方式,查看spark做業運行狀況,這裏的 ip 地址是 master 節點的 ip
http://192.168.0.20:8088/cluster/apps/

3) queuerunner方式運行,步驟以下

# step 1 設置環境變量
export PYTHON_ROOT=~/Python
export LD_LIBRARY_PATH=${PATH}
export PYSPARK_PYTHON=${PYTHON_ROOT}/bin/python
export SPARK_YARN_USER_ENV="PYSPARK_PYTHON=Python/bin/python"
export PATH=${PYTHON_ROOT}/bin/:$PATH
export QUEUE=default

# step 2 上傳文件到hdfs 
hdfs dfs -rm /user/${USER}/mnist/mnist.zip
hdfs dfs -rm -r /user/${USER}/mnist/tfr
hdfs dfs -put ${HOME}/MLdata/mnist/mnist.zip /user/${USER}/mnist/mnist.zip

# step 3 將圖像文件(images)和標籤(labels)轉換爲TFRecords
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 4 \
--executor-memory 4G \
--archives hdfs:///user/${USER}/Python.zip#Python,hdfs:///user/${USER}/mnist/mnist.zip#mnist \
--jars hdfs:///user/${USER}/tensorflow-hadoop-1.0-SNAPSHOT.jar \
${HOME}/TensorFlowOnSpark/examples/mnist/mnist_data_setup.py \
--output mnist/tfr \
--format tfr

# step 4 訓練(train)
hadoop fs -rm -r mnist_model
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 4 \
--executor-memory 4G \
--py-files ${HOME}/TensorFlowOnSpark/tfspark.zip,${HOME}/TensorFlowOnSpark/examples/mnist/tf/mnist_dist.py \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.yarn.executor.memoryOverhead=4096 \
--archives hdfs:///user/${USER}/Python.zip#Python \
--conf spark.executorEnv.LD_LIBRARY_PATH="$JAVA_HOME/jre/lib/amd64/server" \
${HOME}/TensorFlowOnSpark/examples/mnist/tf/mnist_spark.py \
--images mnist/tfr/train \
--format tfr \
--mode train \
--model mnist_model

# step 5 推斷(inference)
hadoop fs -rm -r predictions
${SPARK_HOME}/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 4 \
--executor-memory 4G \
--py-files ${HOME}/TensorFlowOnSpark/tfspark.zip,${HOME}/TensorFlowOnSpark/examples/mnist/tf/mnist_dist.py \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.yarn.executor.memoryOverhead=4096 \
--archives hdfs:///user/${USER}/Python.zip#Python \
--conf spark.executorEnv.LD_LIBRARY_PATH="$JAVA_HOME/jre/lib/amd64/server" \
${HOME}/TensorFlowOnSpark/examples/mnist/tf/mnist_spark.py \
--images mnist/tfr/test \
--mode inference \
--model mnist_model \
--output predictions

# step 6 查看結果(可能有多個文件)
hdfs dfs -ls predictions
hdfs dfs -cat predictions/part-00001
hdfs dfs -cat predictions/part-00002
hdfs dfs -cat predictions/part-00003

#網頁方式,查看spark做業運行狀況,這裏的 ip 地址是 master 節點對應的 ip
http://192.168.0.20:8088/cluster/apps/

5. 參考資料

[1] https://databricks.com/blog/2016/01/25/deep-learning-with-apache-spark-and-tensorflow.html

[2] https://www.infoq.com/news/2017/03/tensorflow-spark

[3] http://blog.csdn.net/sinat_34233802/article/details/68942780

[4] http://blog.csdn.net/dream_an/article/details/52946840

[5] http://blog.csdn.net/hjh00/article/details/64439268

相關文章
相關標籤/搜索