46 votes

Tensorflow - matmul de la matrice d'entrée avec des données de lots

J'ai quelques données représentées par input_x. C'est un tenseur de taille inconnue (doit être saisi par lot) et chaque élément y est de taille n. input_x subit tf.nn.embedding_lookup, de sorte qu' embed maintenant a des dimensions [?, n, m]m est l'incorporation de la taille et de l' ? se réfère à l'inconnu de la taille des lots.

Ce qui est décrit ici:

input_x = tf.placeholder(tf.int32, [None, n], name="input_x") 
embed = tf.nn.embedding_lookup(W, input_x)

Je vais maintenant essayer de multiplier chaque échantillon dans mes données d'entrée (qui est maintenant élargi en intégrant la dimension) par une matrice de variables, U, et je n'arrive pas à obtenir la façon de le faire.

J'ai d'abord essayé d'utiliser tf.matmul , mais il donne une erreur due à une inadéquation dans les formes. J'ai ensuite essayé le suivant, par l'accroissement de la dimension de l' U et en appliquant batch_matmul (j'ai aussi essayé la fonction d' tf.nn.math_ops., le résultat était le même):

U = tf.Variable( ... )    
U1 = tf.expand_dims(U,0)
h=tf.batch_matmul(embed, U1)

Cela passe à la compilation initiale, mais ensuite, lorsque les données réelles est appliqué, j'obtiens l'erreur suivante:

In[0].dim(0) and In[1].dim(0) must be the same: [64,58,128] vs [1,128,128]

Je sais aussi pourquoi ce qui se passe - je répliqué à la dimension de l' U , et il est désormais 1, mais le minibatch taille, 64, ne cadrent pas.

Comment puis-je faire que de la multiplication de matrice sur mon tenseur-matrice d'entrée correctement (inconnue taille du lot)?

88voto

Salvador Dali Points 11667

Les réponses précédentes sont obsolètes. Actuellement, tf.matmul() soutien tenseurs de rang > 2:

Les entrées doivent être des matrices (ou tenseurs de rang > 2, représentant lots de matrices), avec des dimensions intérieures, éventuellement après la transposition.

Aussi tf.batch_matmul() a été supprimé et tf.matmul() est la bonne façon de faire les lots de multiplication. L'idée principale peut être comprise à partir du code suivant:

import tensorflow as tf
batch_size, n, m, k = 10, 3, 5, 2
A = tf.Variable(tf.random_normal(shape=(batch_size, n, m)))
B = tf.Variable(tf.random_normal(shape=(batch_size, m, k)))
tf.matmul(A, B)

Maintenant, vous recevrez un tenseur de la forme (batch_size, n, k). Voici ce qui se passe ici. Supposons que vous disposez d' batch_size de matrices nxm et batch_size de matrices mxk. Maintenant, pour chaque paire d'entre eux vous calculez nxm X mxk qui vous donne un nxk de la matrice. Vous devrez batch_size d'entre eux.

Remarquez que quelque chose comme ceci est également valable:

A = tf.Variable(tf.random_normal(shape=(a, b, n, m)))
B = tf.Variable(tf.random_normal(shape=(a, b, m, k)))
tf.matmul(A, B)

et vous donnera une forme (a, b, n, k)

36voto

P-Gn Points 10410

1. Je veux multiplier un lot de matrices avec un lot de matrices de la même longueur deux à deux

M = tf.random_normal((batch_size, n, m))
N = tf.random_normal((batch_size, m, p))

# python >= 3.5
MN = M @ N
# or the old way,
MN = tf.matmul(M, N)
# MN has shape (batch_size, n, p)

2. Je veux multiplier un lot de matrices avec un lot de vecteurs de même longueur, par paires

Nous retombons de cas 1 par l'ajout et la suppression d'une dimension à l' v.

M = tf.random_normal((batch_size, n, m))
v = tf.random_normal((batch_size, m))

Mv = (M @ v[..., None])[..., 0]
# Mv has shape (batch_size, n)

3. Je veux multiplier une matrice avec un lot de matrices

Dans ce cas, nous ne pouvons pas simplement ajouter un lot de la dimension de l' 1 de la matrice seule, car tf.matmul ne diffuse pas dans le lot de dimension.

3.1. La matrice est sur le côté droit

Dans ce cas, nous pouvons traiter la matrice lot comme une seule matrice de grande taille, à l'aide d'un simple remodeler.

M = tf.random_normal((batch_size, n, m))
N = tf.random_normal((m, p))

MN = tf.reshape(tf.reshape(M, [-1, m]) @ N, [-1, n, p])
# MN has shape (batch_size, n, p)

