はっきり言って、コードを難解だと思わせている記述法にLambdaクラスがある。
あと、K.。。。もだけど、こっちはそういうものだと想像できるが、Lambdaクラスの効用はいまいち。
参考②と③のような一行サンプルはだいたい理解できる。
そういう書き方はコード短縮には便利かも。。位の理解だけど。。。
参考①のコードになるともう一つ理解ができない。
ということで、少し我慢して追求すれば理解できるかもということで、参考①の最初のコード例を納得行くまで動かしてみました。
【参考】
・①Python keras.layers.core.Lambda() Examples
・②18. Lambdas@PythonTips
・③Pythonの無名関数(ラムダ式、lambda)の使い方@note.nkmk.me
コード例
from keras.layers.core import Lambda
def add_def(a, b=1):
return a + b
add_lambda = lambda a, b=1: a + b
print(add_def(3, 4))
print(add_lambda(3, 4))
ここまでは、一行で書けることの確認。
以下が例のコード。。
これ動かしてみます。
def distance_layer(x1, x2):
"""Distance and angle of two inputs.
Compute the concatenation of element-wise subtraction and
multiplication of two inputs.
"""
def _distance(args):
x1 = args[0]
x2 = args[1]
x = K.abs(x1 - x2)
return x
def _multiply(args):
x1 = args[0]
x2 = args[1]
return x1 * x2
distance = Lambda(_distance, output_shape=(K.int_shape(x1)[-1],))([x1, x2])
multiply = Lambda(_multiply, output_shape=(K.int_shape(x1)[-1],))([x1, x2])
return concatenate([distance, multiply])
とりあえず、必要なLibをimportして、x1,x2を定義して関数動かしてみます。
from keras.layers.core import Lambda
import keras.backend as K
from keras.layers import concatenate
def distance_layer(x1, x2):
...
x1=[0,0,1]
x2=[0,2,2]
print(distance_layer(x1, x2))
案の定、エラー
AttributeError: 'list' object has no attribute 'get_shape'
どうやらlistだからget_shapeが無いらしい。。
ということで、np.arrayにしてみます。
import numpy as np
...
def distance_layer(x1, x2):
...
x1=np.array([0,0,1])
x2=np.array([0,2,2])
print(distance_layer(x1, x2))
やはり、同じエラー
AttributeError: 'numpy.ndarray' object has no attribute 'get_shape'
じゃということで、get_shape使わずに直接shape入れよう
distance = Lambda(_distance, output_shape=(x.shape[-1],))([x1, x2])
そうだよなぁ~
TypeError: 'tuple' object is not callable
もう一度、ググってみます。。参考によれば以下のようにtensorsだそうです。
まあ、ここは質問がmodel.add(Lambda(lambda x: resz))なので当然か。。ですが、
Should be model.add(Lambda(resz)), lambda is redundant. Also, input and output of Lambda should be tensors, numpy array is not allowed.
【参考】
・AttributeError: 'function' object has no attribute 'get_shape'` #5987
ということで、たまたまかもですが、入力を以下のとおりに変更します。
import numpy as np
import tensorflow as tf
...
def distance_layer(x1, x2):
...
my_tensor=distance_layer(tf.convert_to_tensor(x1),tf.convert_to_tensor(x2))
print(may_tensor)
これで動きました!
出力は。。。
Tensor("concatenate_1/concat:0", shape=(6,), dtype=int32)
Tensorの型とかいらないんだけど。。。でググりました「tensor to numpy」
【参考】
・How can I convert a tensor into a numpy array in TensorFlow?
print(tf.Session().run(my_tensor))
やっと、望みの結果が得られましたとさ。。。
[0 2 1 0 0 2]
この結果は、x1-x2とx1*x2の結合になっています。
ちなみに、以下もググると出てきます、。。やってみると。。
print(my_tensor.eval(session=tf.Session()))
[0 2 1 0 0 2]
同じ結果が得られました。
なんか一周しすっきりしたので、この記事はここで終わります。
おまけにここまでの全コードを載せておきます。
因みに、Lambdaコメントアウトして、まんま
return concatenate([distance, multiply])
だと、入力をTensorにしろと怒られます。
この関数は、入力Tensor,出力Tensorの関数なんですね。。。
※え~??
まとめ
・Lambdaについてちょっと関数を動かしてみた
・Lambda関数の入出力はTensorのようだ
・Tensorの具体的な値を求めるには、実際にRunしてやる必要がある
・さて、Grad_camのコードを読もう。。。
おまけ
from keras.layers.core import Lambda
import keras.backend as K
import numpy as np
import tensorflow as tf
from keras.layers import concatenate
def add_def(a, b=1):
return a + b
add_lambda = lambda a, b=1: a + b
print(add_def(3, 4))
print(add_lambda(3, 4))
def distance_layer(x1, x2):
"""Distance and angle of two inputs.
Compute the concatenation of element-wise subtraction and
multiplication of two inputs.
"""
def _distance(args):
x1 = args[0]
x2 = args[1]
x = K.abs(x1 - x2)
return x
def _multiply(args):
x1 = args[0]
x2 = args[1]
return x1 * x2
distance = Lambda(_distance, output_shape=(K.int_shape(x1)[-1],))([x1, x2])
multiply = Lambda(_multiply, output_shape=(K.int_shape(x1)[-1],))([x1, x2])
return concatenate([distance, multiply])
x1=[0,0,1]
x2=[0,2,2]
my_tensor=distance_layer(tf.convert_to_tensor(x1),tf.convert_to_tensor(x2))
print(tf.Session().run(my_tensor))
print(my_tensor.eval(session=tf.Session()))