# Path: DeepFried2/utils.py
# def tensors_for_ndarrays(datas, basename):
#     #if isinstance(datas, _np.ndarray):
#     try:
#         dtype, ndim = datas.dtype, datas.ndim
#     except AttributeError:
#         pass  # Not an array-like
#     else:
#         return make_tensor(dtype, ndim, basename)
# 
#     if isinstance(datas, (list, tuple)):
#         return [tensors_for_ndarrays(data, "{}_{}".format(basename, i)) for i, data in enumerate(datas)]
#     # Could potentially make it "any iterable" by removing above check.
#     # But would need to guarantee we never iterate over it twice, which is harder!
#     raise TypeError("I only understand lists or tuples of numpy arrays! (possibly nested)")
# 
# def flatten(what, types=(list, tuple), none_to_empty=False):
#     if what is None and none_to_empty:
#         return []
# 
#     if not isinstance(what, types):
#         return [what]
# 
#     # NOTE: I actually timed that this is faster than the comprehension,
#     #       even though it probably doesn't matter :)
#     # 350us vs 250us
#     ret = []
#     for sub in what:
#         ret += flatten(sub, types=types, none_to_empty=none_to_empty)
#     return ret


import DeepFried2 as df
import numpy as _np
from DeepFried2.utils import tensors_for_ndarrays, flatten
        return self._addparam(shape, init, *a, **kw)


    def zero_grad_parameters(self):
        for p in self.parameters(learnable_only=True):
            p.zero_grad()

    def parameters(self, learnable_only=False):
        params = getattr(self, '_params', [])
        if learnable_only:
            params = [p for p in params if p.learnable()]
        return params

    def evaluate(self):
        self._mode = 'eval'

    def training(self):
        self._mode = 'train'

    def symb_forward(self, symb_input):
        raise NotImplementedError("`{}` needs to implement `symb_forward` method.".format(df.utils.typename(self)))

    def __call__(self, symb_input):
        # Keep track of the symbolic inputs/outputs for things such as `Backward` layer.
        self._last_symb_inp[self._mode] = symb_input
        self._last_symb_out[self._mode] = self.symb_forward(symb_input)
        return self._last_symb_out[self._mode]

    def forward(self, data):
        if self._mode not in self._fn_forward:

# Path: DeepFried2/utils.py
# def tensors_for_ndarrays(datas, basename):
#     #if isinstance(datas, _np.ndarray):
#     try:
#         dtype, ndim = datas.dtype, datas.ndim
#     except AttributeError:
#         pass  # Not an array-like
#     else:
#         return make_tensor(dtype, ndim, basename)
# 
#     if isinstance(datas, (list, tuple)):
#         return [tensors_for_ndarrays(data, "{}_{}".format(basename, i)) for i, data in enumerate(datas)]
#     # Could potentially make it "any iterable" by removing above check.
#     # But would need to guarantee we never iterate over it twice, which is harder!
#     raise TypeError("I only understand lists or tuples of numpy arrays! (possibly nested)")
# 
# def flatten(what, types=(list, tuple), none_to_empty=False):
#     if what is None and none_to_empty:
#         return []
# 
#     if not isinstance(what, types):
#         return [what]
# 
#     # NOTE: I actually timed that this is faster than the comprehension,
#     #       even though it probably doesn't matter :)
#     # 350us vs 250us
#     ret = []
#     for sub in what:
#         ret += flatten(sub, types=types, none_to_empty=none_to_empty)
#     return ret


# Path: DeepFried2/Module.py
import DeepFried2 as df
import numpy as _np
from DeepFried2.utils import tensors_for_ndarrays, flatten

        return self._addparam(shape, init, *a, **kw)


    def zero_grad_parameters(self):
        for p in self.parameters(learnable_only=True):
            p.zero_grad()

    def parameters(self, learnable_only=False):
        params = getattr(self, '_params', [])
        if learnable_only:
            params = [p for p in params if p.learnable()]
        return params

    def evaluate(self):
        self._mode = 'eval'

    def training(self):
        self._mode = 'train'

    def symb_forward(self, symb_input):
        raise NotImplementedError("`{}` needs to implement `symb_forward` method.".format(df.utils.typename(self)))

    def __call__(self, symb_input):
        # Keep track of the symbolic inputs/outputs for things such as `Backward` layer.
        self._last_symb_inp[self._mode] = symb_input
        self._last_symb_out[self._mode] = self.symb_forward(symb_input)
        return self._last_symb_out[self._mode]

    def forward(self, data):
        if self._mode not in self._fn_forward:

            symb_in = tensors_for_ndarrays(data, 'X')