29
loading...
This website collects cookies to deliver better user experience
YoMo is written in the Go language. For streaming Serverless, Golang plugins and shared libraries are used to load users’ code dynamically, which also have certain limitations for developers. Coupled with Serverless architecture's rigid demand for isolation, this makes WebAssembly an excellent choice for running user-defined functions.
Golang version should be newer than 1.15 for our example to work.
$ go install github.com/yomorun/cli/yomo@latest
$ yomo version
YoMo CLI version: v0.0.5
# Install WasmEdge
$ wget https://github.com/second-state/WasmEdge-go/releases/download/v0.8.1/install_wasmedge.sh
$ chmod +x ./install_wasmedge.sh
$ sudo ./install_wasmedge.sh /usr/local
# Install WasmEdge Tensorflow extension
$ wget https://github.com/second-state/WasmEdge-go/releases/download/v0.8.1/install_wasmedge_tensorflow_deps.sh
$ wget https://github.com/second-state/WasmEdge-go/releases/download/v0.8.1/install_wasmedge_tensorflow.sh
$ chmod +x ./install_wasmedge_tensorflow_deps.sh
$ chmod +x ./install_wasmedge_tensorflow.sh
$ sudo ./install_wasmedge_tensorflow_deps.sh /usr/local
$ sudo ./install_wasmedge_tensorflow.sh /usr/local
# Install WasmEdge Images extension
$ wget https://github.com/second-state/WasmEdge-go/releases/download/v0.8.1/install_wasmedge_image_deps.sh
$ wget https://github.com/second-state/WasmEdge-go/releases/download/v0.8.1/install_wasmedge_image.sh
$ chmod +x ./install_wasmedge_image_deps.sh
$ chmod +x ./install_wasmedge_image.sh
$ sudo ./install_wasmedge_image_deps.sh /usr/local
$ sudo ./install_wasmedge_image.sh /usr/local
$ git clone https://github.com/yomorun/yomo-wasmedge-tensorflow.git
#[wasm_bindgen]
pub fn infer(image_data: &[u8]) -> String {
// Load the TFLite model and its meta data (the text label for each recognized object number)
let model_data: &[u8] = include_bytes!("lite-model_aiy_vision_classifier_food_V1_1.tflite");
let labels = include_str!("aiy_food_V1_labelmap.txt");
// Pre-process the image to a format that can be used by this model
let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(image_data, 192, 192);
// Run the TFLite model using the WasmEdge Tensorflow API
let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite);
session.add_input("input", &flat_img, &[1, 192, 192, 3])
.run();
let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Softmax");
// Find the object index in res_vec that has the greatest probability
// Translate the probability into a confidence level
// Translate the object index into a label from the model meta data food_name
ret_str = format!(
"It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture",
confidence, food_name, food_name
);
return ret_str;
}
At this time, we require Rust compiler version 1.50 or less in order for WebAssembly functions to work with WasmEdge’s Golang API. We will catch up to the latest Rust compiler version once the Interface Types spec is finalized and supported.
$ rustup default 1.50.0
$ cd flow/rust_mobilenet_food
$ rustwasmc build `--enable-ext`
# The output WASM will be pkg/rust_mobilenet_food_lib_bg.wasm.
# Copy the wasm bytecode file to the flow/ directory
$ cp pkg/rust_mobilenet_food_lib_bg.wasm ../
package main
... ...
var (
vm *wasmedge.VM
vmConf *wasmedge.Configure
counter uint64
)
func main() {
// Initialize WasmEdge's VM
initVM()
defer vm.Delete()
defer vmConf.Delete()
// Connect to Zipper service
cli, err := client.NewServerless("image-recognition").Connect("localhost", 9000)
if err != nil {
log.Print("❌ Connect to zipper failure: ", err)
return
}
defer cli.Close()
cli.Pipe(Handler)
}
// Handler process the data in the stream
func Handler(rxStream rx.RxStream) rx.RxStream {
stream := rxStream.
Subscribe(ImageDataKey).
OnObserve(decode).
Encode(0x11)
return stream
}
// decode Decode and perform image recognition
var decode = func(v []byte) (interface{}, error) {
// get image binary
p, _, _, err := y3.DecodePrimitivePacket(v)
if err != nil {
return nil, err
}
img := p.ToBytes()
// recognize the image
res, err := vm.ExecuteBindgen("infer", wasmedge.Bindgen_return_array, img)
return hash, nil
}
... ...
// initVM initialize WasmEdge's VM
func initVM() {
wasmedge.SetLogErrorLevel()
vmConf = wasmedge.NewConfigure(wasmedge.WASI)
vm = wasmedge.NewVMWithConfig(vmConf)
var wasi = vm.GetImportObject(wasmedge.WASI)
wasi.InitWasi(
os.Args[1:], /// The args
os.Environ(), /// The envs
[]string{".:."}, /// The mapping directories
[]string{}, /// The preopens will be empty
)
/// Register WasmEdge-tensorflow and WasmEdge-image
var tfobj = wasmedge.NewTensorflowImportObject()
var tfliteobj = wasmedge.NewTensorflowLiteImportObject()
vm.RegisterImport(tfobj)
vm.RegisterImport(tfliteobj)
var imgobj = wasmedge.NewImageImportObject()
vm.RegisterImport(imgobj)
/// Instantiate wasm
vm.LoadWasmFile("rust_mobilenet_food_lib_bg.wasm")
vm.Validate()
vm.Instantiate()
}
$ yomo serve -c ./zipper/workflow.yaml
$ cd flow
$ go run --tags "tensorflow image" app.go
# Download a video file
$ wget -P source 'https://github.com/yomorun/yomo-wasmedge-tensorflow/releases/download/v0.1.0/hot-dog.mp4'
# Stream the video to YoMo
$ go run ./source/main.go ./source/hot-dog.mp4
29