-
Notifications
You must be signed in to change notification settings - Fork 2
Add commonly-used methods on tensors #164
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
base: main
Are you sure you want to change the base?
Changes from all commits
fb87b5e
92fe377
0e9e213
24b73aa
9344c83
e15a720
713ba93
754f033
1e07bda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package dimwit.tensor.tensorops | ||
|
|
||
| import dimwit.jax.Jax | ||
| import dimwit.tensor.Axis | ||
| import dimwit.tensor.DType.Int32 | ||
| import dimwit.tensor.Label | ||
| import dimwit.tensor.Labels | ||
| import dimwit.tensor.ShapeTypeHelpers.AxisIndex | ||
| import dimwit.tensor.ShapeTypeHelpers.AxisIndices | ||
| import dimwit.tensor.ShapeTypeHelpers.UnwrapAxes | ||
| import dimwit.tensor.Tensor | ||
| import dimwit.tensor.Tensor1 | ||
| import dimwit.tensor.TensorOps.IsFloating | ||
| import dimwit.tensor.TensorOps.IsNumber | ||
| import me.shadaj.scalapy.py.SeqConverters | ||
| import dimwit.tensor.tensorops.FunctionalOps.vapply | ||
|
|
||
| /** Operations along an axis that keep all axes of the tensor (unlike reductions, which remove them). */ | ||
| object AlongAxisOps: | ||
|
|
||
| extension [T <: Tuple: Labels, V](t: Tensor[T, V]) | ||
|
|
||
| /** rolls the elements of `t` along the specified axis by `shift` positions. */ | ||
| def roll[L: Label](axis: Axis[L], shift: Int)(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.roll(shift)) | ||
|
|
||
| extension [T <: Tuple: Labels, V: IsNumber](t: Tensor[T, V]) | ||
|
|
||
| /** Returns a tensor of indices that would sort `t` along the specified axes */ | ||
| def argsort[Inputs <: Tuple](axes: Inputs)(using ev: AxisIndices[T, UnwrapAxes[Inputs]]): Tensor[T, Int32] = Tensor(Jax.jnp.argsort(t.jaxValue, axis = ev.indices.toPythonProxy)) | ||
| def argsort[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, Int32] = | ||
| t.vapply(axis)(Tensor1.argsort) | ||
| def argsort: Tensor[T, Int32] = Tensor(Jax.jnp.argsort(t.jaxValue)) | ||
|
|
||
| /** sorts the tensor `t` along the specified axis */ | ||
| def sort[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.sort) | ||
| def sort: Tensor[T, V] = Tensor(Jax.jnp.sort(t.jaxValue)) | ||
|
|
||
| /** computes the cumulative sum of the tensor `t` along the specified axis. */ | ||
| def cumsum[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.cumsum) | ||
|
|
||
| /** computes the cumulative product of the tensor `t` along the specified axis. */ | ||
| def cumprod[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.cumprod) | ||
|
|
||
| /** computes the cumulative maximum of the tensor `t` along the specified axis. */ | ||
| def cummax[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.cummax) | ||
|
|
||
| /** computes the cumulative minimum of the tensor `t` along the specified axis. */ | ||
| def cummin[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.cummin) | ||
|
|
||
| /** computes the discrete difference of the tensor `t` along the specified axis, reducing that axis' size by one. */ | ||
| def diff[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.diff) | ||
|
|
||
| extension [T <: Tuple: Labels, V: IsFloating](t: Tensor[T, V]) | ||
|
|
||
| /** computes the cumulative log-sum-exp of the tensor `t` along the specified axis. */ | ||
| def logcumsumexp[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.logcumsumexp) | ||
|
|
||
| /** computes the softmax of `t` along the specified axis. */ | ||
| def softmax[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.softmax) | ||
|
|
||
| /** computes the log-softmax of `t` along the specified axis. */ | ||
| def logSoftmax[L: Label](axis: Axis[L])(using AxisIndex[T, L]): Tensor[T, V] = | ||
| t.vapply(axis)(Tensor1.logSoftmax) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -126,12 +126,19 @@ object ElementWiseOps: | |
| /** Multiplies each element of a tensor by a scalar tensor, returning a new tensor. */ | ||
| def multiplyScalar[T <: Tuple: Labels, V: IsNumber](t1: Tensor[T, V], s: Tensor0[V]): Tensor[T, V] = Tensor(Jax.jnp.multiply(t1.jaxValue, s.jaxValue)) | ||
|
|
||
| /** Computes the element-wise remainder of `t1 / t2`, matching Python's `%` operator (the result takes the sign of the divisor). */ | ||
| def mod[T <: Tuple: Labels, V: IsNumber](t1: Tensor[T, V], t2: Tensor[T, V]): Tensor[T, V] = Tensor(Jax.jnp.mod(t1.jaxValue, t2.jaxValue)) | ||
|
|
||
| /** Computes the remainder of dividing each element of a tensor by a scalar tensor. */ | ||
| def modScalar[T <: Tuple: Labels, V: IsNumber](t1: Tensor[T, V], s: Tensor0[V]): Tensor[T, V] = Tensor(Jax.jnp.mod(t1.jaxValue, s.jaxValue)) | ||
|
|
||
| // extension methods for the binary operations on two tensors | ||
| extension [T <: Tuple: Labels, V: IsNumber](t: Tensor[T, V]) | ||
|
|
||
| def +(other: Tensor[T, V]): Tensor[T, V] = add(t, other) | ||
| def -(other: Tensor[T, V]): Tensor[T, V] = subtract(t, other) | ||
| def *(other: Tensor[T, V]): Tensor[T, V] = multiply(t, other) | ||
| def %(other: Tensor[T, V]): Tensor[T, V] = mod(t, other) | ||
|
|
||
| // extension methods for the scalar operations. | ||
| extension [T <: Tuple: Labels, V: IsNumber](t: Tensor[T, V]) | ||
|
|
@@ -143,6 +150,7 @@ object ElementWiseOps: | |
|
|
||
| def *(using bc: Broadcast[T, O, V]): Tensor[bc.Out, V] = bc.applyTo(t, other)(multiply) | ||
| def scale(other: Tensor0[V]): Tensor[T, V] = multiplyScalar(t, other) | ||
| def %(using bc: Broadcast[T, O, V]): Tensor[bc.Out, V] = bc.applyTo(t, other)(mod) | ||
|
|
||
| // extension methods | ||
| extension [T <: Tuple: Labels, V: IsNumber](t: Tensor[T, V]) | ||
|
benikm91 marked this conversation as resolved.
|
||
|
|
@@ -173,6 +181,31 @@ object ElementWiseOps: | |
| def sin: Tensor[T, V] = Tensor(Jax.jnp.sin(t.jaxValue)) | ||
| def cos: Tensor[T, V] = Tensor(Jax.jnp.cos(t.jaxValue)) | ||
| def tanh: Tensor[T, V] = Tensor(Jax.jnp.tanh(t.jaxValue)) | ||
| def arcsin: Tensor[T, V] = Tensor(Jax.jnp.arcsin(t.jaxValue)) | ||
| def arccos: Tensor[T, V] = Tensor(Jax.jnp.arccos(t.jaxValue)) | ||
| def arctan: Tensor[T, V] = Tensor(Jax.jnp.arctan(t.jaxValue)) | ||
| def floor: Tensor[T, V] = Tensor(Jax.jnp.floor(t.jaxValue)) | ||
|
benikm91 marked this conversation as resolved.
|
||
| def ceil: Tensor[T, V] = Tensor(Jax.jnp.ceil(t.jaxValue)) | ||
| def round: Tensor[T, V] = Tensor(Jax.jnp.round(t.jaxValue)) | ||
| def isnan: Tensor[T, Bool] = Tensor(Jax.jnp.isnan(t.jaxValue)) | ||
| def isfinite: Tensor[T, Bool] = Tensor(Jax.jnp.isfinite(t.jaxValue)) | ||
|
|
||
| /** replaces NaN by `nan`, +inf by `posInf` and -inf by `negInf`. | ||
| * By default, NaN becomes 0 and ±inf become the largest/smallest finite value of the dtype. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment out-of-date. |
||
| */ | ||
| def nanToNum(using | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This IsFloating[V] can be removed. IsFloating evidence already in extention method. |
||
| IsFloating[V] | ||
| )( | ||
| nan: Tensor0[V], | ||
| posInf: Tensor0[V] = IsFloating[V].maxFinite, | ||
| negInf: Tensor0[V] = IsFloating[V].minFinite | ||
| ): Tensor[T, V] = | ||
| Tensor(Jax.jnp.nan_to_num(t.jaxValue, nan = nan.jaxValue, posinf = posInf.jaxValue, neginf = negInf.jaxValue)) | ||
|
|
||
| // activation functions | ||
| def sigmoid: Tensor[T, V] = Tensor(Jax.jnn.sigmoid(t.jaxValue)) | ||
| def relu: Tensor[T, V] = Tensor(Jax.jnn.relu(t.jaxValue)) | ||
| def gelu: Tensor[T, V] = Tensor(Jax.jnn.gelu(t.jaxValue)) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This changed syntax to |
||
|
|
||
| def approxEquals(other: Tensor[T, V], tolerance: Float = 1e-6f): Tensor0[Bool] = approxElementEquals(other, tolerance).all | ||
| def approxElementEquals(other: Tensor[T, V], tolerance: Float = 1e-6f): Tensor[T, Bool] = | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove default sort (last axis by convention).