ちょっと前回の記事に追記していくとどんどん大きくなりそうだったのでPart2という事で新たに見つかった事象をこちらで報告していきます。
Concatenateが決められた次元でしか出来ない件
こちらの内容。試せていませんと言っていましたが、 Permute
を使って試した所例に漏れず新たなエラーを返してくれました。
そのままConcatenate
まずはそのまま
model_input = [Input(shape=(10,8)),Input(shape=(10,8))]
concate = Concatenate()(model_input)
model = Model(inputs=model_input, outputs=concate)
最終的に(10,16)のShapeになるだけの変哲のないモデルです。ちなみにkerasの Concatenate
はaxisを指定しないとデフォルトで-1、つまり一番うしろの次元でくっつけます。今回の場合はサイズ8となっている2次元目ですね。
1つ注意点としてaxisで指定する数字は0はバッチ次元です。なので1次元目でつなげたい場合は axis=1 と指定します。(知らないままaxis=0で指定するとConcatenateした後も見た目のTensorのサイズが変わっていないように見えて???となります。)
ではこのモデルをcoremltoolsで変換するとどうなるか。
ValueError: Only channel and sequence concatenation are supported.
前の記事でも書いたようにchannel次元かsequence次元でしか接続できないようです。前回は1次元目か3次元目かな、と言っていたのですが厳密には違って
- 全体で1次元のTensorの場合は1次元目(単純接続)
- 全体で2次元のTensorの場合は1次元目(時系列の1次元データ、というイメージ)
- 全体で3次元のTensorの場合は3次元目(画像とみなした時のチャンネル次元)
のようです。なので3次元データに対して「1次元目は時系列として扱うから!」と強く主張してもcoremltoolsは受け入れてくれません。
Permuteを使ってみる
Permuteとは聞き慣れない単語かもしれませんが、要するに転置です。厳密には3次元以上のTensorに対しては転置とは言いませんが、次元の入れ替えですね。ドキュメントを見ればなんとなくわかると思います。
今回は2次元の配列をConcatenateしてcoremltoolsに認めてもらいましょう。
from keras.layers.core import Permute
model_input = [Input(shape=(10,8)),Input(shape=(10,8))]
permuted = [Permute((2,1))(_i) for _i in model_input]
concate = Concatenate(axis=1)(permuted)
permuted2 = Permute((2,1))(concate)
model = Model(inputs=model_input, outputs=permuted2)
こんな感じです。 Permute
の引数は○次元目を×次元目に入れ替える、という×の方の数字を書きます。 Concatenate
と同様にバッチ次元が0なので実質1から書きます。
前の記事からそうなのですが、coreMLを使うつもりのない(というかこれらの知見がない)方がこのモデルを見たら本当に意味がわからないでしょうね。なんでひっくり返してつなげてひっくり返しているのかと…
とにかくこれでちゃんと1次元目でConcatenateできました。さて、coremltools先生に見てもらいましょう。
NotImplementedError: Supports only 3d permutation.
(#^ω^)ビキビキ
ま、まぁはっきりと解決策を提示してくれているので良しとしましょう。3次元のPermuteしか受け入れられないそうです。
では3次元にしてあげようじゃないですか。
model_input = [Input(shape=(10,8)),Input(shape=(10,8))]
permuted = [Permute((1,3,2))(Reshape((10,8,1))(_i)) for _i in model_input]
concate = Concatenate(axis=3)(permuted)
permuted2 = Reshape((10,16))(Permute((1,3,2))(concate))
model = Model(inputs=model_input, outputs=permuted2)
ここまでやってあげることでなんとかcoremltools先生に認められました。おめでとうございます。
パッと見何をしているのか意味がわからなくなってきていますが、
-
Permute
するために3次元化する(チャンネル数1の画像に見立てる) -
Concatenate
したい次元を3次元目(チャンネル次元)に入れ替える -
Concatenate
をチャンネル次元(axis=3にしています)で行う -
Permute
して次元を元に戻す(モデルの形によってはここを省いてReshapeそのまましても良い気もします) -
Reshape
して無駄な次元を消す
こんな感じです。ここまで理解してこれた方はだんだんcoreMLと仲良くなれて来たんじゃないでしょうか。
まとめ
今後もcoremltools先生の機嫌を損ねる事があったりその機嫌を直してもらう方法が分かったら追記するか別記事にして投稿したいと思います。
というか、チュートリアル的なモデルを少しでも外れたものを作ろうという人はあんまりいないんでしょうか…
公式のGithubのIssueも現時点で十数個しかないですし、英語記事を含めてもあんまりこのような解決策を提示している人が見つかりません。coreMLみんな使ってないのかな。。
ググり方が悪いのかもしれないので、おすすめの情報の探し方があるよーって方や自分も同じ状況ですーって方がいたら是非協力しましょう。