ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

Swift-Jupyter をつかってみました

はじめに

こんにちは、iOSエンジニアのしだです。UniFa Advent Calendarで、普段の開発であまり関わりの少ないメンバーの記事を見てにやにやしてます 😏

こちらは、UniFa Advent Calendar 2019 の12日目の記事になります。

もう2019年が終わりますが、今年は、TensorFlow Dev Sumit 2019があったり、TensorFlow 2.0になったり、O'Reilly主催のTF World '19があったりTensorFlowのアップデートが多かった気がします。 その中で、以下の Swift for TensorFlow (TF World '19) の動画を見ていたところ、何やら Jupyter notebook に Swift を書いていてなんじゃこりゃと思って調べてみたらSwift-Jupyterというものを知ったので使ってみます。

Swift-Jupyter

swift-jupyter はそのまま jupyter の Swift 用のカーネルを提供しています。 これを使うと notebook にswiftが書けます。すごいです。

github.com

準備

最初に swift-jupyter をインストールします。 README.md には、いくつかインストール方法がありますが docker 経由でやります。

$ git clone https://github.com/google/swift-jupyter.git
$ cd swift-jupyter

// requirements に Pillow だけ追加しておきます
$ echo "Pillow" >> docker/requirements_py_graphics.txt
$ docker build -f docker/Dockerfile -t swift-jupyter .

起動方法

コンテナを立ち上げると Jupyter が立ち上がるようになっています。swift-jupyter を起動してといつもの localhost:8888 を開けば Jupyter が使えます。あとは好きなようにPythonではなく、Swiftを書いていきます。

// swift-jupyter を起動する
$ docker run -it -p 8888:8888 --cap-add SYS_PTRACE -v /path/to:/notebooks swift-jupyter

// もし GPUを使う場合は、 `--gpus` オプションを付けます
$ $ docker run -it -p 8888:8888 --gpus all --cap-add SYS_PTRACE -v /home/ubuntu:/notebooks swift-jupyter

Python (Numpy, PIL)

Swift for TensorFlowでは、Pythonを使うこともできます。Swift上ではPythonのオブジェクトはすべて PythonObject というオブジェクトになるので、Swift for TensorFlow の Tensor や Arrayへの相互に変換する必要があります。

Numpy in Swift for TensorFlow

numpy と Tensorの変換するときは、型に気をつける必要があります。変換できない場合は nil が返ってきます。

また、Pillow をインストールしておけば、numpy と同じように使えます。 試しに画像ファイルを読み込んで、notebook上に画像を表示します。

Load image in Swift for TensorFlow

Differentiable

Swift for TensorFlow では、 @differentiable という Attributes を付けると微分可能な関数を定義することができます。そして @differentiable を付けると gradient(at:)valueWithGradient(at:) という関数を呼ぶことができ勾配を計算できるようになります。以下は sigmoid の微分の例になります。

Differentiable in Swift for TensorFlow

Custom differentiable

こちらは動画の中にもあった例なのですが、 独自に微分可能な関数を定義することができます。
次の例ですと Glibc の pow関数は @differentiable に対応した関数ではないのですが、@derivative(of:) を付けることで @differentiable に対応することができます。 また、pow関数の x^{a}a^{x} のそれぞれ x に対する微分を自分で記述してあげます。

Custom differentiable in Swift for TensorFlow

念の為、TensorFlow 2.0 (Python) でやった結果と同じになっているので合っていると思います。

// これは Python です。
import tensorflow as tf
a = tf.constant(0.5)
b = tf.constant(3.0)
with tf.GradientTape() as tape:
  tape.watch((a, b))
  y = a ** b
dy_dx = tape.gradient(y, (a, b))
dy_dx[0].numpy(), dy_dx[1].numpy() # ==> (0.75, -0.0866434)

さいごに

Swift for TensorFlow の学習がてら swift-jupyter を使ってみました。 Pythonは、PythonObjectの変換があるので扱いずらいですが、案外使えるかもしれません。iOSやってた身としてはかなり面白いなぁと感じてます。
本当は、Head Pose Estimation(頭部姿勢推定)を Swift for TensorFlowでやるつもりでしたが機会があったら書きます😂

参考