web-dev-qa-db-fra.com

Comment puis-je multiplier un vecteur et une matrice en tensorflow sans remodeler?

Cette:

import numpy as np
a = np.array([1, 2, 1])
w = np.array([[.5, .6], [.7, .8], [.7, .8]])

print(np.dot(a, w))
# [ 2.6  3. ] # plain Nice old matrix multiplication n x (n, m) -> m

import tensorflow as tf

a = tf.constant(a, dtype=tf.float64)
w = tf.constant(w)

with tf.Session() as sess:
    print(tf.matmul(a, w).eval())

résulte en:

C:\_\Python35\python.exe C:/Users/MrD/.PyCharm2017.1/config/scratches/scratch_31.py
[ 2.6  3. ]
# bunch of errors in windows...
Traceback (most recent call last):
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 671, in _call_cpp_shape_fn_impl
    input_tensors_as_shapes, status)
  File "C:\_\Python35\lib\contextlib.py", line 66, in __exit__
    next(self.gen)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 466, in raise_exception_on_not_ok_status
    pywrap_tensorflow.TF_GetCode(status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: Shape must be rank 2 but is rank 1 for 'MatMul' (op: 'MatMul') with input shapes: [3], [3,2].

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/MrD/.PyCharm2017.1/config/scratches/scratch_31.py", line 14, in <module>
    print(tf.matmul(a, w).eval())
  File "C:\_\Python35\lib\site-packages\tensorflow\python\ops\math_ops.py", line 1765, in matmul
    a, b, transpose_a=transpose_a, transpose_b=transpose_b, name=name)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 1454, in _mat_mul
    transpose_b=transpose_b, name=name)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 763, in apply_op
    op_def=op_def)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\ops.py", line 2329, in create_op
    set_shapes_for_outputs(ret)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\ops.py", line 1717, in set_shapes_for_outputs
    shapes = shape_func(op)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\ops.py", line 1667, in call_with_requiring
    return call_cpp_shape_fn(op, require_shape_fn=True)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 610, in call_cpp_shape_fn
    debug_python_shape_fn, require_shape_fn)
  File "C:\_\Python35\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 676, in _call_cpp_shape_fn_impl
    raise ValueError(err.message)
ValueError: Shape must be rank 2 but is rank 1 for 'MatMul' (op: 'MatMul') with input shapes: [3], [3,2].

Process finished with exit code 1

(Je ne sais pas pourquoi la même exception est déclenchée dans sa gestion)

La solution suggérée dans exception Tensorflow avec matmul consiste à remodeler le vecteur en matrice mais cela conduit à un code inutilement compliqué - n'y a-t-il toujours pas d'autre moyen de multiplier un vecteur avec une matrice?

Incidemment en utilisant expand_dims (comme suggéré dans le lien ci-dessus) avec des arguments par défaut soulève un ValueError - qui n'est pas mentionné dans le docs et défait le but d'avoir un argument par défaut.

10
Mr_and_Mrs_D

Matmul a été codé pour les tenseurs de rang deux ou plus. Je ne sais pas pourquoi, pour être honnête, numpy l'a si bien qu'il permet également la multiplication des vecteurs matriciels.

import numpy as np
a = np.array([1, 2, 1])
w = np.array([[.5, .6], [.7, .8], [.7, .8]])

print(np.dot(a, w))
# [ 2.6  3. ] # plain Nice old matix multiplication n x (n, m) -> m
print(np.sum(np.expand_dims(a, -1) * w , axis=0))
# equivalent result [2.6, 3]

import tensorflow as tf

a = tf.constant(a, dtype=tf.float64)
w = tf.constant(w)

with tf.Session() as sess:
  # they all produce the same result as numpy above
  print(tf.matmul(tf.expand_dims(a,0), w).eval())
  print((tf.reduce_sum(tf.multiply(tf.expand_dims(a,-1), w), axis=0)).eval())
  print((tf.reduce_sum(tf.multiply(a, tf.transpose(w)), axis=1)).eval())

  # Note tf.multiply is equivalent to "*"
  print((tf.reduce_sum(tf.expand_dims(a,-1) * w, axis=0)).eval())
  print((tf.reduce_sum(a * tf.transpose(w), axis=1)).eval())
10
Steven

tf.einsum vous donne la possibilité de faire exactement ce dont vous avez besoin sous une forme concise et intuitive:

with tf.Session() as sess:
    print(tf.einsum('n,nm->m', a, w).eval())
    # [ 2.6  3. ] 

Vous pouvez même écrire votre commentaire explicitement n x (n, m) -> m. C'est plus lisible et intuitif à mon avis.

Mon cas d'utilisation préféré est lorsque vous souhaitez multiplier un lot de matrices avec un vecteur de poids:

n_in = 10
n_step = 6
input = tf.placeholder(dtype=tf.float32, shape=(None, n_step, n_in))
weights = tf.Variable(tf.truncated_normal((n_in, 1), stddev=1.0/np.sqrt(n_in)))
Y_predict = tf.einsum('ijk,kl->ijl', input, weights)
print(Y_predict.get_shape())
# (?, 6, 1)

Vous pouvez donc facilement multiplier les poids sur tous les lots sans transformations ni duplication. Vous ne pouvez pas faire cela en développant les dimensions comme dans les autres réponses. Ainsi, vous évitez l'exigence tf.matmul d'avoir des dimensions correspondantes pour le lot et d'autres dimensions extérieures:

Les entrées doivent, après toutes les transpositions, être des tenseurs de rang> = 2 où les 2 dimensions internes spécifient des arguments de multiplication matriciels valides et toutes les autres dimensions externes correspondent.

12
dsalaj

Vous pouvez utiliser tf.tensordot et définissez axes=1. Pour le fonctionnement simple d'un vecteur multiplié par une matrice, c'est un peu plus propre que tf.einsum

tf.tensordot(a, w, 1)
0
Hooked