Voici un résumé de ce que j'ai appris en faisant des calculs de tenseurs, etc. directement en utilisant le backend Keras.
Lors de la construction d'un réseau avec Keras, je pense que la plupart des couches sont définies dans la couche, mais pour une couche spéciale, il est nécessaire de créer une fonction et de plonger dans la couche Lambda ou la couche Merge. Par exemple, ce qui suit crée un modèle avec une couche qui renvoie la valeur absolue de l'entrée.
lambda_layer_exp.py
from keras.models import Model
from keras.layers import Input, Lambda
import keras.backend as K
x_in = Input(shape=(3, 3))
x = Lambda(lambda x: K.abs(x))(x_in)
model = Model(input=x_in, output=x)
Mettons une valeur dans ce modèle.
>>> import numpy as np
>>> model.predict([np.array([[[-1,2,3],[4,-5,6],[7,8,-9]]])])
array([[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]]], dtype=float32)
S'il y a deux entrées ou plus, le calque Merge les gérera. L'exemple ci-dessous ajoute une couche qui prend la somme des valeurs absolues des deux entrées. Lors de l'utilisation d'une fonction dans le calque Merge, il est nécessaire de spécifier output_shape.
merge_layer_exp.py
from keras.models import Model
from keras.layers import Input, merge
import keras.backend as K
x_in1 = Input(shape=(3,))
x_in2 = Input(shape=(3,))
x = merge([x_in1, x_in2], mode=lambda x: K.abs(x[0]) + K.abs(x[1]), output_shape=(3,))
model = Model(input=[x_in1, x_in2], output=x)
Lorsque le calcul est exécuté avec ce modèle, il devient comme suit.
>>> import numpy as np
>>> model.predict([np.array([[-1,-2,3]]), np.array([[4,-5,-6]])])
array([[ 5., 7., 9.]], dtype=float32)
La plupart des fonctions qui existent dans le back-end sont presque les mêmes que celles utilisées dans numpy, Tensorflow, Theano, etc., mais certaines sont difficiles à utiliser, donc je vais me concentrer sur elles.
dot, batch_dot Une chose à garder à l'esprit lorsque vous utilisez le backend Keras et que vous ne l'utilisez pas, c'est qu'avec le backend, vous devez considérer les dimensions du lot comme vous le feriez avec Tensorflow et plus encore. Ceux de Keras 'Layer qui prennent des arguments de forme sont essentiellement considérés sans la dimension batch. Pour les images RVB, donnez-le sous la forme «shape = (3, 32, 32)», mais dans la fonction backend, considérez la dimension du lot comme «shape = (None, 3, 32, 32)». Et il faut penser au calcul. Les fonctions de produit scalaire «dot» et «batch_dot» présentées ici sont des fonctions qui prennent en compte et ne prennent pas en compte les dimensions du lot, respectivement. Un exemple est présenté ci-dessous.
import keras.backend as K
a = K.variable([[1,2],[3,4]])
b = K.variable([[5,6],[7,8]])
print K.eval(K.dot(a, b)) #Multiplier une matrice et une matrice b
print K.eval(K.batch_dot(a, b, 1)) # a[i]Et B[i]Tableau de produits scalaires de
print K.eval(a * b) #Multiplication pour chaque élément
Cela entraînera les résultats suivants:
[[ 19., 22.],
[ 43., 50.]]
[[ 17.],
[ 53.]]
[[ 5., 12.],
[ 21., 32.]]
Aussi, si vous voulez pousser un tel calcul de changement de dimension dans la couche Lambda
, vous devez explicitement donner ʻoutput_shape`.
import numpy as np
from keras.models import Model
from keras.layers import Input, Lambda
import keras.backend as K
x_in = Input(shape=(2, 2))
x = Lambda(lambda x: K.dot(K.variable([0, 1]), x), output_shape=(2,))(x_in)
model = Model(input=x_in, output=x)
print model.predict([np.array([[[1,2],[3,4]]])])
# [[ 3. 4.]]
one_hot Comme toute personne utilisant le traitement du langage naturel ou Tensorflow peut le savoir, «1» comme expliqué dans Wikipedia. Génère une chaîne de bits ❞ telle qu'une seule est High (1) et l'autre est Low (0). Un exemple est présenté ci-dessous.
print K.eval(K.one_hot(K.variable([0,2,1,0], dtype=int), 3))
# [[ 1. 0. 0.]
# [ 0. 0. 1.]
# [ 0. 1. 0.]
# [ 1. 0. 0.]]
Vous pouvez remplacer, ajouter et supprimer des dimensions avec permute_dimensions
, ʻexpand_dims,
squeeze`.
a = K.variable([[[1,2],[3,4]]])
print K.eval(K.shape(a))
# [1, 2, 2]
print K.eval(K.permute_dimensions(a, [1, 2, 0]))
# [[[ 1.],
# [ 2.]],
#
# [[ 3.],
# [ 4.]]]
print K.eval(K.expand_dims(a, 2))
# [[[[ 1., 2.]],
#
# [[ 3., 4.]]]]
print K.eval(K.squeeze(a, 0))
# [[ 1., 2.],
# [ 3., 4.]]
gather
C'est ce qu'on appelle le slicing, mais vous pouvez spécifier un index uniquement pour la première dimension, donc si vous voulez indexer pour n'importe quel axe, vous devez le combiner avec permute_dimensions
.
a = K.variable([[1,2],[3,4],[5,6]])
print K.eval(K.gather(a, 0))
# [ 1., 2.]
print K.eval(K.gather(K.permute_dimensions(a, [1, 0]), 0)) # K.eval(K.gather(K.transpose(a), 0))Équivalent à
# [ 1., 3., 5.]
Enfin, en utilisant les connaissances jusqu'à présent, j'ai essayé de réimplémenter le modèle écrit en chainer avec des keras. L'histoire est Value Iteration Networks (implémentation du chainer @ peisuke). Il semble que ce soit le meilleur article de NIPS2016. Je le poste sur github.