尝试使用Spark × Keras × Docker对深度学习进行可扩展的尝试2:多节点版本
通过 Spark × Keras × Docker 尝试实现可扩展的深度学习2。
我以前尝试将Dist-keras放入Docker中,以创建可扩展的深度学习模型。
您可以在此链接中了解更多信息:http://qiita.com/cvusk/items/3e6c3bade8c0e1c0d9bf
当时的反省点是表现不佳,仔细回顾后发现参数设置错了。
于是为了反省而尝试了很多不同的方法。
之前的故事梗概
请参考先前的帖子获取关于Dist-Keras本身的解释,基本上它是在Spark集群上运行的Keras。
我将其制作成了Docker映像,以便可以轻松地扩展。
另外,Dockerfile已在GitHub上公开。
https://github.com/shibuiwilliam/distkeras-docker
我要做的事情
我想在本次测试中,使用Docker上的Dist-Keras在单主机和多主机上进行验证,以改善性能。
之前,我在单主机上启动了多个容器,创建了Spark集群。
这次,我想增加一些模式。
我们将运行的是MNIST。
MNIST的训练程序是基于dist-keras提供的进行自定义使用。
验证过的结构 le de
我们将使用单主机和多主机进行验证。
无论是单主机还是多主机,都是以Spark主节点+工作节点的配置,并调整工作节点的数量和规格。
在多主机的情况下,有两台服务器。
值得注意的是,主机是使用AWS EC2 CentOS7.3的m4.xlarge。
单个主机的设置方法
在单一主机的情况下,图像会是这样的。
Docker容器的数量会根据验证条件做出调整。

在单一主机上启动多个Docker容器,这是当只有一个主机时的情况。
# docker dist-keras for spark master and slave
docker run -it -p 18080:8080 -p 17077:7077 -p 18888:8888 -p 18081:8081 -p 14040:4040 -p 17001:7001 -p 17002:7002 \
-p 17003:7003 -p 17004:7004 -p 17005:7005 -p 17006:7006 --name spmaster -h spmaster distkeras /bin/bash
# docker dist-keras for spark slave1
docker run -it --link spmaster:master -p 28080:8080 -p 27077:7077 -p 28888:8888 -p 28081:8081 -p 24040:4040 -p 27001:7001 \
-p 27002:7002 -p 27003:7003 -p 27004:7004 -p 27005:7005 -p 27006:7006 --name spslave1 -h spslave1 distkeras /bin/bash
# docker dist-keras for spark slave2
docker run -it --link spmaster:master -p 38080:8080 -p 37077:7077 -p 38888:8888 -p 38081:8081 -p 34040:4040 -p 37001:7001 \
-p 37002:7002 -p 37003:7003 -p 37004:7004 -p 37005:7005 -p 37006:7006 --name spslave2 -h spslave2 distkeras /bin/bash
使用Spark Master来启动Spark主节点和工作节点,而Spark Slave仅用于启动工作节点。
# for spark master
${SPARK_HOME}/sbin/start-master.sh
# for spark worker
${SPARK_HOME}/sbin/start-slave.sh -c 1 -m 3G spark://spmaster:${SPARK_MASTER_PORT}
接下来,我们将在Spark的主节点上对MNIST程序进行定制。
MNIST的示例代码是使用Dist-Keras提供的。
代码存放在目录/opt/dist-keras/examples中,那里包含以下的示例数据和程序。
[root@spm examples]# tree
.
|-- cifar-10-preprocessing.ipynb
|-- data
| |-- atlas_higgs.csv
| |-- mnist.csv
| |-- mnist.zip
| |-- mnist_test.csv
| `-- mnist_train.csv
|-- example_0_data_preprocessing.ipynb
|-- example_1_analysis.ipynb
|-- kafka_producer.py
|-- kafka_spark_high_throughput_ml_pipeline.ipynb
|-- mnist.ipynb
|-- mnist.py
|-- mnist_analysis.ipynb
|-- mnist_preprocessing.ipynb
|-- spark-warehouse
`-- workflow.ipynb
复制原始文件以备份,然后应用以下更改。
cp mnist.py mnist.py.bk
修改项1:导入SparkSession。
我会把以下内容添加到开头。
from pyspark.sql import SparkSession
修改部分2:参数设置
将Spark参数根据本次环境进行更改。
更改的意图如下:
– 使用Spark2
– 使用本地环境
– 在本地环境中定义主节点url
– 根据验证条件更改处理器数量
– 根据验证条件更改工作节点数量
# Modify these variables according to your needs.
application_name = "Distributed Keras MNIST"
using_spark_2 = True # False to True
local = True # False to True
path_train = "data/mnist_train.csv"
path_test = "data/mnist_test.csv"
if local:
# Tell master to use local resources.
# master = "local[*]" comment out
master = "spark://spm:7077" # add
num_processes = 1 # change to number of processors per worker
num_executors = 3 # change to number of workers
else:
# Tell master to use YARN.
master = "yarn-client"
num_executors = 20
num_processes = 1
变更项3:工人的内存
根据验证条件,调整工人的内存。
conf = SparkConf()
conf.set("spark.app.name", application_name)
conf.set("spark.master", master)
conf.set("spark.executor.cores", `num_processes`)
conf.set("spark.executor.instances", `num_executors`)
conf.set("spark.executor.memory", "4g") # change RAM size
conf.set("spark.locality.wait", "0")
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
在Spark主节点上,您可以使用python mnist.py来运行。
多个主机的配置方法
多主机配置如下。

