Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: SequenceErase #461

Merged
merged 5 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
* [tensor.shrink](framework/operators/tensor/tensor.shrink.md)
* [tensor.sequence\_empty](framework/operators/tensor/tensor.sequence\_empty.md)
* [tensor.reduce_mean](framework/operators/tensor/tensor.reduce\_mean.md)
* [tensor.sequence\_erase](framework/operators/tensor/tensor.sequence\_erase.md)
* [tensor.sequence\_insert](framework/operators/tensor/tensor.sequence\_insert.md)
* [Neural Network](framework/operators/neural-network/README.md)
* [nn.relu](framework/operators/neural-network/nn.relu.md)
Expand Down
1 change: 1 addition & 0 deletions docs/framework/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ You can see below the list of current supported ONNX Operators:
| [Shrink](operators/tensor/tensor.shrink.md) | :white\_check\_mark: |
| [SequenceEmpty](operators/tensor/tensor.sequence\_empty.md) | :white\_check\_mark: |
| [ReduceL2](operators/tensor/tensor.reduce\_l2.md) | :white\_check\_mark: |
| [SequenceErase](operators/tensor/tensor.sequence\_erase.md) | :white\_check\_mark: |
| [SequenceInsert](operators/tensor/tensor.sequence\_insert.md) | :white\_check\_mark: |

Current Operators support: **82/156 (53%)**
1 change: 1 addition & 0 deletions docs/framework/operators/tensor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ use orion::operators::tensor::TensorTrait;
| [`tensor.sequence_construct`](tensor.sequence\_construct.md) | Constructs a tensor sequence containing the input tensors. |
| [`tensor.shrink`](tensor.shrink.md) | Shrinks the input tensor element-wise to the output tensor. |
| [`tensor.reduce_mean`](tensor.reduce\_mean.md) | Computes the mean of the input tensor's elements along the provided axes. |
| [`tensor.sequence_erase`](tensor.sequence\_erase.md) | Outputs the tensor sequence with the erased tensor at the specified position. |
| [`tensor.sequence_empty`](tensor.sequence\_empty.md) | Returns an empty tensor sequence. |
| [`tensor.binarizer`](tensor.binarizer.md) | Maps the values of a tensor element-wise to 0 or 1 based on the comparison against a threshold value. |
| [`tensor.array_feature_extractor`](tensor.array\_feature\_extractor.md) | Selects elements of the input tensor based on the indices passed applied to the last tensor axis. |
Expand Down
47 changes: 47 additions & 0 deletions docs/framework/operators/tensor/tensor.sequence_erase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## tensor.sequence_erase

```rust
fn sequence_erase(sequence: Array<Tensor<T>>, position: Option<Tensor<i32>>) -> Array<Tensor<T>>;
```

Outputs the tensor sequence with the erased tensor at the specified position.

## Args

* `tensors`(`Array<Tensor<T>>`) - The tensor sequence.
* `position`(`Option<Tensor<i32>>`) - The optional position tensor (by default erases the last tensor).

## Panics

* Panics if position is not a scalar
* Panics if position is out of bounds [-n, n - 1]

## Returns

The tensor sequence `Array<Tensor<T>>` with the erased tensor at the specified position.

## Examples

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

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

