Skip to content

Commit

Permalink
Merge pull request #225 from dincerguner/clip-impl
Browse files Browse the repository at this point in the history
implement clip
  • Loading branch information
raphaelDkhn authored Oct 6, 2023
2 parents e4893c0 + db7c2ce commit a1af0e4
Show file tree
Hide file tree
Showing 44 changed files with 10,882 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
* [tensor.nonzero](framework/operators/tensor/tensor.nonzero.md)
* [tensor.squeeze](framework/operators/tensor/tensor.squeeze.md)
* [tensor.unsqueeze](framework/operators/tensor/tensor.unsqueeze.md)
* [tensor.clip](framework/operators/tensor/tensor.clip.md)
* [Neural Network](framework/operators/neural-network/README.md)
* [nn.relu](framework/operators/neural-network/nn.relu.md)
* [nn.leaky\_relu](framework/operators/neural-network/nn.leaky\_relu.md)
Expand Down
3 changes: 2 additions & 1 deletion docs/framework/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ You can see below the list of current supported ONNX Operators:
| [Nonzero](operators/tensor/tensor.nonzero.md) | :white\_check\_mark: |
| [Squeeze](operators/tensor/tensor.squeeze.md) | :white\_check\_mark: |
| [Unsqueeze](operators/tensor/tensor.unsqueeze.md) | :white\_check\_mark: |
| [Clip](operators/tensor/tensor.clip.md) | :white\_check\_mark: |

Current Operators support: **49/156 (31%)**
Current Operators support: **50/156 (32%)**
1 change: 1 addition & 0 deletions docs/framework/operators/tensor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use orion::operators::tensor::TensorTrait;
| [`tensor.nonzero`](tensor.nonzero.md) | Produces indices of the elements that are non-zero (in row-major order - by dimension). |
| [`tensor.squeeze`](tensor.squeeze.md) | Removes dimensions of size 1 from the shape of a tensor. |
| [`tensor.unsqueeze`](tensor.unsqueeze.md) | Inserts single-dimensional entries to the shape of an input tensor. |
| [`tensor.clip`](tensor.clip.md) | Clip operator limits the given input within an interval. |

## Arithmetic Operations

Expand Down
39 changes: 39 additions & 0 deletions docs/framework/operators/tensor/tensor.clip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# tensor.clip

```rust
fn clip(self: @Tensor<T>, min: T, max: T) -> Tensor<T>;
```

Clip operator limits the given input within an interval.

## Args

* `self`(`@Tensor<T>`) - Input tensor whose elements to be clipped.
* `min`(`Option<T>`) - Minimum value, under which element is replaced by min.
* `max`(`Option<T>`) - Maximum value, above which element is replaced by max.

## Returns

Output `Tensor<T>` with clipped input elements.

## Example

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

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

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

