# Implementing Generic Framework-Agnostic Functions
Using the conversion functions shown in Converting, we can already define a simple framework-agnostic function.
import eagerpy as ep def norm(x): x = ep.astensor(x) result = x.square().sum().sqrt() return result.raw
This function can be called with a native tensor from any framework and it will return the norm of that tensor, again as a native tensor from that framework.
norm function using a PyTorch tensor:
import torch norm(torch.tensor([1., 2., 3.])) # tensor(3.7417)
norm function using a TensorFlow tensor:
import tensorflow as tf norm(tf.constant([1., 2., 3.])) # <tf.Tensor: shape=(), dtype=float32, numpy=3.7416575>
If we would call the above
norm function with an EagerPy tensor, the
ep.astensor call would simply return its input. The
result.raw call in the last line would however still extract the underlying native tensor. Often it is preferably to implement a generic function that not only transparently handles any native tensor but also EagerPy tensors, that is the return type should always match the input type. This is particularly useful in libraries like Foolbox that allow users to work with EagerPy and native tensors. To achieve that, EagerPy comes with two derivatives of the above conversion functions:
ep.astensors_. Unlike their counterparts without an underscore, they return an additional inversion function that restores the input type. If the input to
astensor_ is a native tensor,
restore_type will be identical to
.raw, but if the original input was an EagerPy tensor,
restore_type will not call
.raw. With that, we can write generic framework-agnostic functions that work transparently for any input.
An improved framework-agnostic
import eagerpy as ep def norm(x): x, restore_type = ep.astensor_(x) result = x.square().sum().sqrt() return restore_type(result)
Converting and restoring multiple inputs using
import eagerpy as ep def example(x, y, z): (x, y, z), restore_type = ep.astensors_(x, y, z) result = (x + y) * z return restore_type(result)