Docker – DECODE https://decode.red/blog data decode, decoder or decoded ... design of code Mon, 15 Dec 2025 06:15:00 +0000 ja hourly 1 https://wordpress.org/?v=4.7.29 WebAssembly Runtime ../../../202307231666/ Sun, 23 Jul 2023 06:48:46 +0000 ../../../?p=1666 wasm(WebAssembly)のランタイムについて、いろいろ調べてみました。
WebAssemblyは何度も扱ってきていますが、WATコード(WebAssembly Text)からコンパイルを試したことがありませんでした。まずは基本を押さえたいと思います。(参考:翔泳社「入門WebAssembly」)

環境) M2 Mac

myadd.wat

(module
	(func (export "myadd")
		(param $value.1 i32) (param $value.2 i32)
		(result i32)
		local.get $value.1
		local.get $value.2
		i32.add
	)
)

value 1,2をスタックに積んで、関数呼び出し。まさにアセンブラですね。

myadd.js

const fs = require('fs');

const bytes = fs.readFileSync(__dirname + '/myadd.wasm');
const v1 = parseInt(process.argv[2]);
const v2 = parseInt(process.argv[3]);

(async () => {
	const obj = await WebAssembly.instantiate(new Uint8Array(bytes));
	let ret = obj.instance.exports.myadd(v1, v2);
	console.log("%d + %d = %d", v1, v2, ret);
})();

% node -v
v18.12.1
% npm -v
8.19.2
% npm install -g wat-wasm

% wat2wasm myadd.wat

  Contact Rick Battagline
  Twitter: @battagline
  https://wasmbook.com
  v1.0.43

no memory
Writing to myadd.wasm
WASM File Saved!

% node myadd.js 1 2
1 + 2 = 3

wat2wasmで、バイトコードに、そしてそれをnode.jsから呼び出しました。

次は、node.jsではなく、wasmtimeというランタイムを使って実行してみます。(brew でインストール)

引用元)https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-tutorial.md

demo.wat

(module
    ;; Import the required fd_write WASI function which will write the given io vectors to stdout
    ;; The function signature for fd_write is:
    ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written
    (import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

    (memory 1)
    (export "memory" (memory 0))

    ;; Write 'hello world\n' to memory at an offset of 8 bytes
    ;; Note the trailing newline which is required for the text to appear
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Creating a new io vector within linear memory
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - This is a pointer to the start of the 'hello world\n' string
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - The length of the 'hello world\n' string

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 for stdout
            (i32.const 0) ;; *iovs - The pointer to the iov array, which is stored at memory location 0
            (i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one.
            (i32.const 20) ;; nwritten - A place in memory to store the number of bytes written
        )
        drop ;; Discard the number of bytes written from the top of the stack
    )
)

% wasmtime -V
wasmtime-cli 10.0.1
% wasmtime demo.wat
hello world
% wat2wasm demo.wat

  Contact Rick Battagline
  Twitter: @battagline
  https://wasmbook.com
  v1.0.43

memory found
Writing to demo.wasm
WASM File Saved!
% wasmtime demo.wasm
hello world

先ほどのWATコードでは、実行はできますが標準出力に書かないためコードを変えています。
(watから直接実行もできるもよう)

ファイル確認

% file demo.wasm
demo.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)
% file myadd.wasm
myadd.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

次は、Rustのコードからコンパイルするため、環境をdockerで構築しました。
引用元) https://qiita.com/toshikisugiyama/items/168cdbf834156b1f1e70

docker-compose.yml

services:
  rust:
    image: rust:latest
    volumes:
      - .:/projects
    working_dir: /projects
    environment:
      - USER=user

% docker compose run –rm rust

このコマンドで一気に環境を作り、コンテナのシェルの状態になります。

root@f4b90a7fb5a9:/projects# cargo new hello_cargo
  Created binary (application) hello_cargo package

root@f4b90a7fb5a9:/projects# ls
docker-compose.yml hello_cargo

root@f4b90a7fb5a9:/projects# cd hello_cargo/
root@f4b90a7fb5a9:/projects/hello_cargo# ls
Cargo.toml src

root@f4b90a7fb5a9:/projects/hello_cargo# cargo run
  Compiling hello_cargo v0.1.0 (/projects/hello_cargo)
  Finished dev [unoptimized + debuginfo] target(s) in 1.07s
  Running target/debug/hello_cargo
Hello, world!

デフオルトプロジェクトの状態で実行できることを確認できました。(これはwasmではない)

hello_cargo/src/main.rs

fn main() {
    println!("Hello, world!");
}

カレントフォルダとコンテナの/projectsが、マウントされているため、ファイルの編集は別コンソールで、できます。(コマンド実行だけコンテナからやればよいことにことに)

そして、この環境を使って、wasmtimeの例を動かしてみます。
引用元) https://wasmtime.dev/

