Building parallel machine learning algorithms: scaling out and up William Benton
 willb@redhat.com • @willb
Motivation
Motivation
Motivation
Motivation
Forecast Introducing our case study: self-organizing maps Parallel implementations for partitioned collections (in particular, RDDs) Beyond the RDD: data frames and ML pipelines Practical considerations and key takeaways
Introducing our case study
Training self-organizing maps
Training self-organizing maps
Training self-organizing maps
Training self-organizing maps
Training self-organizing maps while t < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt
Training self-organizing maps while t < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order
Training self-organizing maps while t < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order the neighborhood size controls how much of the map around the BMU is affected
Training self-organizing maps while t < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order the neighborhood size controls how much of the map around the BMU is affected the learning rate controls how much closer to the example each unit gets
Parallel implementations for partitioned collections
Historical aside: Amdahl’s Law 1 1 - p lim So =sp —> ∞
What forces serial execution?
What forces serial execution?
What forces serial execution? state[t+1] = combine(state[t], x)
What forces serial execution? state[t+1] = combine(state[t], x)
What forces serial execution? f1: (T, T) => T f2: (T, U) => T
What forces serial execution? f1: (T, T) => T f2: (T, U) => T
What forces serial execution? f1: (T, T) => T f2: (T, U) => T
How can we fix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
How can we fix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
How can we fix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
How can we fix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
How can we fix these? L-BGFSSGD a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
How can we fix these? SGD L-BGFS a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c) There will be examples of each of these approaches for many problems in the literature and in open-source code!
Implementing atop RDDs We’ll start with a batch implementation of our technique: for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
Implementing atop RDDs for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods) Each batch produces a model that can be averaged with other models
Implementing atop RDDs Each batch produces a model that can be averaged with other models partition for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
Implementing atop RDDs This won’t always work! for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
An implementation template var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
An implementation template “fold”: update the state for this partition with a single new example var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
An implementation template “reduce”: combine the states from two partitions var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
An implementation template var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } remove the stale broadcasted model broadcast the current working model for this iteration
workersdriver (aggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (aggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (aggregate) Implementing on RDDs
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ driver (treeAggregate) ⊕ ⊕ ⊕ ⊕
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
workersdriver (treeAggregate) Implementing on RDDs ⊕ ⊕
driver (treeAggregate) workers Implementing on RDDs ⊕ ⊕
driver (treeAggregate) workers Implementing on RDDs ⊕ ⊕⊕
Beyond the RDD: Data frames and ML Pipelines
RDDs: some good parts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show()
RDDs: some good parts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile
RDDs: some good parts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile
RDDs: some good parts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile crashes at runtime
RDDs: some good parts rdd.map { vec => (vec, model.value.closestWithSimilarity(vec)) } val predict = udf ((vec: SV) => model.value.closestWithSimilarity(vec)) df.withColumn($"predictions", predict($"features"))
RDDs: some good parts rdd.map { vec => (vec, model.value.closestWithSimilarity(vec)) } val predict = udf ((vec: SV) => model.value.closestWithSimilarity(vec)) df.withColumn($"predictions", predict($"features"))
RDDs versus query planning val numbers1 = sc.parallelize(1 to 100000000) val numbers2 = sc.parallelize(1 to 1000000000) numbers1.cartesian(numbers2) .map((x, y) => (x, y, expensive(x, y))) .filter((x, y, _) => isPrime(x), isPrime(y))
RDDs versus query planning val numbers1 = sc.parallelize(1 to 100000000) val numbers2 = sc.parallelize(1 to 1000000000) numbers1.filter(isPrime(_)) .cartesian(numbers2.filter(isPrime(_))) .map((x, y) => (x, y, expensive(x, y)))
RDDs and the Java heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0))
RDDs and the Java heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0
RDDs and the Java heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0 32 bytes of data…
RDDs and the Java heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0 …and 64 bytes of overhead! 32 bytes of data…
ML pipelines: a quick example from pyspark.ml.clustering import KMeans K, SEED = 100, 0xdea110c8 randomDF = make_random_df() kmeans = KMeans().setK(K).setSeed(SEED).setFeaturesCol("features") model = kmeans.fit(randomDF) withPredictions = model.transform(randomDF).select("x", "y", "prediction")
Working with ML pipelines estimator.fit(df)
Working with ML pipelines estimator.fit(df) model.transform(df)
Working with ML pipelines model.transform(df)
Working with ML pipelines model.transform(df)
Working with ML pipelines estimator.fit(df) model.transform(df)
Working with ML pipelines estimator.fit(df) model.transform(df) inputCol epochs seed outputCol
private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
Don’t repeat yourself /** * Common params for KMeans and KMeansModel */ private[clustering] trait KMeansParams extends Params with HasMaxIter with HasFeaturesCol with HasSeed with HasPredictionCol with HasTol { /* ... */ }
Estimators and transformers estimator.fit(df)
Estimators and transformers estimator.fit(df)
Estimators and transformers estimator.fit(df) model.transform(df)
Estimators and transformers estimator.fit(df) model.transform(df)
Estimators and transformers estimator.fit(df) model.transform(df)
Validate and transform at once def transformSchema(schema: StructType): StructType = { // check that the input columns exist... // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema }
Validate and transform at once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… require(schema.fieldNames.contains($(featuresCol))) // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema }
Validate and transform at once def transformSchema(schema: StructType): StructType = { // check that the input columns exist... // ...and are the proper type schema($(featuresCol)) match { case sf: StructField => require(sf.dataType.equals(VectorType)) } // ...and that the output columns don’t exist // ...and then make a new schema }
Validate and transform at once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… // ...and are the proper type // ...and that the output columns don’t exist require(!schema.fieldNames.contains($(predictionCol))) require(!schema.fieldNames.contains($(similarityCol))) // ...and then make a new schema }
Validate and transform at once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema schema.add($(predictionCol), "int") .add($(similarityCol), "double") }
Training on data frames def fit(examples: DataFrame) = { import examples.sparkSession.implicits._ import org.apache.spark.ml.linalg.{Vector=>SV} val dfexamples = examples.select($(exampleCol)).rdd.map { case Row(sv: SV) => sv } /* construct a model object with the result of training */ new SOMModel(train(dfexamples, $(x), $(y))) }
Practical considerations
Improve serial execution times 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
Improve serial execution times 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
Improve serial execution times 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
<latexit sha1_base64="F0lpnVum/z3V85cOiWhHJHNgpmw=">AAACFHicbVDLSsNAFJ34rPUVdelmsAiCUBIRdFl047KCfUATymQ6aYdOkunMjVDSfoQbf8WNC0XcunDn3zhtI2jrgbkczrmXO/cEUnANjvNlLS2vrK6tFzaKm1vbO7v23n5dJ6mirEYTkahmQDQTPGY14CBYUypGokCwRtC/nviNe6Y0T+I7GErmR6Qb85BTAkZq26deqAjNJPaCVAgGeDDORiMssSk/kqEDU8Ztu+SUnSnwInFzUkI5qm370+skNI1YDFQQrVuuI8HPiAJOBRsXvVQzSWifdFnL0JhETPvZ9KgxPjZKB4eJMi8GPFV/T2Qk0noYBaYzItDT895E/M9rpRBe+hmPZQosprNFYSowJHiSEO5wxSiIoSGEKm7+immPmJTA5Fg0IbjzJy+S+lnZdcru7XmpcpXHUUCH6AidIBddoAq6QVVUQxQ9oCf0gl6tR+vZerPeZ61LVj5zgP7A+vgG1reeqw==</latexit> ||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
<latexit sha1_base64="F0lpnVum/z3V85cOiWhHJHNgpmw=">AAACFHicbVDLSsNAFJ34rPUVdelmsAiCUBIRdFl047KCfUATymQ6aYdOkunMjVDSfoQbf8WNC0XcunDn3zhtI2jrgbkczrmXO/cEUnANjvNlLS2vrK6tFzaKm1vbO7v23n5dJ6mirEYTkahmQDQTPGY14CBYUypGokCwRtC/nviNe6Y0T+I7GErmR6Qb85BTAkZq26deqAjNJPaCVAgGeDDORiMssSk/kqEDU8Ztu+SUnSnwInFzUkI5qm370+skNI1YDFQQrVuuI8HPiAJOBRsXvVQzSWifdFnL0JhETPvZ9KgxPjZKB4eJMi8GPFV/T2Qk0noYBaYzItDT895E/M9rpRBe+hmPZQosprNFYSowJHiSEO5wxSiIoSGEKm7+immPmJTA5Fg0IbjzJy+S+lnZdcru7XmpcpXHUUCH6AidIBddoAq6QVVUQxQ9oCf0gl6tR+vZerPeZ61LVj5zgP7A+vgG1reeqw==</latexit> ||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
<latexit sha1_base64="sgjZxc6SmNq0zTGtiQFaoRPCk2s=">AAACQHicbVC7SgNBFJ2NrxhfUUubwaBYhd0YH2XQxjKCeUB2CbOzN8mQ2dllZlYMSz7Nxk+ws7axUMTWyskDNIkHDhzOPZe5c/yYM6Vt+8XKLC2vrK5l13Mbm1vbO/ndvbqKEkmhRiMeyaZPFHAmoKaZ5tCMJZDQ59Dw+9ejeeMepGKRuNODGLyQdAXrMEq0sdr5hutDl4nUD4mW7GGIHXyMS4an2AUR/Pqun3AOGs/nyyZ7Zng+m2/nC3bRHgMvCmcqCmiKajv/7AYRTUIQmnKiVMuxY+2lRGpGOQxzbqIgJrRPutAyUpAQlJeOCxjiI+MEuBNJQ6Hx2P27kZJQqUHom6S5r6fmZyPzv1kr0Z1LL2UiTjQIOnmok3CsIzxqEwdMAtV8YAShkplbMe0RSag2nedMCc78lxdFvVR07KJzWy5UrqZ1ZNEBOkQnyEEXqIJuUBXVEEWP6BW9ow/ryXqzPq2vSTRjTXf20Qys7x/ZKq4m</latexit>
⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit>
⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit> <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit> <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit> libraryDependencies += "org.scalanlp" %% "breeze-natives" % "0.13.1"
val vec = Array[Double](/* ... */)
val vec = Array[Double](/* ... */)
def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) } val vec = Array[Double](/* ... */)
def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) } val vec = Array[Double](/* ... */) dot(Array(0.1d, 0.2d, 0.3d), Array(1.0d, 0.0d, 0.0d)) dot(Array(0.1f, 0.2f, 0.3f), Array(1.0f, 0.0f, 0.0f))
val vec = Array[Double](/* ... */) vdppd vdppd 0.1d 0.2d 1.0d 0.0d 0.3d (unused) 0.0d (unused) def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) }
val vec = Array[Double](/* ... */) vdppd vdppd 0.1d 0.2d 1.0d 0.0d 0.3d (unused) 0.0d (unused) vdpps 0.3f unused0.2f0.1f 0.0f unused0.0f1.0f def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) }
KEY TAKEAWAYS
THANKS!willb@redhat.com • @willb https://chapeau.freevariable.com https://radanalytics.io also: “Spark for Library Developers” Room 2014 at 5:40 PM today

