【译】Apache spark 2.4:内置 Image Data Source的介绍

随着深度学习在图片分类和对象检测中的应用,Apache Spark 2.4引入了内置图片数据源,简化了图片数据处理流程。此功能支持不同格式、大小和色彩的图片批量导入,提供标准图片抽象,优化图片处理正确性的检测。本文详细介绍图片数据源的使用,包括图片导入、模式转换及通道顺序调整,并展示了如何在Databricks产品中利用这些功能。

Apache spark 2.4:内置 Image Data Source的介绍

[原文链接](https://databricks.com/blog/2018/12/10/introducing-built-in-image-data-source-in-apache-spark-2-4.html

引言

图片分类以及对象检测的深度学习框架的发展使得在apache spark急需支持图片数据处理流程,在支持图片处理流程需要考虑到以下问题:处理不同格式, 大小以及色彩的图片, 如何快速检测图片处理的正确性。
通过图片数据源提供的标准图片抽象可以解决在图片数据处理过程中遇到的大部分问题,在Apache Spark 2.3中,MMLSpark 库提供ImageSchema.readImages API(see Microsoft’s post Image Data Support in Apache Spark)来处理图片数据, 在Apache Spark 2.4中,图片数据作为内置数据源将更易使用,用户可以该内置数据源从目录中批量导入图片进行数据处理。这篇博客主要图片数据源以及如何在databricks的产品里面使用该数据源。

图片导入

首先介绍通过Image Data Source如何将图片数据导入到Spark中,下面是PySpark的代码示例, 在Scala,Java以及R语言中也存在类似的API。

image

mage Data Source路径可以支持递归路径格式,如/path/to/dir/** , 也可以指定特定的分区目录, 如/path/to/dir/date=2018-01-02/category=automobile

图片模式

图片导入到Spark中是以DataFram列的形式存在的,该列包含了以下属性:

image

其中nChannels 表示color channels的数量,对于灰度图片该配置为1,彩色图片该配置为3, mode类型是整型数据, 指定数据类型以及数据通道顺序,其代表的类型一般都会有对应的OpenCV类型,具体的对应关系如下图所示:

image

通道顺序:

通道顺序指定了图片色彩的存储顺序,例如对于红,蓝,绿三通道的图片,存在6种不同的排列顺序,大部分库使用RGB或者BGR的顺序进行存储,OpenCV采用BGR的顺序进行存储。

代码示例

Deep Learning Pipelines 0.4版本之后,使用上述图片模式代替Deep Learning Pipelines项目的图片模式,,对于Deep Learning Pipelines的开发者,新的图片模式通道顺序已经从RGB更改为BGR,因此部分API需要显示指定通道顺序,下面是构建图片分类器的python代码示例:

image

下一步

现阶段通过df.smaple对DataFrame进行抽样是没有优化的,每次抽样需要读取全部图片,下一步将通过下推抽样算子到图片数据源这一层,避免读取全部图片数据,该功能将会在DataSource V2中进行发布。

MNIST Demo 本教程会向你展示如何使用 MLeap 和 Bundle.ML 组件来导出一个 Spark ML Pipeline,并在完全不依赖 Spark Context 的前提下,使用 MLeap 来转换新数据。 我们会构建一个基于 MNIST 数据集训练,包含一个 Vector Assembler、一个 Binarizer、一个 PCA 以及一个 Random Forest Model,用于手写图像分类的 Pipeline。这个练习的目的不是为了训练得到一个最优模型,而是演示在 Spark 中训练一个 Pipeline 然后在 Spark 之外部署这个 Pipeline(数据处理 + 算法)是多么得简单。 本教程的代码分为两个部分: Spark ML Pipeline 代码:原生 Spark 代码,用于训练 ML Pipeline,而后把它序列化成 Bundle.ML。 MLeap 代码:加载一个序列化后的 Bundle 到 MLeap,然后用其转换 Leap Frame。 开始之前,我们先来了解一些术语: 名词 Estimator:真正意义上的机器学习算法,基于 Data Frame 训练 Transformer 并产生一个模型。 模型:在 Spark 里面,模型是代码和元数据,它基于训练过的算法对新数据进行评分。 Transformer:任何用于转换 Data Frame 的都被叫做 Transformer,对于训练一个 Estimator 来说 Transformer 不是必须的(例如一个 Binarizer)。 LeapFrame:一种 Data Frame 的数据结构,用于存储数据以及相关联的 Schema。 训练一个 Spark Pipeline 加载数据 // Note that we are taking advantage of com.databricks:spark-csv package to load the data import org.apache.spark.ml.feature.{VectorAssembler,StringIndexer,IndexToString, Binarizer} import org.apache.spark.ml.classification.{RandomForestClassificationModel, RandomForestClassifier} import org.apache.spark.ml.evaluation.{MulticlassClassificationEvaluator} import org.apache.spark.ml.{Pipeline,PipelineModel} import org.apache.spark.ml.feature.PCA // MLeap/Bundle.ML Serialization Libraries import ml.combust.mleap.spark.SparkSupport._ import resource._ import ml.combust.bundle.BundleFile import org.apache.spark.ml.bundle.SparkBundleContext val datasetPath = "./mleap-demo/data/mnist/mnist_train.csv" var dataset = spark.sqlContext.read.format("com.databricks.spark.csv"). option("header", "true"). option("inferSchema", "true"). load(datasetPath) val testDatasetPath = "./mleap-demo/data/mnist/mnist_test.csv" var test = spark.sqlContext.read.format("com.databricks.spark.csv"). option("inferSchema", "true"). option("header", "true"). load(testDatasetPath) 你可以下载训练和测试数据集(存放在 S3 上),当然你必须要修改成自己的 datasetPath 和 testDatasetPath。 原始数据托管在 Yann LeCun 的网站上 构建 ML Data Pipeline // Define Dependent and Independent Features val predictionCol = "label" val labels = Seq("0","1","2","3","4","5","6","7","8","9") val pixelFeatures = (0 until 784).map(x => s"x$x").toArray val layers = Array[Int](pixelFeatures.length, 784, 800, labels.length) val vector_assembler = new VectorAssembler() .setInputCols(pixelFeatures) .setOutputCol("features") val stringIndexer = { new StringIndexer() .setInputCol(predictionCol) .setOutputCol("label_index") .fit(dataset) } val binarizer = new Binarizer() .setInputCol(vector_assembler.getOutputCol) .setThreshold(127.5) .setOutputCol("binarized_features") val pca = new PCA(). setInputCol(binarizer.getOutputCol). setOutputCol("pcaFeatures"). setK(10) val featurePipeline = new Pipeline().setStages(Array(vector_assembler, stringIndexer, binarizer, pca)) // Transform the raw data with the feature pipeline and persist it val featureModel = featurePipeline.fit(dataset) val datasetWithFeatures = featureModel.transform(dataset) // Select only the data needed for training and persist it val datasetPcaFeaturesOnly = datasetWithFeatures.select(stringIndexer.getOutputCol, pca.getOutputCol) val datasetPcaFeaturesOnlyPersisted = datasetPcaFeaturesOnly.persist() 我们本想让 Pipeline 包含随机森林模型,但目前有一个 Bug (SPARK-16845) 让我们暂时没法这么做(这个问题会在 2.2.0 中得到修复)。 训练一个随机森林模型 // You can optionally experiment with CrossValidator and MulticlassClassificationEvaluator to determine optimal // settings for the random forest val rf = new RandomForestClassifier(). setFeaturesCol(pca.getOutputCol). setLabelCol(stringIndexer.getOutputCol). setPredictionCol("prediction"). setProbabilityCol("probability"). setRawPredictionCol("raw_prediction") val rfModel = rf.fit(datasetPcaFeaturesOnlyPersisted) 序列化 ML Data Pipeline 和 RF Model 为 Bundle.ML import org.apache.spark.ml.mleap.SparkUtil val pipeline = SparkUtil.createPipelineModel(uid = "pipeline", Array(featureModel, rfModel)) val sbc = SparkBundleContext().withDataset(rfModel.transform(datasetWithFeatures)) for(bf <- managed(BundleFile("jar:file:/tmp/mnist-spark-pipeline.zip"))) { pipeline.writeBundle.save(bf)(sbc).get } 反序列化为 MLeap 和评分新数据 这一步的目的是展示如何反序列一个 bundle 然后使用它来对 Leap Frame 进行评分,而无需任何 Spark 依赖。你可以从我们的 S3 存储桶下载这个 mnist.json。 import ml.combust.mleap.runtime.MleapSupport._ import ml.combust.mleap.runtime.MleapContext.defaultContext import java.io.File // load the Spark pipeline we saved in the previous section val mleapPipeline = (for(bf <- managed(BundleFile("jar:file:/tmp/mnist-spark-pipeline.zip"))) yield { bf.loadMleapBundle().get.root }).tried.get 从我们的 mleap-demo Git 仓库中加载一个样例 Leap Frame(data/mnist.json)。 import ml.combust.mleap.runtime.serialization.FrameReader val s = scala.io.Source.fromURL("file:///./mleap-demo/mnist.json").mkString val bytes = s.getBytes("UTF-8") val frame = FrameReader("ml.combust.mleap.json").fromBytes(bytes) // transform the dataframe using our pipeline val frame2 = mleapPipeline.transform(frame).get val data = frame2.dataset 接下来你可以从这里拿到更多的示例和 Notebook。 当前内容版权归 ihainan 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 ihainan . 上一篇:Demos下一篇:Notebooks
最新发布
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值