OpenMined / PySyft

Perform data science on data that remains in someone else's server
https://www.openmined.org/
Apache License 2.0
9.53k stars 1.99k forks source link

Basic Custom Tensor Classes #5046

Closed madhavajay closed 2 years ago

madhavajay commented 3 years ago

Description

Map out the initial basic custom tensor classes and their relationship with each other.

class SyftTensor():
    def __init_(self, child):
        self.child = child

    def __add__(self, other):
        print("__add__")
        return SyftTensor(child=self.child + other.child)

SyftTensor -> Interface DataTensor -> Framework Specific like TorchTensor FixedPrecisionTensor IntegerTensor FloatTensor AutogradTensor self.children -> Can only be Decimal / FloatTensor

HETensor -> Can only be IntegerTensor

Definition of Done

Basic hierarchy in place with some basic ops and examples of nested configurations with tests.

koenvanderveen commented 3 years ago

Few questions before I want to dive in

koenvanderveen commented 3 years ago

So for a FloatTensor that would look something like this, is that the direction you were thinking of.

from syft.decorators import syft_decorator

import syft
import torch
from typing import Union

class DataTensor():

    @syft_decorator(typechecking=True)
    def __init__(self, child: Union[torch.FloatTensor, torch.IntTensor]):
        self.child=child

    def __add__(self, other):
        return DataTensor(child=self.child + other.child)

class FloatTensor():

    @syft_decorator(typechecking=True)
    def __init__(self, child: DataTensor):
        self.child=child

    def __add__(self, other):
        return FloatTensor(child=self.child + other.child)

class IntegerTensor():

    @syft_decorator(typechecking=True)
    def __init__(self, child: DataTensor):
        self.child=child

    def __add__(self, other):
        return FloatTensor(child=self.child + other.child)

class SyftTensor():
    def __init__(self, child: Union[FloatTensor, IntegerTensor]):
        self.child = child

    def __add__(self, other):
        return SyftTensor(child=self.child + other.child)

    @classmethod
    def FloatTensor(cls, data):
        if isinstance(data, list):
            return cls(child=FloatTensor(child=DataTensor(child=torch.FloatTensor(data))))

# test
def get_children_types(t, l=None):
    l = [] if l is None else l
    if hasattr(t, "child"): return l + [type(t)] + get_children_types(t.child, l)
    else: return l + [type(t)]

t = SyftTensor.FloatTensor([1,2,3])
assert get_children_types(t) == [SyftTensor, FloatTensor, DataTensor, torch.Tensor]

t2 = SyftTensor.FloatTensor([4,5,6])
t3 = t + t2
assert all(t3.child.child.child.numpy() == [5.0, 7.0, 9.0])
gmuraru commented 3 years ago

Hey - it looks good!

Some nitpicking stuff:

koenvanderveen commented 3 years ago

1) yes I agree that might be a better name 2) yes both could be possible, I don't have a good enough overview of the rest of the code and constraints to assess that currently

koenvanderveen commented 3 years ago

Hmm, thinking about it again, if we would use "tensor" as name, we would be using it as tensor.tensor, which is a bit confusing.