root@f4b90a7fb5a9:/projects# rustup target add wasm32-wasi
info: downloading component ‘rust-std’ for ‘wasm32-wasi’
info: installing component ‘rust-std’ for ‘wasm32-wasi’
root@f4b90a7fb5a9:/projects# rustc hello.rs –target wasm32-wasi
root@f4b90a7fb5a9:/projects# wasmtime hello.wasm
bash: wasmtime: command not found

コンテナにはwasmtimeを入れていないので、カレントに戻り、

% wasmtime hello.wasm
Hello, world!

(hello.rsは、上記 hello_cargo/src/main.rs と全く同じ)
Rustコードをwasmにコンパイルして実行できることを確認しました。

そして次は、wasmをコンテナにして実行してみます。
引用元) https://developer.mamezou-tech.com/blogs/2023/01/25/using-wasm-on-docker/

% docker run -dp 8080:8080 –name=wasm-example –runtime=io.containerd.wasmedge.v1 –platform=wasi/wasm32 michaelirwin244/wasm-example
Unable to find image ‘michaelirwin244/wasm-example:latest’ locally
latest: Pulling from michaelirwin244/wasm-example
docker: operating system is not supported.
See ‘docker run –help’.

Use containerd for pulling and storing images -> on にします。

% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
029a5376af41 michaelirwin244/wasm-example “/hello_world.wasm” 14 seconds ago Up 9 seconds 0.0.0.0:8080->8080/tcp wasm-example
% docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
michaelirwin244/wasm-example latest 1b0714a5af55 37 seconds ago 4.14MB

% curl localhost:8080
Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to you%
% curl -X POST -d abcdefg localhost:8080
% curl -X POST -d abcdefg localhost:8080/echo
abcdefg%

うまく立ち上がり動作も確認できました。(POST /echo の場合はBodyをEcho)

でもこれではwasmかどうかわかりませんので、サーバの部分を単体で動かしてみます。
(引用元の情報を参考にダウンロード)

% git clone https://github.com/mikesir87/wasm-example.git

% cd wasm-example

コンテナでコマンド実行

root@bea36f5878ef:/projects/wasm-example# rustup target add wasm32-wasi
info: downloading component ‘rust-std’ for ‘wasm32-wasi’
info: installing component ‘rust-std’ for ‘wasm32-wasi’
root@bea36f5878ef:/projects/wasm-example# cargo build –target wasm32-wasi –release

カレントに戻りwasmtime実行

% wasmtime run –tcplisten 127.0.0.1:8080 target/wasm32-wasi/release/hello_world.wasm
Error: failed to run main module target/wasm32-wasi/release/hello_world.wasm

Caused by:
  0: failed to instantiate “target/wasm32-wasi/release/hello_world.wasm”
  1: unknown import: wasi_snapshot_preview1::sock_setsockopt has not been defined

うまく行かず。。。
Runtimeをwasmedgeに差し替えてチャレンジ。

% curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
Using Python: /Users/z/.pyenv/versions/miniforge3-4.10.3-10/bin/python3
INFO – Compatible with current configuration
INFO – Running Uninstaller
WARNING – Uninstaller did not find previous installation
WARNING – SHELL variable not found. Using zsh as SHELL
INFO – shell configuration updated
INFO – Downloading WasmEdge
|============================================================|100.00 %INFO – Downloaded
INFO – Installing WasmEdge
INFO – WasmEdge Successfully installed
INFO – Run:
source /Users/z/.zshenv

% wasmedge target/wasm32-wasi/release/hello_world.wasm
Server is now running

これで、さほどのPOST /echo のcurlアクセスもうまくいきました。(dockerのwasm runtimeはwasmtimeと違うようです)

wasm-example/src/main.rs

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, StatusCode, Server};
use std::convert::Infallible;
use std::net::SocketAddr;
use std::result::Result;

async fn handle_request(req: Request<Body>) -> Result<Response<Body>, anyhow::Error> {
    match (req.method(), req.uri().path()) {
        (&Method::GET, "/") => Ok(Response::new(Body::from(
            "Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to you",
        ))),

        // Simply echo the body back to the client.
        (&Method::POST, "/echo") => Ok(Response::new(req.into_body())),

        // Return the 404 Not Found for other routes.
        _ => {
            let mut not_found = Response::default();
            *not_found.status_mut() = StatusCode::NOT_FOUND;
            Ok(not_found)
        }
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
    let make_svc = make_service_fn(|_| {
        async move {
            Ok::<_, Infallible>(service_fn(move |req| {
                handle_request(req)
            }))
        }
    });
    let server = Server::bind(&addr).serve(make_svc);
    println!("Server is now running");
    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }
    Ok(())
}

ここまでwasmの動かし方について、いろいろ試してみました。前回Goを試しましたがいろいろ調べてみるとRustが非常に向いていると感じました。(まだ関数コールをやる必要がありますが、これは次の機会に・・)
下記サイトに、Goとwasmの関係について、とても参考になる記事があります。

「GoのWASMがライブラリではなくアプリケーションであること」
https://www.kabuku.co.jp/developers/annoying-go-wasm

