Skip to content

Commit

Permalink
Merge pull request #479 from MahmoudMohajer/reduce-prod
Browse files Browse the repository at this point in the history
Feat: ReduceProd
  • Loading branch information
raphaelDkhn authored Nov 30, 2023
2 parents 69ecbb5 + dfe51ba commit 83735c1
Show file tree
Hide file tree
Showing 82 changed files with 1,657 additions and 57 deletions.
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] - 2023-11-27

## Added
- Reduce Prod Operator
-
## [Unreleased] - 2023-11-20

## Added
Expand Down
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
* [tensor.reduce\_sum\_square](framework/operators/tensor/tensor.reduce\_sum\_square.md)
* [tensor.reduce\_l2](framework/operators/tensor/tensor.reduce\_l2.md)
* [tensor.reduce\_l1](framework/operators/tensor/tensor.reduce\_l1.md)
* [tensor.reduce_prod](framework/operators/tensor/tensor.reduce_prod.md)
* [tensor.gather\_elements](framework/operators/tensor/tensor.gather\_elements.md)
* [tensor.sequence\_length](framework/operators/tensor/tensor.sequence\_length.md)
* [tensor.sequence\_at](framework/operators/tensor/tensor.sequence\_at.md)
Expand Down
3 changes: 2 additions & 1 deletion docs/framework/operators/tensor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use orion::operators::tensor::TensorTrait;
| [`tensor.min`](tensor.min.md) | Returns the minimum value in the tensor. |
| [`tensor.max`](tensor.max.md) | Returns the maximum value in the tensor. |
| [`tensor.reduce_sum`](tensor.reduce\_sum.md) | Reduces a tensor by summing its elements along a specified axis. |
| [`tensor.reduce_prod`](tensor.reduce\_prod.md) | Reduces a tensor to its products along specified axis. |
| [`tensor.argmax`](tensor.argmax.md) | Returns the index of the maximum value along the specified axis. |
| [`tensor.argmin`](tensor.argmin.md) | Returns the index of the minimum value along the specified axis. |
| [`tensor.cumsum`](tensor.cumsum.md) | Performs cumulative sum of the input elements along the given axis. |
Expand Down Expand Up @@ -105,7 +106,7 @@ use orion::operators::tensor::TensorTrait;
| [`tensor.reduce_l2`](tensor.reduce\_l2.md) | Computes the L2 norm of the input tensor's elements along the provided axes. |
| [`tensor.gather_elements`](tensor.gather\_elements.md) | GatherElements is an indexing operation that produces its output by indexing into the input data tensor at index positions determined by elements of the indices tensor. |
| [`tensor.reduce_min`](tensor.reduce\_min.md) | Computes the min of the input tensor's elements along the provided axes. |
| [`tensor.sequence_construct`](tensor.sequence\_construct.md) | Constructs a tensor sequence containing the input tensors. |
| [`tensor.sequence_empty`](tensor.sequence\_empty.md) | Returns an empty tensor sequence. |
| [`tensor.sequence_length`](tensor.sequence\_length.md) | Returns the length of the input sequence. |
| [`tensor.sequence_insert`](tensor.sequence\_insert.md) | Insert a tensor into a sequence. |
| [`tensor.sequence_at`](tensor.sequence\_at.md) | Outputs the tensor at the specified position in the input sequence. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ A new `Tensor<T>` of the same shape as the input tensor with selected elements b

```rust
use array::{ArrayTrait, SpanTrait};

use orion::operators::tensor::{TensorTrait, Tensor, I32Tensor, U32Tensor};
use orion::numbers::{i32, IntegerTrait};

Expand Down
3 changes: 1 addition & 2 deletions docs/framework/operators/tensor/tensor.is_inf.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ A new `Tensor<bool>` instance with entries set to true iff the input tensors cor
## Examples

```rust
use array::{ArrayTrait, SpanTrait};

use array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::{BoolTensor, TensorTrait, Tensor, U32Tensor};

