TensorFlowOnSpark运行demo
导读:记录正常运行tensorflowOnSpark的数据转换、模型训练、模型inference的流程,只看官方的文档很难成功运行。主页:https://github.com/yahoo/TensorFlowOnSpark
环境:
- Spark 2.4.5
- Hadoop 3.2.1
- Tensorflow 2.1.0
- TensorflowOnSpark 2.2.0
- python 3.7.6
- 安装的带GPU的伪分布式环境
运行demo
主要参考官方文档运行mnist的示例:
https://github.com/yahoo/TensorFlowOnSpark/wiki/GetStarted_YARN
1. 准备工作
- 环境搭建完成后,需要启动HFDS和yarn,并且需要在github中将tensorflowOnSpark的源码下载下来。
- 配置一些环境变量,如下(注意对应修改为自己的目录):
# set environment variables (if not already done)
export PYTHON_ROOT=./Python #配置为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 #这个即使是default也是可以使用GPU的,可能和tensorflow是否使用GPU有关
# set paths to libjvm.so, libhdfs.so, and libcuda*.so #各路径都按实际填写即可
#export LIB_HDFS=/opt/cloudera/parcels/CDH/lib64 # for CDH (per @wangyum)
export LIB_HDFS=$HADOOP_PREFIX/lib/native/Linux-amd64-64 # path to libhdfs.so, for TF acccess to HDFS
export LIB_JVM=$JAVA_HOME/jre/lib/amd64/server # path to libjvm.so
export LIB_CUDA=/usr/local/cuda-7.5/lib64 # for GPUs only
2. 转换mnist数据集为csv格式和tfrecords格式
主要代码位于TensorFlowOnSpark-master/examples/mnist/mnist_data_setup.py中。
官方代码中通过tensorflow-datasets模块进行mnist数据的加载,首先对tensorflow-datasets模块进行安装:
pip install tensorflow-datasets
ps:这里需要注意的是,在mnist_data_setup.py中,会直接使用
tfds.load(‘mnist’, with_info=True)
进行数据的加载,tfds.load则是从谷歌的源中进行下载,通常都不能下载成功。而如果手动去mnist官网下载的数据则格式可能由于数据格式不一样导致后续出现问题。因此尽量使用原始tfds.load()下载的数据,下载下来的数据默认会放置在
~/tensorflow_datasets目录下。下载数据后,在tfds.load中使用data_dir参数进行目录的指定即可。也就是说,假设将数据放置在/home/root/data/tensorflow_datasets目录下,则修改mnist_data_setup.py中的
tfds.load(‘mnist’, with_info=True)
改为:
tfds.load(‘mnist’, data_dir=”/home/root/data/tensorflow_datasets”, with_info=True)tfds.load加载的mnist似乎还会有很多版本,这里下载的是3.0.0,但后续模型训练的时候发现官方代码里是使用的1.0.0版本。使用3.0.0时后续按正常步骤会有一些错误,但不确定是否是数据版本造成的。(更新:1.0.0版本也会报错)
文章最上面有csdn的下载方式,下面是百度网盘的:
链接:https://pan.baidu.com/s/1yFNo-wQSQXvmLCd7rJtgOw
提取码:6wng
准备好数据,并在mnist_data_setup.py代码中指定数据加载的文件后,运行:
./spark-2.4.5-bin-without-hadoop/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 1 \ #可以按需调整
--executor-memory 2G \ #可以按需调整
--jars /TensorFlowOnSpark-master/lib/tensorflow-hadoop-1.0-SNAPSHOT.jar \ #转化成tfrecords时并写入到HDFS中时需要
--conf spark.executorEnv.LD_LIBRARY_PATH=$LIB_CUDA \
--driver-library-path=$LIB_CUDA \
/home/TensorFlowOnSpark-master/examples/mnist/mnist_data_setup.py \
--num_partitions 10 \ #文件切分的数量,默认是10
--output /output20 #最终输出的位置,默认使用HDFS,以file:///开头则是本地
应该可以在输出文件目录下得到相应的输出。
3. 模型训练
训练模型的代码有TensorFlowOnSpark-master/examples/mnist/keras/mnist_spark.py
和TensorFlowOnSpark-master/examples/mnist/keras/mnist_tf_ds.py
两个,似乎前者对应csv格式的训练数据,后者对应于tfrecords的训练数据。
读取csv格式的数据进行训练:
spark-2.4.5-bin-without-hadoop/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 2 \
--executor-memory 2G \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.executorEnv.LD_LIBRARY_PATH=$LIB_CUDA:$LIB_JVM:$LIB_HDFS \
--driver-library-path=$LIB_CUDA \
TensorFlowOnSpark-master/examples/mnist/keras/mnist_spark.py \
--images_labels /output20/csv/train \ #默认为HDFS文件
--model_dir /home/TFoS_output #checkpoint输出目录,只能输出到本地,使用HDFS会报错
--export_dir /home/TFoS_output #最终模型输出目录,使用HDFS会报错。
读取tfrecords格式的数据进行训练:
spark-2.4.5-bin-without-hadoop/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 2 \
--executor-memory 2G \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.executorEnv.LD_LIBRARY_PATH=$LIB_CUDA:$LIB_JVM:$LIB_HDFS \
--driver-library-path=$LIB_CUDA \
TensorFlowOnSpark-master/examples/mnist/keras/mnist_tf_ds.py \
--images_labels file:home/data/output20/tfr/train/part-* \ #训练数据目录,默认是hdfs中,但是会报错,因此只能使用本地文件了
--model_dir /home/TFoS_output \ #checkpoint输出目录,只能输出到本地,使用HDFS会报错
--export_dir /home/TFoS_output
很遗憾的是,通过上面读取tfrecords格式的数据进行训练,仍然会报错,可能是因为使用了mnist/3.0.0而没有使用mnist/1.0.0的原因。(用1.0.0试了一下仍然报错)
可以使用如下方式进行训练,不同之处做了注释
spark-2.4.5-bin-without-hadoop/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 1 \
--executor-memory 2G \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.executorEnv.LD_LIBRARY_PATH=$LIB_CUDA:$LIB_JVM:$LIB_HDFS \
--driver-library-path=$LIB_CUDA \
TensorFlowOnSpark-master/examples/mnist/keras/mnist_tf_ds.py \
--images_labels file:///home/tensorflow_datasets/mnist/3.0.0/mnist-train.tfrecord-* \ #主要是这里直接使用了mnist/3.0.0下的文件直接进行训练
--data_format tfds \ #模式修改为tfds,默认是tfos,tfos模式是加载数据转换后的类似于part-00xxx这种文件名的训练数据
--model_dir /home/TFoS_output \
--export_dir /home/TFoS_output
ps:使用上一段代码进行训练的时候需要注意mnist_tf_ds.py中的一段注释:# Note: if you part files have an uneven number of records, you may see an “Out of Range” exception at less than the expected number of steps_per_epoch, because the executor with least amount of records will finish first. 当我指定num-executors为2的时候就出现了这个问题。
4. 模型inference
模型inference的代码主要位于TensorFlowOnSpark-master/examples/mnist/keras/mnist_inference.py
中,而且输入的测试数据需要是tfrecords格式,也就是说不论是通过csv格式还是tfrecords格式的数据训练出来的模型,输入都需要是tfrecords格式。
运行代码如下:
./spark-2.4.5-bin-without-hadoop/bin/spark-submit \
--master yarn \
--deploy-mode cluster \
--queue ${QUEUE} \
--num-executors 3 \
--executor-memory 2G \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.yarn.maxAppAttempts=1 \
--conf spark.executorEnv.LD_LIBRARY_PATH=$LIB_CUDA:$LIB_JVM:$LIB_HDFS \
--driver-library-path=$LIB_CUDA \
TensorFlowOnSpark-master/examples/mnist/keras/mnist_inference.py \
--images_labels /home/data/output20/tfr/test \ #测试集目录。
--export_dir /home/TFoS_Output_tfData/mnist_model_10/1583912478/ \ #模型所在目录
--output /home/TFoS_Output_tfData/prediction10 #结果输出的目录
注意:测试集目录不能用HDFS,会报错。
至此,demo的运行就算是完成了,但是里面仍然有很多坑需要填,例如HDFS经常性报错,数据格式的不对等等。
数据格式尝试过自己从mnist官网下载,然后手动转csv格式,可以顺利训练但是无法进行测试。
同时还尝试过手动转换为tfrecords格式,经过tf2和tf1的种种不兼容修改,最终完成了却发现,既无法训练,也无法测试。
最终说明了能翻墙是多么重要的技能,下载到对应的mnist/3.0.0数据集后流程顺利了很多。
------------------------------------------------------分割线--------------------------------------------------
后续发现官方Segmentation示例也比较容易运行,但是同样难搞定的是数据集的下载,这个数据集比较大,约800多M,需要的同学可以留言,如果我看到了,可以发一下。