在多主机环境中,需要使用overlay网络来连接Docker容器。
有关在多主机环境下构建Docker网络的详细步骤,请查阅以下链接:
http://knowledge.sakura.ad.jp/knowledge/4786/
在这里,我只会写出我的步骤。
在EC2上准备host1和host2,安装etcd并在host1上启动。
yum -y install etcd
vi /etc/etcd/etcd.conf
systemctl enable etcd
systemctl start etcd
接下来,我们将在host1和host2上都添加Docker网络的配置。
# edit docker-network file
vi /etc/sysconfig/docker-network
# for host1
DOCKER_NETWORK_OPTIONS='--cluster-store=etcd://<host1>:2379 --cluster-advertise=<host1>:2376'
# for host2
DOCKER_NETWORK_OPTIONS='--cluster-store=etcd://<host1>:2379 --cluster-advertise=<host2>:2376'
# from host2 to ensure network connection to host1 etcd is available
curl -L http://<host1>:2379/version
{"etcdserver":"3.1.3","etcdcluster":"3.1.0"}
这将使得Docker之间的网络连接成为可能,然后只需在host1上创建Docker网络。
在这里,我们将使用子网10.0.1.0/24创建名为test1的Docker网络。
# for host1
docker network create --subnet=10.0.1.0/24 -d overlay test1
如果在最后运行docker network ls命令时,出现了test1网络,则表示OK。
NETWORK ID NAME DRIVER SCOPE
feb90a5a5901 bridge bridge local
de3c98c59ba6 docker_gwbridge bridge local
d7bd500d1822 host host local
d09ac0b6fed4 none null local
9d4c66170ea0 test1 overlay global
接下来将向test1网络中添加Docker容器。
我们将尝试在host1和host2上部署Docker容器。
# for host1 as spark master
docker run -it --net=test1 --ip=10.0.1.10 -p 18080:8080 -p 17077:7077 -p 18888:8888 -p 18081:8081 -p 14040:4040 -p 17001:7001 -p 17002:7002 \
-p 17003:7003 -p 17004:7004 -p 17005:7005 -p 17006:7006 --name spm -h spm distkeras /bin/bash
# for host2 as spark slave
docker run -it --net=test1 --ip=10.0.1.20 --link=spm:master -p 28080:8080 -p 27077:7077 -p 28888:8888 -p 28081:8081 -p 24040:4040 -p 27001:7001 \
-p 27002:7002 -p 27003:7003 -p 27004:7004 -p 27005:7005 -p 27006:7006 --name sps1 -h sps1 distkeras /bin/bash
现在在test1网络中成功部署了两个Docker容器,可以使用多主机。
接下来,按照单主机的步骤启动Spark Master和Spark Worker,并编辑MNIST.py文件,然后执行python mnist.py。
性能验证结果
这个实验是为了验证每种构成的性能而进行的。我们这次测量的是完成所需的时间(秒数)。
多重主机设置可以提高性能。我认为这是因为可用资源的数量产生了性能差异。
尽管验证2和验证4的Docker容器配置和工作资源使用相同,但仍然存在600秒的差距。
无论是比较验证1和验证2,还是验证4和验证5,验证6,Spark工作者数量和资源数量本身似乎并不产生重大的性能差异。
如果想要显著改善性能,最好选择多重主机设置。
【2017/05/26 附言】
我们使用Kubernetes构建了一个集群。
http://qiita.com/cvusk/items/42a5ffd4e3228963234d