fn is_inf_example() -> Tensor<bool> {
Expand Down
2 changes: 1 addition & 1 deletion docs/framework/operators/tensor/tensor.reduce_min.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn reduce_min_example() -> Tensor<u32> {
shape: array![2, 2, 2].span(), data: array![0, 1, 2, 3, 4, 5, 6, 7].span(),
);

// We can call `reduce_mean` function as follows.
// We can call `reduce_min` function as follows.
return tensor.reduce_min(axes: array![1].span(),
keepdims: Option::None(()),
noop_with_empty_axes: Option::None(()));
Expand Down
39 changes: 39 additions & 0 deletions docs/framework/operators/tensor/tensor.reduce_prod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## tensor.reduce_prod

```rust
fn reduce_prod(self: @Tensor<T>, axis: usize, keepdims: bool) -> Tensor<T>;
```

Reduces a tensor by multiplying its elements along a specified axis.

## Args

* `self`(`@Tensor<T>`) - The input tensor.
* `axis`(`usize`) - The dimension to reduce.
* `keepdims`(`bool`) - If true, retains reduced dimensions with length 1.

## Panics

* Panics if axis is not in the range of the input tensor's dimensions.

## Returns

A new `Tensor<T>` instance with the specified axis reduced by multiplying its elements.

## Examples

```rust
use array::{ArrayTrait, SpanTrait};

use orion::operators::tensor::{TensorTrait, Tensor, U32Tensor};

fn reduce_prod_example() -> Tensor<u32> {
let tensor = TensorTrait::<u32>::new(
shape: array![2, 2, 2].span(), data: array![0, 1, 2, 3, 4, 5, 6, 7].span(),
);

// We can call `reduce_prod` function as follows.
return tensor.reduce_prod(axis: 0, keepdims: false);
}
>>> [[0,5],[12,21]]
```
287 changes: 287 additions & 0 deletions nodegen/node/reduce_prod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import numpy as np
from nodegen.node import RunAll
from ..helpers import make_test, to_fp, Tensor, Dtype, FixedImpl


class Reduce_prod(RunAll):
@staticmethod
def reduce_prod_u32():
def reduce_prod_1D():
x = np.array([0, 1, 2,]).astype(np.uint32)
y = np.array([0]).astype(np.uint32)

x = Tensor(Dtype.U32, x.shape, x.flatten())
y = Tensor(Dtype.U32, y.shape, y.flatten())

name = "reduce_prod_u32_1D"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def reduce_prod_2D():
def default():
x = np.array([0, 1, 2, 3]).astype(np.uint32).reshape(2, 2)
y = np.array([0, 3]).astype(np.uint32)

x = Tensor(Dtype.U32, x.shape, x.flatten())
y = Tensor(Dtype.U32, y.shape, y.flatten())

name = "reduce_prod_u32_2D_default"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def keepdims():
x = np.array([0, 1, 2, 3]).astype(np.uint32).reshape(2, 2)
y = np.array([0, 3]).astype(np.uint32).reshape(1, 2)

x = Tensor(Dtype.U32, x.shape, x.flatten())
y = Tensor(Dtype.U32, y.shape, y.flatten())

name = "reduce_prod_u32_2D_keepdims"
make_test(
[x], y, "input_0.reduce_prod(0, true)", name)

def axis_1():
x = np.array([0, 1, 2, 3]).astype(np.uint32).reshape(2, 2)
y = np.array([0, 6]).astype(np.uint32)

x = Tensor(Dtype.U32, x.shape, x.flatten())
y = Tensor(Dtype.U32, y.shape, y.flatten())

name = "reduce_prod_u32_2D_axis_1"
make_test(
[x], y, "input_0.reduce_prod(1, false)", name)

default()
keepdims()
axis_1()
reduce_prod_1D()
reduce_prod_2D()

@staticmethod
def reduce_prod_i32():
def reduce_prod_1D():
x = np.array([0, 1, 2,]).astype(np.int32)
y = np.array([0]).astype(np.int32)

x = Tensor(Dtype.I32, x.shape, x.flatten())
y = Tensor(Dtype.I32, y.shape, y.flatten())

name = "reduce_prod_i32_1D"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def reduce_prod_2D():
def default():
x = np.array([0, 1, 2, 3]).astype(np.int32).reshape(2, 2)
y = np.array([0, 3]).astype(np.int32)

x = Tensor(Dtype.I32, x.shape, x.flatten())
y = Tensor(Dtype.I32, y.shape, y.flatten())

name = "reduce_prod_i32_2D_default"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def keepdims():
x = np.array([0, 1, 2, 3]).astype(np.int32).reshape(2, 2)
y = np.array([0, 3]).astype(np.int32).reshape(1, 2)

x = Tensor(Dtype.I32, x.shape, x.flatten())
y = Tensor(Dtype.I32, y.shape, y.flatten())

name = "reduce_prod_i32_2D_keepdims"
make_test(
[x], y, "input_0.reduce_prod(0, true)", name)

def axis_1():
x = np.array([0, 1, 2, 3]).astype(np.int32).reshape(2, 2)
y = np.array([0, 6]).astype(np.int32)

x = Tensor(Dtype.I32, x.shape, x.flatten())
y = Tensor(Dtype.I32, y.shape, y.flatten())

name = "reduce_prod_i32_2D_axis_1"
make_test(
[x], y, "input_0.reduce_prod(1, false)", name)

default()
keepdims()
axis_1()
reduce_prod_1D()
reduce_prod_2D()

@staticmethod
def reduce_prod_i8():
def reduce_prod_1D():
x = np.array([0, 1, 2,]).astype(np.int8)
y = np.array([0]).astype(np.int8)

x = Tensor(Dtype.FP8x23, x.shape, x.flatten())
y = Tensor(Dtype.FP8x23, y.shape, y.flatten())

name = "reduce_prod_i8_1D"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def reduce_prod_2D():
def default():
x = np.array([0, 1, 2, 3]).astype(np.int8).reshape(2, 2)
y = np.array([0, 3]).astype(np.int8)

x = Tensor(Dtype.FP8x23, x.shape, x.flatten())
y = Tensor(Dtype.FP8x23, y.shape, y.flatten())

name = "reduce_prod_i8_2D_default"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def keepdims():
x = np.array([0, 1, 2, 3]).astype(np.int8).reshape(2, 2)
y = np.array([0, 3]).astype(np.int8).reshape(1, 2)

x = Tensor(Dtype.FP8x23, x.shape, x.flatten())
y = Tensor(Dtype.FP8x23, y.shape, y.flatten())

name = "reduce_prod_i8_2D_keepdims"
make_test(
[x], y, "input_0.reduce_prod(0, true)", name)

def axis_1():
x = np.array([0, 1, 2, 3]).astype(np.int8).reshape(2, 2)
y = np.array([0, 6]).astype(np.int8)
x = Tensor(Dtype.FP8x23, x.shape, x.flatten())
y = Tensor(Dtype.FP8x23, y.shape, y.flatten())

name = "reduce_prod_i8_2D_axis_1"
make_test(
[x], y, "input_0.reduce_prod(1, false)", name)

default()
keepdims()
axis_1()
reduce_prod_1D()
reduce_prod_2D()

@staticmethod
def reduce_prod_fp8x23():
def reduce_prod_1D():
x = np.array([0, 1, 2,]).astype(np.int64)
y = np.array([0]).astype(np.int64)

x = Tensor(Dtype.FP8x23, x.shape, to_fp(
x.flatten(), FixedImpl.FP8x23))
y = Tensor(Dtype.FP8x23, y.shape, to_fp(
y.flatten(), FixedImpl.FP8x23))

name = "reduce_prod_fp8x23_1D"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def reduce_prod_2D():
def default():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 3]).astype(np.int64)