fn sequence_erase_example() -> Tensor<u32> {
let tensor1 = TensorTrait::new(shape: array![2, 2].span(), data: array![0, 1, 2, 3].span());
let tensor2 = TensorTrait::new(shape: array![2, 2].span(), data: array![4, 5, 6, 7].span());
let tensor3 = TensorTrait::new(shape: array![2, 2].span(), data: array![8, 9, 10, 11].span());

let mut sequence = ArrayTrait::new();
sequence.append(tensor1);
sequence.append(tensor2);
sequence.append(tensor3);

let position = TensorTrait::new(shape: array![].span(), data: array![IntegerTrait::new(1, false)].span());

let result = TensorTrait::sequence_erase(sequence, position);
return result;
}
>>> [[0, 1, 2, 3], [8, 9, 10, 11]]
```
303 changes: 303 additions & 0 deletions nodegen/node/sequence_erase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
import numpy as np
from nodegen.node import RunAll
from ..helpers import make_test, to_fp, Tensor, Dtype, FixedImpl


scalar = lambda x: Tensor(Dtype.I32, (), np.array([x]).astype(np.int32).flatten())


class Sequence_erase(RunAll):

@staticmethod
def sequence_erase_u32():
def positive_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(0, 6, shape).astype(np.uint32)
tensor = Tensor(Dtype.U32, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(2)

output_sequence = sequence.copy()
output_sequence.pop(2)

name = "sequence_erase_u32_positive"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def negative_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(0, 6, shape).astype(np.uint32)
tensor = Tensor(Dtype.U32, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(-2)

output_sequence = sequence.copy()
output_sequence.pop(-2)

name = "sequence_erase_u32_negative"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def empty_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(0, 6, shape).astype(np.uint32)
tensor = Tensor(Dtype.U32, values.shape, values.flatten())

sequence.append(tensor)

output_sequence = sequence.copy()
output_sequence.pop(-1)

name = "sequence_erase_u32_empty"
make_test([sequence], output_sequence, "TensorTrait::sequence_erase(input_0, Option::None(()))", name)

positive_position()
negative_position()
empty_position()


@staticmethod
def sequence_erase_i32():
def positive_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int32)
tensor = Tensor(Dtype.I32, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(2)

output_sequence = sequence.copy()
output_sequence.pop(2)

name = "sequence_erase_i32_positive"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def negative_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int32)
tensor = Tensor(Dtype.I32, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(-2)

output_sequence = sequence.copy()
output_sequence.pop(-2)

name = "sequence_erase_i32_negative"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def empty_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int32)
tensor = Tensor(Dtype.I32, values.shape, values.flatten())

sequence.append(tensor)

output_sequence = sequence.copy()
output_sequence.pop(-1)

name = "sequence_erase_i32_empty"
make_test([sequence], output_sequence, "TensorTrait::sequence_erase(input_0, Option::None(()))", name)

positive_position()
negative_position()
empty_position()


@staticmethod
def sequence_erase_i8():
def positive_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int8)
tensor = Tensor(Dtype.I8, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(2)

output_sequence = sequence.copy()
output_sequence.pop(2)

name = "sequence_erase_i8_positive"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def negative_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int8)
tensor = Tensor(Dtype.I8, values.shape, values.flatten())

sequence.append(tensor)

position = scalar(-2)

output_sequence = sequence.copy()
output_sequence.pop(-2)

name = "sequence_erase_i8_negative"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def empty_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.int8)
tensor = Tensor(Dtype.I8, values.shape, values.flatten())

sequence.append(tensor)

output_sequence = sequence.copy()
output_sequence.pop(-1)

name = "sequence_erase_i8_empty"
make_test([sequence], output_sequence, "TensorTrait::sequence_erase(input_0, Option::None(()))", name)

positive_position()
negative_position()
empty_position()


@staticmethod
def sequence_erase_fp8x23():
def positive_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP8x23, values.shape, to_fp(values.flatten(), FixedImpl.FP8x23))

sequence.append(tensor)

position = scalar(2)

output_sequence = sequence.copy()
output_sequence.pop(2)

name = "sequence_erase_fp8x23_positive"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def negative_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP8x23, values.shape, to_fp(values.flatten(), FixedImpl.FP8x23))

sequence.append(tensor)

position = scalar(-2)

output_sequence = sequence.copy()
output_sequence.pop(-2)

name = "sequence_erase_fp8x23_negative"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def empty_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP8x23, values.shape, to_fp(values.flatten(), FixedImpl.FP8x23))

sequence.append(tensor)

output_sequence = sequence.copy()
output_sequence.pop(-1)

name = "sequence_erase_fp8x23_empty"
make_test([sequence], output_sequence, "TensorTrait::sequence_erase(input_0, Option::None(()))", name)

positive_position()
negative_position()
empty_position()


@staticmethod
def sequence_erase_fp16x16():
def positive_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP16x16, values.shape, to_fp(values.flatten(), FixedImpl.FP16x16))

sequence.append(tensor)

position = scalar(2)

output_sequence = sequence.copy()
output_sequence.pop(2)

name = "sequence_erase_fp16x16_positive"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def negative_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP16x16, values.shape, to_fp(values.flatten(), FixedImpl.FP16x16))

sequence.append(tensor)

position = scalar(-2)

output_sequence = sequence.copy()
output_sequence.pop(-2)

name = "sequence_erase_fp16x16_negative"
make_test([sequence, position], output_sequence, "TensorTrait::sequence_erase(input_0, Option::Some(input_1))", name)

def empty_position():
sequence = []
shape = np.random.randint(1, 4, 2)

for _ in range(5):
values = np.random.randint(-6, 6, shape).astype(np.float64)
tensor = Tensor(Dtype.FP16x16, values.shape, to_fp(values.flatten(), FixedImpl.FP16x16))

sequence.append(tensor)

output_sequence = sequence.copy()
output_sequence.pop(-1)

name = "sequence_erase_fp16x16_empty"
make_test([sequence], output_sequence, "TensorTrait::sequence_erase(input_0, Option::None(()))", name)

positive_position()
negative_position()
empty_position()
Loading