3.2. La matrice est sur le côté gauche

Ce cas est plus compliqué. Nous pouvons revenir à des cas 3.1 par la transposition des matrices.

MT = tf.matrix_transpose(M)
NT = tf.matrix_transpose(N)
NTMT = tf.reshape(tf.reshape(NT, [-1, m]) @ MT, [-1, p, n])
MN = tf.matrix_transpose(NTMT)

Toutefois, la transposition peut être une opération coûteuse, et ici il est fait deux fois sur un ensemble de matrices. Il peut être préférable de simplement dupliquer M pour correspondre le lot de dimension:

MN = tf.tile(M[None], [batch_size, 1, 1]) @ N

Le profilage dire l'option qui convient le mieux pour un problème donné/combinaison matérielle.

4. Je veux multiplier une matrice avec un lot de vecteurs

Cela ressemble à l'affaire 3.2 comme la matrice est sur la gauche, mais il est en fait plus simple en raison de la transposition d'un vecteur est essentiellement un no-op. Nous terminons avec

M = tf.random_normal((n, m))
v = tf.random_normal((batch_size, m))

MT = tf.matrix_transpose(M)
Mv = v @ MT

Qu'en einsum?

Tous les précédents multiplications pourrait avoir été écrite avec l' tf.einsum couteau de l'armée suisse. Par exemple, la première solution pour le 3.2 pourrait être écrit simplement comme

MN = tf.einsum('nm,bmp->bnp', M, N)

Notez, cependant, que einsum est finalement en s'appuyant sur tranpose et matmul pour le calcul.

Donc, même si einsum est un moyen très pratique pour écrire la matrice de multiplications, il masque la complexité des opérations de sous - par exemple, il n'est pas simple à deviner combien de fois einsum expression transposer vos données, et donc coûteux, l'opération sera. Aussi, il peut cacher le fait qu'il pourrait y avoir plusieurs solutions de rechange pour la même opération (voir 3.2) et pourrait ne pas forcément choisir la meilleure option.

Pour cette raison, je serais personnellement utiliser des formules explicites comme ceux ci-dessus afin de mieux transmettre leurs respectifs de la complexité. Bien que si vous savez ce que vous faites et comme la simplicité de l' einsum de la syntaxe, puis par tous signifie aller pour elle.

17voto

Styrke Points 1860

Le matmul opération ne fonctionne que sur des matrices (2D tenseurs). Voici deux approches principales pour ce faire, les deux supposer qu' U est un 2D tenseur.

  1. Tranche embed en 2D tenseurs et multiplier chacun d'eux, U individuellement. C'est probablement le plus facile à faire en utilisant tf.scan() comme ceci:

    h = tf.scan(lambda a, x: tf.matmul(x, U), embed)
    
  2. D'autre part, si l'efficacité est importante, il peut être préférable pour remodeler embed être un 2D tenseur ainsi la multiplication peut être fait avec un simple matmul comme ceci:

    embed = tf.reshape(embed, [-1, m])
    h = tf.matmul(embed, U)
    h = tf.reshape(h, [-1, n, c])
    

    c est le nombre de colonnes en U. La dernière remodeler sera assurez-vous que h 3D tenseur où l'0e dimension correspond au lot tout comme l'original x_input et embed.

4voto

Desh Raj Points 86

Comme répondu par @Stryke, il y a deux façons d'y parvenir: 1. La numérisation et de la 2. Le remodelage

  1. tf.analyse nécessite lambda fonctions et est généralement utilisé pour les opérations récursives. Quelques exemples pour le même est ici: https://rdipietro.github.io/tensorflow-scan-examples/

  2. Personnellement, je préfère le remodelage, car il est plus intuitif. Si vous essayez de matrice de multiplier chaque matrice en 3D tenseur par la matrice qui est de la 2D tenseur, comme Cijl = Aijk * Bkl, vous pouvez le faire avec un simple remodeler.

    A' = tf.reshape(Aijk,[i*j,k])
    C' = tf.matmul(A',Bkl)
    C = tf.reshape(C',[i,j,l])
    

0voto

James Points 46

Il semble que dans TensorFlow 1.11.0 les docs pour tf.matmul tort de dire qu'il travaille pour le rang >= 2.

Au lieu de cela, la meilleure solution propre que j'ai trouvé est d'utiliser tf.tensordot(a, b, (-1, 0)) (docs).

Cette fonction obtient le produit scalaire de tout axe de tableau a et quel que soit l'axe de la matrice b dans sa forme générale tf.tensordot(a, b, axis). Offrant axis comme (-1, 0) devient la norme, produit scalaire de deux tableaux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X