x = Tensor(Dtype.FP8x23, x.shape, to_fp(
x.flatten(), FixedImpl.FP8x23))
y = Tensor(Dtype.FP8x23, y.shape, to_fp(
y.flatten(), FixedImpl.FP8x23))

name = "reduce_prod_fp8x23_2D_default"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def keepdims():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 3]).astype(np.int64).reshape(1, 2)

x = Tensor(Dtype.FP8x23, x.shape, to_fp(
x.flatten(), FixedImpl.FP8x23))
y = Tensor(Dtype.FP8x23, y.shape, to_fp(
y.flatten(), FixedImpl.FP8x23))

name = "reduce_prod_fp8x23_2D_keepdims"
make_test(
[x], y, "input_0.reduce_prod(0, true)", name)

def axis_1():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 6]).astype(np.int64)

x = Tensor(Dtype.FP8x23, x.shape, to_fp(
x.flatten(), FixedImpl.FP8x23))
y = Tensor(Dtype.FP8x23, y.shape, to_fp(
y.flatten(), FixedImpl.FP8x23))

name = "reduce_prod_fp8x23_2D_axis_1"
make_test(
[x], y, "input_0.reduce_prod(1, false)", name)

default()
keepdims()
axis_1()

reduce_prod_1D()
reduce_prod_2D()

@staticmethod
def reduce_prod_fp16x16():
def reduce_prod_1D():
x = np.array([0, 1, 2,]).astype(np.int64)
y = np.array([0]).astype(np.int64)

x = Tensor(Dtype.FP16x16, x.shape, to_fp(
x.flatten(), FixedImpl.FP16x16))
y = Tensor(Dtype.FP16x16, y.shape, to_fp(
y.flatten(), FixedImpl.FP16x16))

name = "reduce_prod_fp16x16_1D"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def reduce_prod_2D():
def default():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 3]).astype(np.int64)

x = Tensor(Dtype.FP16x16, x.shape, to_fp(
x.flatten(), FixedImpl.FP16x16))
y = Tensor(Dtype.FP16x16, y.shape, to_fp(
y.flatten(), FixedImpl.FP16x16))

name = "reduce_prod_fp16x16_2D_default"
make_test(
[x], y, "input_0.reduce_prod(0, false)", name)

def keepdims():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 3]).astype(np.int64).reshape(1, 2)

x = Tensor(Dtype.FP16x16, x.shape, to_fp(
x.flatten(), FixedImpl.FP16x16))
y = Tensor(Dtype.FP16x16, y.shape, to_fp(
y.flatten(), FixedImpl.FP16x16))

name = "reduce_prod_fp16x16_2D_keepdims"
make_test(
[x], y, "input_0.reduce_prod(0, true)", name)

def axis_1():
x = np.array([0, 1, 2, 3]).astype(np.int64).reshape(2, 2)
y = np.array([0, 6]).astype(np.int64)

x = Tensor(Dtype.FP16x16, x.shape, to_fp(
x.flatten(), FixedImpl.FP16x16))
y = Tensor(Dtype.FP16x16, y.shape, to_fp(
y.flatten(), FixedImpl.FP16x16))

name = "reduce_prod_fp16x16_2D_axis_1"
make_test(
[x], y, "input_0.reduce_prod(1, false)", name)

default()
keepdims()
axis_1()

reduce_prod_1D()
reduce_prod_2D()
Loading

0 comments on commit 83735c1

Please sign in to comment.