return tensor.clip(
min: Option::None(()),
max: Option::Some(3),
);
}
>>> [[1. 2. 3.]
[3. 3. 3.]]
```
155 changes: 155 additions & 0 deletions nodegen/node/clip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import numpy as np
from nodegen.node import RunAll
from ..helpers import make_node, make_test, to_fp, Tensor, Dtype, FixedImpl


class Clip(RunAll):
@staticmethod
def clip_u32():
def clip_2D():
x = np.random.randint(0, 255, (2, 4)).astype(np.uint32)
y = np.clip(x, np.uint32(10), np.uint32(20))

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

name = "clip_u32_2d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(u32 { mag: 10, sign: false }), Option::Some(u32 { mag: 20, sign: false }))", name)

def clip_3D():
x = np.random.randint(0, 255, (20, 10, 5)).astype(np.uint32)
y = np.clip(x, np.uint32(10), np.uint32(20))

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

name = "clip_u32_3d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(u32 { mag: 10, sign: false }), Option::Some(u32 { mag: 20, sign: false }))", name)

clip_2D()
clip_3D()

@staticmethod
def clip_i32():
def clip_2D():
x = np.random.randint(-127, 127, (2, 4)).astype(np.int32)
y = np.clip(x, np.int32(-10), np.int32(20))

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

name = "clip_i32_2d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(i32 { mag: 10, sign: true }), Option::Some(i32 { mag: 20, sign: false }))", name)

def clip_3D():
x = np.random.randint(-127, 127, (20, 10, 5)).astype(np.int32)
y = np.clip(x, np.int32(-10), np.int32(20))

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

name = "clip_i32_3d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(i32 { mag: 10, sign: true }), Option::Some(i32 { mag: 20, sign: false }))", name)


clip_2D()
clip_3D()

@staticmethod
def clip_i8():
def clip_2D():
x = np.random.randint(-127, 127, (2, 4)).astype(np.int8)
y = np.clip(x, np.int8(-10), np.int8(20))

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

name = "clip_i8_2d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(i8 { mag: 10, sign: true }), Option::Some(i8 { mag: 20, sign: false }))", name)

def clip_3D():
x = np.random.randint(-127, 127, (20, 10, 5)).astype(np.int8)
y = np.clip(x, np.int8(-10), np.int8(20))

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

name = "clip_i8_3d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(i8 { mag: 10, sign: true }), Option::Some(i8 { mag: 20, sign: false }))", name)

clip_2D()
clip_3D()

@staticmethod
def clip_fp8x23():
def clip_2D():
x = to_fp(np.random.randint(-127, 127, (2, 4)
).astype(np.int64), FixedImpl.FP8x23)
y = np.clip(x, to_fp(np.int64(-10), FixedImpl.FP8x23), to_fp(np.int64(20), FixedImpl.FP8x23))

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

name = "clip_fp8x23_2d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(FP8x23 { mag: 83886080, sign: true }), Option::Some(FP8x23 { mag: 167772160, sign: false }))", name)

def clip_3D():
x = to_fp(np.random.randint(-127, 127, (20, 10, 5)
).astype(np.int64), FixedImpl.FP8x23)
y = np.clip(x, to_fp(np.int64(-10), FixedImpl.FP8x23), to_fp(np.int64(20), FixedImpl.FP8x23))

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

name = "clip_fp8x23_3d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(FP8x23 { mag: 83886080, sign: true }), Option::Some(FP8x23 { mag: 167772160, sign: false }))", name)

clip_2D()
clip_3D()

@staticmethod
def clip_fp16x16():
def clip_2D():
x = to_fp(np.random.randint(-127, 127, (2, 4)
).astype(np.int64), FixedImpl.FP16x16)
y = np.clip(x, to_fp(np.int64(-10), FixedImpl.FP16x16), to_fp(np.int64(20), FixedImpl.FP16x16))

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

name = "clip_fp16x16_2d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(FP16x16 { mag: 655360, sign: true }), Option::Some(FP16x16 { mag: 1310720, sign: false }))", name)

def clip_3D():
x = to_fp(np.random.randint(-127, 127, (20, 10, 5)
).astype(np.int64), FixedImpl.FP16x16)
y = np.clip(x, to_fp(np.int64(-10), FixedImpl.FP16x16), to_fp(np.int64(20), FixedImpl.FP16x16))

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

name = "clip_fp16x16_3d"
make_node([x], [y], name)
make_test(
[x], y, "input_0.clip(Option::Some(FP16x16 { mag: 655360, sign: true }), Option::Some(FP16x16 { mag: 1310720, sign: false }))", name)

clip_2D()
clip_3D()
80 changes: 80 additions & 0 deletions src/operators/tensor/core.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2597,6 +2597,47 @@ trait TensorTrait<T> {
self: @Tensor<T>,
axes: Option<Span<i32>>
) -> Tensor<T>;
/// # tensor.clip
///
/// ```rust
/// fn clip(self: @Tensor<T>, min: T, max: T) -> Tensor<T>;
/// ```
///
/// Clip operator limits the given input within an interval.
///
/// ## Args
///
/// * `self`(`@Tensor<T>`) - Input tensor whose elements to be clipped.
/// * `min`(`Option<T>`) - Minimum value, under which element is replaced by min.
/// * `max`(`Option<T>`) - Maximum value, above which element is replaced by max.
///
/// ## Returns
///
/// Output `Tensor<T>` with clipped input elements.
///
/// ## Example
///
/// ```rust
/// use array::{ArrayTrait, SpanTrait};
///
/// use orion::operators::tensor::{TensorTrait, Tensor, U32Tensor};
///
/// fn clip_example() -> Tensor<u32> {
/// let tensor = TensorTrait::<u32>::new(
/// shape: array![2, 3].span(),
/// data: array![[ 1, 2, 3],[4, 5, 6]].span(),
/// );
///
/// return tensor.clip(
/// min: Option::None(()),
/// max: Option::Some(3),
/// );
/// }
/// >>> [[1. 2. 3.]
/// [3. 3. 3.]]
/// ```
///
fn clip(self: @Tensor<T>, min: Option<T>, max: Option<T>) -> Tensor<T>;
}


