chore: import upstream snapshot with attribution
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
from prml.nn.array.broadcast import broadcast_to
|
||||
from prml.nn.array.flatten import flatten
|
||||
from prml.nn.array.reshape import reshape, reshape_method
|
||||
from prml.nn.array.split import split
|
||||
from prml.nn.array.transpose import transpose, transpose_method
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
|
||||
|
||||
Tensor.flatten = flatten
|
||||
Tensor.reshape = reshape_method
|
||||
Tensor.transpose = transpose_method
|
||||
|
||||
__all__ = [
|
||||
"broadcast_to",
|
||||
"flatten",
|
||||
"reshape",
|
||||
"split",
|
||||
"transpose"
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
import numpy as np
|
||||
from prml.nn.tensor.constant import Constant
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
from prml.nn.function import Function
|
||||
|
||||
|
||||
class BroadcastTo(Function):
|
||||
"""
|
||||
Broadcast a tensor to an new shape
|
||||
"""
|
||||
|
||||
def forward(self, x, shape):
|
||||
x = self._convert2tensor(x)
|
||||
self.x = x
|
||||
output = np.broadcast_to(x.value, shape)
|
||||
if isinstance(self.x, Constant):
|
||||
return Constant(output)
|
||||
return Tensor(output, function=self)
|
||||
|
||||
def backward(self, delta):
|
||||
dx = delta
|
||||
if delta.ndim != self.x.ndim:
|
||||
dx = dx.sum(axis=tuple(range(dx.ndim - self.x.ndim)))
|
||||
if isinstance(dx, np.number):
|
||||
dx = np.array(dx)
|
||||
axis = tuple(i for i, len_ in enumerate(self.x.shape) if len_ == 1)
|
||||
if axis:
|
||||
dx = dx.sum(axis=axis, keepdims=True)
|
||||
self.x.backward(dx)
|
||||
|
||||
|
||||
def broadcast_to(x, shape):
|
||||
"""
|
||||
Broadcast a tensor to an new shape
|
||||
"""
|
||||
return BroadcastTo().forward(x, shape)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
from prml.nn.tensor.constant import Constant
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
from prml.nn.function import Function
|
||||
|
||||
|
||||
class Flatten(Function):
|
||||
"""
|
||||
flatten array
|
||||
"""
|
||||
|
||||
def forward(self, x):
|
||||
x = self._convert2tensor(x)
|
||||
self._atleast_ndim(x, 2)
|
||||
self.x = x
|
||||
if isinstance(self.x, Constant):
|
||||
return Constant(x.value.flatten())
|
||||
return Tensor(x.value.flatten(), function=self)
|
||||
|
||||
def backward(self, delta):
|
||||
dx = delta.reshape(*self.x.shape)
|
||||
self.x.backward(dx)
|
||||
|
||||
|
||||
def flatten(x):
|
||||
"""
|
||||
flatten N-dimensional array (N >= 2)
|
||||
"""
|
||||
return Flatten().forward(x)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
from prml.nn.tensor.constant import Constant
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
from prml.nn.function import Function
|
||||
|
||||
|
||||
class Reshape(Function):
|
||||
"""
|
||||
reshape array
|
||||
"""
|
||||
|
||||
def forward(self, x, shape):
|
||||
x = self._convert2tensor(x)
|
||||
self._atleast_ndim(x, 1)
|
||||
self.x = x
|
||||
if isinstance(self.x, Constant):
|
||||
return Constant(x.value.reshape(*shape))
|
||||
return Tensor(x.value.reshape(*shape), function=self)
|
||||
|
||||
def backward(self, delta):
|
||||
dx = delta.reshape(*self.x.shape)
|
||||
self.x.backward(dx)
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
"""
|
||||
reshape N-dimensional array (N >= 1)
|
||||
"""
|
||||
return Reshape().forward(x, shape)
|
||||
|
||||
|
||||
def reshape_method(x, *args):
|
||||
return Reshape().forward(x, args)
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import numpy as np
|
||||
from prml.nn.tensor.constant import Constant
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
from prml.nn.function import Function
|
||||
|
||||
|
||||
class Nth(Function):
|
||||
|
||||
def __init__(self, n):
|
||||
self.n = n
|
||||
|
||||
def forward(self, x):
|
||||
self.x = x
|
||||
if isinstance(self.x, Constant):
|
||||
return Constant(x.value)
|
||||
return Tensor(x.value, function=self)
|
||||
|
||||
def backward(self, delta):
|
||||
self.x.backward(delta, n=self.n)
|
||||
|
||||
|
||||
class Split(Function):
|
||||
|
||||
def __init__(self, indices_or_sections, axis=-1):
|
||||
self.indices_or_sections = indices_or_sections
|
||||
self.axis = axis
|
||||
|
||||
def forward(self, x):
|
||||
x = self._convert2tensor(x)
|
||||
self._atleast_ndim(x, 1)
|
||||
self.x = x
|
||||
output = np.split(x.value, self.indices_or_sections, self.axis)
|
||||
if isinstance(self.x, Constant):
|
||||
return tuple([Constant(out) for out in output])
|
||||
self.n_output = len(output)
|
||||
self.delta = [None for _ in output]
|
||||
return tuple([Tensor(out, function=self) for out in output])
|
||||
|
||||
def backward(self, delta, n):
|
||||
self.delta[n] = delta
|
||||
if all([d is not None for d in self.delta]):
|
||||
dx = np.concatenate(self.delta, axis=self.axis)
|
||||
self.x.backward(dx)
|
||||
|
||||
|
||||
def split(x, indices_or_sections, axis=-1):
|
||||
output = Split(indices_or_sections, axis).forward(x)
|
||||
return tuple([Nth(i).forward(out) for i, out in enumerate(output)])
|
||||
@@ -0,0 +1,36 @@
|
||||
import numpy as np
|
||||
from prml.nn.tensor.constant import Constant
|
||||
from prml.nn.tensor.tensor import Tensor
|
||||
from prml.nn.function import Function
|
||||
|
||||
|
||||
class Transpose(Function):
|
||||
|
||||
def __init__(self, axes=None):
|
||||
self.axes = axes
|
||||
|
||||
def forward(self, x):
|
||||
x = self._convert2tensor(x)
|
||||
if self.axes is not None:
|
||||
self._equal_ndim(x, len(self.axes))
|
||||
self.x = x
|
||||
if isinstance(self.x, Constant):
|
||||
return Constant(np.transpose(x.value, self.axes))
|
||||
return Tensor(np.transpose(x.value, self.axes), function=self)
|
||||
|
||||
def backward(self, delta):
|
||||
if self.axes is None:
|
||||
dx = np.transpose(delta)
|
||||
else:
|
||||
dx = np.transpose(delta, np.argsort(self.axes))
|
||||
self.x.backward(dx)
|
||||
|
||||
|
||||
def transpose(x, axes=None):
|
||||
return Transpose(axes).forward(x)
|
||||
|
||||
|
||||
def transpose_method(x, *args):
|
||||
if args == ():
|
||||
args = None
|
||||
return Transpose(args).forward(x)
|
||||
Reference in New Issue
Block a user