Swift for TensorFlow の randomUniform を読む
モチベーション
以下の Swift for TensorFlow のスレッドで Chris が発言した
https://groups.google.com/a/tensorflow.org/forum/#!topic/swift/IQcQIOslt-I
Take a look at Tensor.swift in the TensorFlow module. We implemented this with the standard swift generics system, no special support necessary.
をみて少し気になった
また前回書いたswift-models の MNIST.swift を読むでも登場したrandomUniform
に関して、どういった実装をしているのか気になり読んでみた
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L61-L62
読んでいくうちに結構面白いと自分でも思えたので過程をブログにすることにした
randomUniform とは
エントリポイントとなるのは以下の initializer
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Tensor.swift#L533-L546
与えられた TensorShape
の要素を全て0-1の正規分布の範囲内の値で埋め尽くすというもの
まずここで気づくのが、単純に Swift for TensorFlow が TensorFlow と Swift のブリッジング/マッパーではないということで、結構な部分(特に型まわり)が pure Swift で実装されている
また読み進める中でいくつかの _
付きの @
attributes がある
@_fixed_layout
@_versioned
@_inlineable @inline(__always)
しっかり調べられていないので後で調べてまた別でブログにしたい
https://bugs.swift.org/browse/SR-260 https://stackoverflow.com/questions/46524232/access-control-in-swift-4 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171002/040061.html
ここからスタート、基本的に見たことのないユニットは一つずつあげていく
TensorShape
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/TensorShape.swift
配列の薄いラッパーで、次元を表現するときに使う
ExpressibleByArrayLiteral
に対応しているので利用する側は配列と思って使っていても問題ない
RandomState
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Utilities.swift#L148
擬似乱数を表現するクラス、全体的にデフォルトだと RandomState.global
を使用しているところが多い
Tensor.init(randomUniform shape: TensorShape, state: RandomState? = nil)
ここでようやく元の initializer に戻れる
この initializer の実態は以下の initializer のラッパーであることがわかる
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Tensor.swift#L543-L545
ラップされた以下の initializer を RAND_MAX で割っていることから、以下の initializer は整数値の range での正規分布を元にした random ということが推測できる
ここで登場している Scalar
クラスはどこで定義されているのか分からなかった。が、行列計算におけるスカラー値を表現していることは容易にわかる
また以下にあるように、AccelerableByTensorFlow
プロトコルに準拠している型は Scalar
として使えるようだった
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/DataTypes.swift#L34
init(randomStandardUniform shape: TensorShape, state: RandomState? = nil)
次にラップされていた上記を読み進める前に、いくつか調べておかないといけないユニットがある
_TFHoistable
_TFHoistable
は () -> TensorHandle<Scalar>
な closure を受け取り、その closure の返り値を return するだけのもの
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Tensor.swift#L124
TensorHandle
TensorHandle
は Tensor
の核となるもので、実は Tensor
は TensorHandle
のラッパー
TensorHandle
は ops や #tfop()
を実行するための型
実際に TensorFlow とやりとりするときに、パラメータの型をより静的にコンパイラに伝えるためのものだと思った
_TFTensorFromScalars<Scalar>(_ scalars: [Scalar], shape: [Int32])
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Tensor.swift#L94-L107
内部の実装を読むと渡された scalar の配列と shape のサイズに違いがないかチェックし、
TensorHandle
を初期化している。 scalarsInitializer
では TensorHandle
に渡す scalars を全てアロケートしないといけないらしい。これも TensorFlow のコアに渡すためなんだろうか
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/TensorHandle.swift#L45
TensorFlow.init(randomStandardUniform shape: TensorShape, state: RandomState? = nil)
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/Tensor.swift#L521-L529
ここまででようやくメインに戻ってくることができる
やっていることとしては、Tensor
を TensorHandle
を引数にして初期化している
その TensorHandle
は _TFHoistable
経由で作成しており、その closure の内部で _TFTensorFromScalars
を使って、ランダムに作られた Int の配列から TensorHandle
を作っていることがわかる
まとめ
サンプルで使われていたある関数を起点として、いかに静的型付けと TensorFlow のコアとのブリッジングを成立させるかの足がかりが見えた。
今回見えた TensorFlow/DataTypes.swift
や TensorFlow/TensorHandle.swift
などはそれに強く関わる部分だと思うので、もっと調べる
https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/DataTypes.swift https://github.com/google/swift/blob/tensorflow/stdlib/public/TensorFlow/TensorHandle.swift
swift-models の MNIST.swift を読む
swift-models
TensorFlow for Swift で実際に使うことができる機械学習のモデルを集めたレポジトリ
https://github.com/tensorflow/swift-models
2018/4/30 現在だと MNIST だけがある
MNIST についての説明は省略するが、MNIST 自体についてのチュートリアルはこれがおすすめ
https://www.tensorflow.org/versions/r1.1/get_started/mnist/beginners
swift-models の実際の実行方法は前に書いたブログを参考にしてほしい
ちなみに Xcode に結合された API doc はまだ見つからなかったので、以下のページを頻繁に使った
https://www.tensorflow.org/api_docs/swift/
MNIST.swift を読む
MNIST.swift はコマンドラインから実行されることを前提としている
内容はとても単純で main という関数を実行しているだけなので、main の1行目から読み進めていけばOK
1.教師データの準備
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L38-L53
これらの行ではファイルから実際の画像データとそれに対するラベルをロードして、Tensor
オブジェクトにしている
readMnist
内で imageData
と labelData
をロードする際に、それぞれ dropFirst
しているのは何故なんだろう…
ロードされたデータは以下のような2次元配列となっている
ラベル: 1x60000 画像: 784x60000
要するに60000個の0-9でラベル付けされた画像がある
またロードされたラベルデータは0-9の値を取るので、one-hot Tensor に変換している
簡単にいうとこんな感じ
変換前: [6, 7, 3…] 変換後: [ [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] ... ]
2.ハイパーパラメータと学習パラメータの準備
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L55-L64
ハイパーパラメータには以下の3つが定義されている
- イテレーションの回数
- 学習率
- 損失
また学習するパラメータは以下のように2段階に設定されている
- 1層目
- 重み w1
- バイアス b1
- 2層目
- 重み w2
- バイアス b2
3.学習ループ
ニューラルネットなので以下のようなループで進む
- 3-1. 前方伝播 forward propagationで推測
- 3-2. 誤差逆伝播 back propagation で誤差計測
- 3-3. 最急降下法 gradient descent でパラメータ更新
- 3-4. 3-1に戻る
3-1.前方伝播 forward propagationで推測
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L71-L75
Tensor のドット積にオペレータとして ⊗
を使用している、単純な定数倍とは明確に区別したいためだろうか…
また sigmoid
は標準関数としてサポートされている。他にも ReLU や soft-max などもされている
3-2.誤差逆伝播 back propagation で誤差計測
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L77-L83
ここでは Tensor
の操作がいくつか出てくる
transpose
これは転置行列
withPermutations
というのは与えられた順列を元に転置を作るぽい。デフォルトが none なので、デフォルトであれば普通の転置行列になるはず。詳細は以下
https://www.tensorflow.org/api_docs/python/tf/transpose
sum
これは任意の axis に sum をしてその axis を潰す ここでは1を指定しているので列方向に潰しているぽい
3-3.最急降下法 gradient descent でパラメータ更新
https://github.com/tensorflow/swift-models/blob/master/MNIST/MNIST.swift#L85-L92
計算された損失に学習率をかけてパラメータを更新する
ここでの * は単純にスカラー倍を意味している
まとめ
Swift API doc をみるのは面白い
https://www.tensorflow.org/api_docs/swift/
以下の stdlib/public も合わせて読む
https://github.com/google/swift/tree/tensorflow/stdlib/public/TensorFlow
Swift for TensorFlow で MNIST を実行する
Swift for TensorFlow
少し前に TensorFlow Dev Summit 2018 でアナウンスされた Swift for TensorFlow の動画は以下
Swift for TensorFlow - TFiwS (TensorFlow Dev Summit 2018)
ついにそれが先週が OSS になった
https://github.com/tensorflow/swift https://www.tensorflow.org/community/swift
色々とすごいところが多いのだけれど、このブログでは Swift for TensorFlow を動かしてみるところに注力してみる
Swift for TensorFlow のインストール
ビルドされた TensorFlow が入ってる Swift を以下のリンク先の .dmg からインストールする
https://github.com/tensorflow/swift/blob/master/Installation.md#pre-built-packages
PATH を通す
コマンドラインからビルドするだけなのでパスを通すだけで OK
export PATH=/Library/Developer/Toolchains/swift-latest/usr/bin:"${PATH}"
(fish の人用にも念のため)
set -x PATH /Library/Developer/Toolchains/swift-latest/usr/bin $PATH
(補足)Xcode からも使いたい場合は以下のリンクを参考に Toolchain を変更する
https://github.com/tensorflow/swift/blob/master/Installation.md#installation
swift-models のレポジトリを clone
以下のレポジトリを clone する https://github.com/tensorflow/swift-models
ちなみにこのレポジトリはcontributeできるので、今後他のモデルも追加されて行きそう
git clone git@github.com:tensorflow/swift-models.git
ビルド
上記の clone したディレクトリに行き、以下のコマンドを実行する
swift -O MNIST.swift
これで MNIST のビルドが始まる
ちなみに -O は compile with optimization
これでビルドができると思う
grpc-swift を Carthage 経由でインストールする方法
grpc-swift
grpc-swift は現時点(2018/2/2)では Carthage には対応していない
https://github.com/grpc/grpc-swift/issues/13
このブログではどうにかして、Carthage 経由でそれをインストールするための方法を説明する
動機としてはサポートされている SPM でのインストールがとても辛かったからというのが大きい
SPM のあれこれはこの手順を読んでもらえるといくつか雰囲気をつかめるかも
また下記の内容はタベリーのライセンスページをみて、grpc-swift を使っていたので ishkawa さんにコンタクトを取って教えてもらった。感謝!
手順
1.別で管理する
何はともあれ grpc-swift をフォークもしくは、
何かしら本流とは別のバージョン管理をする必要がある
これからいくつかの変更を加えるのが理由
2.xcodeproj の生成
以下のコマンドを grpc-swift で実行する
swift package generate-xcodeproj
これを実行すると SwiftGRPC.xcodeproj
というファイルが生成されるので開く
こちらのファイルもバージョン管理に入っていない場合はこれ以降で編集するので追加するといい
3. modulemap のパスの相対化
どうやら Swift Package Manager で設定された modulemap の header パスは実行環境の絶対パスが指定されるようなので、これを別環境でも動くように相対パスにする
以下を参考に BoringSSL と Czlib のそれを修正する
https://github.com/ishkawa/grpc-swift/blob/carthage-0.2.3/SwiftGRPC.xcodeproj/GeneratedModuleMap/BoringSSL/module.modulemap https://github.com/ishkawa/grpc-swift/blob/carthage-0.2.3/SwiftGRPC.xcodeproj/GeneratedModuleMap/Czlib/module.modulemap
4.zlib-example を消す
zlib-example
というビルドターゲットならびにスキームがあるので両方消す
これがあると依存関係で Carthage 実行時にこれもビルドされてしまい、エラーを吐き出す
5.SPM でインストールされた zlib を Git 管理下に置く
.build/checkouts
にあるので追加する
また指定されている zlib の URL は以下が指定されているが
https://github.com/Zewo/zlib.git
こちらは変わっていて以下になっている
https://github.com/ZewoGraveyard/CZlib.git
これが原因でエラーになった場合は一度書き換えるのがいい
6.それぞれのフレームワークのbundle identifierを正しく設定する
これを行わないと実機インストールができないので、適当に com.grpc.swift
などを以下のターゲットにつける
- gRPC
- CgRPC
- BoringSSL
- Czlib
終わりと補足
上記手順を踏むことでおそらく grpc-swift を Carthage でインストールすることが
できるようになるはず。残りやることはいつもの Carthage の手順のみ。
また直近のバージョンだと以下のエラーが頻発するので、現状だと 0.1.x 系を使うことがオススメ。
最近やっていること
今まで一年半くらいGitHub ブログを書いていたが
デザインの修正が苦手なのと流入少なめなのでまたはてなブログに戻ってきた。
年末ということもあるし最近何してるかを簡単に書く。
iOS
相変わらずメルカリで iOS エンジニアとして iOS アプリの開発をしている。
2017年はUSからJPまで、毎期色々なアプリの機能開発をした。
iOS DC Japan 2017 でも以下の発表できた。
また最近では OSS にも貢献したい気持ちが出てきていて、
具体的には以下のようなライブラリに PR を送っている。
iOS 11 Programming を購入して、iOS 11 の進化に驚いたりもした。
ブロックチェーン・暗号通貨
ブロックチェーンや暗号通貨にも少なからず興味を持っていて
趣味で以下のような本を元に勉強したりしている。
実際に手を動かすなどはあまりしておらず、あくまでサンプルを動かすなどにとどまっている。
- 作者: 大塚雄介
- 出版社/メーカー: ディスカヴァー・トゥエンティワン
- 発売日: 2017/03/28
- メディア: Kindle版
- この商品を含むブログを見る
- 作者: アンドレアス・M・アントノプロス,今井崇也,鳩貝淳一郎
- 出版社/メーカー: エヌティティ出版
- 発売日: 2016/07/14
- メディア: 大型本
- この商品を含むブログ (7件) を見る
社会を根底から変えるシェアリングエコノミーの衝撃! 仮想通貨ブロックチェーン&プログラミング入門
- 作者: 玉蔵
- 出版社/メーカー: ヒカルランド
- 発売日: 2017/11/24
- メディア: 単行本
- この商品を含むブログを見る
最初は第一印象などで敬遠していたが、興味半分で触れてみたらとても技術的に新しいし勉強になることも多い。
お金
上とも少し繋がるが、生活環境が変わったことでお金についても昔より考えるようになった。
具体的には今までなんとなくで生きてこられたキャッシュフローを見直して、
将来のための投資や運用に少しずつ行っている。
具体的な内訳としては毎月の給与を天引きで貯蓄口座と確定拠出年金に移動したり、暗号通貨をお遊び程度に買っている程度だけれど。
年明けからは WEALTHNAVI や THEO も使っていく。
今後と来年の抱負
今後も iOS エンジニアとして仕事していく。
もう少し業務の幅を広げつつ、OSS への貢献や勉強会でのアウトプットなどをより積極的に行っていきたい。