RustはOSすらないベアメタル環境でもプログラムを動作させることができます。様々なところで実行できるwasmだけに、こういった成り立ちの違いが大きく影響するのではと感じました。

]]>
TensorFlow ../../../20160710594/ Sun, 10 Jul 2016 04:48:31 +0000 ../../../?p=594 GoogleのDeepLearningをはじめとする機会学習のライブラリがちょっと前に公開されました。まだわからないことばかりですが、少し使ったメモをしておきます。
まずインストールですが、Windowsマシンで使いたかったので、Dockerとともに使うことにしました。

環境: DockerToolbox-1.11.2.exe / Windows 10

WindowsのDockerでうまくいかなかった点は、以下を参考にしました。
https://caffinc.github.io/2015/11/tensorflow-windows/

コンテナを起動するとき、Image IDを指定します。

docker pull b.gcr.io/tensorflow/tensorflow
docker images
winpty docker run -it -p 8888:8888 [id]

今回、インタラクティブにコードを実行する環境のJupyter Nodebookをはじめて使いましたが(これまではiPython)、Dockerと合わせて使ってみて、これらとても便利です。

コンテナを立ち上げ、ブラウザでアクセスします。

192.168.99.100:8888/tree

Homeにある2_getting_started.ipynbをもとに編集しました。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

# Set up the data with a noisy linear relationship between X and Y.
num_examples = 50
X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])

X += np.random.randn(2, num_examples)
x, y = X
x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)

plt.figure(figsize=(4,4))
plt.scatter(X[0], X[1])
plt.show()

# Keep track of the loss at each iteration so we can chart it later
losses = []
# How many iterations to run our training
training_steps = 50
# The learning rate. Also known has the step size. This changes how far
# we move down the gradient toward lower error at each step. Too large
# jumps risk inaccuracy, too small slow the learning.

with tf.Session() as sess:
  # Set up all the tensors, variables, and operations.
  input = tf.constant(x_with_bias)
  target = tf.constant(np.transpose([y]).astype(np.float32))
  weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))

  tf.initialize_all_variables().run()
                      
  yhat = tf.matmul(input, weights)
  yerror = tf.sub(yhat, target)
  loss = tf.reduce_mean(tf.nn.l2_loss(yerror))  

  update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
  
  for _ in range(training_steps):
    # Repeatedly run the operations, updating the TensorFlow variable.
    update_weights.run()   
    #sess.run(update_weights)
    
    #losses.append(loss.eval())
    losses.append(sess.run(loss))

  # Training is done, get the final values for the graphs
  #betas = weights.eval()
  betas = sess.run(weights)
  #yhat = yhat.eval()
  yhat = sess.run(yhat)
    
# Show the fit and the loss over time.
fig, (ax1, ax2) = plt.subplots(1, 2)
plt.subplots_adjust(wspace=.3)
fig.set_size_inches(10, 4)
ax1.scatter(x, y, alpha=.7)
ax1.scatter(x, np.transpose(yhat)[0], c="g", alpha=.6)
line_x_range = (-4, 6)
ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], "g", alpha=0.6)

ax2.plot(range(0, training_steps), losses)
ax2.set_ylabel("Loss")
ax2.set_xlabel("Training steps")
plt.show()

losses = []
training_steps = 10
learning_rate = 0.002

with tf.Session() as sess:
  input = tf.constant(x_with_bias)
  target = tf.constant(np.transpose([y]).astype(np.float32))
  weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))

  tf.initialize_all_variables().run()
                      
  yhat = tf.matmul(input, weights)
  yerror = tf.sub(yhat, target)
  loss = tf.reduce_mean(tf.nn.l2_loss(yerror))  

  update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
  
  for _ in range(training_steps):
    update_weights.run()   
    
    losses.append(sess.run(loss))

  betas = sess.run(weights)
  yhat = sess.run(yhat)
    
fig, (ax3, ax4) = plt.subplots(1, 2)
plt.subplots_adjust(wspace=.3)
fig.set_size_inches(10, 4)
ax3.scatter(x, y, alpha=.7)
ax3.scatter(x, np.transpose(yhat)[0], c="g", alpha=.6)
line_x_range = (-4, 6)
ax3.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], "g", alpha=0.6)

ax4.plot(range(0, training_steps), losses)
ax4.set_ylabel("Loss")
ax4.set_xlabel("Training steps")
plt.show()

同じ初期値を使って違うパラメータでテストをしたかったので、あまりいいやり方ではないのですが、処理を2回記述しています。また同じ意味になるようなので、わかりやすくするためsessを使った書き方にしてみました。

tensor01

実行結果
tensor02

直線を元にした50個の点データのx座標を乱数でちらしたデータのx,yの関係を学習して、最終的に緑色の点を計算して描画するものです。
パラメータによる傾きの違いを確認しました。

この環境いいかも・・

とりあえずここまでメモでした。

]]>