Building Machine Learning Algorithms on Apache Spark: Scaling Out and Up with William Benton

  • 1.
    Building parallel machine learningalgorithms: scaling out and up William Benton
 willb@redhat.com • @willb
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
    Forecast Introducing our casestudy: self-organizing maps Parallel implementations for partitioned collections (in particular, RDDs) Beyond the RDD: data frames and ML pipelines Practical considerations and key takeaways
  • 7.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
    Training self-organizing maps whilet < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt
  • 15.
    Training self-organizing maps whilet < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order
  • 16.
    Training self-organizing maps whilet < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order the neighborhood size controls how much of the map around the BMU is affected
  • 17.
    Training self-organizing maps whilet < maxupdates: random.shuffle(examples) for ex in examples: t = t + 1 if t == maxupdates: break bestMatch = closest(somt, ex) for (unit, wt) in neighborhood(bestMatch, sigma(t)): somt+1[unit] = somt[unit] + (ex - somt[unit]) * alpha(t) * wt process the training set in random order the neighborhood size controls how much of the map around the BMU is affected the learning rate controls how much closer to the example each unit gets
  • 18.
  • 19.
    Historical aside: Amdahl’sLaw 1 1 - p lim So =sp —> ∞
  • 20.
  • 21.
  • 22.
    What forces serialexecution? state[t+1] = combine(state[t], x)
  • 23.
    What forces serialexecution? state[t+1] = combine(state[t], x)
  • 24.
    What forces serialexecution? f1: (T, T) => T f2: (T, U) => T
  • 25.
    What forces serialexecution? f1: (T, T) => T f2: (T, U) => T
  • 26.
    What forces serialexecution? f1: (T, T) => T f2: (T, U) => T
  • 27.
    How can wefix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
  • 28.
    How can wefix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
  • 29.
    How can wefix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
  • 30.
    How can wefix these? a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
  • 31.
    How can wefix these? L-BGFSSGD a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
  • 32.
    How can wefix these? SGD L-BGFS a ⊕ b = b ⊕ a (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c) There will be examples of each of these approaches for many problems in the literature and in open-source code!
  • 33.
    Implementing atop RDDs We’llstart with a batch implementation of our technique: for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
  • 34.
    Implementing atop RDDs fort in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods) Each batch produces a model that can be averaged with other models
  • 35.
    Implementing atop RDDs Eachbatch produces a model that can be averaged with other models partition for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
  • 36.
    Implementing atop RDDs Thiswon’t always work! for t in (1 to iterations): state = newState() for ex in examples: bestMatch = closest(somt-1, ex) hood = neighborhood(bestMatch, sigma(t)) state.matches += ex * hood state.hoods += hood somt = newSOM(state.matches / state.hoods)
  • 37.
    An implementation template varnextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
  • 38.
    An implementation template “fold”:update the state for this partition with a single new example var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
  • 39.
    An implementation template “reduce”:combine the states from two partitions var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist }
  • 40.
    An implementation template varnextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } var nextModel = initialModel for (int i = 0; i < iterations; i++) { val current = sc.broadcast(nextModel) val newState = examples.aggregate(ModelState.empty()) { { case (state: ModelState, example: Example) => state.update(current.value.lookup(example, i), example) } { case (s1: ModelState, s2: ModelState) => s1.combine(s2) } } nextModel = modelFromState(newState) current.unpersist } remove the stale broadcasted model broadcast the current working model for this iteration
  • 41.
    workersdriver (aggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 42.
    workersdriver (aggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 43.
  • 44.
    workersdriver (treeAggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 45.
    workersdriver (treeAggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 46.
    workersdriver (treeAggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 47.
    workersdriver (treeAggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ driver (treeAggregate) ⊕ ⊕ ⊕ ⊕
  • 48.
    workersdriver (treeAggregate) Implementing onRDDs ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕
  • 49.
  • 50.
  • 51.
  • 52.
    Beyond the RDD:Data frames and ML Pipelines
  • 53.
    RDDs: some goodparts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show()
  • 54.
    RDDs: some goodparts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile
  • 55.
    RDDs: some goodparts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile
  • 56.
    RDDs: some goodparts val rdd: RDD[String] = /* ... */ rdd.map(_ * 3.0).collect() val df: DataFrame = /* data frame with one String-valued column */ df.select($"_1" * 3.0).show() doesn’t compile crashes at runtime
  • 57.
    RDDs: some goodparts rdd.map { vec => (vec, model.value.closestWithSimilarity(vec)) } val predict = udf ((vec: SV) => model.value.closestWithSimilarity(vec)) df.withColumn($"predictions", predict($"features"))
  • 58.
    RDDs: some goodparts rdd.map { vec => (vec, model.value.closestWithSimilarity(vec)) } val predict = udf ((vec: SV) => model.value.closestWithSimilarity(vec)) df.withColumn($"predictions", predict($"features"))
  • 59.
    RDDs versus queryplanning val numbers1 = sc.parallelize(1 to 100000000) val numbers2 = sc.parallelize(1 to 1000000000) numbers1.cartesian(numbers2) .map((x, y) => (x, y, expensive(x, y))) .filter((x, y, _) => isPrime(x), isPrime(y))
  • 60.
    RDDs versus queryplanning val numbers1 = sc.parallelize(1 to 100000000) val numbers2 = sc.parallelize(1 to 1000000000) numbers1.filter(isPrime(_)) .cartesian(numbers2.filter(isPrime(_))) .map((x, y) => (x, y, expensive(x, y)))
  • 61.
    RDDs and theJava heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0))
  • 62.
    RDDs and theJava heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0
  • 63.
    RDDs and theJava heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0 32 bytes of data…
  • 64.
    RDDs and theJava heap val mat = Array(Array(1.0, 2.0), Array(3.0, 4.0)) class pointer flags size locks element pointer element pointer class pointer flags size locks 1.0 class pointer flags size locks 3.0 4.0 2.0 …and 64 bytes of overhead! 32 bytes of data…
  • 65.
    ML pipelines: aquick example from pyspark.ml.clustering import KMeans K, SEED = 100, 0xdea110c8 randomDF = make_random_df() kmeans = KMeans().setK(K).setSeed(SEED).setFeaturesCol("features") model = kmeans.fit(randomDF) withPredictions = model.transform(randomDF).select("x", "y", "prediction")
  • 66.
    Working with MLpipelines estimator.fit(df)
  • 67.
    Working with MLpipelines estimator.fit(df) model.transform(df)
  • 68.
    Working with MLpipelines model.transform(df)
  • 69.
    Working with MLpipelines model.transform(df)
  • 70.
    Working with MLpipelines estimator.fit(df) model.transform(df)
  • 71.
    Working with MLpipelines estimator.fit(df) model.transform(df) inputCol epochs seed outputCol
  • 72.
    private[som] trait SOMParamsextends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
  • 73.
    private[som] trait SOMParamsextends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... Defining parameters private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
  • 74.
    Defining parameters private[som] traitSOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
  • 75.
    Defining parameters private[som] traitSOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
  • 76.
    Defining parameters private[som] traitSOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ... private[som] trait SOMParams extends Params with DefaultParamsWritable { final val x: IntParam = new IntParam(this, "x", "width of self-organizing map (>= 1)", ParamValidators.gtEq(1)) final def getX: Int = $(x) final def setX(value: Int): this.type = set(x, value) // ...
  • 77.
    Don’t repeat yourself /** *Common params for KMeans and KMeansModel */ private[clustering] trait KMeansParams extends Params with HasMaxIter with HasFeaturesCol with HasSeed with HasPredictionCol with HasTol { /* ... */ }
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
    Validate and transformat once def transformSchema(schema: StructType): StructType = { // check that the input columns exist... // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema }
  • 84.
    Validate and transformat once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… require(schema.fieldNames.contains($(featuresCol))) // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema }
  • 85.
    Validate and transformat once def transformSchema(schema: StructType): StructType = { // check that the input columns exist... // ...and are the proper type schema($(featuresCol)) match { case sf: StructField => require(sf.dataType.equals(VectorType)) } // ...and that the output columns don’t exist // ...and then make a new schema }
  • 86.
    Validate and transformat once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… // ...and are the proper type // ...and that the output columns don’t exist require(!schema.fieldNames.contains($(predictionCol))) require(!schema.fieldNames.contains($(similarityCol))) // ...and then make a new schema }
  • 87.
    Validate and transformat once def transformSchema(schema: StructType): StructType = { // check that the input columns exist… // ...and are the proper type // ...and that the output columns don’t exist // ...and then make a new schema schema.add($(predictionCol), "int") .add($(similarityCol), "double") }
  • 88.
    Training on dataframes def fit(examples: DataFrame) = { import examples.sparkSession.implicits._ import org.apache.spark.ml.linalg.{Vector=>SV} val dfexamples = examples.select($(exampleCol)).rdd.map { case Row(sv: SV) => sv } /* construct a model object with the result of training */ new SOMModel(train(dfexamples, $(x), $(y))) }
  • 89.
  • 90.
    Improve serial executiontimes 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
  • 91.
    Improve serial executiontimes 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
  • 92.
    Improve serial executiontimes 2 6 6 4 0 0 1 0 1 0 0 0 1 1 0 0 3 7 7 5 • 2 4 0.1 0.7 0.2 3 5 <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit><latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
  • 95.
    <latexit sha1_base64="F0lpnVum/z3V85cOiWhHJHNgpmw=">AAACFHicbVDLSsNAFJ34rPUVdelmsAiCUBIRdFl047KCfUATymQ6aYdOkunMjVDSfoQbf8WNC0XcunDn3zhtI2jrgbkczrmXO/cEUnANjvNlLS2vrK6tFzaKm1vbO7v23n5dJ6mirEYTkahmQDQTPGY14CBYUypGokCwRtC/nviNe6Y0T+I7GErmR6Qb85BTAkZq26deqAjNJPaCVAgGeDDORiMssSk/kqEDU8Ztu+SUnSnwInFzUkI5qm370+skNI1YDFQQrVuuI8HPiAJOBRsXvVQzSWifdFnL0JhETPvZ9KgxPjZKB4eJMi8GPFV/T2Qk0noYBaYzItDT895E/M9rpRBe+hmPZQosprNFYSowJHiSEO5wxSiIoSGEKm7+immPmJTA5Fg0IbjzJy+S+lnZdcru7XmpcpXHUUCH6AidIBddoAq6QVVUQxQ9oCf0gl6tR+vZerPeZ61LVj5zgP7A+vgG1reeqw==</latexit> ||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexitsha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
  • 96.
    <latexit sha1_base64="F0lpnVum/z3V85cOiWhHJHNgpmw=">AAACFHicbVDLSsNAFJ34rPUVdelmsAiCUBIRdFl047KCfUATymQ6aYdOkunMjVDSfoQbf8WNC0XcunDn3zhtI2jrgbkczrmXO/cEUnANjvNlLS2vrK6tFzaKm1vbO7v23n5dJ6mirEYTkahmQDQTPGY14CBYUypGokCwRtC/nviNe6Y0T+I7GErmR6Qb85BTAkZq26deqAjNJPaCVAgGeDDORiMssSk/kqEDU8Ztu+SUnSnwInFzUkI5qm370+skNI1YDFQQrVuuI8HPiAJOBRsXvVQzSWifdFnL0JhETPvZ9KgxPjZKB4eJMi8GPFV/T2Qk0noYBaYzItDT895E/M9rpRBe+hmPZQosprNFYSowJHiSEO5wxSiIoSGEKm7+immPmJTA5Fg0IbjzJy+S+lnZdcru7XmpcpXHUUCH6AidIBddoAq6QVVUQxQ9oCf0gl6tR+vZerPeZ61LVj5zgP7A+vgG1reeqw==</latexit> ||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexitsha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
  • 97.
    ||q||<latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexitsha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit><latexit sha1_base64="Fotu1JHT5+QrvqFi2jYz5La5cyI=">AAAB7nicbVBNS8NAEJ3Ur1q/qh69LBbBU0lE0GPRi8cK9gPaUDbbTbt0s4m7E6Gk/RFePCji1d/jzX/jts1BWx8MPN6bYWZekEhh0HW/ncLa+sbmVnG7tLO7t39QPjxqmjjVjDdYLGPdDqjhUijeQIGStxPNaRRI3gpGtzO/9cS1EbF6wHHC/YgOlAgFo2il1mRCHslk0itX3Ko7B1klXk4qkKPeK391+zFLI66QSWpMx3MT9DOqUTDJp6VuanhC2YgOeMdSRSNu/Gx+7pScWaVPwljbUkjm6u+JjEbGjKPAdkYUh2bZm4n/eZ0Uw2s/EypJkSu2WBSmkmBMZr+TvtCcoRxbQpkW9lbChlRThjahkg3BW355lTQvqp5b9e4vK7WbPI4inMApnIMHV1CDO6hDAxiM4Ble4c1JnBfn3flYtBacfOYY/sD5/AESAY9h</latexit>
  • 98.
  • 99.
    ⇥ 0 0 1 ⇤ • ⇥ 0.10.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit>
  • 100.
    ⇥ 0 0 1 ⇤ • ⇥ 0.10.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit> <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit>
  • 101.
    ⇥ 0 0 1 ⇤ • ⇥ 0.10.7 0.2 ⇤ ⇥ 0 1 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 0 0 1 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ ⇥ 1 0 0 ⇤ • ⇥ 0.1 0.7 0.2 ⇤ <latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit><latexit sha1_base64="zslMj5nDZfArLAY/7Q+RF8nfHL4=">AAADanictVJNS8NAEN0mftT61VZQxMtiVTyFpAj1WPTisYJVoSlls53Wxc0m7G7EEgr+Rm/+Ai/+CDdpQG096sAujzfzeDPDBDFnSrvuW8myl5ZXVstrlfWNza3taq1+q6JEUujSiEfyPiAKOBPQ1UxzuI8lkDDgcBc8Xmb5uyeQikXiRk9i6IdkLNiIUaINNaiVXvwAxkykQUi0ZM9T7OKT/HnYBzH84v0g4Rw0Xqh3vEzhtPK/Oa/yK78Z5JL/NPjXCbzC4E8mGFQbruPmgReBV4AGKqIzqL76w4gmIQhNOVGq57mx7qdEakY5TCt+oiAm9JGMoWegICGofpqfyhQfG2aIR5E0T2ics98VKQmVmoSBqTT9Paj5XEb+luslenTeT5mIEw2CzoxGCcc6wtnd4SGTQDWfGECoZKZXTB+IJFSb66yYJXjzIy+C26bjmV1enzXaF8U6yugAHaJT5KEWaqMr1EFdREvv1qa1a+1ZH3bd3rcPZqVWqdDsoB9hH30CrJcKDw==</latexit> <latexit sha1_base64="yGPDKZdOXUPJZlyEHQdtfy2cnBM=">AAACcHicbVHLSgMxFM2Mr1pf1W4EFaNFERdlpgh1WXTjUsE+oFNKJr1tQzOZIcmIZeja/3PnR7jxC0yng9rWCyHnnnPvTXLiR5wp7Tgflr2yura+kdvMb23v7O4V9g8aKowlhToNeShbPlHAmYC6ZppDK5JAAp9D0x/dT/XmC0jFQvGsxxF0AjIQrM8o0YbqFt48HwZMJH5AtGSvE+zgy3S52PMyMCWy5Edxs8QoIHq/7Z4fcw4aL40tzwaWqzif7pX5xm6h5JSdNPAycDNQQlk8dgvvXi+kcQBCU06UartOpDsJkZpRDpO8FyuICB2RAbQNFCQA1UlSwyb4wjA93A+lWULjlP3bkZBAqXHgm0pzv6Fa1Kbkf1o71v3bTsJEFGsQdHZQP+ZYh3jqPu4xCVTzsQGESmbuiumQSEK1+aO8McFdfPIyaFTKrrHz6aZUu8vsyKEjdI6ukIuqqIYe0COqI4o+raJ1bJ1YX/ahfWqfzUptK+spormwr78BvNCySg==</latexit> libraryDependencies += "org.scalanlp" %% "breeze-natives" % "0.13.1"
  • 102.
    val vec =Array[Double](/* ... */)
  • 103.
    val vec =Array[Double](/* ... */)
  • 104.
    def dot[S](a: Array[S],b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) } val vec = Array[Double](/* ... */)
  • 105.
    def dot[S](a: Array[S],b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) } val vec = Array[Double](/* ... */) dot(Array(0.1d, 0.2d, 0.3d), Array(1.0d, 0.0d, 0.0d)) dot(Array(0.1f, 0.2f, 0.3f), Array(1.0f, 0.0f, 0.0f))
  • 106.
    val vec =Array[Double](/* ... */) vdppd vdppd 0.1d 0.2d 1.0d 0.0d 0.3d (unused) 0.0d (unused) def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) }
  • 107.
    val vec =Array[Double](/* ... */) vdppd vdppd 0.1d 0.2d 1.0d 0.0d 0.3d (unused) 0.0d (unused) vdpps 0.3f unused0.2f0.1f 0.0f unused0.0f1.0f def dot[S](a: Array[S], b: Array[S]) (implicit num: Numeric[S]): S = { import num._ (0 until a.length).foldLeft(num.zero)({ (acc, i) => acc + a(i) * b(i) }) }
  • 108.
  • 113.