SKIL/工作流程/数据转换
数据转换
在实践中,数据很少以方便神经网络使用的格式存在。它是字符串、类别、数字、不同格式的图像的混合体,而且大部分时间它没有被归一化。通常,数据科学家必须花费超过50%的时间来清理和转换数据,然后才能将其输入深度神经网络。
什么是转换?
数据转换是一个广义的术语,用来描述适合于输入函数的数据转换。在深度学习环境中,这通常意味着获取原始文件(如csv)、删除列或计算新列、按公共键对行进行分组(如果创建序列)、规范化数据(通常是统计数据),最后将输入矢量化为NDArrays。
skil支持在DataVec中实现的转换的特定实现。这些转换也可以通过JSON格式序列化。
转换的类型
在skil中,我们可以构建和部署两种类型的转换。
CSV 转换
CSV转换使用文本CSV数据。它们要求首先建立一个概要,该概要指定与每一列相关的元数据,以及数据源中的类型。在概要建立之后,你可以定义要对数据执行的不同转换过程。你可以删除列,更改它们的数据类型,对它们进行分类并归一化数据。
图像转换
图像转换在图像上进行。它们用于通过图像转换过程缩放、过滤和裁剪图像。它们主要以图像为输入,在其上运行转换列表并返回转换后的图像。
转换流程
你可以在skil工作间实验中使用任何Zeppelin笔记本来构建你自己的转换。
CSV 转换
我们可以通过以下方式构建一个csv转换:
创建一个概要
如果示例数据看起来像这样:5.1,3.5,1.4,0.2,Iris-setosa
,其中逗号分隔的序列为sepal length、sepal width、patal length、patal width和label的类别,则概要将如下所示:
import org.datavec.api.transform.schema.Schema
val schema = new Schema.Builder()
.addColumnsDouble("Sepal length", "Sepal width", "Petal length", "Petal width") // 定义"Double"类型的列
.addColumnCategorical("Species", "Iris-setosa", "Iris-versicolor", "Iris-virginica") // 定义分类数据-列名后跟着分类元素
.build();
image.gif
定义一个转换过程(TransformProcess)
如果我们要将类别标签转换为整数符号,可以按以下方式进行转换:
import org.datavec.api.transform.TransformProcess
val tp = new TransformProcess.Builder(schema) // 从初始化创建的概要开始
.categoricalToInteger("Species") // 转换分类为它们对应的整型值
.build();
image.gif
如果你想知道更多细节,请查看datavec的javadocs中的 TransformProcess.
执行转换
你需要定义一个Spark作业来执行转换过程。按以下方式完成:
/* 下载数据 */
import org.apache.commons.io.FileUtils
import java.io.File
import java.net.URL
val filename = "/tmp/iris.data"
val url = new URL("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data")
val irisText = new File(filename)
if (!irisText.exists()){
FileUtils.copyURLToFile(url, irisText)
}
/* ---------------------------------------------------------------------- */
/* 执行CSV转换*/
import org.apache.spark.api.java.JavaRDD
import org.apache.spark.api.java.JavaSparkContext
import org.datavec.api.writable.Writable
import org.datavec.api.records.reader.impl.csv.CSVRecordReader
import org.datavec.spark.transform.misc.StringToWritablesFunction
val jsc = JavaSparkContext.fromSparkContext(sc) //从zeppelin的SparkContext中创建一个JavaSparkContext
val stringData = jsc.textFile(filename) // 将数据读取为JavaRDD[String]
val rr = new CSVRecordReader()
val parsedInputData = stringData.filter((line: String) => !(line.isEmpty())).toJavaRDD().map(new StringToWritablesFunction(rr)); // 把Strings转为Writables的列表
val processedData = SparkTransformExecutor.execute(parsedInputData, tp) //执行转换过程
/* ---------------------------------------------------------------------- */
/* 查看数据 */
import org.datavec.spark.transform.misc.WritablesToStringFunction
import scala.collection.JavaConversions._ // 从Java列表到Scala列表的隐式转换
val processedAsString = processedData.map(new WritablesToStringFunction(",")) // 从JavaRDD 转换为 String
val inputDataParsed = processedAsString.collect() // 执行和收集处理的输入数据
inputDataParsed.foreach { println } // 打印数据
image.gif
执行转换不是必须的
在这里,我们执行转换只是为了显示基本的转换流程。你不必执行转换过程来保存和部署它。至少,你可以定义TransformProcess或ImageTransformProcess并保存它。我们只需要转换过程JSON来部署它。
保存转换
我们的转换现在可以保存了。你可以使用TransformProcess.``toJson
函数保存你实现的转换。
import java.nio.file.{Paths, Files}
import java.nio.charset.StandardCharsets
val transformProcessJson = tp.toJson()
Files.write(Paths.get("/tmp/transformProcess.json"), transformProcessJson.getBytes(StandardCharsets.UTF_8)) // 保存转换过程
image.gif
图像转换
图像转换过程由ImageTransform
列表定义为:
定义一个ImageTransformProcess
图像转换过程可以构建为:
import org.datavec.image.transform.ImageTransformProcess
val itp = new ImageTransformProcess.Builder()
.seed(12345) // 随机种子
.cropImageTransform(10, 10, 100, 100) // Top, Left, Bottom, Right
.build
image.gif
有关ImageTransform实现的更多详细信息,请参见此处。
保存图像转换
图像转换过程也可以与转换过程相同的方式保存。
import java.nio.file.{Paths, Files}
import java.nio.charset.StandardCharsets
val imageTransformProcessJson = itp.toJson()
Files.write(Paths.get("/tmp/imageTransformProcess.json"), imageTransformProcessJson.getBytes(StandardCharsets.UTF_8)) //保存图像转换过程
image.gif