5
5

More than 5 years have passed since last update.

【Lambdaクラス】コード読むのに必須なんだけど。。。(><;

Last updated at Posted at 2019-05-03

はっきり言って、コードを難解だと思わせている記述法に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()))
5
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5