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

はっきり言って、コードを難解だと思わせている記述法にLambdaクラスがある。
あと、K.。。。もだけど、こっちはそういうものだと想像できるが、Lambdaクラスの効用はいまいち。
参考②と③のような一行サンプルはだいたい理解できる。
そういう書き方はコード短縮には便利かも。。位の理解だけど。。。
参考①のコードになるともう一つ理解ができない。
ということで、少し我慢して追求すれば理解できるかもということで、参考①の最初のコード例を納得行くまで動かしてみました。
【参考】
・①[Python keras.layers.core.Lambda() Examples](https://www.programcreek.com/python/example/89762/keras.layers.core.Lambda)
・②[18. Lambdas@PythonTips](http://book.pythontips.com/en/latest/lambdas.html)
・③[Pythonの無名関数（ラムダ式、lambda）の使い方@note.nkmk.me](https://note.nkmk.me/python-lambda-usage/)
###コード例
```py
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))
```
ここまでは、一行で書けることの確認。
以下が例のコード。。
これ動かしてみます。

```py
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を定義して関数動かしてみます。

```py
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にしてみます。

```py
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入れよう

```py
    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](https://github.com/keras-team/keras/issues/5987)
ということで、たまたまかもですが、入力を以下のとおりに変更します。

```py
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?](https://stackoverflow.com/questions/34097281/how-can-i-convert-a-tensor-into-a-numpy-array-in-tensorflow)

```py
print(tf.Session().run(my_tensor))
```
やっと、望みの結果が得られましたとさ。。。
[0 2 1 0 0 2]
この結果は、x1-x2とx1*x2の結合になっています。
ちなみに、以下もググると出てきます、。。やってみると。。

```py
print(my_tensor.eval(session=tf.Session()))
```
[0 2 1 0 0 2]
同じ結果が得られました。

なんか一周しすっきりしたので、この記事はここで終わります。
おまけにここまでの全コードを載せておきます。

因みに、Lambdaコメントアウトして、まんま

```py
return concatenate([distance, multiply]) 
```
だと、入力をTensorにしろと怒られます。
この関数は、入力Tensor,出力Tensorの関数なんですね。。。
※え～？？
###まとめ
・Lambdaについてちょっと関数を動かしてみた
・Lambda関数の入出力はTensorのようだ
・Tensorの具体的な値を求めるには、実際にRunしてやる必要がある

・さて、Grad_camのコードを読もう。。。
###おまけ
```py
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()))
```