SlideShare a Scribd company logo
Tools for Making
Machine Learning
more Reactive
Jeff Smith
@jeffksmithjr
jeffsmith.tech
Reactive Machine Learning
Background Survey
Reactive Systems
Reactive Strategies
Machine Learning Systems
Reactive Machine Learning
Reactive at Intent Media
Language Survey
Languages
● Scala
● Erlang/Elixir
● Python
Responding
Agriculture
Akka
● Scala & Java
● Actor model
● Concurrency
● Distribution
● Supervision
Model Microservices
Model Microservice in Akka HTTP
case class Prediction(id: Long, timestamp: Long, value: Double)
trait Protocols extends DefaultJsonProtocol {
implicit val predictionFormat = jsonFormat3(Prediction)
}
Model Microservice in Akka HTTP
def model(features: Map[Char, Double]) = {
val coefficients = ('a' to 'z').zip(1 to 26).toMap
val predictionValue = features.map {
case (identifier, value) =>
coefficients.getOrElse(identifier, 0) * value
}.sum / features.size
Prediction(Random.nextLong(), System.currentTimeMillis(), predictionValue)
}
def parseFeatures(features: String): Map[String, Double] = {
features.parseJson.convertTo[Map[Char, Double]]
}
def predict(features: String): Prediction = {
model(parseFeatures(features))
}
Model Microservice in Akka HTTP
trait Service extends Protocols {
implicit val system: ActorSystem
implicit def executor: ExecutionContextExecutor
implicit val materializer: Materializer
val logger: LoggingAdapter
val routes = {
logRequestResult("model-service") {
pathPrefix("predict") {
(get & path(Segment)) {
features: String =>
complete {
ToResponseMarshallable(predict(features))}}}}}}
Model Serialization
Random Forest in Spark MLlib
MLlib Model Serialization
{
"class": "org.apache.spark.ml.PipelineModel",
"timestamp": 1467653845388,
"sparkVersion": "2.0.0-preview",
"uid": "pipeline_6b4fb08e8fb0",
"paramMap": {
"stageUids": ["quantileDiscretizer_d3996173db25",
"vecAssembler_2bdcd79fe1cf",
"logreg_9d559ca7e208"]
}
}
MLlib Model Serialization
{ "class": "org.apache.spark.ml.classification.LogisticRegressionModel",
"timestamp": 1467653845650,
"sparkVersion": "2.0.0-preview",
"uid": "logreg_9d559ca7e208",
"paramMap": {
"threshold": 0.5,
"elasticNetParam": 0.0,
"fitIntercept": true,
"tol": 1.0E-6,
"regParam": 0.0,
"maxIter": 5,
"standardization": true,
"featuresCol": "features",
"rawPredictionCol": "rawPrediction",
"predictionCol": "prediction",
"probabilityCol": "probability",
"labelCol": "label"}}
Parquet
Packaging
Containerizing with sbt-docker
dockerfile in docker := {
val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value
val classpath = (managedClasspath in Compile).value
val mainClass = "com.reactivemachinelearning.PredictiveService"
val jarTarget = s"/app/${jarFile.getName}"
val classpathString = classpath.files.map("/app/" + _.getName)
.mkString(":") + ":" + jarTarget
new Dockerfile {
from("java")
add(classpath.files, "/app/")
add(jarFile, jarTarget)
entryPoint("java", "-cp", classpathString, mainClass)
}
}
Containerizing with sbt-docker
FROM java
ADD 0/spark-core_2.11-2.0.0-preview.jar 1/avro-mapred-1.7.7-hadoop2.jar ...
ADD 166/chapter-7_2.11-1.0.jar /app/chapter-7_2.11-1.0.jar
ENTRYPOINT ["java", "-cp", "/app/spark-core_2.11-2.0.0-preview.jar ...
"com.reactivemachinelearning.PredictiveService"]
Model Servers
Transportation
Model Server in http4s
object Models {
val modelA = HttpService {
case GET -> Root / "a" / inputData =>
val response = true
Ok(s"Model A predicted $response.")
}
val modelB = HttpService {
case GET -> Root / "b" / inputData =>
val response = false
Ok(s"Model B predicted $response.")
}
}
Model Server in http4s
object Client {
val client = PooledHttp1Client()
private def call(model: String, input: String) = {
val target = Uri.fromString(s"http://localhost:8080/models/$model/$input").toOption.get
client.expect[String](target)
}
def callA(input: String) = call("a", input)
def callB(input: String) = call("b", input)
}
Model Server in http4s
def splitTraffic(data: String) = {
data.hashCode % 10 match {
case x if x < 4 => Client.callA(data)
case _ => Client.callB(data)
}
}
Model Server in http4s
object ModelServer extends ServerApp {
val apiService = HttpService {
case GET -> Root / "predict" / inputData =>
val response = splitTraffic(inputData).run
Ok(response)
}
override def server(args: List[String]): Task[Server] = {
BlazeBuilder
.bindLocal(8080)
.mountService(apiService, "/api")
.mountService(Models.modelA, "/models")
.mountService(Models.modelB, "/models")
.start
}
}
Model Server in http4s
import scala.util.Random
val modelC = HttpService {
case GET -> Root / "c" / inputData => {
val workingOk = Random.nextBoolean()
val response = true
if (workingOk) {
Ok(s"Model C predicted $response.")
} else {
BadRequest("Model C failed to predict.")
}
}
}
Model Server in http4s
private def call(model: String, input: String): Task[Response] = {
val target = Uri.fromString(
s"http://localhost:8080/models/$model/$input"
).toOption.get
client(target)
}
def callC(input: String) = call("c", input)
Model Server in http4s
def splitTraffic(data: String) = {
data.hashCode % 10 match {
case x if x < 4 => Client.callA(data)
case x if x < 6 => Client.callB(data)
case _ => Client.callC(data)
}
}
val apiService = HttpService {
case GET -> Root / "predict" / inputData =>
val response = splitTraffic(inputData).run
response match {
case r: Response if r.status == Ok => Response(Ok).withBody(r.bodyAsText)
case r => Response(BadRequest).withBody(r.bodyAsText)
}
}
Model Server in http4s
def splitTraffic(data: String) = {
data.hashCode % 10 match {
case x if x < 4 => Client.callA(data)
case x if x < 6 => Client.callB(data)
case _ => Client.callC(data)
}
}
val apiService = HttpService {
case GET -> Root / "predict" / inputData =>
val response = splitTraffic(inputData).run
response match {
case r: Response if r.status == Ok => Response(Ok).withBody(r.bodyAsText)
case r => Response(BadRequest).withBody(r.bodyAsText)
}
}
Model Server in http4s
private def call(model: String, input: String) = {
val target = Uri.fromString(s"http://localhost:8080/models/$model/$input").toOption.get
client(target).retry(Seq(1 second), {_ => true})
}
BEAM
Erlang
Elixir
Knowledge Maintenance
Circuit Breakers in Erlang/Elixir
def update(user_data) do
{user_id, _} = user_data
case verify_fuse(user_id) do
:ok ->
write_to_db(user_data)
|> parse_db_response(user_id)
:sorry ->
IO.puts "This user can't be updated now. ¯_(ツ)_/¯"
:sorry
end
end
Circuit Breakers in Erlang/Elixir
defp verify_fuse(user_id) do
case :fuse.ask(user_id, :sync) do
{:error, :not_found} ->
IO.puts "Installing"
install_fuse(user_id)
:ok
:blown ->
:sorry
_ -> :ok
end
end
Circuit Breakers in Erlang/Elixir
defp install_fuse(user_id) do
:fuse.install(user_id, {{:standard, 3, 60000}, {:reset, 900000}})
end
Circuit Breakers in Erlang/Elixir
defp write_to_db({_user_id, _data}) do
Enum.random([{:ok, ""}, {:error, "The DB dropped the ball. ಠ_ಠ"}])
end
Circuit Breakers in Erlang/Elixir
defp parse_db_response({:ok, _}, _user_id) do
:ok
end
defp parse_db_response({:error, message}, user_id) do
:fuse.melt(user_id)
IO.puts "Error encountered: #{message}.nMelting the fuse!"
:sorry
end
Circuit Breakers in Erlang/Elixir
def update(user_data) do
{user_id, _} = user_data
case verify_fuse(user_id) do
:ok ->
write_to_db(user_data)
|> parse_db_response(user_id)
:sorry ->
IO.puts "This user can't be updated now. ¯_(ツ)_/¯"
:sorry
end
end
Circuit Breakers in Akka
class DangerousActor extends Actor with ActorLogging {
import context.dispatcher
val breaker =
new CircuitBreaker(
context.system.scheduler,
maxFailures = 5,
callTimeout = 10.seconds,
resetTimeout = 1.minute).onOpen(notifyMeOnOpen())
def notifyMeOnOpen(): Unit =
log.warning("My CircuitBreaker is now open, and will not close for one minute")
}
Circuit Breakers in Lagom
def descriptor: Descriptor = {
import Service._
named("hello").withCalls(
namedCall("hi", this.sayHi),
namedCall("hiAgain", this.hiAgain)
.withCircuitBreaker(CircuitBreaker.identifiedBy("hello2"))
)
}
Deep Learning
Python
Galápagos Nǎo
Diversity in Ecosystems
Evolution
def evolve(nets, generations) do
evolve(nets, generations, &decrement/1)
end
def evolve(nets, generations, count_function) when generations > 0 do
Task.Supervisor.async(GN.TaskSupervisor, fn ->
IO.puts("Generations remaining: #{generations}")
learn_generation(nets)
|> select()
|> evolve(count_function.(generations), count_function)
end)
end
def evolve(nets, _generations, _count_function) do
nets
end
Evolution
def learn_generation(nets) do
clean_nets = strip_empties(nets)
tasks =
Task.Supervisor.async_stream_nolink(
GN.TaskSupervisor,
clean_nets,
&start_and_spawn(&1),
timeout: GN.Parameters.get(__MODULE__, :timeout)
)
generation = for {status, net} <- tasks, status == :ok, do: net
IO.puts(inspect(generation))
generation
end
Evolution
def spawn_offspring(seed_layers, mutation_rate  @mutation_rate) do
duplicate(seed_layers, mutation_rate)
|> remove(mutation_rate)
|> Enum.map(&mutate(&1, mutation_rate))
end
Evolution
def select(pid  __MODULE__, nets) do
cutoffs = cutoffs(nets)
for net <- nets do
complexity = length(net.layers)
level = Enum.min(
[Enum.find_index(cutoffs, &(&1 >= complexity)) + 1,
complexity_levels()])
net_acc = net.test_acc
elite_acc = Map.get(get(level), :test_acc)
if is_nil(elite_acc) or net_acc > elite_acc do
put(pid, level, net)
end
end
Evolution
iex(1)> GN.Selection.get_all()
%{
1 => %GN.Network{
id: "0c2020ad-8944-4f2c-80bd-1d92c9d26535",
layers: [
dense: [64, :softrelu],
batch_norm: [],
activation: [:relu],
dropout: [0.5],
dense: [63, :relu]
],
test_acc: 0.8553
},
2 => %GN.Network{
id: "58229333-a05d-4371-8f23-e8e55c37a2ec",
layers: [
dense: [64, :relu],
Continual Learning
iex(2)> GN.Example.infinite_example()
%Task{
owner: #PID<0.171.0>,
pid: #PID<0.213.0>,
ref: #Reference<0.1968944036.911736833.180535>
}
Generations remaining: infinity
Interactive Evolution
Continual Learning
iex(2)> GN.Example.infinite_example()
%Task{
owner: #PID<0.171.0>,
pid: #PID<0.213.0>,
ref: #Reference<0.1968944036.911736833.180535>
}
Generations remaining: infinity
Interactive Evolution
iex(3)> GN.Selection.get_all() |> Map.get(2) |> GN.Library.put()
iex(4)> GN.Library.get("02b2a947-f888-4abf-b2a5-5df25668b0ee") |> GN.Selection.put_unevaluated()
Galápagos Nǎo Tech Stack
● Elixir
● Apache MXNet/Gluon
● Python
● Export/ErlPort
● Docker
● Microsoft Cognitive Toolkit*
● ONNX support*
* coming soon
Model Serialization Revisited
ONNX
● Open interchange format
● Focused on inference
● Broad and growing support
ONNX Format
message AttributeProto {
enum AttributeType {
UNDEFINED = 0;
FLOAT = 1;
INT = 2;
STRING = 3;
TENSOR = 4;
GRAPH = 5;
FLOATS = 6;
INTS = 7;
STRINGS = 8;
TENSORS = 9;
GRAPHS = 10;
}
ONNXS
iex(1)> {:ok, mnist_data} = File.read "./test/examples/mnist.onnx"
{:ok,
<<8, 3, 18, 4, 67, 78, 84, 75, 26, 3, 50, 46, 52, 40, 1, 58, 227, 206, 1, 10,
199, 80, 18, 12, 80, 97, 114, 97, 109, 101, 116, 101, 114, 49, 57, 51, 26,
12, 80, 97, 114, 97, 109, 101, 116, 101, 114, 49, ...>>}
ONNXS
iex(2)> mnist_struct = Onnx.ModelProto.decode(mnist_data)
%Onnx.ModelProto{
doc_string: nil,
domain: nil,
graph: %Onnx.GraphProto{
doc_string: nil,
initializer: [],
input: [
%Onnx.ValueInfoProto{
doc_string: nil,
name: "Input3",
type: %Onnx.TypeProto{
value: {:tensor_type,
%Onnx.TypeProto.Tensor{
elem_type: 1,
shape: %Onnx.TensorShapeProto
...
ONNXS
iex(3)> mnist_updated = %{mnist_struct | model_version: 2}
Thoughts
Model publishing and
serving are hard
problems.
Not all reactive
technologies look like
Erlang.
Reactive patterns are
useful across
toolchains.
Hard problems require
diverse sets of
solutions.
Open standards foster
rich ecosystems.
Wrapping Up
Reactive Machine Learning
Use the code
rmlsnymu
for 40% off the book!
Thanks
Questions
Tools for Making
Machine Learning
more Reactive
Jeff Smith
@jeffksmithjr
jeffsmith.tech

More Related Content

PDF
Frontin like-a-backer
PDF
Min-Maxing Software Costs - Laracon EU 2015
PDF
OpenERP Technical Memento V0.7.3
PDF
PofEAA and SQLAlchemy
PPTX
New in php 7
PDF
JavaScript and the AST
PDF
Presentation of the new OpenERP API. Raphael Collet, OpenERP
PDF
Class-based views with Django
Frontin like-a-backer
Min-Maxing Software Costs - Laracon EU 2015
OpenERP Technical Memento V0.7.3
PofEAA and SQLAlchemy
New in php 7
JavaScript and the AST
Presentation of the new OpenERP API. Raphael Collet, OpenERP
Class-based views with Django

What's hot (20)

PDF
My Top 5 APEX JavaScript API's
PDF
Re-Design with Elixir/OTP
PPTX
Building Progressive Web Apps for Windows devices
PPTX
Effective C++/WinRT for UWP and Win32
PPTX
Crafting beautiful software
PPTX
An ADF Special Report
ODP
An introduction to SQLAlchemy
PDF
Symfony World - Symfony components and design patterns
PPTX
Zero to SOLID
PDF
Introduction to Zend Framework web services
PDF
Workshop 8: Templating: Handlebars, DustJS
PPT
Performance improvements tips and tricks
PDF
ES2015 workflows
KEY
And the Greatest of These Is ... Rack Support
PPT
PDF
Alexey Tsoy Meta Programming in C++ 16.11.17
PPTX
Cfml features modern coding into the box 2018
PDF
How to Create a l10n Payroll Structure
PPTX
Why You Should Use TAPIs
PDF
Php unit the-mostunknownparts
My Top 5 APEX JavaScript API's
Re-Design with Elixir/OTP
Building Progressive Web Apps for Windows devices
Effective C++/WinRT for UWP and Win32
Crafting beautiful software
An ADF Special Report
An introduction to SQLAlchemy
Symfony World - Symfony components and design patterns
Zero to SOLID
Introduction to Zend Framework web services
Workshop 8: Templating: Handlebars, DustJS
Performance improvements tips and tricks
ES2015 workflows
And the Greatest of These Is ... Rack Support
Alexey Tsoy Meta Programming in C++ 16.11.17
Cfml features modern coding into the box 2018
How to Create a l10n Payroll Structure
Why You Should Use TAPIs
Php unit the-mostunknownparts
Ad

Similar to Tools for Making Machine Learning more Reactive (20)

PDF
Scala.io
PDF
Testing in the World of Functional Programming
KEY
Polyglot parallelism
PPTX
Exploring Twitter's Finagle technology stack for microservices
PDF
Async Microservices with Twitter's Finagle
PDF
RESTful API using scalaz (3)
PDF
From polling to real time: Scala, Akka, and Websockets from scratch
PDF
Reasonable RPC with Remotely
PPTX
Sharding and Load Balancing in Scala - Twitter's Finagle
PDF
Julio Capote, Twitter
PDF
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
PDF
Large volume data analysis on the Typesafe Reactive Platform - Big Data Scala...
PPTX
Automatic Scaling Iterative Computations
KEY
Building Distributed Systems in Scala
PDF
Finch + Finagle OAuth2
PPTX
PDF
Scala in Places API
PDF
Akka with Scala
PDF
PredictionIO – A Machine Learning Server in Scala – SF Scala
PDF
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Scala.io
Testing in the World of Functional Programming
Polyglot parallelism
Exploring Twitter's Finagle technology stack for microservices
Async Microservices with Twitter's Finagle
RESTful API using scalaz (3)
From polling to real time: Scala, Akka, and Websockets from scratch
Reasonable RPC with Remotely
Sharding and Load Balancing in Scala - Twitter's Finagle
Julio Capote, Twitter
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
Large volume data analysis on the Typesafe Reactive Platform - Big Data Scala...
Automatic Scaling Iterative Computations
Building Distributed Systems in Scala
Finch + Finagle OAuth2
Scala in Places API
Akka with Scala
PredictionIO – A Machine Learning Server in Scala – SF Scala
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Ad

More from Jeff Smith (16)

PPTX
Questioning Conversational AI
PPTX
Neuroevolution in Elixir
PDF
Building Learning Agents
PDF
Reactive for Machine Learning Teams
PDF
Reactive Machine Learning On and Beyond the JVM
PDF
Bringing Data Scientists and Engineers Together
PDF
Characterizing Intelligence with Elixir
PDF
Reactive Learning Agents
PDF
Spark for Reactive Machine Learning: Building Intelligent Agents at Scale
PDF
Introducing Reactive Machine Learning
PDF
Collecting Uncertain Data the Reactive Way
PDF
Reactive Machine Learning and Functional Programming
PDF
Huhdoop?: Uncertain Data Management on Non-Relational Database Systems
PDF
Breadth or Depth: What's in a column-store?
PDF
Save the server, Save the world
PDF
NoSQL in Perspective
Questioning Conversational AI
Neuroevolution in Elixir
Building Learning Agents
Reactive for Machine Learning Teams
Reactive Machine Learning On and Beyond the JVM
Bringing Data Scientists and Engineers Together
Characterizing Intelligence with Elixir
Reactive Learning Agents
Spark for Reactive Machine Learning: Building Intelligent Agents at Scale
Introducing Reactive Machine Learning
Collecting Uncertain Data the Reactive Way
Reactive Machine Learning and Functional Programming
Huhdoop?: Uncertain Data Management on Non-Relational Database Systems
Breadth or Depth: What's in a column-store?
Save the server, Save the world
NoSQL in Perspective

Recently uploaded (20)

PDF
Understanding Forklifts - TECH EHS Solution
PDF
System and Network Administraation Chapter 3
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
top salesforce developer skills in 2025.pdf
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPT
Introduction Database Management System for Course Database
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Understanding Forklifts - TECH EHS Solution
System and Network Administraation Chapter 3
PTS Company Brochure 2025 (1).pdf.......
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Wondershare Filmora 15 Crack With Activation Key [2025
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
top salesforce developer skills in 2025.pdf
Design an Analysis of Algorithms I-SECS-1021-03
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
2025 Textile ERP Trends: SAP, Odoo & Oracle
VVF-Customer-Presentation2025-Ver1.9.pptx
Introduction Database Management System for Course Database
Which alternative to Crystal Reports is best for small or large businesses.pdf
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
CHAPTER 2 - PM Management and IT Context
Design an Analysis of Algorithms II-SECS-1021-03
ManageIQ - Sprint 268 Review - Slide Deck
Lecture 3: Operating Systems Introduction to Computer Hardware Systems

Tools for Making Machine Learning more Reactive

  • 1. Tools for Making Machine Learning more Reactive Jeff Smith @jeffksmithjr jeffsmith.tech
  • 13. Akka ● Scala & Java ● Actor model ● Concurrency ● Distribution ● Supervision
  • 15. Model Microservice in Akka HTTP case class Prediction(id: Long, timestamp: Long, value: Double) trait Protocols extends DefaultJsonProtocol { implicit val predictionFormat = jsonFormat3(Prediction) }
  • 16. Model Microservice in Akka HTTP def model(features: Map[Char, Double]) = { val coefficients = ('a' to 'z').zip(1 to 26).toMap val predictionValue = features.map { case (identifier, value) => coefficients.getOrElse(identifier, 0) * value }.sum / features.size Prediction(Random.nextLong(), System.currentTimeMillis(), predictionValue) } def parseFeatures(features: String): Map[String, Double] = { features.parseJson.convertTo[Map[Char, Double]] } def predict(features: String): Prediction = { model(parseFeatures(features)) }
  • 17. Model Microservice in Akka HTTP trait Service extends Protocols { implicit val system: ActorSystem implicit def executor: ExecutionContextExecutor implicit val materializer: Materializer val logger: LoggingAdapter val routes = { logRequestResult("model-service") { pathPrefix("predict") { (get & path(Segment)) { features: String => complete { ToResponseMarshallable(predict(features))}}}}}}
  • 19. Random Forest in Spark MLlib
  • 20. MLlib Model Serialization { "class": "org.apache.spark.ml.PipelineModel", "timestamp": 1467653845388, "sparkVersion": "2.0.0-preview", "uid": "pipeline_6b4fb08e8fb0", "paramMap": { "stageUids": ["quantileDiscretizer_d3996173db25", "vecAssembler_2bdcd79fe1cf", "logreg_9d559ca7e208"] } }
  • 21. MLlib Model Serialization { "class": "org.apache.spark.ml.classification.LogisticRegressionModel", "timestamp": 1467653845650, "sparkVersion": "2.0.0-preview", "uid": "logreg_9d559ca7e208", "paramMap": { "threshold": 0.5, "elasticNetParam": 0.0, "fitIntercept": true, "tol": 1.0E-6, "regParam": 0.0, "maxIter": 5, "standardization": true, "featuresCol": "features", "rawPredictionCol": "rawPrediction", "predictionCol": "prediction", "probabilityCol": "probability", "labelCol": "label"}}
  • 24. Containerizing with sbt-docker dockerfile in docker := { val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value val classpath = (managedClasspath in Compile).value val mainClass = "com.reactivemachinelearning.PredictiveService" val jarTarget = s"/app/${jarFile.getName}" val classpathString = classpath.files.map("/app/" + _.getName) .mkString(":") + ":" + jarTarget new Dockerfile { from("java") add(classpath.files, "/app/") add(jarFile, jarTarget) entryPoint("java", "-cp", classpathString, mainClass) } }
  • 25. Containerizing with sbt-docker FROM java ADD 0/spark-core_2.11-2.0.0-preview.jar 1/avro-mapred-1.7.7-hadoop2.jar ... ADD 166/chapter-7_2.11-1.0.jar /app/chapter-7_2.11-1.0.jar ENTRYPOINT ["java", "-cp", "/app/spark-core_2.11-2.0.0-preview.jar ... "com.reactivemachinelearning.PredictiveService"]
  • 28. Model Server in http4s object Models { val modelA = HttpService { case GET -> Root / "a" / inputData => val response = true Ok(s"Model A predicted $response.") } val modelB = HttpService { case GET -> Root / "b" / inputData => val response = false Ok(s"Model B predicted $response.") } }
  • 29. Model Server in http4s object Client { val client = PooledHttp1Client() private def call(model: String, input: String) = { val target = Uri.fromString(s"http://localhost:8080/models/$model/$input").toOption.get client.expect[String](target) } def callA(input: String) = call("a", input) def callB(input: String) = call("b", input) }
  • 30. Model Server in http4s def splitTraffic(data: String) = { data.hashCode % 10 match { case x if x < 4 => Client.callA(data) case _ => Client.callB(data) } }
  • 31. Model Server in http4s object ModelServer extends ServerApp { val apiService = HttpService { case GET -> Root / "predict" / inputData => val response = splitTraffic(inputData).run Ok(response) } override def server(args: List[String]): Task[Server] = { BlazeBuilder .bindLocal(8080) .mountService(apiService, "/api") .mountService(Models.modelA, "/models") .mountService(Models.modelB, "/models") .start } }
  • 32. Model Server in http4s import scala.util.Random val modelC = HttpService { case GET -> Root / "c" / inputData => { val workingOk = Random.nextBoolean() val response = true if (workingOk) { Ok(s"Model C predicted $response.") } else { BadRequest("Model C failed to predict.") } } }
  • 33. Model Server in http4s private def call(model: String, input: String): Task[Response] = { val target = Uri.fromString( s"http://localhost:8080/models/$model/$input" ).toOption.get client(target) } def callC(input: String) = call("c", input)
  • 34. Model Server in http4s def splitTraffic(data: String) = { data.hashCode % 10 match { case x if x < 4 => Client.callA(data) case x if x < 6 => Client.callB(data) case _ => Client.callC(data) } } val apiService = HttpService { case GET -> Root / "predict" / inputData => val response = splitTraffic(inputData).run response match { case r: Response if r.status == Ok => Response(Ok).withBody(r.bodyAsText) case r => Response(BadRequest).withBody(r.bodyAsText) } }
  • 35. Model Server in http4s def splitTraffic(data: String) = { data.hashCode % 10 match { case x if x < 4 => Client.callA(data) case x if x < 6 => Client.callB(data) case _ => Client.callC(data) } } val apiService = HttpService { case GET -> Root / "predict" / inputData => val response = splitTraffic(inputData).run response match { case r: Response if r.status == Ok => Response(Ok).withBody(r.bodyAsText) case r => Response(BadRequest).withBody(r.bodyAsText) } }
  • 36. Model Server in http4s private def call(model: String, input: String) = { val target = Uri.fromString(s"http://localhost:8080/models/$model/$input").toOption.get client(target).retry(Seq(1 second), {_ => true}) }
  • 37. BEAM
  • 41. Circuit Breakers in Erlang/Elixir def update(user_data) do {user_id, _} = user_data case verify_fuse(user_id) do :ok -> write_to_db(user_data) |> parse_db_response(user_id) :sorry -> IO.puts "This user can't be updated now. ¯_(ツ)_/¯" :sorry end end
  • 42. Circuit Breakers in Erlang/Elixir defp verify_fuse(user_id) do case :fuse.ask(user_id, :sync) do {:error, :not_found} -> IO.puts "Installing" install_fuse(user_id) :ok :blown -> :sorry _ -> :ok end end
  • 43. Circuit Breakers in Erlang/Elixir defp install_fuse(user_id) do :fuse.install(user_id, {{:standard, 3, 60000}, {:reset, 900000}}) end
  • 44. Circuit Breakers in Erlang/Elixir defp write_to_db({_user_id, _data}) do Enum.random([{:ok, ""}, {:error, "The DB dropped the ball. ಠ_ಠ"}]) end
  • 45. Circuit Breakers in Erlang/Elixir defp parse_db_response({:ok, _}, _user_id) do :ok end defp parse_db_response({:error, message}, user_id) do :fuse.melt(user_id) IO.puts "Error encountered: #{message}.nMelting the fuse!" :sorry end
  • 46. Circuit Breakers in Erlang/Elixir def update(user_data) do {user_id, _} = user_data case verify_fuse(user_id) do :ok -> write_to_db(user_data) |> parse_db_response(user_id) :sorry -> IO.puts "This user can't be updated now. ¯_(ツ)_/¯" :sorry end end
  • 47. Circuit Breakers in Akka class DangerousActor extends Actor with ActorLogging { import context.dispatcher val breaker = new CircuitBreaker( context.system.scheduler, maxFailures = 5, callTimeout = 10.seconds, resetTimeout = 1.minute).onOpen(notifyMeOnOpen()) def notifyMeOnOpen(): Unit = log.warning("My CircuitBreaker is now open, and will not close for one minute") }
  • 48. Circuit Breakers in Lagom def descriptor: Descriptor = { import Service._ named("hello").withCalls( namedCall("hi", this.sayHi), namedCall("hiAgain", this.hiAgain) .withCircuitBreaker(CircuitBreaker.identifiedBy("hello2")) ) }
  • 53. Evolution def evolve(nets, generations) do evolve(nets, generations, &decrement/1) end def evolve(nets, generations, count_function) when generations > 0 do Task.Supervisor.async(GN.TaskSupervisor, fn -> IO.puts("Generations remaining: #{generations}") learn_generation(nets) |> select() |> evolve(count_function.(generations), count_function) end) end def evolve(nets, _generations, _count_function) do nets end
  • 54. Evolution def learn_generation(nets) do clean_nets = strip_empties(nets) tasks = Task.Supervisor.async_stream_nolink( GN.TaskSupervisor, clean_nets, &start_and_spawn(&1), timeout: GN.Parameters.get(__MODULE__, :timeout) ) generation = for {status, net} <- tasks, status == :ok, do: net IO.puts(inspect(generation)) generation end
  • 55. Evolution def spawn_offspring(seed_layers, mutation_rate @mutation_rate) do duplicate(seed_layers, mutation_rate) |> remove(mutation_rate) |> Enum.map(&mutate(&1, mutation_rate)) end
  • 56. Evolution def select(pid __MODULE__, nets) do cutoffs = cutoffs(nets) for net <- nets do complexity = length(net.layers) level = Enum.min( [Enum.find_index(cutoffs, &(&1 >= complexity)) + 1, complexity_levels()]) net_acc = net.test_acc elite_acc = Map.get(get(level), :test_acc) if is_nil(elite_acc) or net_acc > elite_acc do put(pid, level, net) end end
  • 57. Evolution iex(1)> GN.Selection.get_all() %{ 1 => %GN.Network{ id: "0c2020ad-8944-4f2c-80bd-1d92c9d26535", layers: [ dense: [64, :softrelu], batch_norm: [], activation: [:relu], dropout: [0.5], dense: [63, :relu] ], test_acc: 0.8553 }, 2 => %GN.Network{ id: "58229333-a05d-4371-8f23-e8e55c37a2ec", layers: [ dense: [64, :relu],
  • 58. Continual Learning iex(2)> GN.Example.infinite_example() %Task{ owner: #PID<0.171.0>, pid: #PID<0.213.0>, ref: #Reference<0.1968944036.911736833.180535> } Generations remaining: infinity
  • 60. Continual Learning iex(2)> GN.Example.infinite_example() %Task{ owner: #PID<0.171.0>, pid: #PID<0.213.0>, ref: #Reference<0.1968944036.911736833.180535> } Generations remaining: infinity
  • 61. Interactive Evolution iex(3)> GN.Selection.get_all() |> Map.get(2) |> GN.Library.put() iex(4)> GN.Library.get("02b2a947-f888-4abf-b2a5-5df25668b0ee") |> GN.Selection.put_unevaluated()
  • 62. Galápagos Nǎo Tech Stack ● Elixir ● Apache MXNet/Gluon ● Python ● Export/ErlPort ● Docker ● Microsoft Cognitive Toolkit* ● ONNX support* * coming soon
  • 64. ONNX ● Open interchange format ● Focused on inference ● Broad and growing support
  • 65. ONNX Format message AttributeProto { enum AttributeType { UNDEFINED = 0; FLOAT = 1; INT = 2; STRING = 3; TENSOR = 4; GRAPH = 5; FLOATS = 6; INTS = 7; STRINGS = 8; TENSORS = 9; GRAPHS = 10; }
  • 66. ONNXS iex(1)> {:ok, mnist_data} = File.read "./test/examples/mnist.onnx" {:ok, <<8, 3, 18, 4, 67, 78, 84, 75, 26, 3, 50, 46, 52, 40, 1, 58, 227, 206, 1, 10, 199, 80, 18, 12, 80, 97, 114, 97, 109, 101, 116, 101, 114, 49, 57, 51, 26, 12, 80, 97, 114, 97, 109, 101, 116, 101, 114, 49, ...>>}
  • 67. ONNXS iex(2)> mnist_struct = Onnx.ModelProto.decode(mnist_data) %Onnx.ModelProto{ doc_string: nil, domain: nil, graph: %Onnx.GraphProto{ doc_string: nil, initializer: [], input: [ %Onnx.ValueInfoProto{ doc_string: nil, name: "Input3", type: %Onnx.TypeProto{ value: {:tensor_type, %Onnx.TypeProto.Tensor{ elem_type: 1, shape: %Onnx.TensorShapeProto ...
  • 68. ONNXS iex(3)> mnist_updated = %{mnist_struct | model_version: 2}
  • 70. Model publishing and serving are hard problems.
  • 71. Not all reactive technologies look like Erlang.
  • 72. Reactive patterns are useful across toolchains.
  • 73. Hard problems require diverse sets of solutions.
  • 76. Reactive Machine Learning Use the code rmlsnymu for 40% off the book!
  • 79. Tools for Making Machine Learning more Reactive Jeff Smith @jeffksmithjr jeffsmith.tech