Expand Down Expand Up @@ -3079,3 +3120,42 @@ fn unsqueeze<T>(self: @Tensor<T>, axes: Span<usize>) -> Tensor<T> {

return Tensor::<T> { shape: output_shape.span(), data: *self.data };
}
/// Cf: TensorTrait::clip docstring
fn clip<T, MAG, impl TCopy: Copy<T>, impl TDrop: Drop<T>, impl TTensor: TensorTrait<T>, impl TPartialOrd: PartialOrd<T>, impl TNumber: NumberTrait<T, MAG>>(self: @Tensor<T>, min: Option<T>, max: Option<T>) -> Tensor<T> {
let min = match min {
Option::Some(min) => min,
Option::None(_) => {
NumberTrait::min_value()
},
};
let max = match max {
Option::Some(max) => max,
Option::None(_) => {
NumberTrait::max_value()
},
};

let mut return_data: Array<T> = ArrayTrait::new();
let mut self_data_copy = *self.data;

loop {
match self_data_copy.pop_front() {
Option::Some(val) => {
if *val < min {
return_data.append(min);
}
else if *val > max {
return_data.append(max);
}
else {
return_data.append(*val);
}
},
Option::None(_) => {
break ();
}
};
};

return Tensor::<T> {shape: *self.shape, data: return_data.span()};
}
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp16x16.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ impl FP16x16Tensor of TensorTrait<FP16x16> {
fn unsqueeze(self: @Tensor<FP16x16>, axes: Span<usize>) -> Tensor<FP16x16> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<FP16x16>, min: Option<FP16x16>, max: Option<FP16x16>) -> Tensor<FP16x16> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<FP16x16>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp32x32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ impl FP32x32Tensor of TensorTrait<FP32x32> {
fn unsqueeze(self: @Tensor<FP32x32>, axes: Span<usize>) -> Tensor<FP32x32> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<FP32x32>, min: Option<FP32x32>, max: Option<FP32x32>) -> Tensor<FP32x32> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<FP32x32>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp64x64.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ impl FP64x64Tensor of TensorTrait<FP64x64> {
fn unsqueeze(self: @Tensor<FP64x64>, axes: Span<usize>) -> Tensor<FP64x64> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<FP64x64>, min: Option<FP64x64>, max: Option<FP64x64>) -> Tensor<FP64x64> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<FP64x64>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp8x23.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ impl FP8x23Tensor of TensorTrait<FP8x23> {
fn unsqueeze(self: @Tensor<FP8x23>, axes: Span<usize>) -> Tensor<FP8x23> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<FP8x23>, min: Option<FP8x23>, max: Option<FP8x23>) -> Tensor<FP8x23> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<FP8x23>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_i32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ impl I32Tensor of TensorTrait<i32> {
fn unsqueeze(self: @Tensor<i32>, axes: Span<usize>) -> Tensor<i32> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<i32>, min: Option<i32>, max: Option<i32>) -> Tensor<i32> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<i32>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_i8.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ impl I8Tensor of TensorTrait<i8> {
fn unsqueeze(self: @Tensor<i8>, axes: Span<usize>) -> Tensor<i8> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<i8>, min: Option<i8>, max: Option<i8>) -> Tensor<i8> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<i8>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_u32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ impl U32Tensor of TensorTrait<u32> {
fn unsqueeze(self: @Tensor<u32>, axes: Span<usize>) -> Tensor<u32> {
core::unsqueeze(self, axes)
}

fn clip(self: @Tensor<u32>, min: Option<u32>, max: Option<u32>) -> Tensor<u32> {
core::clip(self, min, max)
}
}

/// Implements addition for `Tensor<u32>` using the `Add` trait.
Expand Down
Loading

0 comments on commit a1af0e4

Please sign in to comment.