Theanoでキャストする方法

# Theanoにおけるキャスト

theanoは型付が非常に厳格なライブラリです。

pythonのような強力な型推論はないので、当然キャストを活用することになります。

# とりあえずcastしてみる

theanoのキャストはtheano.tensor.cast()で実装されています。

早速castを使ってみましょう。
デフォルトではfloat64型で定義される行列を、int32型に変換します。

```py3:
import theano.tensor as T
x = T.matrix()
x_as_int = T.cast(x, 'int32')

type(x), type(x_as_int)
```

```py3:出力結果
(theano.tensor.var.TensorVariable, theano.tensor.var.TensorVariable)
```

# キャストされてない？

上の結果ではどちらも同じ型（TensorVariable）が表示されています。

これはTheanoの仕様で、値ではなくシンボルを変数で定義しているからです。

シンボルの中身の型を見るには、theano.printing.debugprint()を使います。

```py3:xの型
import theano
theano.printing.debugprint(x)
```

```py3:出力結果
<TensorType(float64, matrix)> [id A]
```

```py3:x_as_intの型
theano.printing.debugprint(x_as_int)
```

```py3:出力結果
Elemwise{Cast{int32}} [id A] ''   
 |<TensorType(float64, matrix)> [id B]
```

なるほど、もともとfloat64型だったのが、x_as_intではint32にキャストされてそうです。

実際に値を入れてみて、挙動を確認しましょう。

# 関数を通して型を確認

シンボルに値を入れるには、関数を定義する必要があります。

シンボルを用いた数式を関数として定義して、その関数に値を入力することで、数式の処理結果が関数の返り値として返ります。

この際、入力値の型がシンボルの型に依存します。

不適な型を入れた場合にはエラーを吐くので、

int32型のシンボルx_as_intを入力に設定した場合、小数を入力するとエラーとなるはずです。

```py3:関数の定義
import numpy as np

mat = np.array([[1.0, 0.0], [0.0, 1.0]], dtype="float64")
mat_int = np.array([[1, 0], [0, 1]], dtype="int32")

y = x * 2
f = theano.function(inputs=[x], outputs=y)

y_as_int = x_as_int * 2
f_as_int = theano.function(inputs=[x_as_int], outputs=y_as_int)
```

```py3:f(x)
f(mat)
```

```py3:実行結果
array([[ 2.,  0.],
       [ 0.,  2.]])
```

```py3:f(x_as_int)
f(mat_int)
```

```py3:実行結果
array([[ 2.,  0.],
       [ 0.,  2.]])
```

```py3:f_as_int(x)
f_as_int(mat)
```

```py3:実行結果

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-56-31692f0163e9> in <module>()
----> 1 f_as_int(mat)

/home/ubuntu/anaconda3/lib/python3.5/site-packages/theano/compile/function_module.py in __call__(self, *args, **kwargs)
    786                         s.storage[0] = s.type.filter(
    787                             arg, strict=s.strict,
--> 788                             allow_downcast=s.allow_downcast)
    789 
    790                     except Exception as e:

/home/ubuntu/anaconda3/lib/python3.5/site-packages/theano/tensor/type.py in filter(self, data, strict, allow_downcast)
    138                             '"function".'
    139                             % (self, data.dtype, self.dtype))
--> 140                         raise TypeError(err_msg, data)
    141                 elif (allow_downcast is None and
    142                         type(data) is float and

TypeError: ('Bad input argument to theano function with name "<ipython-input-54-50af382d0dd4>:2" at index 0 (0-based)', 'TensorType(int32, matrix) cannot store a value of dtype float64 without risking loss of precision. If you do not mind this loss, you can: 1) explicitly cast your data to int32, or 2) set "allow_input_downcast=True" when calling "function".', array([[ 1.,  0.],
       [ 0.,  1.]]))
```

```py3:f_as_int(x_as_int)
array([[2, 0],
       [0, 2]], dtype=int32)
```

予想通りに、入力シンボルにint32型を指定しながら入力値をfloat64型としたf_as_int(mat)ではエラーを吐きました。

これで無事にtheanoにおけるキャストの動きがわかりました。