Matrix multiply two tensors with rank 1 or 2. If both tensors have rank 2, a matrix-matrix product is performed. If one tensor has rank 1 and the other has rank 2, then a matrix-vector product is performed. If both tensors have rank 1, then a vector dot-product is performed. (This behavio
(a, b, name=None)
| 763 | @tc.accepts(core.LabeledTensorLike, core.LabeledTensorLike, |
| 764 | tc.Optional(string_types)) |
| 765 | def matmul(a, b, name=None): |
| 766 | """Matrix multiply two tensors with rank 1 or 2. |
| 767 | |
| 768 | If both tensors have rank 2, a matrix-matrix product is performed. |
| 769 | If one tensor has rank 1 and the other has rank 2, then a matrix-vector |
| 770 | product is performed. |
| 771 | If both tensors have rank 1, then a vector dot-product is performed. |
| 772 | (This behavior matches that of `numpy.dot`.) |
| 773 | |
| 774 | Both tensors must share exactly one dimension in common, which is the |
| 775 | dimension the operation is summed along. The inputs will be automatically |
| 776 | transposed if necessary as part of the matmul op. |
| 777 | |
| 778 | We intend to eventually support `matmul` on higher rank input, and also |
| 779 | eventually support summing over any number shared dimensions (via an `axis` |
| 780 | argument), but neither of these features has been implemented yet. |
| 781 | |
| 782 | Args: |
| 783 | a: First LabeledTensor. |
| 784 | b: Second LabeledTensor. |
| 785 | name: Optional op name. |
| 786 | |
| 787 | Returns: |
| 788 | LabeledTensor with the result of matrix multiplication. Axes are ordered by |
| 789 | the current axis_order_scope, if set, or in or order of appearance on the |
| 790 | inputs. |
| 791 | |
| 792 | Raises: |
| 793 | NotImplementedError: If inputs have rank >2 or share multiple axes. |
| 794 | ValueError: If the inputs have rank 0 or do not share any axes. |
| 795 | """ |
| 796 | with ops.name_scope(name, 'lt_matmul', [a, b]) as scope: |
| 797 | |
| 798 | a = core.convert_to_labeled_tensor(a) |
| 799 | b = core.convert_to_labeled_tensor(b) |
| 800 | |
| 801 | if len(a.axes) > 2 or len(b.axes) > 2: |
| 802 | # We could pass batched inputs to tf.matmul to make this work, but we |
| 803 | # would also need to use tf.tile and/or tf.transpose. These are more |
| 804 | # expensive than doing reshapes, so it's not clear if it's a good idea to |
| 805 | # do this automatically. |
| 806 | raise NotImplementedError( |
| 807 | 'matmul currently requires inputs with rank 2 or less, but ' |
| 808 | 'inputs have ranks %r and %r' % (len(a.axes), len(b.axes))) |
| 809 | |
| 810 | if not a.axes or not b.axes: |
| 811 | raise ValueError( |
| 812 | 'matmul currently requires inputs with at least rank 1, but ' |
| 813 | 'inputs have ranks %r and %r' % (len(a.axes), len(b.axes))) |
| 814 | |
| 815 | shared_axes = set(a.axes) & set(b.axes) |
| 816 | if len(shared_axes) > 1: |
| 817 | raise NotImplementedError( |
| 818 | 'matmul does not yet support summing over multiple shared axes: %r. ' |
| 819 | 'Use transpose and reshape to create a single shared axis to sum ' |
| 820 | 'over.' % shared_axes) |
| 821 | if not shared_axes: |
| 822 | raise ValueError('there must have exactly one axis in common between ' |