diff --git a/syft/frameworks/torch/fl/dataset.py b/syft/frameworks/torch/fl/dataset.py index 73e1dd6972b..5d6793a7d16 100644 --- a/syft/frameworks/torch/fl/dataset.py +++ b/syft/frameworks/torch/fl/dataset.py @@ -1,13 +1,16 @@ import math import logging - +from syft.generic.object import AbstractObject +from syft.workers.base import BaseWorker +from syft.generic.pointers.pointer_dataset import PointerDataset import torch from torch.utils.data import Dataset +import syft logger = logging.getLogger(__name__) -class BaseDataset: +class BaseDataset(AbstractObject): """ This is a base class to be used for manipulating a dataset. This is composed of a .data attribute for inputs and a .targets one for labels. It is to @@ -22,8 +25,10 @@ class BaseDataset: """ - def __init__(self, data, targets, transform=None): - + def __init__(self, data, targets, transform=None, owner=None, **kwargs): + if owner is None: + owner = syft.framework.hook.local_worker + super().__init__(owner=owner, **kwargs) self.data = data self.targets = targets self.transform_ = transform @@ -68,21 +73,9 @@ def transform(self, transform): raise TypeError("Transforms can be applied only on torch tensors") - def send(self, worker): - """ - Args: - - worker[worker class]: worker to which the data must be sent - - Returns: - - self: Return the object instance with data sent to corresponding worker - - """ - - self.data.send_(worker) - self.targets.send_(worker) - return self + def send(self, location: BaseWorker): + ptr = self.owner.send(self, workers=location) + return ptr def get(self): """ @@ -93,6 +86,12 @@ def get(self): self.targets.get_() return self + def get_data(self): + return self.data + + def get_targets(self): + return self.targets + def fix_prec(self, *args, **kwargs): """ Converts data of BaseDataset into fixed precision @@ -121,6 +120,34 @@ def share(self, *args, **kwargs): self.targets.share_(*args, **kwargs) return self + def create_pointer( + self, owner, garbage_collect_data, location=None, id_at_location=None, **kwargs + ): + return PointerDataset( + owner=owner, + location=location, + id_at_location=id_at_location or self.id, + garbage_collect_data=garbage_collect_data, + tags=self.tags, + description=self.description, + ) + + def __repr__(self): + + fmt_str = "BaseDataset\n" + fmt_str += f"\tData: {self.data}\n" + fmt_str += f"\ttargets: {self.targets}" + + if self.tags is not None and len(self.tags): + fmt_str += "\n\tTags: " + for tag in self.tags: + fmt_str += str(tag) + " " + + if self.description is not None: + fmt_str += "\n\tDescription: " + str(self.description).split("\n")[0] + "..." + + return fmt_str + @property def location(self): """ @@ -128,6 +155,36 @@ def location(self): """ return self.data.location + @staticmethod + def simplify(worker, dataset: "BaseDataset") -> tuple: + chain = None + if hasattr(dataset, "child"): + chain = syft.serde.msgpack.serde._simplify(worker, dataset.child) + return ( + syft.serde.msgpack.serde._simplify(worker, dataset.data), + syft.serde.msgpack.serde._simplify(worker, dataset.targets), + dataset.id, + syft.serde.msgpack.serde._simplify(worker, dataset.tags), + syft.serde.msgpack.serde._simplify(worker, dataset.description), + chain, + ) + + @staticmethod + def detail(worker, dataset_tuple: tuple) -> "BaseDataset": + data, targets, id, tags, description, chain = dataset_tuple + dataset = BaseDataset( + syft.serde.msgpack.serde._detail(worker, data), + syft.serde.msgpack.serde._detail(worker, targets), + id=id, + tags=syft.serde.msgpack.serde._detail(worker, tags), + description=syft.serde.msgpack.serde._detail(worker, description), + ) + if chain is not None: + chain = syft.serde.msgpack.serde._detail(worker, chain) + dataset.child = chain + + return dataset + def dataset_federate(dataset, workers): """ @@ -174,8 +231,8 @@ def __init__(self, datasets): # Check that data and targets for a worker are consistent for worker_id in self.workers: dataset = self.datasets[worker_id] - assert len(dataset.data) == len( - dataset.targets + assert ( + dataset.data.shape == dataset.targets.shape ), "On each worker, the input and target must have the same number of rows." @property diff --git a/syft/generic/pointers/pointer_dataset.py b/syft/generic/pointers/pointer_dataset.py new file mode 100644 index 00000000000..ccf1bf44426 --- /dev/null +++ b/syft/generic/pointers/pointer_dataset.py @@ -0,0 +1,79 @@ +from typing import List +from typing import Union + +import syft as sy +from syft.generic.pointers.object_pointer import ObjectPointer +from syft.workers.abstract import AbstractWorker + + +class PointerDataset(ObjectPointer): + def __init__( + self, + location: "AbstractWorker" = None, + id_at_location: Union[str, int] = None, + owner: "AbstractWorker" = None, + garbage_collect_data: bool = True, + id: Union[str, int] = None, + tags: List[str] = None, + description: str = None, + ): + if owner is None: + owner = sy.framework.hook.local_worker + super().__init__( + location=location, + id_at_location=id_at_location, + owner=owner, + garbage_collect_data=garbage_collect_data, + id=id, + tags=tags, + description=description, + ) + + @property + def data(self): + command = ("get_data", self.id_at_location, [], {}) + ptr = self.owner.send_command(message=command, recipient=self.location).wrap() + return ptr + + @property + def targets(self): + command = ("get_targets", self.id_at_location, [], {}) + ptr = self.owner.send_command(message=command, recipient=self.location).wrap() + return ptr + + def wrap(self): + return self + + def __repr__(self): + type_name = type(self).__name__ + out = f"[" f"{type_name} | " f"owner: {str(self.owner.id)}, id:{self.id}" + + if self.point_to_attr is not None: + out += "::" + str(self.point_to_attr).replace(".", "::") + + big_str = False + + if self.tags is not None and len(self.tags): + big_str = True + out += "\n\tTags: " + for tag in self.tags: + out += str(tag) + " " + + if big_str and hasattr(self, "shape"): + out += "\n\tShape: " + str(self.shape) + + if self.description is not None: + big_str = True + out += "\n\tDescription: " + str(self.description).split("\n")[0] + "..." + + return out + + def __len__(self): + command = ("__len__", self.id_at_location, [], {}) + len = self.owner.send_command(message=command, recipient=self.location) + return len + + def __getitem__(self, index): + command = ("__getitem__", self.id_at_location, [index], {}) + data_elem, target_elem = self.owner.send_command(message=command, recipient=self.location) + return data_elem.wrap(), target_elem.wrap() diff --git a/syft/serde/msgpack/serde.py b/syft/serde/msgpack/serde.py index aa9fe70c1e2..3df0f9bd722 100644 --- a/syft/serde/msgpack/serde.py +++ b/syft/serde/msgpack/serde.py @@ -70,6 +70,7 @@ from syft.serde.msgpack.native_serde import MAP_NATIVE_SIMPLIFIERS_AND_DETAILERS from syft.workers.abstract import AbstractWorker from syft.workers.base import BaseWorker +from syft.frameworks.torch.fl import BaseDataset from syft.exceptions import GetNotPermittedError from syft.exceptions import ResponseSignatureError @@ -130,6 +131,7 @@ PlanCommandMessage, GradFunc, String, + BaseDataset, ] # If an object implements its own force_simplify and force_detail functions it should be stored in this list diff --git a/test/common/test_util.py b/test/common/test_util.py deleted file mode 100644 index e825389c55b..00000000000 --- a/test/common/test_util.py +++ /dev/null @@ -1,38 +0,0 @@ -import torch -import itertools - -from syft.common.util import chebyshev_series, chebyshev_polynomials - - -def test_chebyshev_polynomials(): - """Tests evaluation of chebyshev polynomials""" - sizes = [(1, 10), (3, 5), (3, 5, 10)] - possible_terms = [6, 40] - tolerance = 0.05 - - for size, terms in itertools.product(sizes, possible_terms): - tensor = torch.rand(torch.Size(size)) * 42 - 42 - result = chebyshev_polynomials(tensor, terms) - - # check number of polynomials - assert result.shape[0] == terms // 2 - - assert torch.all(result[0] == tensor), "first term is incorrect" - - second_term = 4 * tensor ** 3 - 3 * tensor - diff = (result[1] - second_term).abs() - norm_diff = diff.div(result[1].abs() + second_term.abs()) - assert torch.all(norm_diff <= tolerance), "second term is incorrect" - - -def test_chebyshev_series(): - """Checks coefficients returned by chebyshev_series are correct""" - for width, terms in [(6, 10), (6, 20)]: - result = chebyshev_series(torch.tanh, width, terms) - - # check shape - assert result.shape == torch.Size([terms]) - - # check terms - assert result[0] < 1e-4 - assert torch.isclose(result[-1], torch.tensor(3.5e-2), atol=1e-1) diff --git a/test/efficiency/__init__.py b/test/efficiency/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/efficiency/assertions.py b/test/efficiency/assertions.py deleted file mode 100644 index 8a159a1acea..00000000000 --- a/test/efficiency/assertions.py +++ /dev/null @@ -1,23 +0,0 @@ -import time -from functools import wraps - - -def assert_time(max_time): - """ - Decorator used to assert time execution of functions. - Args: - max_time: int or float. Maximum time in seconds that the decorated - function should take to be executed - """ - - def decorate(func): - @wraps(func) - def wrapper(*args, **kwargs): - t0 = time.time() - func(*args, **kwargs) - dt = time.time() - t0 - assert dt < max_time, f"Test run in {round(dt, 2)} > {round(max_time, 2)} s" - - return wrapper - - return decorate diff --git a/test/efficiency/test_activations_time.py b/test/efficiency/test_activations_time.py deleted file mode 100644 index 23ad6e154c7..00000000000 --- a/test/efficiency/test_activations_time.py +++ /dev/null @@ -1,18 +0,0 @@ -import pytest -import torch -import syft as sy -from test.efficiency.assertions import assert_time - - -@pytest.mark.parametrize("activation", ["tanh", "sigmoid"]) -@assert_time(max_time=10) -def test_activation(activation, hook, workers): - - activation_func = torch.tanh if activation == "tanh" else torch.sigmoid - - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - x = torch.randn([10, 10]).fix_precision().share(bob, alice, crypto_provider=crypto_prov) - activation_func(x) diff --git a/test/efficiency/test_linalg_time.py b/test/efficiency/test_linalg_time.py deleted file mode 100644 index 0cce636e1ee..00000000000 --- a/test/efficiency/test_linalg_time.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest -import torch -import syft as sy -from syft.frameworks.torch.linalg import inv_sym -from syft.frameworks.torch.linalg.operations import _norm_mpc -from test.efficiency.assertions import assert_time - - -@assert_time(max_time=40) -def test_inv_sym(hook, workers): - torch.manual_seed(42) # Truncation might not always work so we set the random seed - N = 100 - K = 2 - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - x = torch.randn(N, K).fix_precision().share(bob, alice, crypto_provider=crypto_prov) - gram = x.t().matmul(x) - gram_inv = inv_sym(gram) diff --git a/test/execution/test_plan.py b/test/execution/test_plan.py deleted file mode 100644 index d7fe9e0c27d..00000000000 --- a/test/execution/test_plan.py +++ /dev/null @@ -1,1013 +0,0 @@ -import unittest.mock as mock - -import pytest -import torch as th -import torch.nn as nn -import torch.nn.functional as F -import torch.optim as optim - -import syft as sy -from syft.generic.pointers.pointer_tensor import PointerTensor -from syft.generic.frameworks.types import FrameworkTensor -from syft.execution.plan import Plan -from syft.serde.serde import deserialize -from syft.serde.serde import serialize - - -def test_plan_built_automatically(): - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - assert isinstance(plan_abs.__str__(), str) - assert len(plan_abs.readable_plan) > 0 - assert plan_abs.is_built - - -def test_stateful_plan_built_automatically(hook): - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def foo(x, state): - (bias,) = state.read() - x = x * 2 - return x + bias - - assert isinstance(foo.__str__(), str) - assert len(foo.readable_plan) > 0 - assert foo.is_built - - t = th.tensor([1.0, 2]) - x = foo(t) - - assert (x == th.tensor([3.0, 5])).all() - - -def test_plan_build(): - @sy.func2plan(args_shape=()) - def plan_abs(data): - return data.abs() - - assert not plan_abs.is_built - assert not len(plan_abs.readable_plan) - - plan_abs.build(th.tensor([-1])) - - assert len(plan_abs.readable_plan) - assert plan_abs.is_built - - -def test_stateful_plan_build(hook): - @sy.func2plan(state=(th.tensor([1.0]),)) - def foo(x, state): - (bias,) = state.read() - x = x * 2 - return x + bias - - t = th.tensor([1.0, 2]) - x = foo(t) - - assert (x == th.tensor([3.0, 5])).all() - - -def test_plan_built_automatically_with_any_dimension(): - @sy.func2plan(args_shape=[(-1, 1)]) - def plan_abs(data): - return data.abs() - - assert isinstance(plan_abs.__str__(), str) - assert len(plan_abs.readable_plan) > 0 - - -def test_raise_exception_for_invalid_shape(): - - with pytest.raises(ValueError): - - @sy.func2plan(args_shape=[(1, -20)]) - def _(data): - return data # pragma: no cover - - -def test_raise_exception_when_sending_unbuilt_plan(workers): - bob = workers["bob"] - - @sy.func2plan() - def plan(data): - return data # pragma: no cover - - with pytest.raises(RuntimeError): - plan.send(bob) - - -def test_plan_execute_locally(): - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - x = th.tensor([-1, 2, 3]) - x_abs = plan_abs(x) - assert (x_abs == th.tensor([1, 2, 3])).all() - - -def test_plan_execute_locally_ambiguous_output(workers): - bob, alice = workers["bob"], workers["alice"] - from syft.serde.msgpack import serde - - @sy.func2plan(args_shape=[(1,)]) - def serde_plan(x): - x = x + x - y = x * 2 - return x - - serde_plan_simplified = serde._simplify(bob, serde_plan) - serde_plan_detailed = serde._detail(bob, serde_plan_simplified) - t = th.tensor([2.3]) - expected = serde_plan(t) - actual = serde_plan_detailed(t) - assert actual == expected - - -def test_plan_execute_locally_ambiguous_input(workers): - bob, alice = workers["bob"], workers["alice"] - from syft.serde.msgpack import serde - - @sy.func2plan(args_shape=[(1,), (1,), (1,)]) - def serde_plan(x, y, z): - a = x + x # 2 - b = x + z # 4 - c = y + z # 5 - return c, b, a # 5, 4, 2 - - serde_plan_simplified = serde._simplify(bob, serde_plan) - serde_plan_detailed = serde._detail(bob, serde_plan_simplified) - t1, t2, t3 = th.tensor([1]), th.tensor([2]), th.tensor([3]) - expected = serde_plan(t1, t2, t3) - actual = serde_plan_detailed(t1, t2, t3) - print(actual) - print(expected) - assert actual == expected - - -def test_add_to_state(): - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = th.tensor([1.0]) - - def forward(self, x): - pass # pragma: no cover - - model = Net() - - assert len(model.state.state_placeholders) == 3 - - -def test_plan_method_execute_locally(hook): - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = self.fc2(x) - x = self.fc3(x) - return F.log_softmax(x, dim=0) - - model = Net() - - model.build(th.tensor([1.0, 2])) - - # Call one time - assert model(th.tensor([1.0, 2])) == 0 - - # Call one more time - assert model(th.tensor([1.0, 2.1])) == 0 - - -def test_stateful_plan_method_execute_locally(hook): - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 1) - self.bias = th.tensor([1000.0]) - - def forward(self, x): - x = self.fc1(x) - return F.log_softmax(x, dim=0) + self.bias - - model = Net() - - model.build(th.tensor([1.0, 2])) - - # Call one time - assert model(th.tensor([1.0, 2])) == th.tensor([1000.0]) - - # Call one more time - assert model(th.tensor([1.0, 2.1])) == th.tensor([1000.0]) - - -def test_plan_multiple_send(workers): - bob, alice = workers["bob"], workers["alice"] - - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - plan_ptr = plan_abs.send(bob) - x_ptr = th.tensor([-1, 7, 3]).send(bob) - p = plan_ptr(x_ptr) - x_abs = p.get() - - assert (x_abs == th.tensor([1, 7, 3])).all() - - # Test get / send plan - plan_ptr = plan_abs.send(alice) - - x_ptr = th.tensor([-1, 2, 3]).send(alice) - p = plan_ptr(x_ptr) - x_abs = p.get() - assert (x_abs == th.tensor([1, 2, 3])).all() - - -def test_stateful_plan_multiple_send(hook, workers): - bob, alice = workers["bob"], workers["alice"] - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan_abs(x, state): - (bias,) = state.read() - x = x.abs() - return x + bias - - plan_ptr = plan_abs.send(bob) - x_ptr = th.tensor([-1.0, 7, 3]).send(bob) - p = plan_ptr(x_ptr) - res = p.get() - - assert (res == th.tensor([2.0, 8, 4])).all() - - # Test get / send plan - plan_ptr = plan_abs.send(alice) - - x_ptr = th.tensor([-1.0, 2, 3]).send(alice) - p = plan_ptr(x_ptr) - res = p.get() - assert (res == th.tensor([2.0, 3, 4])).all() - - -def test_plan_built_on_class(hook): - """ - Test class Plans and plan send / get / send - """ - - x11 = th.tensor([-1, 2.0]).tag("input_data") - x21 = th.tensor([-1, 2.0]).tag("input_data") - - device_1 = sy.VirtualWorker(hook, id="device_1", data=(x11,)) - device_2 = sy.VirtualWorker(hook, id="device_2", data=(x21,)) - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 1) - - self.bias = th.tensor([1000.0]) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = self.fc2(x) - return F.log_softmax(x, dim=0) + self.bias - - net = Net() - - # build - net.build(th.tensor([1, 2.0])) - - net_ptr = net.send(device_1) - pointer_to_data = device_1.search("input_data")[0] - pointer_to_result = net_ptr(pointer_to_data) - - result = pointer_to_result.get() - assert isinstance(result, th.Tensor) - assert result == th.tensor([1000.0]) - - net_ptr = net.send(device_2) - - pointer_to_data = device_2.search("input_data")[0] - pointer_to_result = net_ptr(pointer_to_data) - - result = pointer_to_result.get() - assert isinstance(result, th.Tensor) - assert result == th.tensor([1000.0]) - - -def test_multiple_workers(workers): - bob, alice = workers["bob"], workers["alice"] - - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - plan_ptr = plan_abs.send(bob, alice) - x_ptr = th.tensor([-1, 7, 3]).send(bob) - p = plan_ptr(x_ptr) - x_abs = p.get() - assert (x_abs == th.tensor([1, 7, 3])).all() - - x_ptr = th.tensor([-1, 9, 3]).send(alice) - p = plan_ptr(x_ptr) - x_abs = p.get() - assert (x_abs == th.tensor([1, 9, 3])).all() - - -def test_stateful_plan_multiple_workers(hook, workers): - bob, alice = workers["bob"], workers["alice"] - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1]),)) - def plan_abs(x, state): - (bias,) = state.read() - x = x.abs() - return x + bias - - plan_ptr = plan_abs.send(bob, alice) - x_ptr = th.tensor([-1, 7, 3]).send(bob) - p = plan_ptr(x_ptr) - x_abs = p.get() - assert (x_abs == th.tensor([2, 8, 4])).all() - - x_ptr = th.tensor([-1, 9, 3]).send(alice) - p = plan_ptr(x_ptr) - x_abs = p.get() - assert (x_abs == th.tensor([2, 10, 4])).all() - - -def test_fetch_plan(hook, workers): - alice = workers["alice"] - - @sy.func2plan(args_shape=[(1,)]) - def plan(data): - return data * 3 - - plan.send(alice) - - # Fetch plan - fetched_plan = plan.owner.fetch_plan(plan.id, alice) - - # Execute it locally - x = th.tensor([-1.0, 2, 3]) - assert (plan(x) == th.tensor([-3.0, 6, 9])).all() - assert (fetched_plan(x) == th.tensor([-3.0, 6, 9])).all() - assert fetched_plan.forward is None - assert fetched_plan.is_built - - -@pytest.mark.parametrize("is_func2plan", [True, False]) -def test_fetch_stateful_plan(hook, is_func2plan, workers): - - if is_func2plan: - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan(data, state): - (bias,) = state.read() - return data * bias - - else: - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - - alice = workers["alice"] - plan_ptr = plan.send(alice) - - # Fetch plan - fetched_plan = plan.owner.fetch_plan(plan_ptr.id_at_location, alice) - - # Execute it locally - x = th.tensor([-1.26]) - assert th.all(th.eq(fetched_plan(x), plan(x))) - # assert fetched_plan.state.state_placeholders != plan.state.state_placeholders #TODO - - # Make sure fetched_plan is using the readable_plan - assert fetched_plan.forward is None - assert fetched_plan.is_built - - # Make sure plan is using the blueprint: forward - assert plan.forward is not None - - -@pytest.mark.parametrize("is_func2plan", [True, False]) -def test_fetch_stateful_plan_remote(hook, is_func2plan, start_remote_worker): - - server, remote_proxy = start_remote_worker( - id="test_fetch_stateful_plan_remote_{}".format(is_func2plan), hook=hook, port=8802 - ) - - if is_func2plan: - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([3.0]),)) - def plan(data, state): - (bias,) = state.read() - return data * bias - - else: - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - - x = th.tensor([-1.26]) - expected = plan(x) - plan_ptr = plan.send(remote_proxy) - - # Fetch plan - fetched_plan = plan.owner.fetch_plan(plan_ptr.id_at_location, remote_proxy) - - # Execute it locally - assert th.all(th.eq(fetched_plan(x), expected)) - # assert fetched_plan.state.state_placeholders != plan.state.state_placeholders #TODO - - # Make sure fetched_plan is using the readable_plan - assert fetched_plan.forward is None - assert fetched_plan.is_built - - # Make sure plan is using the blueprint: forward - assert plan.forward is not None - - remote_proxy.close() - server.terminate() - - -# TODO: Re-enable these once the rest of the Plan rework is completed - - -def test_binding_fix_precision_plan(hook): - """Here we make sure the attributes of a plan are still bound to state elements when calling fix_precision""" - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - original_weight = plan.fc1.weight.clone() - - plan.fix_precision() - plan.fc1.weight.float_prec_() - - assert (plan.fc1.weight - original_weight) < 10e-2 - - -def test_binding_encrypted_plan(hook, workers): - """Here we make sure the attributes of a plan are still bound to state elements when calling fix_prec + share""" - - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - original_weight = plan.fc1.weight.clone() - - plan.fix_precision().share(alice, bob, crypto_provider=charlie) - plan.fc1.weight.get_().float_prec_() - - assert (plan.fc1.weight - original_weight) < 10e-2 - - -@pytest.mark.parametrize("is_func2plan", [True, False]) -def test_fetch_encrypted_stateful_plan(hook, is_func2plan, workers): - # TODO: this test is not working properly with remote workers. - # We need to investigate why this might be the case. - - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - - if is_func2plan: - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([3.0]),)) - def plan(data, state): - (bias,) = state.read() - return data * bias - - else: - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - - x = th.tensor([-1.0]) - expected = plan(x) - - plan.fix_precision().share(alice, bob, crypto_provider=charlie) - ptr_plan = plan.send(james) - - # Fetch plan - fetched_plan = plan.owner.fetch_plan(ptr_plan.id_at_location, james) - - # Execute the fetch plan - x = th.tensor([-1.0]) - x_sh = x.fix_precision().share(alice, bob, crypto_provider=charlie) - decrypted = fetched_plan(x_sh).get().float_prec() - - # Compare with local plan - assert th.all(decrypted - expected.detach() < 1e-2) - # assert fetched_plan.state.state_placeholders != plan.state.state_placeholders #TODO - - # Make sure fetched_plan is using the readable_plan - assert fetched_plan.forward is None - assert fetched_plan.is_built - - # Make sure plan is using the blueprint: forward - assert plan.forward is not None - - -@pytest.mark.parametrize("is_func2plan", [True, False]) -def test_fetch_plan_multiple_times(hook, is_func2plan, workers): - - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - - if is_func2plan: - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([3.0]),)) - def plan(data, state): - (bias,) = state.read() - return data * bias - - else: - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(1, 1) - - def forward(self, x): - return self.fc1(x) - - plan = Net() - plan.build(th.tensor([1.2])) - - plan_pointer = plan.send(james) - - # Fetch plan - fetched_plan = plan_pointer.owner.fetch_plan(plan_pointer.id_at_location, james, copy=True) - - # Execute the fetch plan - x = th.tensor([-1.0]) - result1 = fetched_plan(x) - - # 2. Re-fetch Plan - fetched_plan = plan_pointer.owner.fetch_plan(plan_pointer.id_at_location, james, copy=True) - - # Execute the fetch plan - x = th.tensor([-1.0]) - result2 = fetched_plan(x) - - assert th.all(result1 - result2 < 1e-2) - - -def test_fetch_plan_remote(hook, start_remote_worker): - - server, remote_proxy = start_remote_worker(id="test_fetch_plan_remote", hook=hook, port=8803) - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan_mult_3(data, state): - (bias,) = state.read() - return data * 3 + bias - - plan_mult_3.send(remote_proxy) - - # Fetch plan - fetched_plan = plan_mult_3.owner.fetch_plan(plan_mult_3.id, remote_proxy) - - # Execute it locally - x = th.tensor([-1.0, 2, 3]) - assert (plan_mult_3(x) == th.tensor([-2.0, 7, 10])).all() - assert (fetched_plan(x) == th.tensor([-2.0, 7, 10])).all() - assert fetched_plan.forward is None - assert fetched_plan.is_built - - remote_proxy.close() - server.terminate() - - -def test_plan_serde(hook): - @sy.func2plan(args_shape=[(1, 3)]) - def my_plan(data): - x = data * 2 - y = (x - 2) * 10 - return x + y - - serialized_plan = serialize(my_plan) - deserialized_plan = deserialize(serialized_plan) - - x = th.tensor([-1, 2, 3]) - assert (deserialized_plan(x) == th.tensor([-42, 24, 46])).all() - - -def test_execute_plan_remotely(hook, start_remote_worker): - """Test plan execution remotely.""" - - @sy.func2plan(args_shape=[(1,)]) - def my_plan(data): - x = data * 2 - y = (x - 2) * 10 - return x + y - - x = th.tensor([-1, 2, 3]) - local_res = my_plan(x) - - server, remote_proxy = start_remote_worker(id="test_plan_worker", hook=hook, port=8799) - - plan_ptr = my_plan.send(remote_proxy) - x_ptr = x.send(remote_proxy) - ptr = plan_ptr(x_ptr) - assert isinstance(ptr, FrameworkTensor) and ptr.is_wrapper - plan_res = ptr.get() - - assert (plan_res == local_res).all() - - # delete remote object before websocket connection termination - del x_ptr - - remote_proxy.close() - server.terminate() - - -def test_execute_plan_module_remotely(hook, start_remote_worker): - """Test plan execution remotely.""" - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - - self.bias = th.tensor([1000.0]) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = self.fc2(x) - return F.log_softmax(x, dim=0) + self.bias - - net = Net() - - x = th.tensor([-1, 2.0]) - local_res = net(x) - assert not net.is_built - - net.build(x) - - server, remote_proxy = start_remote_worker(id="test_plan_worker_2", port=8799, hook=hook) - - plan_ptr = net.send(remote_proxy) - x_ptr = x.send(remote_proxy) - ptr = plan_ptr(x_ptr) - assert isinstance(ptr, FrameworkTensor) and ptr.is_wrapper - remote_res = ptr.get() - - assert (remote_res == local_res).all() - - # delete remote object before websocket connection termination - del x_ptr - - remote_proxy.close() - server.terminate() - - -def test_train_plan_locally_and_then_send_it(hook, start_remote_worker): - """Test training a plan locally and then executing it remotely.""" - - # Create toy model - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = self.fc2(x) - return F.log_softmax(x, dim=0) - - net = Net() - - # Create toy data - x = th.tensor([-1, 2.0]) - y = th.tensor([1.0]) - - # Train Model - opt = optim.SGD(params=net.parameters(), lr=0.01) - previous_loss = None - - for _ in range(5): - # 1) erase previous gradients (if they exist) - opt.zero_grad() - - # 2) make a prediction - pred = net(x) - - # 3) calculate how much we missed - loss = ((pred - y) ** 2).sum() - - # 4) figure out which weights caused us to miss - loss.backward() - - # 5) change those weights - opt.step() - - if previous_loss is not None: - assert loss < previous_loss - - previous_loss = loss - - local_res = net(x) - net.build(x) - - server, remote_proxy = start_remote_worker(id="test_plan_worker_3", port=8800, hook=hook) - - plan_ptr = net.send(remote_proxy) - x_ptr = x.send(remote_proxy) - remote_res = plan_ptr(x_ptr).get() - - assert (remote_res == local_res).all() - - # delete remote object before websocket connection termination - del x_ptr - - remote_proxy.close() - server.terminate() - - -# Plans are not supporting non-local computation flows for the moment -# def test_send_with_plan(workers): -# bob = workers["bob"] -# -# raise NotImplementedError -# -# @sy.func2plan([th.Size((1, 3))]) -# def plan_double_abs(x): -# x = x.send(bob) -# x = x + x -# x = th.abs(x) -# return x -# -# expected = th.tensor([4.0, 4.0, 4.0]) -# ptr_result = plan_double_abs(th.tensor([-2.0, 2.0, 2.0])) -# assert isinstance(ptr_result.child, sy.PointerTensor) -# result = ptr_result.get() -# assert th.equal(result, expected) - - -def test_cached_plan_send(workers): - bob = workers["bob"] - - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - plan_bob_ptr1 = plan_abs.send(bob) - plan_bob_ptr2 = plan_abs.send(bob) - pointers = plan_abs.get_pointers() - - assert len(pointers) == 1 - assert plan_bob_ptr1 is plan_bob_ptr2 - - -def test_cached_multiple_location_plan_send(workers): - bob, alice = workers["bob"], workers["alice"] - - @sy.func2plan(args_shape=[(1,)]) - def plan_abs(data): - return data.abs() - - plan_group_ptr1 = plan_abs.send(bob, alice) - plan_group_ptr2 = plan_abs.send(bob, alice) - - pointers = plan_abs.get_pointers() - - assert len(pointers) == 2 - - -def test_plan_nested_no_build_inner(workers): - alice = workers["alice"] - expected_res = th.tensor(200) - - @sy.func2plan() - def plan_double(data): - return 2 * data - - @sy.func2plan() - def plan_abs(data): - return plan_double(data).abs() - - x = th.tensor(100) - plan_abs.build(x) - - # Run plan locally - assert plan_abs(x) == expected_res - - # Run plan remote - x_ptr = x.send(alice) - plan_abs_ptr = plan_abs.send(alice) - res = plan_abs_ptr(x_ptr) - - assert res.get() == expected_res - - -def test_plan_nested_build_inner_plan_before(workers): - alice = workers["alice"] - expected_res = th.tensor(200) - - @sy.func2plan(args_shape=[(1,)]) - def plan_double(data): - return -2 * data - - @sy.func2plan() - def plan_abs(data): - return plan_double(data).abs() - - x = th.tensor(100) - plan_abs.build(x) - - # Run plan locally - assert plan_abs(x) == expected_res - - x_ptr = x.send(alice) - plan_abs_ptr = plan_abs.send(alice) - res = plan_abs_ptr(x_ptr) - - assert res.get() == expected_res - - -def test_plan_nested_build_inner_plan_after(workers): - alice = workers["alice"] - expected_res = th.tensor(200) - - @sy.func2plan() - def plan_double(data): - return -2 * data - - @sy.func2plan() - def plan_abs(data): - return plan_double(data).abs() - - x = th.tensor(100) - plan_abs.build(x) - plan_double.build(x) - - # Test locally - assert plan_abs(x) == expected_res - - # Test remote - x_ptr = x.send(alice) - plan_double_ptr = plan_abs.send(alice) - res = plan_double_ptr(x_ptr) - - assert res.get() == expected_res - - -def test_plan_nested_build_inner_plan_state(hook, workers): - alice = workers["alice"] - expected_res = th.tensor(199) - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1]),)) - def plan_double(data, state): - (bias,) = state.read() - return -2 * data + bias - - @sy.func2plan() - def plan_abs(data): - return plan_double(data).abs() - - x = th.tensor(100) - plan_abs.build(x) - - # Test locally - assert plan_abs(x) == expected_res - - # Test remote - x_ptr = x.send(alice) - plan_abs_ptr = plan_abs.send(alice) - plan_abs_ptr(x_ptr) - - res = plan_abs_ptr(x_ptr) - assert res.get() == expected_res - - -def test_plan_nested_build_multiple_plans_state(hook, workers): - alice = workers["alice"] - expected_res = th.tensor(1043) - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([3]),)) - def plan_3(data, state): - (bias,) = state.read() - return data + bias + 42 - - @sy.func2plan(args_shape=[(1,)]) - def plan_2_2(data): - return data + 1331 - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([2]),)) - def plan_2_1(data, state): - (bias,) = state.read() - return -2 * plan_3(data) + bias - - @sy.func2plan() - def plan_1(data): - res = plan_2_1(data) - return plan_2_2(res) - - # (-2 * (x + tensor(3) + 42) + tensor(2) + 1331) - # ------------------- - # plan_3 - # -------------------------------------- - # plan_2_1 - # ----------------------------------------------- - # plan_2_2 - - x = th.tensor(100) - plan_1.build(x) - - # Test locally - assert plan_1(x) == expected_res - - # Test remote - x_ptr = x.send(alice) - plan_1_ptr = plan_1.send(alice) - - res = plan_1_ptr(x_ptr) - assert res.get() == expected_res - - -def test_plan_can_be_jit_traced(hook, workers): - args_shape = [(1,)] - - @sy.func2plan(args_shape=args_shape, state=(th.tensor([1.0]),)) - def foo(x, state): - (bias,) = state.read() - x = x * 2 - return x + bias - - assert isinstance(foo.__str__(), str) - assert len(foo.readable_plan) > 0 - assert foo.is_built - - t = th.tensor([1.0, 2]) - x = foo(t) - - assert (x == th.tensor([3.0, 5])).all() - - args = Plan._create_placeholders(args_shape) - torchscript_plan = th.jit.trace(foo, args) - - y = torchscript_plan(t) - - assert (y == th.tensor([3.0, 5])).all() diff --git a/test/execution/test_protocol.py b/test/execution/test_protocol.py deleted file mode 100644 index bdd396f9155..00000000000 --- a/test/execution/test_protocol.py +++ /dev/null @@ -1,202 +0,0 @@ -import pytest -import torch as th - -import syft as sy -from syft.generic.frameworks.types import FrameworkTensor -from syft.generic.pointers.pointer_protocol import PointerProtocol -from syft.generic.pointers.pointer_tensor import PointerTensor - - -def _create_inc_protocol(): - @sy.func2plan(args_shape=[(1,)]) - def inc1(x): - return x + 1 - - @sy.func2plan(args_shape=[(1,)]) - def inc2(x): - return x + 1 - - @sy.func2plan(args_shape=[(1,)]) - def inc3(x): - return x + 1 - - protocol = sy.Protocol([("worker1", inc1), ("worker2", inc2), ("worker3", inc3)]) - return protocol - - -def test_deploy(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - """ - alice, bob, charlie = workers["alice"], workers["bob"], workers["charlie"] - - protocol = _create_inc_protocol() - - workers = alice, bob, charlie - - protocol.deploy(*workers) - - assert protocol.workers_resolved - - protocol._assert_is_resolved() - - # Assert the plan were sent to a consistent worker - assert all(plan_ptr.location.id == worker.id for worker, plan_ptr in protocol.plans) - - # Assert the order of the worker was preserved - assert all( - plan_ptr.location.id == worker.id for (_, plan_ptr), worker in zip(protocol.plans, workers) - ) - - -def test_deploy_with_resolver(workers): - """ - Like test_deploy, but now two of the three plans should be given to the same - worker - """ - alice, bob, charlie = workers["alice"], workers["bob"], workers["charlie"] - - protocol = _create_inc_protocol() - worker3_plan = protocol.plans[2][1] - protocol.plans[2] = ("worker1", worker3_plan) - - workers = alice, bob - - protocol.deploy(*workers) - - assert protocol.workers_resolved - - # Assert the plan were sent to a consistent worker - assert all(plan_ptr.location.id == worker.id for worker, plan_ptr in protocol.plans) - - # Now test the error case - protocol = _create_inc_protocol() - - with pytest.raises(RuntimeError): - protocol.deploy(alice, bob) - - -def test_synchronous_run(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - A runs the protocol - """ - alice, bob, charlie = workers["alice"], workers["bob"], workers["charlie"] - - protocol = _create_inc_protocol() - - protocol.deploy(alice, bob, charlie) - - x = th.tensor([1.0]) - ptr = protocol.run(x) - - assert ptr.location == charlie - - assert ( - isinstance(ptr, FrameworkTensor) and ptr.is_wrapper and isinstance(ptr.child, PointerTensor) - ) - - assert ptr.get() == th.tensor([4.0]) - - -def test_synchronous_remote_run(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - A sends the protocol to the cloud C - A asks a remote run on C - """ - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - - protocol = _create_inc_protocol() - - protocol.deploy(alice, bob, charlie) - - protocol.send(james) - - x = th.tensor([1.0]).send(james) - ptr = protocol.run(x) - - assert ptr.location == james - assert isinstance(ptr, FrameworkTensor) and ptr.is_wrapper - - ptr = ptr.get() - - assert ptr.location == charlie - assert ( - isinstance(ptr, FrameworkTensor) and ptr.is_wrapper and isinstance(ptr.child, PointerTensor) - ) - - res = ptr.get() - - assert res == th.tensor([4.0]) - - # BONUS: Error case when data is not correctly located - - x = th.tensor([1.0]) - with pytest.raises(RuntimeError): - protocol.run(x) - - -def test_search_and_deploy(workers): - """ - This test validates the following scenario: - A creates a protocol (which is not deployed) - A sends it to the cloud C - B search C for a protocol and get it back - B deploys the protocol on workers D, E and F - B runs the protocol - """ - alice, bob, charlie, james, me = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - workers["me"], - ) - - protocol = _create_inc_protocol() - - protocol.send(james) - - ptr_protocol = me.request_search([protocol.id], location=james)[0] - - assert isinstance(ptr_protocol, PointerProtocol) - - protocol_back = ptr_protocol.get() - - protocol_back.deploy(alice, bob, charlie) - - x = th.tensor([1.0]) - ptr = protocol_back.run(x) - - assert ptr.location == charlie - assert ( - isinstance(ptr, FrameworkTensor) and ptr.is_wrapper and isinstance(ptr.child, PointerTensor) - ) - - res = ptr.get() - - assert res == th.tensor([4.0]) - - # BONUS: Re-send to cloud and run remotely - - james.clear_objects() - protocol = protocol_back - - protocol.send(james) - ptr_protocol = me.request_search([protocol.id], location=james)[0] - x = th.tensor([1.0]).send(james) - ptr = ptr_protocol.run(x) - res = ptr.get().get() - assert res == th.tensor([4.0]) diff --git a/test/federated/__init__.py b/test/federated/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/federated/test_federated_client.py b/test/federated/test_federated_client.py deleted file mode 100644 index a334e8331df..00000000000 --- a/test/federated/test_federated_client.py +++ /dev/null @@ -1,308 +0,0 @@ -import pytest - -import torch - -import syft as sy -from syft.federated.federated_client import FederatedClient -from syft.federated.train_config import TrainConfig -from syft.generic.pointers.object_wrapper import ObjectWrapper -from syft.frameworks.torch.fl import utils - -PRINT_IN_UNITTESTS = False - -# To make execution deterministic to some extent -# For more information - refer https://pytorch.org/docs/stable/notes/randomness.html -torch.manual_seed(0) -torch.cuda.manual_seed_all(0) -torch.backends.cudnn.benchmark = False -torch.backends.cudnn.deterministic = True - - -def test_add_dataset(): - # Create a client to execute federated learning - fed_client = FederatedClient() - # Create a dataset - dataset = "my_dataset" - key = "string_dataset" - # Add new dataset - fed_client.add_dataset(dataset, key) - - assert "string_dataset" in fed_client.datasets - - -def test_add_dataset_with_duplicate_key(): - # Create a client to execute federated learning - fed_client = FederatedClient() - # Create a dataset - dataset = "my_dataset" - key = "string_dataset" - # Add new dataset - fed_client.add_dataset(dataset, key) - - assert "string_dataset" in fed_client.datasets - # Raise an error if the key is already exists - with pytest.raises(ValueError): - fed_client.add_dataset(dataset, "string_dataset") - - -def test_remove_dataset(): - # Create a client to execute federated learning - fed_client = FederatedClient() - # Create a dataset - dataset = "my_dataset" - key = "string_dataset" - # Add new dataset - fed_client.add_dataset(dataset, key) - - assert key in fed_client.datasets - # Remove new dataset - fed_client.remove_dataset(key) - - assert key not in fed_client.datasets - - -def test_set_obj_train_config(): - fed_client = FederatedClient() - fed_client.optimizer = True - - train_config = TrainConfig(id=100, model=None, loss_fn=None) - - fed_client.set_obj(train_config) - - assert fed_client.train_config.id == train_config.id - assert fed_client.optimizer is None - - -def test_set_obj_other(): - fed_client = FederatedClient() - - dummy_data = torch.tensor(42) - dummy_data.id = 43 - - fed_client.set_obj(dummy_data) - - assert len(fed_client._objects) == 1 - assert fed_client._objects[dummy_data.id] == dummy_data - - -def evaluate_model(fed_client, model_id, loss_fn, data, target): # pragma: no cover - new_model = fed_client.get_obj(model_id) - pred = new_model.obj(data) - loss_after = loss_fn(target=target, pred=pred) - return loss_after - - -def train_model( - fed_client, fit_dataset_key, available_dataset_key, nr_rounds, device -): # pragma: no cover - loss = None - for curr_round in range(nr_rounds): - if fit_dataset_key == available_dataset_key: - loss = fed_client.fit(dataset_key=fit_dataset_key, device=device) - else: - with pytest.raises(ValueError): - loss = fed_client.fit(dataset_key=fit_dataset_key, device=device) - if PRINT_IN_UNITTESTS and curr_round % 2 == 0: # pragma: no cover - print("-" * 50) - print("Iteration %s: alice's loss: %s" % (curr_round, loss)) - - -@pytest.mark.parametrize( - "fit_dataset_key, epochs, device", - [ - ("gaussian_mixture", 1, "cpu"), - ("gaussian_mixture", 10, "cpu"), - ("another_dataset", 1, "cpu"), - ("gaussian_mixture", 10, "cuda"), - ], -) -def test_fit(fit_dataset_key, epochs, device): - - if device == "cuda" and not torch.cuda.is_available(): - return - - data, target = utils.create_gaussian_mixture_toy_data(nr_samples=100) - - fed_client = FederatedClient() - dataset = sy.BaseDataset(data, target) - dataset_key = "gaussian_mixture" - fed_client.add_dataset(dataset, key=dataset_key) - - def loss_fn(pred, target): - return torch.nn.functional.cross_entropy(input=pred, target=target) - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(2, 3) - self.fc2 = torch.nn.Linear(3, 2) - - torch.nn.init.xavier_normal_(self.fc1.weight) - torch.nn.init.xavier_normal_(self.fc2.weight) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - x = torch.nn.functional.relu(self.fc2(x)) - return x - - data_device = data.to(torch.device(device)) - target_device = target.to(torch.device(device)) - model_untraced = Net().to(torch.device(device)) - model = torch.jit.trace(model_untraced, data_device) - model_id = 0 - model_ow = ObjectWrapper(obj=model, id=model_id) - loss_id = 1 - loss_ow = ObjectWrapper(obj=loss_fn, id=loss_id) - pred = model(data_device) - loss_before = loss_fn(target=target_device, pred=pred) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss before training: {}".format(loss_before)) - - # Create and send train config - train_config = sy.TrainConfig( - batch_size=8, - model=None, - loss_fn=None, - model_id=model_id, - loss_fn_id=loss_id, - optimizer_args={"lr": 0.05, "weight_decay": 0.01}, - epochs=epochs, - ) - - fed_client.set_obj(model_ow) - fed_client.set_obj(loss_ow) - fed_client.set_obj(train_config) - fed_client.optimizer = None - - train_model( - fed_client, fit_dataset_key, available_dataset_key=dataset_key, nr_rounds=3, device=device - ) - - if dataset_key == fit_dataset_key: - loss_after = evaluate_model(fed_client, model_id, loss_fn, data_device, target_device) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss after training: {}".format(loss_after)) - - if loss_after >= loss_before: # pragma: no cover - if PRINT_IN_UNITTESTS: - print("Loss not reduced, train more: {}".format(loss_after)) - - train_model( - fed_client, fit_dataset_key, available_dataset_key=dataset_key, nr_rounds=10 - ) - loss_after = evaluate_model(fed_client, model_id, loss_fn, data, target) - - assert loss_after < loss_before - - -def test_evaluate(): # pragma: no cover - data, target = utils.iris_data_partial() - - fed_client = FederatedClient() - dataset = sy.BaseDataset(data, target) - dataset_key = "iris" - fed_client.add_dataset(dataset, key=dataset_key) - - def loss_fn(pred, target): - return torch.nn.functional.cross_entropy(input=pred, target=target) - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(4, 3) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - return x - - model_untraced = Net() - - with torch.no_grad(): - model_untraced.fc1.weight.set_( - torch.tensor( - [ - [0.0160, 1.3753, -0.1202, -0.9129], - [0.1539, 0.3092, 0.0749, 0.2142], - [0.0984, 0.6248, 0.0274, 0.1735], - ] - ) - ) - model_untraced.fc1.bias.set_(torch.tensor([0.3477, 0.2970, -0.0799])) - - model = torch.jit.trace(model_untraced, data) - model_id = 0 - model_ow = ObjectWrapper(obj=model, id=model_id) - loss_id = 1 - loss_ow = ObjectWrapper(obj=loss_fn, id=loss_id) - pred = model(data) - loss_before = loss_fn(target=target, pred=pred) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss before training: {}".format(loss_before)) - - # Create and send train config - train_config = sy.TrainConfig( - batch_size=8, - model=None, - loss_fn=None, - model_id=model_id, - loss_fn_id=loss_id, - optimizer_args=None, - epochs=1, - ) - - fed_client.set_obj(model_ow) - fed_client.set_obj(loss_ow) - fed_client.set_obj(train_config) - fed_client.optimizer = None - - result = fed_client.evaluate( - dataset_key=dataset_key, return_histograms=True, nr_bins=3, return_loss=True - ) - - test_loss_before = result["loss"] - correct_before = result["nr_correct_predictions"] - len_dataset = result["nr_predictions"] - hist_pred_before = result["histogram_predictions"] - hist_target = result["histogram_target"] - - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Evaluation result before training: {}".format(result)) - - assert len_dataset == 30 - assert (hist_target == [10, 10, 10]).all() - - train_config = sy.TrainConfig( - batch_size=8, - model=None, - loss_fn=None, - model_id=model_id, - loss_fn_id=loss_id, - optimizer="SGD", - optimizer_args={"lr": 0.01}, - shuffle=True, - epochs=2, - ) - fed_client.set_obj(train_config) - train_model( - fed_client, dataset_key, available_dataset_key=dataset_key, nr_rounds=50, device="cpu" - ) - - result = fed_client.evaluate( - dataset_key=dataset_key, return_histograms=True, nr_bins=3, return_loss=True - ) - - test_loss_after = result["loss"] - correct_after = result["nr_correct_predictions"] - len_dataset = result["nr_predictions"] - hist_pred_after = result["histogram_predictions"] - hist_target = result["histogram_target"] - - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Evaluation result: {}".format(result)) - - assert len_dataset == 30 - assert (hist_target == [10, 10, 10]).all() - assert correct_after > correct_before - assert torch.norm(torch.tensor(hist_target - hist_pred_after)) < torch.norm( - torch.tensor(hist_target - hist_pred_before) - ) diff --git a/test/federated/test_train_config.py b/test/federated/test_train_config.py deleted file mode 100644 index 12288f7f379..00000000000 --- a/test/federated/test_train_config.py +++ /dev/null @@ -1,434 +0,0 @@ -import pytest - -from unittest import mock - -import torch -import torch.nn as nn -import torch.nn.functional as F -import syft as sy - -from syft.workers.websocket_client import WebsocketClientWorker -from syft.workers.websocket_server import WebsocketServerWorker -from syft.frameworks.torch.fl import utils - -PRINT_IN_UNITTESTS = False - -# TODO: I'm not sure this is valid torch JIT anyway -@pytest.mark.skip(reason="fails currently as it needs functions as torch.nn.linear to be unhooked.") -def test_train_config_with_jit_script_module(hook, workers): # pragma: no cover - alice = workers["alice"] - me = workers["me"] - - data = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]], requires_grad=True) - target = torch.tensor([[1], [0], [1], [0]]) - - dataset = sy.BaseDataset(data, target) - alice.add_dataset(dataset, key="vectors") - - @hook.torch.jit.script - def loss_fn(real, pred): - return ((real.float() - pred.float()) ** 2).mean() - - # Model - class Net(torch.jit.ScriptModule): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - @torch.jit.script_method - def forward(self, x): - x = F.relu(self.fc1(x)) - x = F.relu(self.fc2(x)) - x = self.fc3(x) - return x - - model = Net() - model.id = sy.ID_PROVIDER.pop() - - loss_fn.id = sy.ID_PROVIDER.pop() - - model_ptr = me.send(model, alice) - loss_fn_ptr = me.send(loss_fn, alice) - - # Create and send train config - train_config = sy.TrainConfig(model=model, loss_fn=loss_fn, batch_size=2) - train_config.send(alice) - - for epoch in range(5): - loss = alice.fit(dataset="vectors") - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("-" * 50) - print("Iteration %s: alice's loss: %s" % (epoch, loss)) - - if PRINT_IN_UNITTESTS: - print(alice) - new_model = model_ptr.get() - data = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]], requires_grad=True) - target = torch.tensor([[1], [0], [1], [0]]) - - pred = model(data) - loss_before = loss_fn(real=target, pred=pred) - - pred = new_model(data) - loss_after = loss_fn(real=target, pred=pred) - - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("Loss before training: {}".format(loss_before)) - print("Loss after training: {}".format(loss_after)) - - assert loss_after < loss_before - - -def test_train_config_with_jit_trace(hook, workers): # pragma: no cover - alice = workers["alice"] - - data = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]], requires_grad=True) - target = torch.tensor([[1], [0], [1], [0]]) - - dataset = sy.BaseDataset(data, target) - alice.add_dataset(dataset, key="gaussian_mixture") - - @hook.torch.jit.script - def loss_fn(pred, target): - return ((target.float() - pred.float()) ** 2).mean() - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = F.relu(self.fc2(x)) - x = self.fc3(x) - return x - - model_untraced = Net() - - model = torch.jit.trace(model_untraced, data) - - if PRINT_IN_UNITTESTS: - print("Evaluation before training") - pred = model(data) - loss_before = loss_fn(target=target, pred=pred) - - if PRINT_IN_UNITTESTS: - print("Loss: {}".format(loss_before)) - - # Create and send train config - train_config = sy.TrainConfig(model=model, loss_fn=loss_fn, batch_size=2) - train_config.send(alice) - - for epoch in range(5): - loss = alice.fit(dataset_key="gaussian_mixture") - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("-" * 50) - print("Iteration %s: alice's loss: %s" % (epoch, loss)) - - new_model = train_config.model_ptr.get() - pred = new_model.obj(data) - loss_after = loss_fn(target=target, pred=pred) - - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("Loss before training: {}".format(loss_before)) - print("Loss after training: {}".format(loss_after)) - - assert loss_after < loss_before - - -def test_train_config_with_jit_trace_send_twice_with_fit(hook, workers): # pragma: no cover - torch.manual_seed(0) - alice = workers["alice"] - model, loss_fn, data, target, loss_before, dataset_key = prepare_training(hook, alice) - - # Create and send train config - train_config_0 = sy.TrainConfig(model=model, loss_fn=loss_fn, batch_size=2) - train_config_0.send(alice) - - for epoch in range(5): - loss = alice.fit(dataset_key=dataset_key) - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("-" * 50) - print("TrainConfig 0, iteration %s: alice's loss: %s" % (epoch, loss)) - - new_model = train_config_0.model_ptr.get() - pred = new_model.obj(data) - loss_after_0 = loss_fn(pred=pred, target=target) - - assert loss_after_0 < loss_before - - train_config = sy.TrainConfig(model=model, loss_fn=loss_fn, batch_size=2) - train_config.send(alice) - - for epoch in range(5): - loss = alice.fit(dataset_key=dataset_key) - - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("-" * 50) - print("TrainConfig 1, iteration %s: alice's loss: %s" % (epoch, loss)) - - new_model = train_config.model_ptr.get() - pred = new_model.obj(data) - loss_after = loss_fn(pred=pred, target=target) - if PRINT_IN_UNITTESTS: # pragma: no cover: - print("Loss after training with TrainConfig 0: {}".format(loss_after_0)) - print("Loss after training with TrainConfig 1: {}".format(loss_after)) - - assert loss_after < loss_before - - -def prepare_training(hook, alice): # pragma: no cover - - data, target = utils.create_gaussian_mixture_toy_data(nr_samples=100) - dataset_key = "gaussian_mixture" - - dataset = sy.BaseDataset(data, target) - alice.add_dataset(dataset, key=dataset_key) - - @hook.torch.jit.script - def loss_fn(pred, target): - return ((target.float() - pred.float()) ** 2).mean() - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - nn.init.xavier_uniform_(self.fc1.weight) - nn.init.xavier_uniform_(self.fc2.weight) - nn.init.xavier_uniform_(self.fc3.weight) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = F.relu(self.fc2(x)) - x = self.fc3(x) - return x - - model_untraced = Net() - - model = torch.jit.trace(model_untraced, data) - - pred = model(data) - loss_before = loss_fn(target=target, pred=pred) - return model, loss_fn, data, target, loss_before, dataset_key - - -def test___str__(): - train_config = sy.TrainConfig(batch_size=2, id=99887766, model=None, loss_fn=None) - - train_config_str = str(train_config) - str_expected = ( - "" - ) - - assert str_expected == train_config_str - - -def test_send(workers): - alice = workers["alice"] - - train_config = sy.TrainConfig(batch_size=2, id="id", model=None, loss_fn=None) - train_config.send(alice) - - assert alice.train_config.id == train_config.id - assert alice.train_config._model_id == train_config._model_id - assert alice.train_config._loss_fn_id == train_config._loss_fn_id - assert alice.train_config.batch_size == train_config.batch_size - assert alice.train_config.epochs == train_config.epochs - assert alice.train_config.optimizer == train_config.optimizer - assert alice.train_config.optimizer_args == train_config.optimizer_args - assert alice.train_config.location == train_config.location - - -def test_send_model_and_loss_fn(workers): - train_config = sy.TrainConfig( - batch_size=2, id="send_model_and_loss_fn_tc", model=None, loss_fn=None - ) - alice = workers["alice"] - - orig_func = sy.ID_PROVIDER.pop - model_id = 44 - model_id_at_location = 44000 - loss_fn_id = 55 - loss_fn_id_at_location = 55000 - sy.ID_PROVIDER.pop = mock.Mock( - side_effect=[model_id, model_id_at_location, loss_fn_id, loss_fn_id_at_location] - ) - - train_config.send(alice) - - assert alice.train_config.id == train_config.id - assert alice.train_config._model_id == train_config._model_id - assert alice.train_config._loss_fn_id == train_config._loss_fn_id - assert alice.train_config.batch_size == train_config.batch_size - assert alice.train_config.epochs == train_config.epochs - assert alice.train_config.optimizer == train_config.optimizer - assert alice.train_config.optimizer_args == train_config.optimizer_args - assert alice.train_config.location == train_config.location - assert alice.train_config._model_id == model_id - assert alice.train_config._loss_fn_id == loss_fn_id - - sy.ID_PROVIDER.pop = orig_func - - -@pytest.mark.asyncio -async def test_train_config_with_jit_trace_async(hook, start_proc): # pragma: no cover - kwargs = {"id": "async_fit", "host": "localhost", "port": 8777, "hook": hook} - # data = torch.tensor([[0.0, 1.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]], requires_grad=True) - # target = torch.tensor([[1.0], [1.0], [0.0], [0.0]], requires_grad=False) - # dataset_key = "xor" - data, target = utils.create_gaussian_mixture_toy_data(100) - dataset_key = "gaussian_mixture" - - mock_data = torch.zeros(1, 2) - - # TODO check reason for error (RuntimeError: This event loop is already running) when starting websocket server from pytest-asyncio environment - # dataset = sy.BaseDataset(data, target) - - # server, remote_proxy = start_remote_worker(id="async_fit", port=8777, hook=hook, dataset=(dataset, dataset_key)) - - # time.sleep(0.1) - - remote_proxy = WebsocketClientWorker(**kwargs) - - @hook.torch.jit.script - def loss_fn(pred, target): - return ((target.view(pred.shape).float() - pred.float()) ** 2).mean() - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = F.relu(self.fc2(x)) - x = self.fc3(x) - return x - - model_untraced = Net() - - model = torch.jit.trace(model_untraced, mock_data) - - pred = model(data) - loss_before = loss_fn(target=target, pred=pred) - - # Create and send train config - train_config = sy.TrainConfig( - model=model, loss_fn=loss_fn, batch_size=2, optimizer="SGD", optimizer_args={"lr": 0.1} - ) - train_config.send(remote_proxy) - - for epoch in range(5): - loss = await remote_proxy.async_fit(dataset_key=dataset_key) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("-" * 50) - print("Iteration %s: alice's loss: %s" % (epoch, loss)) - - new_model = train_config.model_ptr.get() - - assert not (model.fc1._parameters["weight"] == new_model.obj.fc1._parameters["weight"]).all() - assert not (model.fc2._parameters["weight"] == new_model.obj.fc2._parameters["weight"]).all() - assert not (model.fc3._parameters["weight"] == new_model.obj.fc3._parameters["weight"]).all() - assert not (model.fc1._parameters["bias"] == new_model.obj.fc1._parameters["bias"]).all() - assert not (model.fc2._parameters["bias"] == new_model.obj.fc2._parameters["bias"]).all() - assert not (model.fc3._parameters["bias"] == new_model.obj.fc3._parameters["bias"]).all() - - new_model.obj.eval() - pred = new_model.obj(data) - loss_after = loss_fn(target=target, pred=pred) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss before training: {}".format(loss_before)) - print("Loss after training: {}".format(loss_after)) - - remote_proxy.close() - # server.terminate() - - assert loss_after < loss_before - - -def test_train_config_with_jit_trace_sync(hook, start_remote_worker): # pragma: no cover - data, target = utils.create_gaussian_mixture_toy_data(100) - dataset = sy.BaseDataset(data, target) - dataset_key = "gaussian_mixture" - - server, remote_proxy = start_remote_worker( - id="sync_fit", hook=hook, port=9000, dataset=(dataset, dataset_key) - ) - - @hook.torch.jit.script - def loss_fn(pred, target): - return ((target.view(pred.shape).float() - pred.float()) ** 2).mean() - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = nn.Linear(2, 3) - self.fc2 = nn.Linear(3, 2) - self.fc3 = nn.Linear(2, 1) - - def forward(self, x): - x = F.relu(self.fc1(x)) - x = F.relu(self.fc2(x)) - x = self.fc3(x) - return x - - model_untraced = Net() - - model = torch.jit.trace(model_untraced, data) - - pred = model(data) - loss_before = loss_fn(pred=pred, target=target) - - # Create and send train config - train_config = sy.TrainConfig(model=model, loss_fn=loss_fn, batch_size=2, epochs=1) - train_config.send(remote_proxy) - - for epoch in range(5): - loss = remote_proxy.fit(dataset_key=dataset_key) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("-" * 50) - print("Iteration %s: alice's loss: %s" % (epoch, loss)) - - new_model = train_config.model_ptr.get() - - # assert that the new model has updated (modified) parameters - assert not ( - (model.fc1._parameters["weight"] - new_model.obj.fc1._parameters["weight"]).abs() < 10e-3 - ).all() - assert not ( - (model.fc2._parameters["weight"] - new_model.obj.fc2._parameters["weight"]).abs() < 10e-3 - ).all() - assert not ( - (model.fc3._parameters["weight"] - new_model.obj.fc3._parameters["weight"]).abs() < 10e-3 - ).all() - assert not ( - (model.fc1._parameters["bias"] - new_model.obj.fc1._parameters["bias"]).abs() < 10e-3 - ).all() - assert not ( - (model.fc2._parameters["bias"] - new_model.obj.fc2._parameters["bias"]).abs() < 10e-3 - ).all() - assert not ( - (model.fc3._parameters["bias"] - new_model.obj.fc3._parameters["bias"]).abs() < 10e-3 - ).all() - - new_model.obj.eval() - pred = new_model.obj(data) - loss_after = loss_fn(pred=pred, target=target) - - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss before training: {}".format(loss_before)) - print("Loss after training: {}".format(loss_after)) - - remote_proxy.close() - server.terminate() - - assert loss_after < loss_before diff --git a/test/generic/__init__.py b/test/generic/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/generic/test_id_provider.py b/test/generic/test_id_provider.py deleted file mode 100644 index 06bca580dbc..00000000000 --- a/test/generic/test_id_provider.py +++ /dev/null @@ -1,148 +0,0 @@ -import unittest.mock as mock -import pytest - -from syft import exceptions -from syft.generic import id_provider - - -def test_pop_no_given_ids(hook): - provider = id_provider.IdProvider() - values = [10, 4, 15, 4, 2, 0] - - orig_func = id_provider.create_random_id - mocked_random_numbers = mock.Mock() - mocked_random_numbers.side_effect = values - id_provider.create_random_id = mocked_random_numbers - - val = provider.pop() - assert val == values[0] - - val = provider.pop() - assert val == values[1] - - val = provider.pop() - assert val == values[2] - - # values[3] is skipped, as value already used. - - val = provider.pop() - assert val == values[4] - - val = provider.pop() - assert val == values[5] - - id_provider.create_random_id = orig_func - - -def test_pop_with_given_ids(hook): - given_ids = [4, 15, 2] - provider = id_provider.IdProvider(given_ids=given_ids.copy()) - values = [10, 4, 15, 4, 2, 0] - - orig_func = id_provider.create_random_id - mocked_random_numbers = mock.Mock() - mocked_random_numbers.side_effect = values - id_provider.create_random_id = mocked_random_numbers - - val = provider.pop() - assert val == given_ids[-1] - - val = provider.pop() - assert val == given_ids[-2] - - val = provider.pop() - assert val == given_ids[-3] - - val = provider.pop() - assert val == values[0] - - # values[1, 2, 3, 4] are skipped, as value already used. - - val = provider.pop() - assert val == values[5] - - id_provider.create_random_id = orig_func - - -def test_given_ids_side_effect(hook): - given_ids = [4, 15, 2] - provider = id_provider.IdProvider(given_ids=given_ids) - - assert len(given_ids) == 3 - provider.pop() - - assert len(given_ids) == 2 - - provider.pop() - assert len(given_ids) == 1 - - provider.pop() - assert len(given_ids) == 0 - - -def test_set_next_ids(hook): - initial_given_ids = [2, 3] - provider = id_provider.IdProvider(given_ids=initial_given_ids.copy()) - - next_ids = [4, 5] - provider.set_next_ids(next_ids.copy()) - - val = provider.pop() - assert val == next_ids[-1] - val = provider.pop() - assert val == next_ids[-2] - - val = provider.pop() - assert val == initial_given_ids[-1] - val = provider.pop() - assert val == initial_given_ids[-2] - - -def test_set_next_ids_with_id_checking(hook): - initial_given_ids = [2, 3] - provider = id_provider.IdProvider() - provider.set_next_ids(initial_given_ids.copy(), check_ids=False) - - # generated the initial 3 ids - provider.pop() - provider.pop() - provider.pop() - - next_ids = [1, 2, 5] - with pytest.raises(exceptions.IdNotUniqueError, match=r"\{2\}"): - provider.set_next_ids(next_ids.copy(), check_ids=True) - - next_ids = [2, 3, 5] - with pytest.raises(exceptions.IdNotUniqueError, match=r"\{2, 3\}"): - provider.set_next_ids(next_ids.copy(), check_ids=True) - - -def test_start_recording_ids(): - initial_given_ids = [2, 3] - provider = id_provider.IdProvider(given_ids=initial_given_ids.copy()) - provider.pop() - provider.start_recording_ids() - provider.pop() - - ids = provider.get_recorded_ids() - assert len(ids) == 1 - assert ids[0] == initial_given_ids[-2] - - -def test_get_recorded_ids(): - initial_given_ids = [2, 3, 4] - provider = id_provider.IdProvider(given_ids=initial_given_ids.copy()) - provider.pop() - provider.start_recording_ids() - provider.pop() - - ids = provider.get_recorded_ids(continue_recording=True) - assert len(ids) == 1 - assert ids[0] == initial_given_ids[-2] - - provider.pop() - - ids = provider.get_recorded_ids() - assert len(ids) == 2 - assert ids[0] == initial_given_ids[-2] - assert ids[1] == initial_given_ids[-3] diff --git a/test/generic/test_object_storage.py b/test/generic/test_object_storage.py deleted file mode 100644 index f7066956a03..00000000000 --- a/test/generic/test_object_storage.py +++ /dev/null @@ -1,39 +0,0 @@ -import torch - -from syft.generic import object_storage - - -def test_clear_objects(): - obj_storage = object_storage.ObjectStorage() - - x = torch.tensor(1) - obj_storage.set_obj(x) - - objs = obj_storage.current_objects() - - assert len(objs) == 1 - assert objs[x.id] == x - - ret_val = obj_storage.clear_objects() - - objs = obj_storage.current_objects() - assert len(objs) == 0 - assert ret_val == obj_storage - - -def test_clear_objects_return_None(): - obj_storage = object_storage.ObjectStorage() - - x = torch.tensor(1) - obj_storage.set_obj(x) - - objs = obj_storage.current_objects() - - assert len(objs) == 1 - assert objs[x.id] == x - - ret_val = obj_storage.clear_objects(return_self=False) - - objs = obj_storage.current_objects() - assert len(objs) == 0 - assert ret_val is None diff --git a/test/generic/test_string.py b/test/generic/test_string.py deleted file mode 100644 index d832bfd78f3..00000000000 --- a/test/generic/test_string.py +++ /dev/null @@ -1,69 +0,0 @@ -from syft.generic.string import String -import syft as sy - - -def test_string_methods(): - """Tests some of the `String` methods which are hooked from `str`. - more tests are to be added - """ - - # Create a string - string = String("Hello PySyft") - - assert isinstance(string.upper(), String) - assert isinstance(string.lower(), String) - assert isinstance(string.title(), String) - - assert string == "Hello PySyft" - assert string == String("Hello PySyft") - - assert string.upper() == "HELLO PYSYFT" - assert string.upper() == String("HELLO PYSYFT") - - assert string.lower() == "hello pysyft" - assert string.lower() == String("hello pysyft") - - assert string.title() == "Hello Pysyft" - assert string.title() == String("Hello Pysyft") - assert string.title() >= String("Hello Pysyft") - assert string.title() <= String("Hello Pysyft") - - assert string.startswith("Hel") == True - assert string.startswith(String("Hel")) == True - - assert string.endswith("Syft") == True - assert string.endswith(String("Syft")) == True - - assert (string > "Hello PySyfa") == True - assert (string >= "Hello PySyfa") == True - - assert (string < "Hello PySyfz") == True - assert (string <= "Hello PySyfz") == True - - assert String(" Hello").lstrip() == "Hello" - assert String("Hello ").rstrip() == "Hello" - - assert String("Hello").center(9) == " Hello " - assert String("Hello").center(9) == String(" Hello ") - - assert String("Hello").rjust(10) == " Hello" - assert String("Hello").rjust(10) == String(" Hello") - - assert String("Hello").ljust(10) == "Hello " - assert String("Hello").ljust(10) == String("Hello ") - - assert string + string == "Hello PySyftHello PySyft" - assert isinstance(string + string, String) - assert isinstance(string + " !", String) - - assert f"{string} !" == "Hello PySyft !" - - assert String("Hello {}").format(String("PySyft")) == string - assert String("Hello %s") % "PySyft" == string - - assert str(string) == "Hello PySyft" - - x = String("Hello PySyft") - bob = sy.VirtualWorker(id="bob", hook=sy.hook) - out = x.send(bob) - assert isinstance(out, sy.generic.pointers.string_pointer.StringPointer) diff --git a/test/keras/test_sequential.py b/test/keras/test_sequential.py deleted file mode 100644 index a4f64ccc6a5..00000000000 --- a/test/keras/test_sequential.py +++ /dev/null @@ -1,105 +0,0 @@ -import pytest - -import numpy as np -import syft as sy -from syft import dependency_check - -if dependency_check.tfe_available: # pragma: no cover - import tensorflow as tf - import tf_encrypted as tfe - - -@pytest.mark.skipif(not dependency_check.tfe_available, reason="tf_encrypted not installed") -def test_instantiate_tfe_layer(): # pragma: no cover - """tests tfe layer by running a constant 4*5 input matrix on a network - with one constant tensor of weights, using tf.keras then tfe and comparing results""" - - from syft.frameworks.keras.model.sequential import _instantiate_tfe_layer - - hook = sy.KerasHook(tf.keras) - - # creates input and weights constant tensors - input_shape = [4, 5] - input_data = np.ones(input_shape) - kernel = np.random.normal(size=[5, 5]) - initializer = tf.keras.initializers.Constant(kernel) - - # creates a network with 4*5 input shape, 5 output units, and 5*5 weights matrix - d_tf = tf.keras.layers.Dense( - 5, kernel_initializer=initializer, batch_input_shape=input_shape, use_bias=True - ) - - # runs the model using tf.keras - with tf.Session() as sess: - x = tf.Variable(input_data, dtype=tf.float32) - y = d_tf(x) - sess.run(tf.global_variables_initializer()) - expected = sess.run(y) - - stored_keras_weights = {d_tf.name: d_tf.get_weights()} - - # runs the model using tfe - with tf.Graph().as_default(): - p_x = tfe.define_private_variable(input_data) - d_tfe = _instantiate_tfe_layer(d_tf, stored_keras_weights) - - out = d_tfe(p_x) - - with tfe.Session() as sess: - sess.run(tf.global_variables_initializer()) - - actual = sess.run(out.reveal()) - - # compares results and raises error if not equal up to 0.001 - np.testing.assert_allclose(actual, expected, rtol=0.001) - - -@pytest.mark.skipif(not dependency_check.tfe_available, reason="tf_encrypted not installed") -def test_share(): # pragma: no cover - """tests tfe federated learning functionality by running a constant input on same model using tf.keras - then tfe on remote workers and comparing the outputs of both cases """ - from tensorflow.keras import Sequential - from tensorflow.keras.layers import Dense - - hook = sy.KerasHook(tf.keras) - - # creates input and weights constant tensors - input_shape = (4, 5) - kernel = np.random.normal(size=(5, 5)) - initializer = tf.keras.initializers.Constant(kernel) - dummy_input = np.ones(input_shape).astype(np.float32) - - model = Sequential() - - model.add( - Dense(5, kernel_initializer=initializer, batch_input_shape=input_shape, use_bias=True) - ) - output_shape = model.output_shape - result_public = model.predict(dummy_input) # runs constant input on the model using tf.keras - - # creats a cluster of tfe workers(remote machines) - client = sy.TFEWorker(host=None) - alice = sy.TFEWorker(host=None) - bob = sy.TFEWorker(host=None) - carol = sy.TFEWorker(host=None) - cluster = sy.TFECluster(alice, bob, carol) - - cluster.start() - - model.share(cluster) # sends the model to the workers - - # runs same input on same model on the romte workers and gets back the output - with model._tfe_graph.as_default(): - client.connect_to_model(input_shape, output_shape, cluster, sess=model._tfe_session) - - client.query_model_async(dummy_input) - - model.serve(num_requests=1) - - result_private = client.query_model_join().astype(np.float32) - # compares results and raises error if not equal up to 0.01 - np.testing.assert_allclose(result_private, result_public, atol=0.01) - - model.stop() - - cluster.stop() diff --git a/test/message/__init__.py b/test/message/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/message/test_message.py b/test/message/test_message.py deleted file mode 100644 index 093144fca97..00000000000 --- a/test/message/test_message.py +++ /dev/null @@ -1,140 +0,0 @@ -import syft as sy -import torch as th - -import syft as sy -from syft.messaging import message - - -def test_message_serde(): - - x = message.Message([1, 2, 3]) - x_bin = sy.serde.serialize(x) - y = sy.serde.deserialize(x_bin, sy.local_worker) - - assert x.contents == y.contents - - -def test_cmd_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) - - y = x + x # this is the test - assert isinstance(bob._get_msg(-1), message.OperationMessage) - - y = y.get() - - assert (y == th.tensor([2, 4, 6, 8])).all() - - bob.log_msgs = False - - -def test_obj_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) # this is the test - - assert isinstance(bob._get_msg(-1), message.ObjectMessage) - - y = x + x - - y = y.get() - - assert (y == th.tensor([2, 4, 6, 8])).all() - - bob.log_msgs = False - - -def test_obj_req_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) - - y = x + x - - y = y.get() # this is the test - assert isinstance(bob._get_msg(-1), message.ObjectRequestMessage) - - assert (y == th.tensor([2, 4, 6, 8])).all() - - bob.log_msgs = False - - -def test_get_shape_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) - - y = x + x - - z = y.shape # this is the test - assert isinstance(bob._get_msg(-1), message.GetShapeMessage) - - assert z == th.Size([4]) - - bob.log_msgs = False - - -def test_force_object_delete_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) - - id_on_worker = x.id_at_location - - assert id_on_worker in bob._objects - - del x # this is the test - assert isinstance(bob._get_msg(-1), message.ForceObjectDeleteMessage) - - assert id_on_worker not in bob._objects - - bob.log_msgs = False - - -def test_is_none_message(workers): - - bob = workers["bob"] - - bob.log_msgs = True - - x = th.tensor([1, 2, 3, 4]).send(bob) - - y = th.tensor([1]).send(bob) - y.child.id_at_location = x.id_at_location - - assert not bob.request_is_remote_tensor_none(x) - assert isinstance(bob._get_msg(-1), message.IsNoneMessage) - assert not x.child.is_none() - assert isinstance(bob._get_msg(-1), message.IsNoneMessage) - - del x - - assert y.child.is_none() - - bob.log_msgs = True - - -def test_search_message_serde(): - - x = message.SearchMessage([1, 2, 3]) - - x_bin = sy.serde.serialize(x) - y = sy.serde.deserialize(x_bin, sy.local_worker) - - assert x.contents == y.contents diff --git a/test/notebooks/git-diff.txt b/test/notebooks/git-diff.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/notebooks/test_notebooks.py b/test/notebooks/test_notebooks.py deleted file mode 100644 index 253e1599a51..00000000000 --- a/test/notebooks/test_notebooks.py +++ /dev/null @@ -1,240 +0,0 @@ -import glob -import os -import sys -import time -import urllib.request -from pathlib import Path -from zipfile import ZipFile -import codecs - -import pytest -import nbformat -import numpy as np -import pandas as pd -import papermill as pm -import torch - -import syft as sy -from syft import TorchHook -from syft.workers.websocket_server import WebsocketServerWorker - -# lets start by finding all notebooks currently available in examples and subfolders -all_notebooks = [n for n in glob.glob("examples/tutorials/**/*.ipynb", recursive=True)] -basic_notebooks = [n for n in glob.glob("examples/tutorials/*.ipynb")] -advanced_notebooks = [ - n for n in glob.glob("examples/tutorials/advanced/**/*.ipynb", recursive=True) -] -translated_notebooks = [ - n for n in glob.glob("examples/tutorials/translations/**/*.ipynb", recursive=True) -] -# Exclude all translated basic tutorials that are also -# excluded in their original version. -excluded_translated_notebooks = [ - Path(nb).name for part in ["10", "13b", "13c"] for nb in translated_notebooks if part in nb -] - - -# Include only the translations that have been changed -gitdiff = Path("test/notebooks/git-diff.txt") -changed_files = [] -if gitdiff.is_file(): - changed_files = open(gitdiff, "r") - changed_files = changed_files.readlines() - changed_files = [ - codecs.decode(file.replace('"', "").replace("\n", ""), "unicode-escape") - .encode("latin-1") - .decode() - for file in changed_files - ] -translated_notebooks_diff = list(set(changed_files) & set(translated_notebooks)) - -# buggy notebooks with explanation what does not work -exclusion_list_notebooks = [ - # Part 10 needs either torch.log2 to be implemented or numpy to be hooked - "Part 10 - Federated Learning with Secure Aggregation.ipynb", - # Part 13b and c need fixing of the tensorflow serving with PySyft - "Part 13b - Secure Classification with Syft Keras and TFE - Secure Model Serving.ipynb", - "Part 13c - Secure Classification with Syft Keras and TFE - Private Prediction Client.ipynb", - # This notebook is excluded as it needs library code modification which I might add later on - "Build your own tensor type (advanced).ipynb", - "Federated Recurrent Neural Network.ipynb", - # Outdated training method - "Introduction to TrainConfig.ipynb", - # Outdated websocket client code - "Federated learning with websockets and federated averaging.ipynb", -] - -# Add excluded translated notebooks to the exclusion list -exclusion_list_notebooks += excluded_translated_notebooks - -exclusion_list_folders = [ - "examples/tutorials/websocket", - "examples/tutorials/advanced/Monitor_Network_Traffic", - "examples/tutorials/advanced/websockets-example-MNIST-parallel", - # To run these notebooks, we need to run grid nodes / grid gateway previously (they aren't in this repository) - "examples/tutorials/grid", - "examples/tutorials/grid/federated_learning/spam_prediction", - "examples/tutorials/grid/federated_learning/mnist", - # This notebook is skipped because it fails in github actions and we do not know why for the moment - "examples/tutorials/advanced/Federated SMS Spam prediction", -] - - -excluded_notebooks = [] -for nb in all_notebooks: - if Path(nb).name in exclusion_list_notebooks: - excluded_notebooks += [nb] -for folder in exclusion_list_folders: - excluded_notebooks += glob.glob(f"{folder}/**/*.ipynb", recursive=True) - -tested_notebooks = [] - - -@pytest.mark.parametrize("notebook", sorted(set(basic_notebooks) - set(excluded_notebooks))) -def test_notebooks_basic(isolated_filesystem, notebook): - """Test Notebooks in the tutorial root folder.""" - notebook = notebook.split("/")[-1] - list_name = Path("examples/tutorials/") / notebook - tested_notebooks.append(str(list_name)) - res = pm.execute_notebook( - notebook, - "/dev/null", - parameters={"epochs": 1, "n_test_batches": 5, "n_train_items": 64, "n_test_items": 64}, - timeout=300, - ) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - - -@pytest.mark.translation -@pytest.mark.parametrize( - "translated_notebook", sorted(set(translated_notebooks) - set(excluded_notebooks)) -) -def test_notebooks_basic_translations(isolated_filesystem, translated_notebook): # pragma: no cover - """Test Notebooks in the tutorial translations folder.""" - notebook = "/".join(translated_notebook.split("/")[-2:]) - notebook = f"translations/{notebook}" - list_name = Path(f"examples/tutorials/{notebook}") - tested_notebooks.append(str(list_name)) - res = pm.execute_notebook( - notebook, - "/dev/null", - parameters={"epochs": 1, "n_test_batches": 5, "n_train_items": 64, "n_test_items": 64}, - timeout=300, - ) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - - -@pytest.mark.translation -@pytest.mark.parametrize( - "translated_notebook", sorted(set(translated_notebooks_diff) - set(excluded_notebooks)) -) -def test_notebooks_basic_translations_diff( - isolated_filesystem, translated_notebook -): # pragma: no cover - """ - Test Notebooks in the tutorial translations folder if they have been - modified in the current pull request. This test should not consider any - notebooks locally. It should be used on Github Actions. - """ - notebook = "/".join(translated_notebook.split("/")[-2:]) - notebook = f"translations/{notebook}" - list_name = Path(f"examples/tutorials/{notebook}") - tested_notebooks.append(str(list_name)) - res = pm.execute_notebook( - notebook, - "/dev/null", - parameters={"epochs": 1, "n_test_batches": 5, "n_train_items": 64, "n_test_items": 64}, - timeout=300, - ) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - - -@pytest.mark.parametrize("notebook", sorted(set(advanced_notebooks) - set(excluded_notebooks))) -def test_notebooks_advanced(isolated_filesystem, notebook): - notebook = notebook.replace("examples/tutorials/", "") - list_name = Path("examples/tutorials/") / notebook - tested_notebooks.append(str(list_name)) - res = pm.execute_notebook(notebook, "/dev/null", parameters={"epochs": 1}, timeout=300) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - - -def test_fl_with_trainconfig(isolated_filesystem, start_remote_server_worker_only, hook): - os.chdir("advanced/Federated Learning with TrainConfig/") - notebook = "Introduction to TrainConfig.ipynb" - p_name = Path("examples/tutorials/advanced/Federated Learning with TrainConfig/") - tested_notebooks.append(str(p_name / notebook)) - hook.local_worker.remove_worker_from_registry("alice") - kwargs = {"id": "alice", "host": "localhost", "port": 8777, "hook": hook} - data = torch.tensor([[0.0, 1.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]], requires_grad=True) - target = torch.tensor([[1.0], [1.0], [0.0], [0.0]], requires_grad=False) - dataset = sy.BaseDataset(data, target) - process_remote_worker = start_remote_server_worker_only(dataset=(dataset, "xor"), **kwargs) - res = pm.execute_notebook(notebook, "/dev/null", timeout=300) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - process_remote_worker.terminate() - sy.VirtualWorker(id="alice", hook=hook, is_client_worker=False) - - -@pytest.mark.skip -def test_fl_sms(isolated_filesystem): # pragma: no cover - sys.path.append("advanced/Federated SMS Spam prediction/") - import preprocess - - os.chdir("advanced/Federated SMS Spam prediction/") - - notebook = "Federated SMS Spam prediction.ipynb" - p_name = Path("examples/tutorials/advanced/Federated SMS Spam prediction/") - tested_notebooks.append(str(p_name / notebook)) - Path("data").mkdir(parents=True, exist_ok=True) - url = "https://archive.ics.uci.edu/ml/machine-learning-databases/00228/smsspamcollection.zip" - urllib.request.urlretrieve(url, "data.zip") - with ZipFile("data.zip", "r") as zipObj: - # Extract all the contents of the zip file in current directory - zipObj.extractall() - preprocess.main() - res = pm.execute_notebook(notebook, "/dev/null", parameters={"epochs": 1}, timeout=300) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - - -def test_fl_with_websockets_and_averaging( - isolated_filesystem, start_remote_server_worker_only, hook -): - os.chdir("advanced/websockets-example-MNIST/") - notebook = "Federated learning with websockets and federated averaging.ipynb" - p_name = Path("examples/tutorials/advanced/websockets-example-MNIST/") - tested_notebooks.append(str(p_name / notebook)) - for n in ["alice", "bob", "charlie"]: - hook.local_worker.remove_worker_from_registry(n) - kwargs_list = [ - {"id": "alice", "host": "localhost", "port": 8777, "hook": hook}, - {"id": "bob", "host": "localhost", "port": 8778, "hook": hook}, - {"id": "charlie", "host": "localhost", "port": 8779, "hook": hook}, - ] - processes = [start_remote_server_worker_only(**kwargs) for kwargs in kwargs_list] - res = pm.execute_notebook( - notebook, - "/dev/null", - parameters={"args": ["--epochs", "1", "--test_batch_size", "100"], "abort_after_one": True}, - timeout=300, - ) - assert isinstance(res, nbformat.notebooknode.NotebookNode) - [server.terminate() for server in processes] - for n in ["alice", "bob", "charlie"]: - sy.VirtualWorker(id=n, hook=hook, is_client_worker=False) - - -### These tests must always be last -def test_all_notebooks_except_translations(): - untested_notebooks = ( - set(all_notebooks) - - set(excluded_notebooks) - - set(translated_notebooks) - - set(tested_notebooks) - ) - assert len(untested_notebooks) == 0, untested_notebooks - - -@pytest.mark.translation -def test_all_translation_notebooks(): # pragma: no cover - untested_notebooks = set(translated_notebooks) - set(excluded_notebooks) - set(tested_notebooks) - assert len(untested_notebooks) == 0, untested_notebooks diff --git a/test/run_websocket_server.py b/test/run_websocket_server.py deleted file mode 100644 index 8b323fa3e04..00000000000 --- a/test/run_websocket_server.py +++ /dev/null @@ -1,134 +0,0 @@ -import logging -import syft as sy -from syft.workers import WebsocketServerWorker -import torch -import argparse -from torchvision import datasets -from torchvision import transforms -import numpy as np -from syft.frameworks.torch.federated import utils - -KEEP_LABELS_DICT = { - "alice": [0, 1, 2, 3], - "bob": [4, 5, 6], - "charlie": [7, 8, 9], - "testing": list(range(10)), -} # pragma: no cover - - -def start_websocket_server_worker( - id, host, port, hook, verbose, keep_labels=None, training=True -): # pragma: no cover - """Helper function for spinning up a websocket server and setting up the local datasets.""" - - server = WebsocketServerWorker(id=id, host=host, port=port, hook=hook, verbose=verbose) - - # Setup toy data (mnist example) - mnist_dataset = datasets.MNIST( - root="./data", - train=training, - download=True, - transform=transforms.Compose( - [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] - ), - ) - - if training: - indices = np.isin(mnist_dataset.targets, keep_labels).astype("uint8") - logger.info("number of true indices: %s", indices.sum()) - selected_data = ( - torch.native_masked_select(mnist_dataset.data.transpose(0, 2), torch.tensor(indices)) - .view(28, 28, -1) - .transpose(2, 0) - ) - logger.info("after selection: %s", selected_data.shape) - selected_targets = torch.native_masked_select(mnist_dataset.targets, torch.tensor(indices)) - - dataset = sy.BaseDataset( - data=selected_data, targets=selected_targets, transform=mnist_dataset.transform - ) - key = "mnist" - else: - dataset = sy.BaseDataset( - data=mnist_dataset.data, - targets=mnist_dataset.targets, - transform=mnist_dataset.transform, - ) - key = "mnist_testing" - - server.add_dataset(dataset, key=key) - - # Setup toy data (vectors example) - data_vectors = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]], requires_grad=True) - target_vectors = torch.tensor([[1], [0], [1], [0]]) - - server.add_dataset(sy.BaseDataset(data_vectors, target_vectors), key="vectors") - - # Setup toy data (xor example) - data_xor = torch.tensor([[0.0, 1.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]], requires_grad=True) - target_xor = torch.tensor([1.0, 1.0, 0.0, 0.0], requires_grad=False) - - server.add_dataset(sy.BaseDataset(data_xor, target_xor), key="xor") - - # Setup gaussian mixture dataset - data, target = utils.create_gaussian_mixture_toy_data(nr_samples=100) - server.add_dataset(sy.BaseDataset(data, target), key="gaussian_mixture") - - # Setup partial iris dataset - data, target = utils.iris_data_partial() - dataset = sy.BaseDataset(data, target) - dataset_key = "iris" - server.add_dataset(dataset, key=dataset_key) - - logger.info("datasets: %s", server.datasets) - if training: - logger.info("len(datasets[mnist]): %s", len(server.datasets["mnist"])) - - server.start() - return server - - -if __name__ == "__main__": # pragma: no cover - # Logging setup - logger = logging.getLogger("run_websocket_server") - FORMAT = "%(asctime)s %(levelname)s %(filename)s(l:%(lineno)d, p:%(process)d) - %(message)s" - logging.basicConfig(format=FORMAT) - logger.setLevel(level=logging.DEBUG) - - # Parse args - parser = argparse.ArgumentParser(description="Run websocket server worker.") - parser.add_argument( - "--port", - "-p", - type=int, - help="port number of the websocket server worker, e.g. --port 8777", - ) - parser.add_argument("--host", type=str, default="localhost", help="host for the connection") - parser.add_argument( - "--id", type=str, help="name (id) of the websocket server worker, e.g. --id alice" - ) - parser.add_argument( - "--testing", - action="store_true", - help="if set, websocket server worker will load the test dataset instead of the training dataset", - ) - parser.add_argument( - "--verbose", - "-v", - action="store_true", - help="if set, websocket server worker will be started in verbose mode", - ) - - args = parser.parse_args() - - # Hook and start server - hook = sy.TorchHook(torch) - server = start_websocket_server_worker( - id=args.id, - host=args.host, - port=args.port, - hook=hook, - verbose=args.verbose, - keep_labels=KEEP_LABELS_DICT[args.id] if args.id in KEEP_LABELS_DICT else list(range(10)), - training=not args.testing, - ) diff --git a/test/scripts/run_websocket_server.py b/test/scripts/run_websocket_server.py deleted file mode 100644 index a81d8ece2ef..00000000000 --- a/test/scripts/run_websocket_server.py +++ /dev/null @@ -1,134 +0,0 @@ -import logging -import syft as sy -from syft.workers.websocket_server import WebsocketServerWorker -import torch -import argparse -from torchvision import datasets -from torchvision import transforms -import numpy as np -from syft.frameworks.torch.fl import utils - -KEEP_LABELS_DICT = { - "alice": [0, 1, 2, 3], - "bob": [4, 5, 6], - "charlie": [7, 8, 9], - "testing": list(range(10)), -} # pragma: no cover - - -def start_websocket_server_worker( - id, host, port, hook, verbose, keep_labels=None, training=True -): # pragma: no cover - """Helper function for spinning up a websocket server and setting up the local datasets.""" - - server = WebsocketServerWorker(id=id, host=host, port=port, hook=hook, verbose=verbose) - - # Setup toy data (mnist example) - mnist_dataset = datasets.MNIST( - root="./data", - train=training, - download=True, - transform=transforms.Compose( - [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] - ), - ) - - if training: - indices = np.isin(mnist_dataset.targets, keep_labels).astype("uint8") - logger.info("number of true indices: %s", indices.sum()) - selected_data = ( - torch.native_masked_select(mnist_dataset.data.transpose(0, 2), torch.tensor(indices)) - .view(28, 28, -1) - .transpose(2, 0) - ) - logger.info("after selection: %s", selected_data.shape) - selected_targets = torch.native_masked_select(mnist_dataset.targets, torch.tensor(indices)) - - dataset = sy.BaseDataset( - data=selected_data, targets=selected_targets, transform=mnist_dataset.transform - ) - key = "mnist" - else: - dataset = sy.BaseDataset( - data=mnist_dataset.data, - targets=mnist_dataset.targets, - transform=mnist_dataset.transform, - ) - key = "mnist_testing" - - server.add_dataset(dataset, key=key) - - # Setup toy data (vectors example) - data_vectors = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]], requires_grad=True) - target_vectors = torch.tensor([[1], [0], [1], [0]]) - - server.add_dataset(sy.BaseDataset(data_vectors, target_vectors), key="vectors") - - # Setup toy data (xor example) - data_xor = torch.tensor([[0.0, 1.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]], requires_grad=True) - target_xor = torch.tensor([1.0, 1.0, 0.0, 0.0], requires_grad=False) - - server.add_dataset(sy.BaseDataset(data_xor, target_xor), key="xor") - - # Setup gaussian mixture dataset - data, target = utils.create_gaussian_mixture_toy_data(nr_samples=100) - server.add_dataset(sy.BaseDataset(data, target), key="gaussian_mixture") - - # Setup partial iris dataset - data, target = utils.iris_data_partial() - dataset = sy.BaseDataset(data, target) - dataset_key = "iris" - server.add_dataset(dataset, key=dataset_key) - - logger.info("datasets: %s", server.datasets) - if training: - logger.info("len(datasets[mnist]): %s", len(server.datasets["mnist"])) - - server.start() - return server - - -if __name__ == "__main__": # pragma: no cover - # Logging setup - logger = logging.getLogger("run_websocket_server") - FORMAT = "%(asctime)s %(levelname)s %(filename)s(l:%(lineno)d, p:%(process)d) - %(message)s" - logging.basicConfig(format=FORMAT) - logger.setLevel(level=logging.DEBUG) - - # Parse args - parser = argparse.ArgumentParser(description="Run websocket server worker.") - parser.add_argument( - "--port", - "-p", - type=int, - help="port number of the websocket server worker, e.g. --port 8777", - ) - parser.add_argument("--host", type=str, default="localhost", help="host for the connection") - parser.add_argument( - "--id", type=str, help="name (id) of the websocket server worker, e.g. --id alice" - ) - parser.add_argument( - "--testing", - action="store_true", - help="if set, websocket server worker will load the test dataset instead of the training dataset", - ) - parser.add_argument( - "--verbose", - "-v", - action="store_true", - help="if set, websocket server worker will be started in verbose mode", - ) - - args = parser.parse_args() - - # Hook and start server - hook = sy.TorchHook(torch) - server = start_websocket_server_worker( - id=args.id, - host=args.host, - port=args.port, - hook=hook, - verbose=args.verbose, - keep_labels=KEEP_LABELS_DICT[args.id] if args.id in KEEP_LABELS_DICT else list(range(10)), - training=not args.testing, - ) diff --git a/test/serde/msgpack/test_msgpack_serde.py b/test/serde/msgpack/test_msgpack_serde.py deleted file mode 100644 index e1c0edd3a4e..00000000000 --- a/test/serde/msgpack/test_msgpack_serde.py +++ /dev/null @@ -1,847 +0,0 @@ -""" -This file tests the ability for serde.py to convert complex types into -simple python types which are serializable by standard serialization tools. -For more on how/why this works, see serde.py directly. -""" -import msgpack as msgpack_lib -import numpy -import pytest -import torch -from torch import Tensor - -import syft -from syft.frameworks.torch.tensors.interpreters.additive_shared import AdditiveSharingTensor -from syft.generic.pointers.object_wrapper import ObjectWrapper -from syft.generic.pointers.pointer_tensor import PointerTensor -from syft.serde import compression -from syft.serde import msgpack -from syft.serde import serde -from syft.serde.msgpack import native_serde -from syft.serde.msgpack import torch_serde -from syft.workers.virtual import VirtualWorker - -from syft.exceptions import CompressionNotFoundException - - -def test_tuple_simplify(workers): - """This tests our ability to simplify tuple types. - - This test is pretty simple since tuples just serialize to - themselves, with a tuple wrapper with the correct ID (1) - for tuples so that the detailer knows how to interpret it.""" - - me = workers["me"] - input = ("hello", "world") - tuple_detail_code = msgpack.proto_type_info(tuple).code - str_detail_code = msgpack.proto_type_info(str).code - target = (tuple_detail_code, ((str_detail_code, (b"hello",)), (str_detail_code, (b"world",)))) - assert msgpack.serde._simplify(me, input) == target - - -def test_list_simplify(workers): - """This tests our ability to simplify list types. - - This test is pretty simple since lists just serialize to - themselves, with a tuple wrapper with the correct ID (2) - for lists so that the detailer knows how to interpret it.""" - - me = workers["me"] - input = ["hello", "world"] - list_detail_code = msgpack.proto_type_info(list).code - str_detail_code = msgpack.proto_type_info(str).code - target = (list_detail_code, ((str_detail_code, (b"hello",)), (str_detail_code, (b"world",)))) - assert msgpack.serde._simplify(me, input) == target - - -def test_set_simplify(workers): - """This tests our ability to simplify set objects. - - This test is pretty simple since sets just serialize to - lists, with a tuple wrapper with the correct ID (3) - for sets so that the detailer knows how to interpret it.""" - - me = workers["me"] - input = set(["hello", "world"]) - set_detail_code = msgpack.proto_type_info(set).code - str_detail_code = msgpack.proto_type_info(str).code - target = (set_detail_code, ((str_detail_code, (b"hello",)), (str_detail_code, (b"world",)))) - assert msgpack.serde._simplify(me, input)[0] == target[0] - assert set(msgpack.serde._simplify(me, input)[1]) == set(target[1]) - - -def test_float_simplify(workers): - """This tests our ability to simplify float objects. - - This test is pretty simple since floats just serialize to - themselves, with no tuple/id necessary.""" - - me = workers["me"] - input = 5.6 - target = 5.6 - assert msgpack.serde._simplify(me, input) == target - - -def test_int_simplify(workers): - """This tests our ability to simplify int objects. - - This test is pretty simple since ints just serialize to - themselves, with no tuple/id necessary.""" - - me = workers["me"] - input = 5 - target = 5 - assert msgpack.serde._simplify(me, input) == target - - -def test_string_simplify(workers): - """This tests our ability to simplify string objects. - - This test is pretty simple since strings just serialize to - themselves, with no tuple/id necessary.""" - - me = workers["me"] - input = "hello" - target = (msgpack.proto_type_info(str).code, (b"hello",)) - assert msgpack.serde._simplify(me, input) == target - - -def test_dict_simplify(workers): - """This tests our ability to simplify dict objects. - - This test is pretty simple since dicts just serialize to - themselves, with a tuple wrapper with the correct ID - for dicts so that the detailer knows how to interpret it.""" - - me = workers["me"] - input = {"hello": "world"} - detail_dict_code = msgpack.proto_type_info(dict).code - detail_str_code = msgpack.proto_type_info(str).code - target = (detail_dict_code, (((detail_str_code, (b"hello",)), (detail_str_code, (b"world",))),)) - assert msgpack.serde._simplify(me, input) == target - - -def test_range_simplify(workers): - """This tests our ability to simplify range objects. - - This test is pretty simple since range objs just serialize to - themselves, with a tuple wrapper with the correct ID (5) - for dicts so that the detailer knows how to interpret it.""" - - me = workers["me"] - input = range(1, 3, 4) - target = (msgpack.proto_type_info(range).code, (1, 3, 4)) - assert msgpack.serde._simplify(me, input) == target - - -def test_torch_tensor_simplify(workers): - """This tests our ability to simplify torch.Tensor objects - using "torch" serialization strategy. - - At the time of writing, tensors simplify to a tuple where the - first value in the tuple is the tensor's ID and the second - value is a serialized version of the Tensor (serialized - by PyTorch's torch.save method) - """ - - me = workers["me"] - - # create a tensor - input = Tensor(numpy.random.random((100, 100))) - - # simplify the tnesor - output = msgpack.serde._simplify(me, input) - - # make sure outer type is correct - assert type(output) == tuple - - # make sure the object type ID is correct - # (0 for torch.Tensor) - assert msgpack.serde.detailers[output[0]] == torch_serde._detail_torch_tensor - - # make sure inner type is correct - assert type(output[1]) == tuple - - # make sure ID is correctly encoded - assert output[1][0] == input.id - - # make sure tensor data type is correct - assert type(output[1][1]) == bytes - - -def test_torch_tensor_simplify_generic(workers): - """This tests our ability to simplify torch.Tensor objects - using "all" serialization strategy - """ - - worker = VirtualWorker(None, id="non-torch") - - # create a tensor - input = Tensor(numpy.random.random((3, 3, 3))) - - # simplify the tensor - output = msgpack.serde._simplify(worker, input) - - # make sure outer type is correct - assert type(output) == tuple - - # make sure the object type ID is correct - # (0 for torch.Tensor) - assert msgpack.serde.detailers[output[0]] == torch_serde._detail_torch_tensor - - # make sure inner type is correct - assert type(output[1]) == tuple - - # make sure ID is correctly encoded - assert output[1][0] == input.id - - # make sure tensor data type is correct - assert type(output[1][1]) == tuple - assert type(output[1][1][1]) == tuple - - # make sure tensor data matches - assert output[1][1][1][0][1] == input.size() - assert output[1][1][1][2][1] == tuple(input.flatten().tolist()) - - -def test_torch_tensor_serde_generic(workers): - """This tests our ability to ser-de torch.Tensor objects - using "all" serialization strategy - """ - - worker = VirtualWorker(None, id="non-torch") - - # create a tensor - input = Tensor(numpy.random.random((100, 100))) - - # ser-de the tensor - output = msgpack.serde._simplify(worker, input) - detailed = msgpack.serde._detail(worker, output) - - # check tensor contents - assert input.size() == detailed.size() - assert input.dtype == detailed.dtype - assert (input == detailed).all() - - -def test_tensor_gradient_serde(): - # create a tensor - x = torch.tensor([1, 2, 3, 4.0], requires_grad=True) - - # create gradient on tensor - x.sum().backward(torch.tensor(1.0)) - - # save gradient - orig_grad = x.grad - - # serialize - blob = syft.serde.serialize(x) - - # deserialize - t = syft.serde.deserialize(blob) - - # check that gradient was properly serde - assert (t.grad == orig_grad).all() - - -def test_ndarray_simplify(workers): - """This tests our ability to simplify numpy.array objects - - At the time of writing, arrays simplify to an object inside - of a tuple which specifies the ID for the np.array type (6) so - that the detailer knows to turn the simplifed form to a np.array - """ - - me = workers["me"] - input = numpy.random.random((100, 100)) - output = msgpack.serde._simplify(me, input) - - # make sure simplified type ID is correct - assert msgpack.serde.detailers[output[0]] == native_serde._detail_ndarray - - # make sure serialized form is correct - assert type(output[1][0]) == bytes - assert output[1][1] == msgpack.serde._simplify(me, input.shape) - assert output[1][2] == msgpack.serde._simplify(me, input.dtype.name) - - -def test_numpy_number_simplify(workers): - """This tests our ability to simplify numpy.float objects - - At the time of writing, numpy number simplify to an object inside - of a tuple where the first value is a byte representation of the number - and the second value is the dtype - """ - me = workers["me"] - - input = numpy.float32(2.0) - output = msgpack.serde._simplify(me, input) - - # make sure simplified type ID is correct - assert msgpack.serde.detailers[output[0]] == native_serde._detail_numpy_number - - # make sure serialized form is correct - assert type(output[1][0]) == bytes - assert output[1][1] == msgpack.serde._simplify(me, input.dtype.name) - - -def test_ellipsis_simplify(workers): - """Make sure ellipsis simplifies correctly.""" - me = workers["me"] - - assert ( - msgpack.serde.detailers[msgpack.serde._simplify(me, Ellipsis)[0]] - == native_serde._detail_ellipsis - ) - - # the simplified ellipsis (empty object) - assert msgpack.serde._simplify(me, Ellipsis)[1] == (b"",) - - -def test_torch_device_simplify(workers): - """Test the simplification of torch.device""" - - me = workers["me"] - device = torch.device("cpu") - - assert ( - msgpack.serde.detailers[msgpack.serde._simplify(me, device)[0]] - == torch_serde._detail_torch_device - ) - - # the simplified torch.device - assert msgpack.serde._simplify(me, device)[1][0] == msgpack.serde._simplify(me, "cpu") - - -def test_pointer_tensor_simplify(workers): - """Test the simplification of PointerTensor""" - - alice, me = workers["alice"], workers["me"] - - input_tensor = PointerTensor(id=1000, location=alice, owner=alice) - - output = msgpack.serde._simplify(me, input_tensor) - - assert output[1][0] == input_tensor.id - assert output[1][1] == input_tensor.id_at_location - assert output[1][2] == msgpack.serde._simplify(me, input_tensor.owner.id) - - -@pytest.mark.parametrize("compress", [True, False]) -def test_torch_Tensor(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - t = Tensor(numpy.random.random((100, 100))) - t_serialized = syft.serde.serialize(t) - t_serialized_deserialized = syft.serde.deserialize(t_serialized) - assert (t == t_serialized_deserialized).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_torch_Tensor_convenience(compress): - """This test evaluates torch.Tensor.serialize() - - As opposed to using syft.serde.serialize(), torch objects - have a convenience function which lets you call .serialize() - directly on the tensor itself. This tests to makes sure it - works correctly.""" - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - t = Tensor(numpy.random.random((100, 100))) - t_serialized = t.serialize() - t_serialized_deserialized = syft.serde.deserialize(t_serialized) - assert (t == t_serialized_deserialized).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_tuple(compress): - # Test with a simple datatype - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - tuple = (1, 2) - tuple_serialized = syft.serde.serialize(tuple) - tuple_serialized_deserialized = syft.serde.deserialize(tuple_serialized) - assert tuple == tuple_serialized_deserialized - - # Test with a complex data structure - tensor_one = Tensor(numpy.random.random((100, 100))) - tensor_two = Tensor(numpy.random.random((100, 100))) - tuple = (tensor_one, tensor_two) - tuple_serialized = syft.serde.serialize(tuple) - tuple_serialized_deserialized = syft.serde.deserialize(tuple_serialized) - # `assert tuple_serialized_deserialized == tuple` does not work, therefore it's split - # into 3 assertions - assert type(tuple_serialized_deserialized) == type(tuple) - assert (tuple_serialized_deserialized[0] == tensor_one).all() - assert (tuple_serialized_deserialized[1] == tensor_two).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_bytearray(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - bytearr = bytearray("This is a teststring", "utf-8") - bytearr_serialized = syft.serde.serialize(bytearr) - bytearr_serialized_desirialized = syft.serde.deserialize(bytearr_serialized) - assert bytearr == bytearr_serialized_desirialized - - bytearr = bytearray(numpy.random.random((100, 100))) - bytearr_serialized = syft.serde.serialize(bytearr) - bytearr_serialized_desirialized = syft.serde.deserialize(bytearr_serialized) - assert bytearr == bytearr_serialized_desirialized - - -@pytest.mark.parametrize("compress", [True, False]) -def test_ndarray_serde(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - arr = numpy.random.random((100, 100)) - arr_serialized = syft.serde.serialize(arr) - - arr_serialized_deserialized = syft.serde.deserialize(arr_serialized) - - assert numpy.array_equal(arr, arr_serialized_deserialized) - - -@pytest.mark.parametrize( - "compress_scheme", [compression.LZ4, compression.ZSTD, compression.NO_COMPRESSION] -) -def test_compress_decompress(compress_scheme): - if compress_scheme == compression.LZ4: - compression._apply_compress_scheme = compression.apply_lz4_compression - elif compress_scheme == compression.ZSTD: - compression._apply_compress_scheme = compression.apply_zstd_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - original = msgpack_lib.dumps([1, 2, 3]) - compressed = compression._compress(original) - decompressed = compression._decompress(compressed) - assert type(compressed) == bytes - assert original == decompressed - - -@pytest.mark.parametrize( - "compress_scheme", [compression.LZ4, compression.ZSTD, compression.NO_COMPRESSION] -) -def test_compressed_serde(compress_scheme): - if compress_scheme == compression.LZ4: - compression._apply_compress_scheme = compression.apply_lz4_compression - elif compress_scheme == compression.ZSTD: - compression._apply_compress_scheme = compression.apply_zstd_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - # using numpy.ones because numpy.random.random is not compressed. - arr = numpy.ones((100, 100)) - - arr_serialized = syft.serde.serialize(arr) - - arr_serialized_deserialized = syft.serde.deserialize(arr_serialized) - assert numpy.array_equal(arr, arr_serialized_deserialized) - - -@pytest.mark.parametrize("compress", [True, False]) -def test_dict(compress): - # Test with integers - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - _dict = {1: 1, 2: 2, 3: 3} - dict_serialized = syft.serde.serialize(_dict) - dict_serialized_deserialized = syft.serde.deserialize(dict_serialized) - assert _dict == dict_serialized_deserialized - - # Test with strings - _dict = {"one": 1, "two": 2, "three": 3} - dict_serialized = syft.serde.serialize(_dict) - dict_serialized_deserialized = syft.serde.deserialize(dict_serialized) - assert _dict == dict_serialized_deserialized - - # Test with a complex data structure - tensor_one = Tensor(numpy.random.random((100, 100))) - tensor_two = Tensor(numpy.random.random((100, 100))) - _dict = {0: tensor_one, 1: tensor_two} - dict_serialized = syft.serde.serialize(_dict) - dict_serialized_deserialized = syft.serde.deserialize(dict_serialized) - # `assert dict_serialized_deserialized == _dict` does not work, therefore it's split - # into 3 assertions - assert type(dict_serialized_deserialized) == type(_dict) - assert (dict_serialized_deserialized[0] == tensor_one).all() - assert (dict_serialized_deserialized[1] == tensor_two).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_range_serde(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - _range = range(1, 2, 3) - - range_serialized = syft.serde.serialize(_range) - range_serialized_deserialized = syft.serde.deserialize(range_serialized) - - assert _range == range_serialized_deserialized - - -@pytest.mark.parametrize("compress", [True, False]) -def test_list(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - # Test with integers - _list = [1, 2] - list_serialized = syft.serde.serialize(_list) - list_serialized_deserialized = syft.serde.deserialize(list_serialized) - assert _list == list_serialized_deserialized - - # Test with strings - _list = ["hello", "world"] - list_serialized = syft.serde.serialize(_list) - list_serialized_deserialized = syft.serde.deserialize(list_serialized) - assert _list == list_serialized_deserialized - - # Test with a complex data structure - tensor_one = Tensor(numpy.ones((100, 100))) - tensor_two = Tensor(numpy.ones((100, 100)) * 2) - _list = (tensor_one, tensor_two) - - list_serialized = syft.serde.serialize(_list) - if compress: - assert list_serialized[0] == compression.LZ4 - else: - assert list_serialized[0] == compression.NO_COMPRESSION - - list_serialized_deserialized = syft.serde.deserialize(list_serialized) - # `assert list_serialized_deserialized == _list` does not work, therefore it's split - # into 3 assertions - assert type(list_serialized_deserialized) == type(_list) - assert (list_serialized_deserialized[0] == tensor_one).all() - assert (list_serialized_deserialized[1] == tensor_two).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_set(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - # Test with integers - _set = set([1, 2]) - set_serialized = syft.serde.serialize(_set) - - set_serialized_deserialized = syft.serde.deserialize(set_serialized) - assert _set == set_serialized_deserialized - - # Test with strings - _set = set(["hello", "world"]) - set_serialized = syft.serde.serialize(_set) - set_serialized_deserialized = syft.serde.deserialize(set_serialized) - assert _set == set_serialized_deserialized - - # Test with a complex data structure - tensor_one = Tensor(numpy.ones((100, 100))) - tensor_two = Tensor(numpy.ones((100, 100)) * 2) - _set = (tensor_one, tensor_two) - - set_serialized = syft.serde.serialize(_set) - if compress: - assert set_serialized[0] == compression.LZ4 - else: - assert set_serialized[0] == compression.NO_COMPRESSION - - set_serialized_deserialized = syft.serde.deserialize(set_serialized) - # `assert set_serialized_deserialized == _set` does not work, therefore it's split - # into 3 assertions - assert type(set_serialized_deserialized) == type(_set) - assert (set_serialized_deserialized[0] == tensor_one).all() - assert (set_serialized_deserialized[1] == tensor_two).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_slice(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - s = slice(0, 100, 2) - x = numpy.random.rand(100) - s_serialized = syft.serde.serialize(s) - s_serialized_deserialized = syft.serde.deserialize(s_serialized) - - assert type(s) == type(s_serialized_deserialized) - assert (x[s] == x[s_serialized_deserialized]).all() - - s = slice(40, 50) - x = numpy.random.rand(100) - s_serialized = syft.serde.serialize(s) - s_serialized_deserialized = syft.serde.deserialize(s_serialized) - - assert type(s) == type(s_serialized_deserialized) - assert (x[s] == x[s_serialized_deserialized]).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_float(compress): - if compress: - compression._apply_compress_scheme = compression.apply_lz4_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - x = 0.5 - y = 1.5 - - x_serialized = syft.serde.serialize(x) - x_serialized_deserialized = syft.serde.deserialize(x_serialized) - - y_serialized = syft.serde.serialize(y) - y_serialized_deserialized = syft.serde.deserialize(y_serialized) - - assert x_serialized_deserialized == x - assert y_serialized_deserialized == y - - -@pytest.mark.parametrize( - "compress, compress_scheme", - [ - (True, compression.LZ4), - (False, compression.LZ4), - (True, compression.ZSTD), - (False, compression.ZSTD), - (True, compression.NO_COMPRESSION), - (False, compression.NO_COMPRESSION), - ], -) -def test_hooked_tensor(compress, compress_scheme): - if compress: - if compress_scheme == compression.LZ4: - compression._apply_compress_scheme = compression.apply_lz4_compression - elif compress_scheme == compression.ZSTD: - compression._apply_compress_scheme = compression.apply_zstd_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - else: - compression._apply_compress_scheme = compression.apply_no_compression - - t = Tensor(numpy.ones((100, 100))) - t_serialized = syft.serde.serialize(t) - assert ( - t_serialized[0] == compress_scheme - if compress - else t_serialized[0] == compression.NO_COMPRESSION - ) - t_serialized_deserialized = syft.serde.deserialize(t_serialized) - assert (t == t_serialized_deserialized).all() - - -def test_pointer_tensor(hook, workers): - compression._apply_compress_scheme = compression.apply_no_compression - t = PointerTensor( - id=1000, location=workers["alice"], owner=workers["alice"], id_at_location=12345 - ) - t_serialized = syft.serde.serialize(t) - t_serialized_deserialized = syft.serde.deserialize(t_serialized) - assert t.id == t_serialized_deserialized.id - assert t.location.id == t_serialized_deserialized.location.id - assert t.id_at_location == t_serialized_deserialized.id_at_location - - -@pytest.mark.parametrize("id", [1000, "1000"]) -def test_pointer_tensor_detail(id): - alice = syft.VirtualWorker(syft.torch.hook, id=id) - x = torch.tensor([1, -1, 3, 4]) - x_ptr = x.send(alice) - x_ptr = 2 * x_ptr - x_back = x_ptr.get() - assert (x_back == 2 * x).all() - - -@pytest.mark.parametrize( - "tensor", - [ - (torch.tensor(numpy.ones((10, 10)), requires_grad=False)), - (torch.tensor([[0.25, 1.5], [0.15, 0.25], [1.25, 0.5]], requires_grad=True)), - (torch.randint(low=0, high=10, size=[3, 7], requires_grad=False)), - ], -) -def test_numpy_tensor_serde(tensor): - compression._apply_compress_scheme = compression.apply_lz4_compression - - serde._serialize_tensor = syft.serde.msgpack.torch_serde.numpy_tensor_serializer - serde._deserialize_tensor = syft.serde.msgpack.torch_serde.numpy_tensor_deserializer - - tensor_serialized = syft.serde.serialize(tensor) - assert tensor_serialized[0] != compression.NO_COMPRESSION - tensor_deserialized = syft.serde.deserialize(tensor_serialized) - - # Back to Pytorch serializer - serde._serialize_tensor = syft.serde.msgpack.torch_serde.torch_tensor_serializer - serde._deserialize_tensor = syft.serde.msgpack.torch_serde.torch_tensor_deserializer - - assert torch.eq(tensor_deserialized, tensor).all() - - -@pytest.mark.parametrize("compress", [True, False]) -def test_additive_sharing_tensor_serde(compress, workers): - alice, bob, james, me = workers["alice"], workers["bob"], workers["james"], workers["me"] - - x = torch.tensor([[3.1, 4.3]]).fix_prec().share(alice, bob, crypto_provider=james) - - additive_sharing_tensor = x.child.child - data = AdditiveSharingTensor.simplify(me, additive_sharing_tensor) - additive_sharing_tensor_reconstructed = AdditiveSharingTensor.detail(me, data) - - assert additive_sharing_tensor_reconstructed.field == additive_sharing_tensor.field - - assert ( - additive_sharing_tensor_reconstructed.child.keys() == additive_sharing_tensor.child.keys() - ) - - -@pytest.mark.parametrize("compress", [True, False]) -def test_fixed_precision_tensor_serde(compress, workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = ( - torch.tensor([[3.1, 4.3]]) - .fix_prec(base=12, precision_fractional=5) - .share(alice, bob, crypto_provider=james) - ) - - serialized_x = syft.serde.serialize(x) - deserialized_x = syft.serde.deserialize(serialized_x) - - assert x.id == deserialized_x.child.id - assert x.child.field == deserialized_x.child.field - assert x.child.kappa == deserialized_x.child.kappa - assert x.child.precision_fractional == deserialized_x.child.precision_fractional - assert x.child.base == deserialized_x.child.base - - -def test_serde_object_wrapper_int(): - obj = 4 - obj_wrapper = ObjectWrapper(obj, id=100) - msg = syft.serde.serialize(obj_wrapper) - - obj_wrapper_received = syft.serde.deserialize(msg) - - assert obj_wrapper.obj == obj_wrapper_received.obj - assert obj_wrapper.id == obj_wrapper_received.id - - -@pytest.mark.skipif( - torch.__version__ >= "1.1", - reason="bug in pytorch version 1.1.0, jit.trace returns raw C function", -) -def test_serialize_and_deserialize_torch_scriptmodule(): # pragma: no cover - @torch.jit.script - def foo(x): - return x + 2 - - bin_message = torch_serde._simplify_script_module(foo) - foo_loaded = torch_serde._detail_script_module(None, bin_message) - - assert foo.code == foo_loaded.code - - -@pytest.mark.skipif( - torch.__version__ >= "1.1", - reason="bug in pytorch version 1.1.0, jit.trace returns raw C function", -) -def test_torch_jit_script_module_serde(): # pragma: no cover - @torch.jit.script - def foo(x): - return x + 2 - - msg = syft.serde.serialize(foo) - foo_received = syft.serde.deserialize(msg) - - assert foo.code == foo_received.code - - -def test_serde_virtual_worker(hook): - virtual_worker = syft.VirtualWorker(hook=hook, id="deserialized_worker1") - # Populate worker - tensor1, tensor2 = torch.tensor([1.0, 2.0]), torch.tensor([0.0]) - ptr1, ptr2 = tensor1.send(virtual_worker), tensor2.send(virtual_worker) - - serialized_worker = syft.serde.serialize(virtual_worker, force_full_simplification=False) - deserialized_worker = syft.serde.deserialize(serialized_worker) - - assert virtual_worker.id == deserialized_worker.id - - -def test_full_serde_virtual_worker(hook): - virtual_worker = syft.VirtualWorker(hook=hook, id="deserialized_worker2") - # Populate worker - tensor1, tensor2 = torch.tensor([1.0, 2.0]), torch.tensor([0.0]) - ptr1, ptr2 = tensor1.send(virtual_worker), tensor2.send(virtual_worker) - - serialized_worker = syft.serde.serialize(virtual_worker, force_full_simplification=True) - - deserialized_worker = syft.serde.deserialize(serialized_worker) - - assert virtual_worker.id == deserialized_worker.id - assert virtual_worker.auto_add == deserialized_worker.auto_add - assert len(deserialized_worker._objects) == 2 - assert tensor1.id in deserialized_worker._objects - assert tensor2.id in deserialized_worker._objects - - -def test_serde_object_wrapper_traced_module(): - - data = torch.tensor([[-1, 2.0], [0, 1.1], [-1, 2.1], [0, 1.2]]) - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(2, 3) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - return x - - obj = torch.jit.trace(Net(), data) - - obj_wrapper = ObjectWrapper(obj, id=200) - msg = syft.serde.serialize(obj_wrapper) - - obj_wrapper_received = syft.serde.deserialize(msg) - - pred_before = obj(data) - - pred_after = obj_wrapper_received.obj(data) - - assert (pred_before == pred_after).all() - assert obj_wrapper.id == obj_wrapper_received.id - - -def test_no_simplifier_found(workers): - """Test that types that can not be simplified are cached.""" - me = workers["me"] - # Clean cache. - msgpack.serde.no_simplifiers_found = set() - x = 1.3 - assert type(x) not in msgpack.serde.no_simplifiers_found - _ = msgpack.serde._simplify(me, x) - assert type(x) in msgpack.serde.no_simplifiers_found diff --git a/test/serde/msgpack/test_msgpack_serde_full.py b/test/serde/msgpack/test_msgpack_serde_full.py deleted file mode 100644 index 47708032c15..00000000000 --- a/test/serde/msgpack/test_msgpack_serde_full.py +++ /dev/null @@ -1,147 +0,0 @@ -from collections import OrderedDict -import pytest -import numpy -import torch -from functools import partial -import traceback -import io - -import syft -from syft.serde import msgpack -from test.serde.serde_helpers import * - -# Dictionary containing test samples functions -samples = OrderedDict() - -# Native -samples[float] = make_float -samples[int] = make_int -samples[dict] = make_dict -samples[tuple] = make_tuple -samples[list] = make_list -samples[set] = make_set -samples[slice] = make_slice -samples[str] = make_str -samples[range] = make_range -samples[type(Ellipsis)] = make_ellipsis - -# Numpy -samples[numpy.ndarray] = make_numpy_ndarray -samples[numpy.float32] = partial(make_numpy_number, numpy.float32) -samples[numpy.float64] = partial(make_numpy_number, numpy.float64) -samples[numpy.int32] = partial(make_numpy_number, numpy.int32) -samples[numpy.int64] = partial(make_numpy_number, numpy.int64) - -# PyTorch -samples[torch.device] = make_torch_device -samples[torch.jit.ScriptModule] = make_torch_scriptmodule -samples[torch.jit.ScriptFunction] = make_torch_scriptfunction -samples[torch.jit.TopLevelTracedModule] = make_torch_topleveltracedmodule -samples[torch.nn.Parameter] = make_torch_parameter -samples[torch.Tensor] = make_torch_tensor -samples[torch.Size] = make_torch_size -samples[torch.memory_format] = make_torch_memoryformat - -# PySyft -samples[ - syft.frameworks.torch.tensors.interpreters.additive_shared.AdditiveSharingTensor -] = make_additivesharingtensor -samples[ - syft.frameworks.torch.tensors.interpreters.precision.FixedPrecisionTensor -] = make_fixedprecisiontensor -samples[ - syft.frameworks.torch.tensors.interpreters.crt_precision.CRTPrecisionTensor -] = make_crtprecisiontensor -samples[syft.frameworks.torch.tensors.decorators.logging.LoggingTensor] = make_loggingtensor -samples[syft.generic.pointers.multi_pointer.MultiPointerTensor] = make_multipointertensor -samples[syft.execution.plan.Plan] = make_plan -samples[syft.execution.state.State] = make_state -samples[syft.execution.protocol.Protocol] = make_protocol -samples[syft.generic.pointers.pointer_tensor.PointerTensor] = make_pointertensor -samples[syft.generic.pointers.pointer_plan.PointerPlan] = make_pointerplan -samples[syft.generic.pointers.pointer_protocol.PointerProtocol] = make_pointerprotocol -samples[syft.generic.pointers.object_wrapper.ObjectWrapper] = make_objectwrapper -samples[syft.generic.pointers.object_pointer.ObjectPointer] = make_objectpointer -samples[syft.generic.string.String] = make_string -samples[syft.federated.train_config.TrainConfig] = make_trainconfig -samples[syft.workers.base.BaseWorker] = make_baseworker -samples[syft.frameworks.torch.tensors.interpreters.autograd.AutogradTensor] = make_autogradtensor -samples[syft.frameworks.torch.tensors.interpreters.private.PrivateTensor] = make_privatetensor -samples[syft.frameworks.torch.tensors.interpreters.placeholder.PlaceHolder] = make_placeholder - -samples[syft.messaging.message.Message] = make_message -samples[syft.messaging.message.OperationMessage] = make_operation -samples[syft.messaging.message.ObjectMessage] = make_objectmessage -samples[syft.messaging.message.ObjectRequestMessage] = make_objectrequestmessage -samples[syft.messaging.message.IsNoneMessage] = make_isnonemessage -samples[syft.messaging.message.GetShapeMessage] = make_getshapemessage -samples[syft.messaging.message.ForceObjectDeleteMessage] = make_forceobjectdeletemessage -samples[syft.messaging.message.SearchMessage] = make_searchmessage -samples[syft.messaging.message.PlanCommandMessage] = make_plancommandmessage - -samples[syft.frameworks.torch.tensors.interpreters.gradients_core.GradFunc] = make_gradfn - -samples[syft.exceptions.GetNotPermittedError] = make_getnotpermittederror -samples[syft.exceptions.ResponseSignatureError] = make_responsesignatureerror - -# Dynamically added to msgpack.serde.simplifiers by some other test -samples[syft.workers.virtual.VirtualWorker] = make_baseworker - - -def test_serde_coverage(): - """Checks all types in serde are tested""" - for cls, _ in msgpack.serde.simplifiers.items(): - has_sample = cls in samples - assert has_sample is True, "Serde for %s is not tested" % cls - - -@pytest.mark.parametrize("cls", samples) -def test_serde_roundtrip(cls, workers): - """Checks that values passed through serialization-deserialization stay same""" - _samples = samples[cls](workers=workers) - for sample in _samples: - _simplify = ( - msgpack.serde._simplify - if not sample.get("forced", False) - else msgpack.serde._force_full_simplify - ) - serde_worker = syft.hook.local_worker - serde_worker.framework = sample.get("framework", torch) - obj = sample.get("value") - simplified_obj = _simplify(serde_worker, obj) - if not isinstance(obj, Exception): - detailed_obj = msgpack.serde._detail(serde_worker, simplified_obj) - else: - try: - msgpack.serde._detail(serde_worker, simplified_obj) - except Exception as e: - detailed_obj = e - - if sample.get("cmp_detailed", None): - # Custom detailed objects comparison function. - assert sample.get("cmp_detailed")(detailed_obj, obj) is True - else: - assert type(detailed_obj) == type(obj) - assert detailed_obj == obj - - -@pytest.mark.parametrize("cls", samples) -def test_serde_simplify(cls, workers): - """Checks that simplified structures match expected""" - _samples = samples[cls](workers=workers) - for sample in _samples: - obj, expected_simplified_obj = sample.get("value"), sample.get("simplified") - _simplify = ( - msgpack.serde._simplify - if not sample.get("forced", False) - else msgpack.serde._force_full_simplify - ) - serde_worker = syft.hook.local_worker - serde_worker.framework = sample.get("framework", torch) - simplified_obj = _simplify(syft.hook.local_worker, obj) - - if sample.get("cmp_simplified", None): - # Custom simplified objects comparison function. - assert sample.get("cmp_simplified")(simplified_obj, expected_simplified_obj) is True - else: - assert simplified_obj == expected_simplified_obj diff --git a/test/serde/protobuf/test_protobuf_serde.py b/test/serde/protobuf/test_protobuf_serde.py deleted file mode 100644 index 0e052237ea3..00000000000 --- a/test/serde/protobuf/test_protobuf_serde.py +++ /dev/null @@ -1,86 +0,0 @@ -import torch - -import syft -from syft.serde import protobuf -from syft.serde.torch.serde import TORCH_STR_DTYPE - -from test.serde.serde_helpers import * - - -dtypes = [ - "uint8", - "int8", - "int16", - "int32", - "int64", - "float16", - "float32", - "float64", - "bool", - "bfloat16", -] -quantized_dtypes = ["qint8", "quint8", "qint32"] -complex_types = [] # not yet implemented in PyTorch - - -@pytest.mark.parametrize("str_dtype", dtypes) -def test_protobuf_serde_tensor_roundtrip(str_dtype): - """Checks that tensors passed through serialization-deserialization stay same""" - - def compare(roundtrip, original): - assert type(roundtrip) == torch.Tensor - assert roundtrip.dtype == original.dtype - - # PyTorch doesn't implement equality checking for bfloat16, so convert to float - if original.dtype == torch.bfloat16: - roundtrip = roundtrip.float() - original = original.float() - - # PyTorch doesn't implement equality checking for float16, so use numpy - assert numpy.array_equal(roundtrip.data.numpy(), original.data.numpy()) - return True - - serde_worker = syft.hook.local_worker - original_framework = serde_worker.framework - serde_worker.framework = None - - tensor = torch.rand([10, 10]) * 16 - tensor = tensor.to(TORCH_STR_DTYPE[str_dtype]) - - protobuf_tensor = protobuf.serde._bufferize(serde_worker, tensor) - roundtrip_tensor = protobuf.serde._unbufferize(serde_worker, protobuf_tensor) - - serde_worker.framework = original_framework - - assert compare(roundtrip_tensor, tensor) is True - - -# quantized types can't be created by conversion with `tensor.to()` -@pytest.mark.parametrize("str_dtype", quantized_dtypes) -def test_protobuf_serde_tensor_roundtrip_quantized(str_dtype): - """Checks that tensors passed through serialization-deserialization stay same""" - - def compare(roundtrip, original): - assert type(roundtrip) == torch.Tensor - assert roundtrip.dtype == original.dtype - roundtrip_np = roundtrip.dequantize().numpy() - original_np = original.dequantize().numpy() - # PyTorch does implement equality checking for float tensors, but - # quantized tensors may not be exactly the same after a round trip - # plus dequantizing so use numpy close checking with a tolerance - assert numpy.allclose(roundtrip_np, original_np, atol=2 / original.q_scale()) - return True - - serde_worker = syft.hook.local_worker - original_framework = serde_worker.framework - serde_worker.framework = None - - tensor = torch.rand([10, 10]) * 16 - tensor = torch.quantize_per_tensor(tensor, 0.1, 10, TORCH_STR_DTYPE[str_dtype]) - - protobuf_tensor = protobuf.serde._bufferize(serde_worker, tensor) - roundtrip_tensor = protobuf.serde._unbufferize(serde_worker, protobuf_tensor) - - serde_worker.framework = original_framework - - assert compare(roundtrip_tensor, tensor) is True diff --git a/test/serde/protobuf/test_protobuf_serde_full.py b/test/serde/protobuf/test_protobuf_serde_full.py deleted file mode 100644 index b9078513b2d..00000000000 --- a/test/serde/protobuf/test_protobuf_serde_full.py +++ /dev/null @@ -1,76 +0,0 @@ -from collections import OrderedDict -import pytest -import numpy -import torch -from functools import partial -import traceback -import io - -import syft -from syft.serde import protobuf -from test.serde.serde_helpers import * - -# Dictionary containing test samples functions -samples = OrderedDict() - -# Native -samples[type(None)] = make_none - -# PyTorch -samples[torch.device] = make_torch_device -samples[torch.jit.ScriptModule] = make_torch_scriptmodule -samples[torch.jit.ScriptFunction] = make_torch_scriptfunction -samples[torch.jit.TopLevelTracedModule] = make_torch_topleveltracedmodule -samples[torch.nn.Parameter] = make_torch_parameter -samples[torch.Tensor] = make_torch_tensor -samples[torch.Size] = make_torch_size - -# PySyft -samples[ - syft.frameworks.torch.tensors.interpreters.additive_shared.AdditiveSharingTensor -] = make_additivesharingtensor -samples[syft.frameworks.torch.tensors.interpreters.placeholder.PlaceHolder] = make_placeholder -samples[syft.execution.plan.Plan] = make_plan -samples[syft.generic.pointers.pointer_tensor.PointerTensor] = make_pointertensor -samples[syft.execution.protocol.Protocol] = make_protocol -samples[syft.execution.state.State] = make_state - -# Syft Messages -samples[syft.messaging.message.ObjectMessage] = make_objectmessage -samples[syft.messaging.message.OperationMessage] = make_operation - - -def test_serde_coverage(): - """Checks all types in serde are tested""" - for cls, _ in protobuf.serde.bufferizers.items(): - has_sample = cls in samples - assert has_sample is True, "Serde for %s is not tested" % cls - - -@pytest.mark.parametrize("cls", samples) -def test_serde_roundtrip_protobuf(cls, workers): - """Checks that values passed through serialization-deserialization stay same""" - serde_worker = syft.hook.local_worker - original_framework = serde_worker.framework - _samples = samples[cls](workers=workers) - for sample in _samples: - _to_protobuf = ( - protobuf.serde._bufferize - if not sample.get("forced", False) - else protobuf.serde._force_full_bufferize - ) - serde_worker.framework = sample.get("framework", torch) - obj = sample.get("value") - protobuf_obj = _to_protobuf(serde_worker, obj) - roundtrip_obj = None - if not isinstance(obj, Exception): - roundtrip_obj = protobuf.serde._unbufferize(serde_worker, protobuf_obj) - - serde_worker.framework = original_framework - - if sample.get("cmp_detailed", None): - # Custom detailed objects comparison function. - assert sample.get("cmp_detailed")(roundtrip_obj, obj) is True - else: - assert type(roundtrip_obj) == type(obj) - assert roundtrip_obj == obj diff --git a/test/serde/serde_helpers.py b/test/serde/serde_helpers.py deleted file mode 100644 index 9a77e41b81c..00000000000 --- a/test/serde/serde_helpers.py +++ /dev/null @@ -1,1700 +0,0 @@ -from collections import OrderedDict -import pytest -import numpy -import torch -from functools import partial -import traceback -import io - -import syft -from syft.serde import msgpack - -# Make dict of type codes -CODE = OrderedDict() -for cls, simplifier in msgpack.serde.simplifiers.items(): - CODE[cls] = simplifier[0] -FORCED_CODE = OrderedDict() -for cls, simplifier in msgpack.serde.forced_full_simplifiers.items(): - FORCED_CODE[cls] = simplifier[0] - -######################################################################## -# Functions that return list of serde samples in the following format: -# [ -# { -# "value": original_value, -# "simplified": simplified_value, -# "cmp_detailed": custom_detailed_values_comparison_function, # optional -# "cmp_simplified": custom_simplified_values_comparison_function, # optional -# "framework": None or torch, # optional, affects tensor serialization strategy -# "forced": (bool), # optional, enables forced full simplification -# }, -# ... -# ] -######################################################################## - -######################################################################## -# Native types. -######################################################################## - -# None - - -def make_none(**kwargs): - return [{"value": None}] - - -# Dict. -def make_dict(**kwargs): - return [ - { - "value": {1: "hello", 2: "world"}, - "simplified": ( - CODE[dict], - ( - (1, (CODE[str], (b"hello",))), # [not simplified tuple] # key # value - (2, (CODE[str], (b"world",))), - ), - ), - }, - { - "value": {"hello": "world"}, - "simplified": ( - CODE[dict], - ( - ( # [not simplified tuple] - (CODE[str], (b"hello",)), # key - (CODE[str], (b"world",)), # value - ), - ), - ), - }, - {"value": {}, "simplified": (CODE[dict], tuple())}, - ] - - -# List. -def make_list(**kwargs): - return [ - { - "value": ["hello", "world"], - "simplified": ( - CODE[list], - ((CODE[str], (b"hello",)), (CODE[str], (b"world",))), # item - ), - }, - {"value": ["hello"], "simplified": (CODE[list], ((CODE[str], (b"hello",)),))}, # item - {"value": [], "simplified": (CODE[list], tuple())}, - # Tests that forced full simplify should return just simplified object if it doesn't have full simplifier - { - "forced": True, - "value": ["hello"], - "simplified": (CODE[list], ((CODE[str], (b"hello",)),)), # item - }, - ] - - -# Tuple. -def make_tuple(**kwargs): - return [ - { - "value": ("hello", "world"), - "simplified": (CODE[tuple], ((CODE[str], (b"hello",)), (CODE[str], (b"world",)))), - }, - {"value": ("hello",), "simplified": (CODE[tuple], ((CODE[str], (b"hello",)),))}, - {"value": tuple(), "simplified": (CODE[tuple], tuple())}, - ] - - -# Set. -def make_set(**kwargs): - def compare_simplified(actual, expected): - """When set is simplified and converted to tuple, elements order in tuple is random - We compare tuples as sets because the set order is undefined""" - assert actual[0] == expected[0] - assert set(actual[1]) == set(expected[1]) - return True - - return [ - { - "value": {"hello", "world"}, - "simplified": (CODE[set], ((CODE[str], (b"world",)), (CODE[str], (b"hello",)))), - "cmp_simplified": compare_simplified, - }, - {"value": {"hello"}, "simplified": (CODE[set], ((CODE[str], (b"hello",)),))}, - {"value": set([]), "simplified": (CODE[set], tuple())}, - ] - - -# Slice. -def make_slice(**kwargs): - return [ - {"value": slice(10, 20, 30), "simplified": (CODE[slice], (10, 20, 30))}, - {"value": slice(10, 20), "simplified": (CODE[slice], (10, 20, None))}, - {"value": slice(10), "simplified": (CODE[slice], (None, 10, None))}, - ] - - -# Range. -def make_range(**kwargs): - return [ - {"value": range(1, 3, 4), "simplified": (CODE[range], (1, 3, 4))}, - {"value": range(1, 3), "simplified": (CODE[range], (1, 3, 1))}, - ] - - -# String. -def make_str(**kwargs): - return [ - {"value": "a string", "simplified": (CODE[str], (b"a string",))}, - {"value": "", "simplified": (CODE[str], (b"",))}, - ] - - -# Int. -def make_int(**kwargs): - return [ - {"value": 5, "simplified": 5}, - # Tests that forced full simplify should return just simplified object if it doesn't have full simplifier - {"forced": True, "value": 5, "simplified": 5}, - ] - - -# Float. -def make_float(**kwargs): - return [{"value": 5.1, "simplified": 5.1}] - - -# Ellipsis. -def make_ellipsis(**kwargs): - return [{"value": ..., "simplified": (CODE[type(Ellipsis)], (b"",))}] - - -######################################################################## -# Numpy. -######################################################################## - -# numpy.ndarray -def make_numpy_ndarray(**kwargs): - np_array = numpy.random.random((2, 2)) - - def compare(detailed, original): - """Compare numpy arrays""" - assert numpy.array_equal(detailed, original) - return True - - return [ - { - "value": np_array, - "simplified": ( - CODE[type(np_array)], - ( - np_array.tobytes(), # (bytes) serialized bin - (CODE[tuple], (2, 2)), # (tuple) shape - (CODE[str], (b"float64",)), # (str) dtype.name - ), - ), - "cmp_detailed": compare, - } - ] - - -# numpy.float32, numpy.float64, numpy.int32, numpy.int64 -def make_numpy_number(dtype, **kwargs): - num = numpy.array([2.2], dtype=dtype)[0] - return [ - { - "value": num, - "simplified": ( - CODE[dtype], - ( - num.tobytes(), # (bytes) - (CODE[str], (num.dtype.name.encode("utf-8"),)), # (str) dtype.name - ), - ), - } - ] - - -######################################################################## -# PyTorch. -######################################################################## - -# Utility functions. - - -def compare_modules(detailed, original): - """Compare ScriptModule instances""" - input = torch.randn(10, 3) - # NOTE: after serde TopLevelTracedModule or jit.ScriptFunction become - # ScriptModule (that's what torch.jit.load returns in detail function) - assert isinstance(detailed, torch.jit.ScriptModule) - # Code changes after torch.jit.load(): function becomes `forward` method - if type(original) != torch.jit.ScriptFunction: - assert detailed.code == original.code - # model outputs match - assert detailed(input).equal(original(input)) - return True - - -def save_to_buffer(tensor) -> bin: - """Serializes a pytorch tensor to binary""" - binary_stream = io.BytesIO() - torch.save(tensor, binary_stream) - return binary_stream.getvalue() - - -# torch.device -def make_torch_device(**kwargs): - torch_device = torch.device("cpu") - return [ - { - "value": torch_device, - "simplified": (CODE[type(torch_device)], ((CODE[str], (b"cpu",)),)), # (str) device - } - ] - - -# torch.jit.ScriptModule -def make_torch_scriptmodule(**kwargs): - class ScriptModule(torch.jit.ScriptModule): - def __init__(self): - super(ScriptModule, self).__init__() - - @torch.jit.script_method - def forward(self, x): # pragma: no cover - return x + 2 - - sm = ScriptModule() - return [ - { - "value": sm, - "simplified": ( - CODE[torch.jit.ScriptModule], - (sm.save_to_buffer(),), # (bytes) serialized torchscript - ), - "cmp_detailed": compare_modules, - } - ] - - -# torch.jit.ScriptFunction -def make_torch_scriptfunction(**kwargs): - @torch.jit.script - def func(x): # pragma: no cover - return x + 2 - - return [ - { - "value": func, - "simplified": ( - CODE[torch.jit.ScriptFunction], - (func.save_to_buffer(),), # (bytes) serialized torchscript - ), - "cmp_detailed": compare_modules, - } - ] - - -# torch.memory_format -def make_torch_memoryformat(**kwargs): - memory_format = torch.preserve_format - - return [{"value": memory_format, "simplified": (CODE[torch.memory_format], 3)}] - - -# torch.jit.TopLevelTracedModule -# NOTE: if the model is created inside the function, it will be serialized differently depending on the context -class TopLevelTraceModel(torch.nn.Module): - def __init__(self): - super(TopLevelTraceModel, self).__init__() - self.w1 = torch.nn.Parameter(torch.randn(3, 1), requires_grad=True) - self.b1 = torch.nn.Parameter(torch.randn(1), requires_grad=True) - - def forward(self, x): - x = x @ self.w1 + self.b1 - return x - - -topLevelTraceModel = TopLevelTraceModel() - - -def make_torch_topleveltracedmodule(**kwargs): - tm = torch.jit.trace(topLevelTraceModel, torch.randn(10, 3)) - - return [ - { - "value": tm, - "simplified": ( - CODE[torch.jit.TopLevelTracedModule], - (tm.save_to_buffer(),), # (bytes) serialized torchscript - ), - "cmp_detailed": compare_modules, - } - ] - - -# torch.nn.parameter.Parameter -def make_torch_parameter(**kwargs): - param = torch.nn.Parameter(torch.randn(3, 3), requires_grad=True) - - def compare(detailed, original): - assert type(detailed) == torch.nn.Parameter - assert detailed.data.equal(original.data) - assert detailed.id == original.id - assert detailed.requires_grad == original.requires_grad - return True - - return [ - { - "value": param, - "simplified": ( - CODE[torch.nn.Parameter], - ( - param.id, # (int) id - msgpack.serde._simplify(syft.hook.local_worker, param.data), # (Tensor) data - param.requires_grad, # (bool) requires_grad - None, - ), - ), - "cmp_detailed": compare, - } - ] - - -# torch.Tensor -def make_torch_tensor(**kwargs): - tensor = torch.randn(3, 3) - tensor.tag("tag1") - tensor.describe("desc") - - def compare(detailed, original): - assert type(detailed) == torch.Tensor - assert detailed.data.equal(original.data) - assert detailed.id == original.id - assert detailed.requires_grad == original.requires_grad - assert detailed.tags == original.tags - assert detailed.description == original.description - return True - - return [ - # Default pytorch tensor serialization strategy - { - "value": tensor, - "simplified": ( - CODE[torch.Tensor], - ( - tensor.id, # (int) id - save_to_buffer(tensor), # (bytes) serialized tensor - None, # (AbstractTensor) chain - None, # (AbstractTensor) grad_chain - (CODE[set], ((CODE[str], (b"tag1",)),)), # (set of str) tags - (CODE[str], (b"desc",)), # (str) description - (CODE[str], (b"torch",)), # (str) framework - ), - ), - "cmp_detailed": compare, - }, - # "All" tensor serialization strategy - { - "framework": None, - "value": tensor, - "simplified": ( - CODE[torch.Tensor], - ( - tensor.id, # (int) id - ( - CODE[tuple], - ( # serialized tensor - (CODE[tuple], (3, 3)), # tensor.shape - (CODE[str], (b"float32",)), # tensor.dtype - ( - CODE[list], - tuple(tensor.flatten().tolist()), - ), # tensor contents as flat list - ), - ), - None, # (AbstractTensor) chain - None, # (AbstractTensor) grad_chain - (CODE[set], ((CODE[str], (b"tag1",)),)), # (set of str) tags - (CODE[str], (b"desc",)), # (str) description - (CODE[str], (b"all",)), # (str) framework - ), - ), - "cmp_detailed": compare, - }, - ] - - -# torch.Size -def make_torch_size(**kwargs): - return [ - { - "value": torch.randn(3, 3).size(), - "simplified": (CODE[torch.Size], (3, 3)), # (int) *shape - } - ] - - -######################################################################## -# PySyft. -######################################################################## - -# Utility functions - - -def compare_operations(detailed, original): - """Compare 2 Operation's""" - assert len(detailed) == len(original) - for i, detailed_op in enumerate(detailed): - original_op = original[i] - compare_placeholders_list(original_op.cmd_args, detailed_op.cmd_args) - # return_ids is not a list (why?) - compare_placeholders_list([original_op.return_ids], [detailed_op.return_ids]) - assert original_op.cmd_name == detailed_op.cmd_name - assert original_op.cmd_kwargs == detailed_op.cmd_kwargs - return True - - -def compare_placeholders_list(detailed, original): - """Compare 2 lists of placeholders""" - assert len(detailed) == len(original) - for i, detailed_ph in enumerate(detailed): - original_ph = original[i] - assert detailed_ph.id == original_ph.id - assert detailed_ph.tags == original_ph.tags - assert detailed_ph.description == original_ph.description - return True - - -def compare_placeholders_dict(detailed, original): - """Compare 2 dicts of placeholders""" - assert len(detailed) == len(original) - for key, detailed_ph in detailed.items(): - original_ph = original[key] - assert detailed_ph.id == original_ph.id - assert detailed_ph.tags == original_ph.tags - assert detailed_ph.description == original_ph.description - return True - - -# AdditiveSharingTensor -def make_additivesharingtensor(**kwargs): - workers = kwargs["workers"] - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - tensor = torch.tensor([[3.1, 4.3]]).fix_prec().share(alice, bob, crypto_provider=james) - ast = tensor.child.child - - def compare(detailed, original): - assert ( - type(detailed) - == syft.frameworks.torch.tensors.interpreters.additive_shared.AdditiveSharingTensor - ) - assert detailed.id == original.id - assert detailed.field == original.field - assert detailed.child.keys() == original.child.keys() - return True - - return [ - { - "value": ast, - "simplified": ( - CODE[ - syft.frameworks.torch.tensors.interpreters.additive_shared.AdditiveSharingTensor - ], - ( - ast.id, # (int or str) id - ast.field, # (int) field - (CODE[str], (ast.crypto_provider.id.encode("utf-8"),)), # (str) worker_id - msgpack.serde._simplify( - syft.hook.local_worker, ast.child - ), # (dict of AbstractTensor) simplified chain - ), - ), - "cmp_detailed": compare, - } - ] - - -# FixedPrecisionTensor -def make_fixedprecisiontensor(**kwargs): - workers = kwargs["workers"] - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - t = torch.tensor([[3.1, 4.3]]) - fpt_tensor = t.fix_prec(base=12, precision_fractional=5).share( - alice, bob, crypto_provider=james - ) - fpt = fpt_tensor.child - fpt.tag("tag1") - fpt.describe("desc") - # AdditiveSharingTensor.simplify sets garbage_collect_data=False on child tensors during simplify - # This changes tensors' internal state in chain and is required to pass the test - msgpack.serde._simplify(syft.hook.local_worker, fpt) - - def compare(detailed, original): - assert ( - type(detailed) - == syft.frameworks.torch.tensors.interpreters.precision.FixedPrecisionTensor - ) - assert detailed.id == original.id - assert detailed.field == original.field - assert detailed.base == original.base - assert detailed.precision_fractional == original.precision_fractional - assert detailed.kappa == original.kappa - assert detailed.tags == original.tags - assert detailed.description == original.description - return True - - return [ - { - "value": fpt, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.precision.FixedPrecisionTensor], - ( - fpt.id, # (int or str) id - fpt.field, # (int) field - 12, # (int) base - 5, # (int) precision_fractional - fpt.kappa, # (int) kappa - (CODE[set], ((CODE[str], (b"tag1",)),)), # (set of str) tags - (CODE[str], (b"desc",)), # (str) description - msgpack.serde._simplify( - syft.hook.local_worker, fpt.child - ), # (AbstractTensor) chain - ), - ), - "cmp_detailed": compare, - } - ] - - -# CRTPrecisionTensor -def make_crtprecisiontensor(**kwargs): - workers = kwargs["workers"] - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - t = torch.tensor([[3.1, 4.3]]) - cpt = t.fix_prec(storage="crt").share(alice, bob, crypto_provider=james).child - # AdditiveSharingTensor.simplify sets garbage_collect_data=False on child tensors during simplify - # This changes tensors' internal state in chain and is required to pass the test - msgpack.serde._simplify(syft.hook.local_worker, cpt) - - def compare(detailed, original): - assert ( - type(detailed) - == syft.frameworks.torch.tensors.interpreters.crt_precision.CRTPrecisionTensor - ) - assert detailed.id == original.id - assert detailed.base == original.base - assert detailed.precision_fractional == original.precision_fractional - return True - - return [ - { - "value": cpt, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.crt_precision.CRTPrecisionTensor], - ( - cpt.id, # (int) id - cpt.base, # (int) base - cpt.precision_fractional, # (int) precision_fractional - msgpack.serde._simplify( - syft.hook.local_worker, cpt.child - ), # (dict of AbstractTensor) simplified chain - ), - ), - "cmp_detailed": compare, - } - ] - - -# LoggingTensor -def make_loggingtensor(**kwargs): - t = torch.randn(3, 3) - lt = syft.frameworks.torch.tensors.decorators.logging.LoggingTensor().on(t).child - - def compare(detailed, original): - assert type(detailed) == syft.frameworks.torch.tensors.decorators.logging.LoggingTensor - assert detailed.id == original.id - assert detailed.child.equal(original.child) - return True - - return [ - { - "value": lt, - "simplified": ( - CODE[syft.frameworks.torch.tensors.decorators.logging.LoggingTensor], - ( - lt.id, # (int or str) id - msgpack.serde._simplify( - syft.hook.local_worker, lt.child - ), # (AbstractTensor) chain - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.multi_pointer.MultiPointerTensor -def make_multipointertensor(**kwargs): - workers = kwargs["workers"] - alice, bob = workers["alice"], workers["bob"] - t = torch.randn(3, 3) - mpt = t.send(alice, bob).child - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.multi_pointer.MultiPointerTensor - assert detailed.id == original.id - assert detailed.child.keys() == original.child.keys() - return True - - return [ - { - "value": mpt, - "simplified": ( - CODE[syft.generic.pointers.multi_pointer.MultiPointerTensor], - ( - mpt.id, # (int or str) id - msgpack.serde._simplify(syft.hook.local_worker, mpt.child), # (dict) - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.execution.plan.Plan -def make_plan(**kwargs): - # Function to plan - @syft.func2plan([torch.Size((3,))]) - def plan(x): - x = x + x - y = torch.abs(x) - return x - - # Model to plan - class Net(syft.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(3, 3) - self.fc2 = torch.nn.Linear(3, 2) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - x = self.fc2(x) - return torch.nn.functional.log_softmax(x, dim=0) - - with syft.hook.local_worker.registration_enabled(): - model_plan = Net() - model_plan.build(torch.tensor([1.0, 2.0, 3.0])) - - def compare(detailed, original): - assert type(detailed) == syft.execution.plan.Plan - assert detailed.id == original.id - compare_placeholders_dict(detailed.placeholders, original.placeholders) - compare_operations(detailed.operations, original.operations) - # State - compare_placeholders_list( - detailed.state.state_placeholders, original.state.state_placeholders - ) - - assert detailed.include_state == original.include_state - assert detailed.is_built == original.is_built - compare_placeholders_dict(detailed.placeholders, original.placeholders) - assert detailed.name == original.name - assert detailed.tags == original.tags - assert detailed.description == original.description - with syft.hook.local_worker.registration_enabled(): - t = torch.tensor([1.1, -2, 3]) - res1 = detailed(t) - res2 = original(t) - assert res1.equal(res2) - return True - - return [ - { - "value": plan, - "simplified": ( - CODE[syft.execution.plan.Plan], - ( - plan.id, # (int or str) id - msgpack.serde._simplify(syft.hook.local_worker, plan.operations), - msgpack.serde._simplify(syft.hook.local_worker, plan.state), # (State) - plan.include_state, # (bool) include_state - plan.is_built, # (bool) is_built - msgpack.serde._simplify(syft.hook.local_worker, plan.name), # (str) name - msgpack.serde._simplify(syft.hook.local_worker, plan.tags), # (set of str) tags - msgpack.serde._simplify( - syft.hook.local_worker, plan.description - ), # (str) description - # (PlaceHolder) placeholders - msgpack.serde._simplify(syft.hook.local_worker, plan.placeholders), - ), - ), - "cmp_detailed": compare, - }, - { - "value": model_plan, - "simplified": ( - CODE[syft.execution.plan.Plan], - ( - model_plan.id, # (int or str) id - msgpack.serde._simplify(syft.hook.local_worker, model_plan.operations), - msgpack.serde._simplify(syft.hook.local_worker, model_plan.state), # (State) - model_plan.include_state, # (bool) include_state - model_plan.is_built, # (bool) is_built - msgpack.serde._simplify(syft.hook.local_worker, model_plan.name), # (str) name - msgpack.serde._simplify(syft.hook.local_worker, model_plan.tags), # (list) tags - msgpack.serde._simplify( - syft.hook.local_worker, model_plan.description - ), # (str) description - # (PlaceHolder) placeholders - msgpack.serde._simplify(syft.hook.local_worker, model_plan.placeholders), - ), - ), - "cmp_detailed": compare, - }, - ] - - -# State -def make_state(**kwargs): - me = kwargs["workers"]["me"] - - t1, t2 = torch.randn(3, 3), torch.randn(3, 3) - p1, p2 = syft.PlaceHolder(), syft.PlaceHolder() - p1.tag("state1"), p2.tag("state2") - p1.instantiate(t1), p2.instantiate(t2) - state = syft.execution.state.State(owner=me, state_placeholders=[p1, p2]) - - def compare(detailed, original): - assert type(detailed) == syft.execution.state.State - compare_placeholders_list(detailed.state_placeholders, original.state_placeholders) - for i in range(len(original.tensors())): - assert detailed.tensors()[i].equal(original.tensors()[i]) - return True - - return [ - { - "value": state, - "simplified": ( - CODE[syft.execution.state.State], - ( - ( - CODE[list], - ( # (list) state_placeholders - msgpack.serde._simplify(syft.hook.local_worker, p1), - msgpack.serde._simplify(syft.hook.local_worker, p2), - ), - ), - ( - CODE[list], - ( # (list) tensors - msgpack.serde._simplify(syft.hook.local_worker, t1), - msgpack.serde._simplify(syft.hook.local_worker, t2), - ), - ), - ), - ), - "cmp_detailed": compare, - } - ] - - -# Protocol -def make_protocol(**kwargs): - me = kwargs["workers"]["me"] - - @syft.func2plan([torch.Size((1, 3))]) - def plan(x): - x = x + x - x = torch.abs(x) - return x - - with me.registration_enabled(): - me.register_obj(plan) - - protocol = syft.execution.protocol.Protocol([("me", plan), ("me", plan)]) - protocol.tag("aaa") - protocol.describe("desc") - - def compare(detailed, original): - assert type(detailed) == syft.execution.protocol.Protocol - assert detailed.id == original.id - assert detailed.tags == original.tags - assert detailed.description == original.description - assert detailed.plans == original.plans - assert detailed.owner == original.owner - assert detailed.workers_resolved == original.workers_resolved - return True - - return [ - { - "value": protocol, - "simplified": ( - CODE[syft.execution.protocol.Protocol], - ( - protocol.id, # (int) - (CODE[set], ((CODE[str], (b"aaa",)),)), # (set of strings) tags - (CODE[str], (b"desc",)), # (str) description - ( - CODE[list], # (list) plans reference - ( - # (tuple) reference: worker_id (int/str), plan_id (int/str) - (CODE[tuple], ((CODE[str], (b"me",)), plan.id)), - (CODE[tuple], ((CODE[str], (b"me",)), plan.id)), - ), - ), - False, # (bool) workers_resolved - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.pointer_tensor.PointerTensor -def make_pointertensor(**kwargs): - alice = kwargs["workers"]["alice"] - tensor = torch.randn(3, 3) - ptr = tensor.send(alice).child - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.pointer_tensor.PointerTensor - assert detailed.id == original.id - assert detailed.id_at_location == original.id_at_location - assert detailed.location == original.location - assert detailed.point_to_attr == original.point_to_attr - # Not testing grabage collect data as we are always setting it as False at receiver end - # irrespective of its initial value - assert detailed.garbage_collect_data == original.garbage_collect_data - assert detailed.get().equal(tensor) - return True - - return [ - { - "value": ptr, - "simplified": ( - CODE[syft.generic.pointers.pointer_tensor.PointerTensor], - ( - ptr.id, # (int or str) id - ptr.id_at_location, # (int or str) id_at_location - (CODE[str], (b"alice",)), # (str) worker_id - None, # (str) point_to_attr - (CODE[torch.Size], (3, 3)), # (torch.Size) _shape - True, # (bool) garbage_collect_data - ptr.tags, - ptr.description, - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.pointer_plan.PointerPlan -def make_pointerplan(**kwargs): - alice, me = kwargs["workers"]["alice"], kwargs["workers"]["me"] - - @syft.func2plan([torch.Size((1, 3))]) - def plan(x): - x = x + x - x = torch.abs(x) - return x - - plan.send(alice) - ptr = me.request_search([plan.id], location=alice)[0] - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.pointer_plan.PointerPlan - assert detailed.id == original.id - assert detailed.id_at_location == original.id_at_location - assert detailed.location == original.location - assert detailed.garbage_collect_data == original.garbage_collect_data - # execute - t = torch.randn(3, 3).send(alice) - assert detailed(t).get().equal(original(t).get()) - return True - - return [ - { - "value": ptr, - "simplified": ( - CODE[syft.generic.pointers.pointer_plan.PointerPlan], - ( - ptr.id, # (int) id - ptr.id_at_location, # (int) id_at_location - (CODE[str], (b"alice",)), # (str) worker_id - False, # (bool) garbage_collect_data - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.pointer_protocol.PointerProtocol -def make_pointerprotocol(**kwargs): - alice, me = kwargs["workers"]["alice"], kwargs["workers"]["me"] - - @syft.func2plan([torch.Size((1, 3))]) - def plan(x): - x = x + x - x = torch.abs(x) - return x - - protocol = syft.execution.protocol.Protocol( - [("worker1", plan), ("worker2", plan)], tags=["aaa", "bbb"], description="desc" - ) - protocol.send(alice) - ptr = me.request_search([protocol.id], location=alice)[0] - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.pointer_protocol.PointerProtocol - assert detailed.id == original.id - assert detailed.id_at_location == original.id_at_location - assert detailed.location == original.location - assert detailed.garbage_collect_data == original.garbage_collect_data - return True - - return [ - { - "value": ptr, - "simplified": ( - CODE[syft.generic.pointers.pointer_protocol.PointerProtocol], - ( - ptr.id, # (int or str) id - ptr.id_at_location, # (int) id_at_location - (CODE[str], (b"alice",)), # (str) location.id - False, # (bool) garbage_collect_data - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.object_wrapper.ObjectWrapper -def make_objectwrapper(**kwargs): - obj = torch.randn(3, 3) - wrapper = syft.generic.pointers.object_wrapper.ObjectWrapper(obj, id=123) - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.object_wrapper.ObjectWrapper - assert detailed.id == original.id - # tensors - assert detailed.obj.equal(original.obj) - return True - - return [ - { - "value": wrapper, - "simplified": ( - CODE[syft.generic.pointers.object_wrapper.ObjectWrapper], - ( - 123, # (int) id - msgpack.serde._simplify(syft.hook.local_worker, obj), # (Any) obj - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.pointers.object_pointer.ObjectPointer -def make_objectpointer(**kwargs): - alice = kwargs["workers"]["alice"] - obj = torch.randn(3, 3) - obj_ptr = obj.send(alice) - ptr = syft.generic.pointers.object_pointer.ObjectPointer.create_pointer(obj, alice, obj.id) - - def compare(detailed, original): - assert type(detailed) == syft.generic.pointers.object_pointer.ObjectPointer - assert detailed.id == original.id - assert detailed.id_at_location == original.id_at_location - assert detailed.location == original.location - assert detailed.point_to_attr == original.point_to_attr - assert detailed.garbage_collect_data == original.garbage_collect_data - return True - - return [ - { - "value": ptr, - "simplified": ( - CODE[syft.generic.pointers.object_pointer.ObjectPointer], - ( - ptr.id, # (int or str) id - ptr.id_at_location, # (int or str) id - (CODE[str], (b"alice",)), # (str) location.id - None, # (str) point_to_attr - True, # (bool) garbage_collect_data - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.generic.string.String -def make_string(**kwargs): - def compare_simplified(actual, expected): - """This is a custom comparison functino. - The reason for using this is that when set is that tags are use. Tags are sets. - When sets are simplified and converted to tuple, elements order in tuple is random - We compare tuples as sets because the set order is undefined. - - This function is inspired by the one with the same name defined above in `make_set`. - """ - assert actual[0] == expected[0] - assert actual[1][0] == expected[1][0] - assert actual[1][1] == expected[1][1] - assert actual[1][2][0] == expected[1][2][0] - assert set(actual[1][2][1]) == set(expected[1][2][1]) - assert actual[1][3] == expected[1][3] - return True - - return [ - { - "value": syft.generic.string.String( - "Hello World", id=1234, tags=set(["tag1", "tag2"]), description="description" - ), - "simplified": ( - CODE[syft.generic.string.String], - ( - (CODE[str], (b"Hello World",)), - 1234, - (CODE[set], ((CODE[str], (b"tag1",)), (CODE[str], (b"tag2",)))), - (CODE[str], (b"description",)), - ), - ), - "cmp_simplified": compare_simplified, - } - ] - - -# syft.federated.train_config.TrainConfig -def make_trainconfig(**kwargs): - class Model(torch.jit.ScriptModule): - def __init__(self): - super(Model, self).__init__() - self.w1 = torch.nn.Parameter(torch.randn(10, 1), requires_grad=True) - self.b1 = torch.nn.Parameter(torch.randn(1), requires_grad=True) - - @torch.jit.script_method - def forward(self, x): # pragma: no cover - x = x @ self.w1 + self.b1 - return x - - class Loss(torch.jit.ScriptModule): - def __init__(self): - super(Loss, self).__init__() - - @torch.jit.script_method - def forward(self, pred, target): # pragma: no cover - return ((target.view(pred.shape).float() - pred.float()) ** 2).mean() - - loss = Loss() - model = Model() - conf = syft.federated.train_config.TrainConfig( - model=model, loss_fn=loss, batch_size=2, optimizer="SGD", optimizer_args={"lr": 0.1} - ) - - def compare(detailed, original): - assert type(detailed) == syft.federated.train_config.TrainConfig - assert detailed.id == original.id - assert detailed._model_id == original._model_id - assert detailed._loss_fn_id == original._loss_fn_id - assert detailed.batch_size == original.batch_size - assert detailed.epochs == original.epochs - assert detailed.optimizer == original.optimizer - assert detailed.optimizer_args == original.optimizer_args - assert detailed.max_nr_batches == original.max_nr_batches - assert detailed.shuffle == original.shuffle - return True - - return [ - { - "value": conf, - "simplified": ( - CODE[syft.federated.train_config.TrainConfig], - ( - None, # (int) _model_id - None, # (int) _loss_fn_id - 2, # (int) batch_size - 1, # (int) epochs - (CODE[str], (b"SGD",)), # (str) optimizer - (CODE[dict], (((CODE[str], (b"lr",)), 0.1),)), # (dict) optimizer_args - conf.id, # (int or str) - -1, # (int) max_nr_batches - True, # (bool) shuffle - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.workers.base.BaseWorker -def make_baseworker(**kwargs): - bob = kwargs["workers"]["bob"] - t = torch.rand(3, 3) - with bob.registration_enabled(): - bob.register_obj(t) - - def compare(detailed, original): - assert isinstance(detailed, syft.workers.base.BaseWorker) - assert detailed.id == original.id - return True - - return [ - { - "value": bob, - "simplified": ( - CODE[syft.workers.base.BaseWorker], - ((CODE[str], (b"bob",)),), # id (str) - ), - "cmp_detailed": compare, - }, - # Forced simplification - { - "forced": True, - "value": bob, - "simplified": ( - FORCED_CODE[syft.workers.base.BaseWorker], - ( - (CODE[str], (b"bob",)), # id (str) - msgpack.serde._simplify( - syft.hook.local_worker, bob._objects - ), # (dict) _objects - True, # (bool) auto_add - ), - ), - "cmp_detailed": compare, - }, - ] - - -# syft.frameworks.torch.tensors.interpreters.autograd.AutogradTensor -def make_autogradtensor(**kwargs): - t = torch.tensor([1, 2, 3]) - agt = syft.frameworks.torch.tensors.interpreters.autograd.AutogradTensor().on(t).child - agt.tag("aaa") - agt.describe("desc") - - def compare(detailed, original): - assert type(detailed) == syft.frameworks.torch.tensors.interpreters.autograd.AutogradTensor - assert detailed.owner == original.owner - assert detailed.id == original.id - assert detailed.child.equal(original.child) - assert detailed.requires_grad == original.requires_grad - assert detailed.preinitialize_grad == original.preinitialize_grad - assert detailed.grad_fn == original.grad_fn - assert detailed.tags == original.tags - assert detailed.description == original.description - return True - - return [ - { - "value": agt, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.autograd.AutogradTensor], - ( - None, # owner - agt.id, # (int) - msgpack.serde._simplify( - syft.hook.local_worker, agt.child - ), # (AbstractTensor) chain - True, # (bool) requires_grad - False, # (bool) preinitialize_grad - None, # [always None, ignored in constructor] grad_fn - (CODE[set], ((CODE[str], (b"aaa",)),)), # (set of str) tags - (CODE[str], (b"desc",)), # (str) description - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.frameworks.torch.tensors.interpreters.private.PrivateTensor -def make_privatetensor(**kwargs): - t = torch.tensor([1, 2, 3]) - pt = t.private_tensor(allowed_users=("test",)) - pt.tag("tag1") - pt.describe("private") - pt = pt.child - - def compare(detailed, original): - assert type(detailed) == syft.frameworks.torch.tensors.interpreters.private.PrivateTensor - assert detailed.id == original.id - assert detailed.allowed_users == original.allowed_users - assert detailed.tags == original.tags - assert detailed.description == original.description - assert detailed.child.equal(original.child) - return True - - return [ - { - "value": pt, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.private.PrivateTensor], - ( - pt.id, # (int or str) id - (CODE[tuple], ((CODE[str], (b"test",)),)), # (tuple of ?) allowed_users - (CODE[set], ((CODE[str], (b"tag1",)),)), # (set of str) tags - (CODE[str], (b"private",)), # (str) description - msgpack.serde._simplify(syft.hook.local_worker, t), # (AbstractTensor) chain - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.frameworks.torch.tensors.interpreters.PlaceHolder -def make_placeholder(**kwargs): - ph = syft.frameworks.torch.tensors.interpreters.placeholder.PlaceHolder() - ph.tag("tag1") - ph.describe("just a placeholder") - - def compare(detailed, original): - assert type(detailed) == syft.frameworks.torch.tensors.interpreters.placeholder.PlaceHolder - assert detailed.id == original.id - assert detailed.tags == original.tags - assert detailed.description == original.description - return True - - return [ - { - "value": ph, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.placeholder.PlaceHolder], - ( - ph.id, # (int) id - (CODE[set], ((CODE[str], (b"tag1",)),)), # (set of str) tags - (CODE[str], (b"just a placeholder",)), # (str) description - ), - ), - "cmp_detailed": compare, - } - ] - - -# Message -def make_message(**kwargs): - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.Message - assert detailed.contents == original.contents - return True - - return [ - { - "value": syft.messaging.message.Message([1, 2, 3]), - "simplified": ( - CODE[syft.messaging.message.Message], - ((CODE[list], (1, 2, 3)),), # (Any) simplified content - ), - "cmp_detailed": compare, - }, - { - "value": syft.messaging.message.Message((1, 2, 3)), - "simplified": ( - CODE[syft.messaging.message.Message], - ((CODE[tuple], (1, 2, 3)),), # (Any) simplified content - ), - "cmp_detailed": compare, - }, - ] - - -# syft.messaging.message.OperationMessage -def make_operation(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - - x = torch.tensor([1, 2, 3, 4]).send(bob) - y = x * 2 - op1 = bob._get_msg(-1) - - a = torch.tensor([[1, 2], [3, 4]]).send(bob) - b = a.sum(1, keepdim=True) - op2 = bob._get_msg(-1) - - bob.log_msgs = False - - def compare(detailed, original): - detailed_msg = ( - detailed.cmd_name, - detailed.cmd_owner, - detailed.cmd_args, - detailed.cmd_kwargs, - ) - original_msg = ( - original.cmd_name, - original.cmd_owner, - original.cmd_args, - original.cmd_kwargs, - ) - assert type(detailed) == syft.messaging.message.OperationMessage - for i in range(len(original_msg)): - if type(original_msg[i]) != torch.Tensor: - assert detailed_msg[i] == original_msg[i] - else: - assert detailed_msg[i].equal(original_msg[i]) - assert detailed.return_ids == original.return_ids - return True - - message1 = (op1.cmd_name, op1.cmd_owner, op1.cmd_args, op1.cmd_kwargs) - message2 = (op2.cmd_name, op2.cmd_owner, op2.cmd_args, op2.cmd_kwargs) - - return [ - { - "value": op1, - "simplified": ( - CODE[syft.messaging.message.OperationMessage], - ( - msgpack.serde._simplify(syft.hook.local_worker, message1), # (Any) message - (CODE[tuple], (op1.return_ids[0],)), # (tuple) return_ids - ), - ), - "cmp_detailed": compare, - }, - { - "value": op2, - "simplified": ( - CODE[syft.messaging.message.OperationMessage], - ( - msgpack.serde._simplify(syft.hook.local_worker, message2), # (Any) message - (CODE[tuple], (op2.return_ids[0],)), # (tuple) return_ids - ), - ), - "cmp_detailed": compare, - }, - ] - - -# syft.messaging.message.ObjectMessage -def make_objectmessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - x = torch.tensor([1, 2, 3, 4]).send(bob) - obj = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.ObjectMessage - # torch tensors - assert detailed.contents.equal(original.contents) - return True - - return [ - { - "value": obj, - "simplified": ( - CODE[syft.messaging.message.ObjectMessage], - ( - msgpack.serde._simplify( - syft.hook.local_worker, obj.contents - ), # (Any) simplified contents - ), - ), - "cmp_detailed": compare, - } - ] - - -# ObjectRequestMessage -def make_objectrequestmessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - x = torch.tensor([1, 2, 3, 4]).send(bob) - x.get() - obj_req = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.ObjectRequestMessage - assert detailed.contents == original.contents - return True - - return [ - { - "value": obj_req, - "simplified": ( - CODE[syft.messaging.message.ObjectRequestMessage], - ( - msgpack.serde._simplify( - syft.hook.local_worker, obj_req.contents - ), # (Any) simplified contents - ), - ), - "cmp_detailed": compare, - } - ] - - -# IsNoneMessage -def make_isnonemessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - t = torch.tensor([1, 2, 3, 4]) - x = t.send(bob) - x.child.is_none() - nm = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.IsNoneMessage - # torch tensors - assert detailed.contents.equal(original.contents) - return True - - return [ - { - "value": nm, - "simplified": ( - CODE[syft.messaging.message.IsNoneMessage], - ( - msgpack.serde._simplify( - syft.hook.local_worker, nm.contents - ), # (Any) simplified contents - ), - ), - "cmp_detailed": compare, - } - ] - - -# GetShapeMessage -def make_getshapemessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - t = torch.tensor([1, 2, 3, 4]) - x = t.send(bob) - z = x + x - s = z.shape - shape_message = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.GetShapeMessage - # torch tensor - assert detailed.contents.equal(original.contents) - return True - - return [ - { - "value": shape_message, - "simplified": ( - CODE[syft.messaging.message.GetShapeMessage], - ( - msgpack.serde._simplify( - syft.hook.local_worker, shape_message.contents - ), # (Any) simplified contents - ), - ), - "cmp_detailed": compare, - } - ] - - -# ForceObjectDeleteMessage -def make_forceobjectdeletemessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - t = torch.tensor([1, 2, 3, 4]) - id = t.id - x = t.send(bob) - del x - del_message = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.ForceObjectDeleteMessage - assert detailed.contents == original.contents - return True - - return [ - { - "value": del_message, - "simplified": ( - CODE[syft.messaging.message.ForceObjectDeleteMessage], - (id,), # (int) id - ), - "cmp_detailed": compare, - } - ] - - -# SearchMessage -def make_searchmessage(**kwargs): - search_message = syft.messaging.message.SearchMessage([1, "test", 3]) - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.SearchMessage - assert detailed.contents == original.contents - return True - - return [ - { - "value": search_message, - "simplified": ( - CODE[syft.messaging.message.SearchMessage], - ((CODE[list], (1, (CODE[str], (b"test",)), 3)),), # (Any) message - ), - "cmp_detailed": compare, - } - ] - - -# PlanCommandMessage -def make_plancommandmessage(**kwargs): - bob = kwargs["workers"]["bob"] - bob.log_msgs = True - - @syft.func2plan(args_shape=[(1,)]) - def plan(data): - return data * 3 - - plan.send(bob) - plan.owner.fetch_plan(plan.id, bob) - fetch_plan_cmd = bob._get_msg(-1) - bob.log_msgs = False - - def compare(detailed, original): - assert type(detailed) == syft.messaging.message.PlanCommandMessage - assert detailed.contents == original.contents - return True - - return [ - { - "value": fetch_plan_cmd, - "simplified": ( - CODE[syft.messaging.message.PlanCommandMessage], - ( - (CODE[str], (b"fetch_plan",)), # (str) command - (CODE[tuple], (plan.id, False)), # (tuple) args - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.exceptions.GetNotPermittedError -def make_getnotpermittederror(**kwargs): - try: - raise syft.exceptions.GetNotPermittedError() - except syft.exceptions.GetNotPermittedError as e: - err = e - - def compare(detailed, original): - assert type(detailed) == syft.exceptions.GetNotPermittedError - assert ( - traceback.format_tb(detailed.__traceback__)[-1] - == traceback.format_tb(original.__traceback__)[-1] - ) - return True - - return [ - { - "value": err, - "simplified": ( - CODE[syft.exceptions.GetNotPermittedError], - ( - (CODE[str], (b"GetNotPermittedError",)), # (str) __name__ - msgpack.serde._simplify( - syft.hook.local_worker, - "Traceback (most recent call last):\n" - + "".join(traceback.format_tb(err.__traceback__)), - ), # (str) traceback - (CODE[dict], tuple()), # (dict) attributes - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.exceptions.ResponseSignatureError -def make_responsesignatureerror(**kwargs): - try: - raise syft.exceptions.ResponseSignatureError() - except syft.exceptions.ResponseSignatureError as e: - err = e - - def compare(detailed, original): - assert type(detailed) == syft.exceptions.ResponseSignatureError - assert ( - traceback.format_tb(detailed.__traceback__)[-1] - == traceback.format_tb(original.__traceback__)[-1] - ) - assert detailed.get_attributes() == original.get_attributes() - return True - - return [ - { - "value": err, - "simplified": ( - CODE[syft.exceptions.ResponseSignatureError], - ( - (CODE[str], (b"ResponseSignatureError",)), # (str) __name__ - msgpack.serde._simplify( - syft.hook.local_worker, - "Traceback (most recent call last):\n" - + "".join(traceback.format_tb(err.__traceback__)), - ), # (str) traceback - msgpack.serde._simplify( - syft.hook.local_worker, err.get_attributes() - ), # (dict) attributes - ), - ), - "cmp_detailed": compare, - } - ] - - -# syft.frameworks.torch.tensors.interpreters.gradients_core.GradFunc -def make_gradfn(**kwargs): - alice, bob = kwargs["workers"]["alice"], kwargs["workers"]["bob"] - t = torch.tensor([1, 2, 3]) - - x_share = t.share(alice, bob, requires_grad=True) - y_share = t.share(alice, bob, requires_grad=True) - z_share = x_share + y_share # AddBackward - - # This is bad. We should find something robust - x_share.child.child.set_garbage_collect_data(False) - y_share.child.child.set_garbage_collect_data(False) - - grad_fn = z_share.child.grad_fn - - def compare(detailed, original): - assert isinstance( - detailed, syft.frameworks.torch.tensors.interpreters.gradients_core.GradFunc - ) - assert detailed.__class__.__name__ == original.__class__.__name__ - - # This block only works only for syft tensor attributes - for detailed_attr, original_attr in zip(detailed._attributes, original._attributes): - assert detailed_attr.__class__.__name__ == original_attr.__class__.__name__ - assert detailed_attr.get().equal(t) - - return True - - return [ - { - "value": grad_fn, - "simplified": ( - CODE[syft.frameworks.torch.tensors.interpreters.gradients_core.GradFunc], - ( - CODE[list], - ( - (CODE[str], (b"AddBackward",)), - msgpack.serde._simplify(syft.hook.local_worker, x_share.child), - msgpack.serde._simplify(syft.hook.local_worker, y_share.child), - ), - ), - ), - "cmp_detailed": compare, - } - ] diff --git a/test/test_dependency_check.py b/test/test_dependency_check.py deleted file mode 100644 index 337b539d346..00000000000 --- a/test/test_dependency_check.py +++ /dev/null @@ -1,51 +0,0 @@ -import sys -import pytest -from syft import dependency_check - - -@pytest.mark.skipif(not dependency_check.tensorflow_available, reason="tf 2.0+ not installed") -def test_tensorflow_available(): # pragma: no cover - sys.modules.pop("syft", None) - sys.modules.pop("syft.dependency_check", None) - from syft import dependency_check - - assert dependency_check.tensorflow_available - - -@pytest.mark.skipif(not dependency_check.tfe_available, reason="tf_encrypted not installed") -def test_tf_encrypted_available(): # pragma: no cover - sys.modules.pop("syft", None) - sys.modules.pop("syft.dependency_check", None) - from syft import dependency_check - - assert dependency_check.tfe_available - - -@pytest.mark.skipif(not dependency_check.torch_available, reason="torch not installed") -def test_torch_available(): # pragma: no cover - sys.modules.pop("syft", None) - sys.modules.pop("syft.dependency_check", None) - from syft import dependency_check - - assert dependency_check.torch_available - - -@pytest.mark.usefixtures("hide_module") -def test_tensorflow_missing(): # pragma: no cover - sys.modules.pop("syft", None) - sys.modules.pop("syft.dependency_check", None) - sys.modules.pop("tensorflow", None) - sys.modules.pop("tf", None) - import syft.dependency_check - - assert not syft.dependency_check.tensorflow_available - - -@pytest.mark.usefixtures("hide_module") -def test_tf_encrypted_missing(): # pragma: no cover - sys.modules.pop("syft.dependency_check", None) - sys.modules.pop("tf_encrypted", None) - sys.modules.pop("tfe", None) - import syft.dependency_check - - assert not syft.dependency_check.tfe_available diff --git a/test/test_exceptions.py b/test/test_exceptions.py deleted file mode 100644 index 62c3c004a48..00000000000 --- a/test/test_exceptions.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest -import torch as th -import syft as sy - -from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor - - -def test_tensors_not_collated_exception(workers): - """ - Ensure that the sy.combine_pointers works as expected - """ - - bob = workers["bob"] - alice = workers["alice"] - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 2, 3, 4, 5]).send(alice) - - with pytest.raises(sy.exceptions.TensorsNotCollocatedException): - b = x + y - - x = th.tensor([1, 2, 3, 4, 5]).send(alice) - y = th.tensor([1, 2, 3, 4, 5]).send(bob) - - with pytest.raises(sy.exceptions.TensorsNotCollocatedException): - b = x + y - - x = th.tensor([1, 2, 3, 4, 5]).send(alice) - y = th.tensor([1, 2, 3, 4, 5]) - - with pytest.raises(sy.exceptions.TensorsNotCollocatedException): - b = x + y - - x = th.tensor([1, 2, 3, 4, 5]) - y = th.tensor([1, 2, 3, 4, 5]).send(alice) - - with pytest.raises(sy.exceptions.TensorsNotCollocatedException): - b = x + y diff --git a/test/test_grid.py b/test/test_grid.py deleted file mode 100644 index fb8e91b575e..00000000000 --- a/test/test_grid.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest -import torch -from torch import Tensor -import syft as sy - - -def test_virtual_grid(workers): - """This tests our ability to simplify tuple types. - - This test is pretty simple since tuples just serialize to - themselves, with a tuple wrapper with the correct ID (1) - for tuples so that the detailer knows how to interpret it.""" - - print(len(workers)) - print(workers) - - bob = workers["bob"] - alice = workers["alice"] - james = workers["james"] - - grid = sy.PrivateGridNetwork(*[bob, alice, james]) - - x = torch.tensor([1, 2, 3, 4]).tag("#bob", "#male").send(bob) - y = torch.tensor([1, 2, 3, 4]).tag("#alice", "#female").send(alice) - z = torch.tensor([1, 2, 3, 4]).tag("#james", "#male").send(james) - - results = grid.search() - assert len(results) == 3 - - assert "bob" in results.keys() - assert "alice" in results.keys() - assert "james" in results.keys() - - results = grid.search("#bob") - assert len(results["bob"]) == 1 - assert "alice" not in results - assert "james" not in results - - results = grid.search("#male") - assert len(results["bob"]) == 1 - assert "alice" not in results - assert len(results["james"]) == 1 diff --git a/test/test_local_worker.py b/test/test_local_worker.py deleted file mode 100644 index 55cebc01d60..00000000000 --- a/test/test_local_worker.py +++ /dev/null @@ -1,74 +0,0 @@ -import syft as sy -import torch as th - - -def test_client_worker_does_not_register_object(hook): - me = hook.local_worker - me.is_client_worker = True - x = th.tensor([1, 2, 3]) - assert x.id not in me._objects - - -def test_object_registration(hook): - me = hook.local_worker - me.is_client_worker = False - x = th.tensor([1, 2, 3]) - assert x.id in me._objects - - me.is_client_worker = True - - -def test_pointer_registration(workers, hook): - alice = workers["alice"] - me = hook.local_worker - me.is_client_worker = False - x_ptr = th.tensor([1, 2, 3]).send(alice) - assert x_ptr.id in me._objects - - me.is_client_worker = True - - -def test_fix_prec_tensor_registration(hook): - me = hook.local_worker - me.is_client_worker = False - x_sh = th.tensor([1.0, 2, 3]).fix_prec() - assert x_sh.id in me._objects - - me.is_client_worker = True - - -def test_shared_tensor_registration(workers, hook): - alice, bob, charlie = workers["alice"], workers["bob"], workers["charlie"] - me = hook.local_worker - me.is_client_worker = False - x_sh = th.tensor([1.0, 2, 3]).fix_prec().share(alice, bob, crypto_provider=charlie) - assert x_sh.id in me._objects - - me.is_client_worker = True - - -def test_shared_tensor_registration_pointer(workers, hook): - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - me = hook.local_worker - me.is_client_worker = False - x_ptr = th.tensor([1, 2, 3]).send(alice) - x_sh = x_ptr.fix_prec().share(bob, charlie, crypto_provider=james) - assert x_sh.id in me._objects - - me.is_client_worker = True - - -def test_in_known_workers(hook): - # Get local worker - local_worker = hook.local_worker - id = local_worker.id - - # Get known workers dict - known_workers = local_worker._known_workers - - assert id in known_workers and local_worker == known_workers[id] diff --git a/test/test_sandbox.py b/test/test_sandbox.py deleted file mode 100644 index 6b88a41ce02..00000000000 --- a/test/test_sandbox.py +++ /dev/null @@ -1,34 +0,0 @@ -import pytest -import torch -import syft as sy - -# Import Hook -from syft.frameworks.torch.hook.hook import TorchHook - -# Import grids -from syft.grid.private_grid import PrivateGridNetwork - - -def test_sandbox(): - sy.create_sandbox(globals(), download_data=False) - - assert alice == alice # noqa: F821 - assert isinstance(alice, sy.VirtualWorker) # noqa: F821 - assert andy == andy # noqa: F821 - assert isinstance(andy, sy.VirtualWorker) # noqa: F821 - assert bob == bob # noqa: F821 - assert isinstance(bob, sy.VirtualWorker) # noqa: F821 - assert jason == jason # noqa: F821 - assert isinstance(jason, sy.VirtualWorker) # noqa: F821 - assert jon == jon # noqa: F821 - assert isinstance(jon, sy.VirtualWorker) # noqa: F821 - assert theo == theo # noqa: F821 - assert isinstance(theo, sy.VirtualWorker) # noqa: F821 - - assert hook == hook # noqa: F821 - assert isinstance(hook, TorchHook) # noqa: F821 - - assert grid == grid # noqa: F821 - assert isinstance(grid, PrivateGridNetwork) # noqa: F821 - - assert workers == [bob, theo, jason, alice, andy, jon] # noqa: F821 diff --git a/test/test_udacity.py b/test/test_udacity.py deleted file mode 100644 index acdc67d47de..00000000000 --- a/test/test_udacity.py +++ /dev/null @@ -1,835 +0,0 @@ -import torch - - -def test_section_1_differential_privacy(): - """This tests the Udacity course content found at - https://github.com/Udacity/private-ai - """ - - # the number of entries in our database - num_entries = 5000 - - db = torch.rand(num_entries) > 0.5 - - db = torch.rand(num_entries) > 0.5 - - def get_parallel_db(db, remove_index): - return torch.cat((db[0:remove_index], db[remove_index + 1 :])) - - get_parallel_db(db, 52352) - - def get_parallel_dbs(db): - parallel_dbs = list() - - for i in range(len(db)): - pdb = get_parallel_db(db, i) - parallel_dbs.append(pdb) - - return parallel_dbs - - pdbs = get_parallel_dbs(db) - - def create_db_and_parallels(num_entries): - db = torch.rand(num_entries) > 0.5 - pdbs = get_parallel_dbs(db) - - return db, pdbs - - db, pdbs = create_db_and_parallels(20) - - db, pdbs = create_db_and_parallels(5000) - - def query(db): - return db.sum() - - full_db_result = query(db) - - sensitivity = 0 - for pdb in pdbs: - pdb_result = query(pdb) - - db_distance = torch.abs(pdb_result - full_db_result) - - if db_distance > sensitivity: - sensitivity = db_distance - - def sensitivity(query, n_entries=1000): - - db, pdbs = create_db_and_parallels(n_entries) - - full_db_result = query(db) - - max_distance = 0 - for pdb in pdbs: - pdb_result = query(pdb) - - db_distance = torch.abs(pdb_result - full_db_result) - - if db_distance > max_distance: - max_distance = db_distance - - return max_distance - - def query(db): - return db.float().mean() - - sensitivity(query) - - db, pdbs = create_db_and_parallels(20) - - db - - def query(db, threshold=5): - return (db.sum() > threshold).float() - - for i in range(10): - sens_f = sensitivity(query, n_entries=10) - print(sens_f) - - db, _ = create_db_and_parallels(100) - - pdb = get_parallel_db(db, remove_index=10) - - db[10] - - sum(db) - - # differencing attack using sum query - - sum(db) - sum(pdb) - - # differencing attack using mean query - - (sum(db).float() / len(db)) - (sum(pdb).float() / len(pdb)) - - # differencing attack using threshold - - (sum(db).float() > 49).float() - (sum(pdb).float() > 49).float() - - def query(db): - - true_result = torch.mean(db.float()) - - first_coin_flip = (torch.rand(len(db)) > 0.5).float() - second_coin_flip = (torch.rand(len(db)) > 0.5).float() - - augmented_database = db.float() * first_coin_flip + (1 - first_coin_flip) * second_coin_flip - - db_result = torch.mean(augmented_database.float()) * 2 - 0.5 - - return db_result, true_result - - db, pdbs = create_db_and_parallels(10) - private_result, true_result = query(db) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(100) - private_result, true_result = query(db) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(1000) - private_result, true_result = query(db) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(10000) - private_result, true_result = query(db) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - def query(db, noise=0.2): - - true_result = torch.mean(db.float()) - - first_coin_flip = (torch.rand(len(db)) > noise).float() - second_coin_flip = (torch.rand(len(db)) > 0.5).float() - - augmented_database = db.float() * first_coin_flip + (1 - first_coin_flip) * second_coin_flip - - sk_result = augmented_database.float().mean() - - private_result = ((sk_result / noise) - 0.5) * noise / (1 - noise) - - return private_result, true_result - - db, pdbs = create_db_and_parallels(100) - private_result, true_result = query(db, noise=0.1) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(100) - private_result, true_result = query(db, noise=0.2) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(100) - private_result, true_result = query(db, noise=0.4) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(100) - private_result, true_result = query(db, noise=0.8) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(10000) - private_result, true_result = query(db, noise=0.8) - print("With Noise:" + str(private_result)) - print("Without Noise:" + str(true_result)) - - db, pdbs = create_db_and_parallels(100) - - def query(db): - return torch.sum(db.float()) - - # def M(db): - # query(db) # + noise - # - query(db) - - epsilon = 0.0001 - - import numpy as np - - db, pdbs = create_db_and_parallels(100) - - def sum_query(db): - return db.sum() - - def laplacian_mechanism(db, query, sensitivity): - - beta = sensitivity / epsilon - noise = torch.tensor(np.random.laplace(0, beta, 1)) - - return query(db) + noise - - def mean_query(db): - return torch.mean(db.float()) - - laplacian_mechanism(db, sum_query, 1) - - laplacian_mechanism(db, mean_query, 1 / 100) - - import numpy as np - - num_teachers = 10 # we're working with 10 partner hospitals - num_examples = 10000 # the size of OUR dataset - num_labels = 10 # number of lablels for our classifier - - preds = ( - (np.random.rand(num_teachers, num_examples) * num_labels).astype(int).transpose(1, 0) - ) # fake predictions - - new_labels = list() - for an_image in preds: - - label_counts = np.bincount(an_image, minlength=num_labels) - - epsilon = 0.1 - beta = 1 / epsilon - - for i in range(len(label_counts)): - label_counts[i] += np.random.laplace(0, beta, 1) - - new_label = np.argmax(label_counts) - - new_labels.append(new_label) - - labels = np.array([9, 9, 3, 6, 9, 9, 9, 9, 8, 2]) - counts = np.bincount(labels, minlength=10) - query_result = np.argmax(counts) - query_result - - from syft.frameworks.torch.dp import pate - - num_teachers, num_examples, num_labels = (100, 100, 10) - preds = (np.random.rand(num_teachers, num_examples) * num_labels).astype(int) # fake preds - indices = (np.random.rand(num_examples) * num_labels).astype(int) # true answers - - preds[:, 0:10] *= 0 - - data_dep_eps, data_ind_eps = pate.perform_analysis( - teacher_preds=preds, indices=indices, noise_eps=0.1, delta=1e-5 - ) - - assert data_dep_eps < data_ind_eps - - data_dep_eps, data_ind_eps = pate.perform_analysis( - teacher_preds=preds, indices=indices, noise_eps=0.1, delta=1e-5 - ) - print("Data Independent Epsilon:", data_ind_eps) - print("Data Dependent Epsilon:", data_dep_eps) - - preds[:, 0:50] *= 0 - - data_dep_eps, data_ind_eps = pate.perform_analysis( - teacher_preds=preds, indices=indices, noise_eps=0.1, delta=1e-5, moments=20 - ) - print("Data Independent Epsilon:", data_ind_eps) - print("Data Dependent Epsilon:", data_dep_eps) - - -def test_section_2_federated_learning(hook): - """This tests the Udacity course content found at - https://github.com/Udacity/private-ai - """ - - import torch as th - - x = th.tensor([1, 2, 3, 4, 5]) - x - - y = x + x - - print(y) - - import syft as sy - - # commented out because the test needs to use the global one - # hook = sy.TorchHook(th) - - th.tensor([1, 2, 3, 4, 5]) - - bob = sy.VirtualWorker(hook, id="bob_udacity") - - bob._objects - - x = th.tensor([1, 2, 3, 4, 5]) - - x = x.send(bob) - - bob._objects - - assert len(bob._objects) == 1 - - x.location - - x.id_at_location - - x.id - - x.owner - - hook.local_worker - - x - - x = x.get() - x - - bob._objects - - assert len(bob._objects) == 0 - - alice = sy.VirtualWorker(hook, id="alice_udacity") - - x = th.tensor([1, 2, 3, 4, 5]) - - x_ptr = x.send(bob, alice) - - x_ptr.get() - - x = th.tensor([1, 2, 3, 4, 5]).send(bob, alice) - - x.get(sum_results=True) - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 1, 1, 1, 1]).send(bob) - - x - y - - z = x + y - - z - - z = z.get() - z - - z = th.add(x, y) - z - - z = z.get() - z - - x = th.tensor([1.0, 2, 3, 4, 5], requires_grad=True).send(bob) - y = th.tensor([1.0, 1, 1, 1, 1], requires_grad=True).send(bob) - - z = (x + y).sum() - - z.backward() - - x = x.get() - - x - - x.grad - - input = th.tensor([[1.0, 1], [0, 1], [1, 0], [0, 0]], requires_grad=True).send(bob) - target = th.tensor([[1.0], [1], [0], [0]], requires_grad=True).send(bob) - - weights = th.tensor([[0.0], [0.0]], requires_grad=True).send(bob) - - for i in range(10): - pred = input.mm(weights) - - loss = ((pred - target) ** 2).sum() - - loss.backward() - - weights.data.sub_(weights.grad * 0.1) - weights.grad *= 0 - - print(loss.get().data) - - bob = bob.clear_objects() - - assert len(bob._objects) == 0 - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - assert len(bob._objects) == 1 - - del x - - assert len(bob._objects) == 0 - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - assert len(bob._objects) == 1 - - x = "asdf" - - assert len(bob._objects) == 0 - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - bob._objects - - x = "asdf" - - bob._objects - - del x - - bob._objects - - bob = bob.clear_objects() - bob._objects - - for i in range(1000): - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - assert len(bob._objects) == 1 - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 1, 1, 1, 1]) - - # throws error - # z = x + y - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 1, 1, 1, 1]).send(alice) - - # throws error - # z = x + y - - from torch import nn, optim - - # A Toy Dataset - data = th.tensor([[1.0, 1], [0, 1], [1, 0], [0, 0]], requires_grad=True) - target = th.tensor([[1.0], [1], [0], [0]], requires_grad=True) - - # A Toy Model - model = nn.Linear(2, 1) - - opt = optim.SGD(params=model.parameters(), lr=0.1) - - def train(iterations=20): - for iter in range(iterations): - opt.zero_grad() - - pred = model(data) - - loss = ((pred - target) ** 2).sum() - - loss.backward() - - opt.step() - - print(loss.data) - - train() - - data_bob = data[0:2].send(bob) - target_bob = target[0:2].send(bob) - - data_alice = data[2:4].send(alice) - target_alice = target[2:4].send(alice) - - datasets = [(data_bob, target_bob), (data_alice, target_alice)] - - def train(iterations=20): - - model = nn.Linear(2, 1) - opt = optim.SGD(params=model.parameters(), lr=0.1) - - for iter in range(iterations): - - for _data, _target in datasets: - # send model to the data - model = model.send(_data.location) - - # do normal training - opt.zero_grad() - pred = model(_data) - loss = ((pred - _target) ** 2).sum() - loss.backward() - opt.step() - - # get smarter model back - model = model.get() - - print(loss.get()) - - train() - - bob.clear_objects() - alice.clear_objects() - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - x = x.send(alice) - - bob._objects - - alice._objects - - y = x + x - - y - - bob._objects - - alice._objects - - jon = sy.VirtualWorker(hook, id="jon") - - bob.clear_objects() - alice.clear_objects() - - x = th.tensor([1, 2, 3, 4, 5]).send(bob).send(alice) - - bob._objects - - alice._objects - - x = x.get() - x - - bob._objects - - alice._objects - - x = x.get() - x - - bob._objects - - bob.clear_objects() - alice.clear_objects() - - x = th.tensor([1, 2, 3, 4, 5]).send(bob).send(alice) - - bob._objects - - alice._objects - - del x - - bob._objects - - alice._objects - - bob.clear_objects() - alice.clear_objects() - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - - bob._objects - - alice._objects - - x.move(alice) - - bob._objects - - alice._objects - - x = th.tensor([1, 2, 3, 4, 5]).send(bob).send(alice) - - bob._objects - - alice._objects - - x.remote_get() - - bob._objects - - alice._objects - - x.move(bob) - - x - - bob._objects - - alice._objects - - -def test_section_3_securing_fl(hook): - """This tests the Udacity course content found at - https://github.com/Udacity/private-ai - """ - - import syft as sy - import torch as th - - # hook = sy.TorchHook(th) - from torch import nn, optim - - # create a couple workers - - bob = sy.VirtualWorker(hook, id="bob_udacity_3") - alice = sy.VirtualWorker(hook, id="alice_udacity_3") - secure_worker = sy.VirtualWorker(hook, id="secure_worker_udacity_3") - - bob.add_workers([alice, secure_worker]) - alice.add_workers([bob, secure_worker]) - secure_worker.add_workers([alice, bob]) - - # A Toy Dataset - data = th.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]], requires_grad=True) - target = th.tensor([[0], [0], [1], [1.0]], requires_grad=True) - - # get pointers to training data on each worker by - # sending some training data to bob and alice - bobs_data = data[0:2].send(bob) - bobs_target = target[0:2].send(bob) - - alices_data = data[2:].send(alice) - alices_target = target[2:].send(alice) - - # Iniitalize A Toy Model - model = nn.Linear(2, 1) - - bobs_model = model.copy().send(bob) - alices_model = model.copy().send(alice) - - bobs_opt = optim.SGD(params=bobs_model.parameters(), lr=0.1) - alices_opt = optim.SGD(params=alices_model.parameters(), lr=0.1) - - for i in range(10): - # Train Bob's Model - bobs_opt.zero_grad() - bobs_pred = bobs_model(bobs_data) - bobs_loss = ((bobs_pred - bobs_target) ** 2).sum() - bobs_loss.backward() - - bobs_opt.step() - bobs_loss = bobs_loss.get().data - - # Train Alice's Model - alices_opt.zero_grad() - alices_pred = alices_model(alices_data) - alices_loss = ((alices_pred - alices_target) ** 2).sum() - alices_loss.backward() - - alices_opt.step() - alices_loss = alices_loss.get().data - alices_loss - - alices_model.move(secure_worker) - bobs_model.move(secure_worker) - - with th.no_grad(): - - model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get()) - model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get()) - - iterations = 10 - worker_iters = 5 - - for a_iter in range(iterations): - - bobs_model = model.copy().send(bob) - alices_model = model.copy().send(alice) - - bobs_opt = optim.SGD(params=bobs_model.parameters(), lr=0.1) - alices_opt = optim.SGD(params=alices_model.parameters(), lr=0.1) - - for wi in range(worker_iters): - # Train Bob's Model - bobs_opt.zero_grad() - bobs_pred = bobs_model(bobs_data) - bobs_loss = ((bobs_pred - bobs_target) ** 2).sum() - bobs_loss.backward() - - bobs_opt.step() - bobs_loss = bobs_loss.get().data - - # Train Alice's Model - alices_opt.zero_grad() - alices_pred = alices_model(alices_data) - alices_loss = ((alices_pred - alices_target) ** 2).sum() - alices_loss.backward() - - alices_opt.step() - alices_loss = alices_loss.get().data - - alices_model.move(secure_worker) - bobs_model.move(secure_worker) - - with th.no_grad(): - - model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get()) - model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get()) - - print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss)) - - preds = model(data) - loss = ((preds - target) ** 2).sum() - - print(preds) - print(target) - print(loss.data) - - x = 5 - - bob_x_share = 2 - alice_x_share = 3 - - decrypted_x = bob_x_share + alice_x_share - decrypted_x - - bob_x_share = 2 * 2 - alice_x_share = 3 * 2 - - decrypted_x = bob_x_share + alice_x_share - decrypted_x - - # encrypted "5" - bob_x_share = 2 - alice_x_share = 3 - - # encrypted "7" - bob_y_share = 5 - alice_y_share = 2 - - # encrypted 5 + 7 - bob_z_share = bob_x_share + bob_y_share - alice_z_share = alice_x_share + alice_y_share - - decrypted_z = bob_z_share + alice_z_share - decrypted_z - - x = 5 - - Q = 23740629843760239486723 - - bob_x_share = 23552870267 # <- a random number - alice_x_share = Q - bob_x_share + x - alice_x_share - - (bob_x_share + alice_x_share) % Q - - x_share = (2, 5, 7) - - import random - - Q = 23740629843760239486723 - - def encrypt(x, n_share=3): - - shares = list() - - for i in range(n_share - 1): - shares.append(random.randint(0, Q)) - - shares.append(Q - (sum(shares) % Q) + x) - - return tuple(shares) - - def decrypt(shares): - return sum(shares) % Q - - shares = encrypt(3) - shares - - decrypt(shares) - - def add(a, b): - c = list() - for i in range(len(a)): - c.append((a[i] + b[i]) % Q) - return tuple(c) - - x = encrypt(5) - y = encrypt(7) - z = add(x, y) - decrypt(z) - - BASE = 10 - PRECISION = 4 - - def encode(x): - return int((x * (BASE ** PRECISION)) % Q) - - def decode(x): - return (x if x <= Q / 2 else x - Q) / BASE ** PRECISION - - encode(3.5) - - decode(35000) - - x = encrypt(encode(5.5)) - y = encrypt(encode(2.3)) - z = add(x, y) - decode(decrypt(z)) - - bob = bob.clear_objects() - alice = alice.clear_objects() - secure_worker = secure_worker.clear_objects() - - x = th.tensor([1, 2, 3, 4, 5]) - - x = x.share(bob, alice, secure_worker) - - bob._objects - - y = x + x - - y - - y.get() - - x = th.tensor([0.1, 0.2, 0.3]) - - x = x.fix_prec() - - x.child.child - - y = x + x - - y = y.float_prec() - y - - x = th.tensor([0.1, 0.2, 0.3]) - - x = x.fix_prec().share(bob, alice, secure_worker) - - y = x + x - - y.get().float_prec() diff --git a/test/torch/crypto/__init__.py b/test/torch/crypto/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/crypto/test_snn.py b/test/torch/crypto/test_snn.py deleted file mode 100644 index 2ce3cb09cd8..00000000000 --- a/test/torch/crypto/test_snn.py +++ /dev/null @@ -1,197 +0,0 @@ -import pytest - -import torch -import torch as th - -import syft -from syft.frameworks.torch.mpc.securenn import ( - private_compare, - decompose, - share_convert, - relu_deriv, - division, - maxpool, - maxpool2d, - maxpool_deriv, -) -from syft.generic.pointers.multi_pointer import MultiPointerTensor - - -def test_xor_implementation(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - r = decompose(th.tensor([3])).send(alice, bob).child - x_bit_sh = decompose(th.tensor([23])).share(alice, bob, crypto_provider=james).child - j0 = torch.zeros(x_bit_sh.shape).long().send(bob) - j1 = torch.ones(x_bit_sh.shape).long().send(alice) - j = MultiPointerTensor(children=[j0.child, j1.child]) - w = (j * r) + x_bit_sh - (2 * x_bit_sh * r) - - r_real = r.virtual_get()[0] - x_real = x_bit_sh.virtual_get() - w_real = r_real + x_real - 2 * r_real * x_real - assert (w.virtual_get() == w_real).all() - - -def test_private_compare(workers): - """ - Test private compare which returns: β′ = β ⊕ (x > r). - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x_bit_sh = decompose(torch.LongTensor([13])).share(alice, bob, crypto_provider=james).child - r = torch.LongTensor([12]).send(alice, bob).child - - beta = torch.LongTensor([1]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert not beta_p - - beta = torch.LongTensor([0]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert beta_p - - # Big values - x_bit_sh = decompose(torch.LongTensor([2 ** 60])).share(alice, bob, crypto_provider=james).child - r = torch.LongTensor([2 ** 61]).send(alice, bob).child - - beta = torch.LongTensor([1]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert beta_p - - beta = torch.LongTensor([0]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert not beta_p - - # Multidimensional tensors - x_bit_sh = ( - decompose(torch.LongTensor([[13, 44], [1, 28]])) - .share(alice, bob, crypto_provider=james) - .child - ) - r = torch.LongTensor([[12, 44], [12, 33]]).send(alice, bob).child - - beta = torch.LongTensor([1]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert (beta_p == torch.tensor([[0, 1], [1, 1]])).all() - - beta = torch.LongTensor([0]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert (beta_p == torch.tensor([[1, 0], [0, 0]])).all() - - # Negative values - x_val = -105 % 2 ** 62 - r_val = -52 % 2 ** 62 # The protocol works only for values in Zq - x_bit_sh = decompose(torch.LongTensor([x_val])).share(alice, bob, crypto_provider=james).child - r = torch.LongTensor([r_val]).send(alice, bob).child - - beta = torch.LongTensor([1]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert beta_p - - beta = torch.LongTensor([0]).send(alice, bob).child - beta_p = private_compare(x_bit_sh, r, beta) - assert not beta_p - - -def test_share_convert(workers): - """ - This is a light test as share_convert is not used for the moment - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - L = 2 ** 62 - x_bit_sh = ( - torch.LongTensor([13, 3567, 2 ** 60]) - .share(alice, bob, crypto_provider=james, field=L) - .child - ) - - res = share_convert(x_bit_sh) - assert res.field == L - 1 - assert (res.get() % L == torch.LongTensor([13, 3567, 2 ** 60])).all() - - -def test_relu_deriv(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - x = th.tensor([10, 0, -3]).share(alice, bob, crypto_provider=james).child - r = relu_deriv(x) - - assert (r.get() == th.tensor([1, 1, 0])).all() - - -def test_relu(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - x = th.tensor([1, -3]).share(alice, bob, crypto_provider=james) - r = x.relu() - - assert (r.get() == th.tensor([1, 0])).all() - - x = th.tensor([1.0, 3.1, -2.1]).fix_prec().share(alice, bob, crypto_provider=james) - r = x.relu() - - assert (r.get().float_prec() == th.tensor([1, 3.1, 0])).all() - - -def test_division(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x0 = th.tensor(10).share(alice, bob, crypto_provider=james).child - y0 = th.tensor(2).share(alice, bob, crypto_provider=james).child - res0 = division(x0, y0, bit_len_max=5) - - x1 = th.tensor([[25, 9], [10, 30]]).share(alice, bob, crypto_provider=james).child - y1 = th.tensor([[5, 12], [2, 7]]).share(alice, bob, crypto_provider=james).child - res1 = division(x1, y1, bit_len_max=5) - - assert res0.get() == torch.tensor(5) - assert (res1.get() == torch.tensor([[5, 0], [5, 4]])).all() - - -def test_maxpool(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - x = th.tensor([[10, 0], [15, 7]]).share(alice, bob, crypto_provider=james).child - max, ind = maxpool(x) - - assert max.get() == torch.tensor(15) - assert ind.get() == torch.tensor(2) - - -def test_maxpool_deriv(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - x = th.tensor([[10, 0], [15, 7]]).share(alice, bob, crypto_provider=james).child - max_d = maxpool_deriv(x) - - assert (max_d.get() == torch.tensor([[0, 0], [1, 0]])).all() - - -@pytest.mark.parametrize( - "kernel_size, stride", [(1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2), (3, 3)] -) -def test_maxpool2d(workers, kernel_size, stride): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - def _test_maxpool2d(x): - x_sh = x.long().share(alice, bob, crypto_provider=james).wrap() - y = maxpool2d(x_sh, kernel_size=kernel_size, stride=stride) - - torch_maxpool = torch.nn.MaxPool2d(kernel_size, stride=stride) - assert torch.all(torch.eq(y.get(), torch_maxpool(x).long())) - - x1 = torch.Tensor( - [ - [ - [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]], - [[10.0, 11.0, 12.0], [13.0, 14.0, 15.0], [16.0, 17.0, 18.0]], - ] - ] - ) - - _test_maxpool2d(x1) - - x2 = th.tensor( - [ - [[[10, 9.1, 1, 1], [0.72, -2.5, 1, 1], [0.72, -2.5, 1, 1], [0.72, -2.5, 1, 1]]], - [[[15, 0.6, 1, 1], [1, -3, 1, 1], [1, -3, 1, 1], [1, -3, 1, 1]]], - [[[1.2, 0.3, 1, 1], [5.5, 6.2, 1, 1], [1, -3, 1, 1], [1, -3, 1, 1]]], - ] - ) - - _test_maxpool2d(x2) diff --git a/test/torch/differential_privacy/__init__.py b/test/torch/differential_privacy/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/differential_privacy/test_pate.py b/test/torch/differential_privacy/test_pate.py deleted file mode 100644 index d7064761e35..00000000000 --- a/test/torch/differential_privacy/test_pate.py +++ /dev/null @@ -1,62 +0,0 @@ -import numpy as np - -import torch - -from syft.frameworks.torch.dp import pate - -np.random.seed(0) - - -def test_base_dataset(): - - num_teachers, num_examples, num_labels = (100, 50, 10) - preds = (np.random.rand(num_teachers, num_examples) * num_labels).astype(int) # fake preds - - indices = (np.random.rand(num_examples) * num_labels).astype(int) # true answers - - preds[:, 0:10] *= 0 - - data_dep_eps, data_ind_eps = pate.perform_analysis( - teacher_preds=preds, indices=indices, noise_eps=0.1, delta=1e-5 - ) - - assert data_dep_eps < data_ind_eps - - -def test_base_dataset_torch(): - - num_teachers, num_examples, num_labels = (100, 50, 10) - preds = (np.random.rand(num_teachers, num_examples) * num_labels).astype(int) # fake preds - - indices = (np.random.rand(num_examples) * num_labels).astype(int) # true answers - - preds[:, 0:10] *= 0 - - data_dep_eps, data_ind_eps = pate.perform_analysis_torch( - preds, indices, noise_eps=0.1, delta=1e-5 - ) - - assert data_dep_eps < data_ind_eps - - -def test_torch_ref_match(): - - # Verify if the torch implementation values match the original Numpy implementation. - - num_teachers, num_examples, num_labels = (100, 50, 10) - preds = (np.random.rand(num_teachers, num_examples) * num_labels).astype(int) # fake preds - - indices = (np.random.rand(num_examples) * num_labels).astype(int) # true answers - - preds[:, 0:10] *= 0 - - data_dep_eps, data_ind_eps = pate.perform_analysis_torch( - preds, indices, noise_eps=0.1, delta=1e-5 - ) - - data_dep_eps_ref, data_ind_eps_ref = pate.perform_analysis( - preds, indices, noise_eps=0.1, delta=1e-5 - ) - - assert torch.isclose(data_dep_eps, torch.tensor(data_dep_eps_ref)) - assert torch.isclose(data_ind_eps, torch.tensor(data_ind_eps_ref)) diff --git a/test/torch/federated/test_dataset.py b/test/torch/federated/test_dataset.py index 0e192c4dd42..6a099071ade 100644 --- a/test/torch/federated/test_dataset.py +++ b/test/torch/federated/test_dataset.py @@ -15,7 +15,7 @@ def test_base_dataset(workers): assert len(dataset) == 4 assert dataset[2] == (3, 3) - dataset.send(bob) + dataset = dataset.send(bob) assert dataset.data.location.id == "bob" assert dataset.targets.location.id == "bob" assert dataset.location.id == "bob" @@ -61,8 +61,7 @@ def test_federated_dataset(workers): assert fed_dataset.workers == ["bob", "alice"] assert len(fed_dataset) == 6 - fed_dataset["alice"].get() - assert (fed_dataset["alice"].data == alice_base_dataset.data).all() + assert (fed_dataset["alice"].get().data == alice_base_dataset.data).all() assert fed_dataset["alice"][2] == (5, 5) assert len(fed_dataset["alice"]) == 4 assert len(fed_dataset) == 6 @@ -114,3 +113,12 @@ def test_federated_dataset_search(workers): counter += 1 assert counter == len(train_loader), f"{counter} == {len(fed_dataset)}" + + +def test_abstract_dataset(): + inputs = th.tensor([1, 2, 3, 4.0]) + targets = th.tensor([1, 2, 3, 4.0]) + dataset = BaseDataset(inputs, targets, id=1) + + assert dataset.id == 1 + assert dataset.description == None diff --git a/test/torch/hook/__init__.py b/test/torch/hook/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/hook/test_hook.py b/test/torch/hook/test_hook.py deleted file mode 100644 index 1f9d177b793..00000000000 --- a/test/torch/hook/test_hook.py +++ /dev/null @@ -1,62 +0,0 @@ -import pytest -import torch - - -# import syft - - -@pytest.mark.skipif(not torch.cuda.is_available(), reason="cuda not available") -def test_to(): # pragma: no cover - a = torch.Tensor([1.0, 2.0, 3.0]) - assert a.is_cuda is False - a = a.to(torch.device("cuda")) - assert a.is_cuda is True - a = a.to(torch.device("cpu")) - assert a.is_cuda is False - - -@pytest.mark.skipif(not torch.cuda.is_available(), reason="cuda not available") -def test_cuda(): # pragma: no cover - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(2, 3) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - return x - - model = Net() - assert model.fc1.weight.is_cuda is False - model = model.cuda() - assert model.fc1.weight.is_cuda is True - - -@pytest.mark.skipif(not torch.cuda.is_available(), reason="cuda not available") -def test_data(): # pragma: no cover - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(2, 3) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - return x - - model = Net() - input = torch.tensor([2.0, 4.0]) - out_cpu = model(input) - assert model.fc1.weight.is_cuda is False - model = model.cuda() - assert model.fc1.weight.is_cuda is True - out_cuda = model(input.cuda()) - assert (out_cpu - out_cuda.cpu() < 1e-3).all() - - -@pytest.mark.skipif(not torch.cuda.is_available(), reason="cuda not available") -def test_param_data(): # pragma: no cover - param = torch.nn.Parameter(data=torch.Tensor([2.0, 3.0])) - data2 = torch.Tensor([4.0, 5.0]).to("cuda") - param.data = data2 - assert (param.data == data2).all() - assert param.is_cuda diff --git a/test/torch/hook/test_hook_args.py b/test/torch/hook/test_hook_args.py deleted file mode 100644 index a8148c653c7..00000000000 --- a/test/torch/hook/test_hook_args.py +++ /dev/null @@ -1,126 +0,0 @@ -from syft.generic.frameworks.hook import hook_args -from syft.generic.pointers.pointer_tensor import PointerTensor -import torch -import numpy as np - - -def test_build_rule_syft_tensors_and_pointers(): - pointer = PointerTensor(id=1000, location="location", owner="owner", garbage_collect_data=False) - result = hook_args.build_rule(([torch.tensor([1, 2]), pointer], 42)) - assert result == ([1, 1], 0) - - -def test_build_rule_numpy(): - arr = np.array([2.0, 3.0, 4.0]) - result = hook_args.build_rule([arr, arr + 2, [2, 4, "string"]]) - assert result == [1, 1, [0, 0, 0]] - - -def test_backward_multiple_use(workers): - """ - Test using backward() in different contexts (FL or Encrypted) within - the same session. - """ - big_hospital, small_hospital, crypto_provider = ( - workers["bob"], - workers["alice"], - workers["james"], - ) - - # A Toy Model - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc = torch.nn.Linear(2, 1) - - def forward(self, x): - x = self.fc(x) - return x - - def federated(): - # A Toy Dataset - data = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]]) - target = torch.tensor([[0], [0], [1], [1.0]]) - - model = Net() - - model_weight = model.fc.weight.copy() - - # Training Logic - opt = torch.optim.SGD(params=model.parameters(), lr=0.1) - - data = data.send(big_hospital) - target = target.send(big_hospital) - - # NEW) send model to correct worker - model.send(data.location) - - # 1) erase previous gradients (if they exist) - opt.zero_grad() - - # 2) make a prediction - pred = model(data) - - # 3) calculate how much we missed - loss = ((pred - target) ** 2).sum() - - # 4) figure out which weights caused us to miss - loss.backward() - - # 5) change those weights - opt.step() - - assert (model_weight - model.get().fc.weight).sum().abs() > 1.0e-3 - - def encrypted(): - # A Toy Dataset - data2 = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]]) - target2 = torch.tensor([[0], [0], [1], [1.0]]) - - model2 = Net() - - model2_weight = model2.fc.weight.copy() - - # We encode everything - data2 = data2.fix_precision().share( - big_hospital, small_hospital, crypto_provider=crypto_provider, requires_grad=True - ) - target2 = target2.fix_precision().share( - big_hospital, small_hospital, crypto_provider=crypto_provider, requires_grad=True - ) - model2 = model2.fix_precision().share( - big_hospital, small_hospital, crypto_provider=crypto_provider, requires_grad=True - ) - - opt2 = torch.optim.SGD(params=model2.parameters(), lr=0.1).fix_precision() - - # 1) erase previous gradients (if they exist) - opt2.zero_grad() - - # 2) make a prediction - pred2 = model2(data2) - - # 3) calculate how much we missed - loss2 = ((pred2 - target2) ** 2).sum() - - # 4) figure out which weights caused us to miss - loss2.backward() - - # 5) change those weights - opt2.step() - - weight_diff = (model2_weight - model2.fc.weight.get().float_prec()).sum().abs() - assert weight_diff > 1.0e-3 - - federated() - encrypted() - - -def test_backward_different_signature(workers): - bob = workers["bob"] - a = torch.tensor([0.0], requires_grad=True).send(bob) - b = torch.tensor([0.0], requires_grad=True).send(bob) - a.backward() - a.backward(b) - - assert a.get().grad == torch.tensor([1.0]) diff --git a/test/torch/linalg/__init__.py b/test/torch/linalg/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/linalg/test_lr.py b/test/torch/linalg/test_lr.py deleted file mode 100644 index 0945dfb4dd4..00000000000 --- a/test/torch/linalg/test_lr.py +++ /dev/null @@ -1,119 +0,0 @@ -import pytest -import torch -import syft as sy -from syft.frameworks.torch.linalg import EncryptedLinearRegression -from syft.frameworks.torch.linalg import DASH - - -@pytest.mark.parametrize("fit_intercept", [False, True]) -def test_crypto_lr(fit_intercept, hook, workers): - """ - Test EncryptedLinearRegression, i.e. distributed linear regression with MPC - """ - - bob = workers["bob"] - alice = workers["alice"] - james = workers["james"] - crypto_prov = workers["james"] - hbc_worker = workers["charlie"] - - ###### Simulate data ###### - - K = 2 # number of features - - beta = torch.Tensor([1.0, 2.0]).view(-1, 1) # "real" coefficients - intercept = 0.5 if fit_intercept else 0 # "real" intercept - - # Alice's data - torch.manual_seed(0) # Truncation might not always work so we set the random seed - N1 = 10000 - X_alice = torch.randn(N1, K).send(alice) - y_alice = X_alice @ beta.copy().send(alice) + intercept - - # Bob's data - torch.manual_seed(42) # Setting another seed to avoid creation of singular matrices - N2 = 20000 - X_bob = torch.randn(N2, K).send(bob) - y_bob = X_bob @ beta.copy().send(bob) + intercept - - # James's data - N3 = 15000 - X_james = torch.randn(N3, K).send(james) - y_james = X_james @ beta.copy().send(james) + intercept - - # Gather pointers into lists - X_ptrs = [X_alice, X_bob, X_james] - y_ptrs = [y_alice, y_bob, y_james] - - # Perform linear regression - crypto_lr = EncryptedLinearRegression(crypto_prov, hbc_worker, fit_intercept=fit_intercept) - crypto_lr.fit(X_ptrs, y_ptrs) - - if fit_intercept: - assert abs(crypto_lr.intercept.item() - intercept) < 1e-3 - - assert ((crypto_lr.coef - beta.squeeze()).abs() < 1e-3).all() - - ###### Test prediction ####### - # Pointer tensor - diff = crypto_lr.predict(X_alice) - y_alice.squeeze() - assert (diff.get().abs() < 1e-3).all() - - # Local tensor - X_local = X_alice.get() - y_local = y_alice.get() - diff = crypto_lr.predict(X_local) - y_local.squeeze() - assert (diff.abs() < 1e-3).all() - - ##### Test summarize ###### - - crypto_lr.summarize() - - -def test_DASH(hook, workers): - """ - Test DASH (Distributed Association Scan Hammer), i.e. distributed linear regression for genetics with SMPC - """ - - bob = workers["bob"] - alice = workers["alice"] - james = workers["james"] - crypto_prov = sy.VirtualWorker(hook, id="crypto_prov") - hbc_worker = sy.VirtualWorker(hook, id="hbc_worker") - - ###### Simulate data ###### - torch.manual_seed(0) # Truncation might not always work so we set the random seed - - K = 2 # Number of permanent covariates - M = 5 # Number of transient covariates - - # Alice - N1 = 100 - y1 = torch.randn(N1).send(alice) - X1 = torch.randn(N1, M).send(alice) - C1 = torch.randn(N1, K).send(alice) - - # Bob - N2 = 200 - y2 = torch.randn(N2).send(bob) - X2 = torch.randn(N2, M).send(bob) - C2 = torch.randn(N2, K).send(bob) - - # James - N3 = 150 - y3 = torch.randn(N3).send(james) - X3 = torch.randn(N3, M).send(james) - C3 = torch.randn(N3, K).send(james) - - X_ptrs = [X1, X2, X3] - C_ptrs = [C1, C2, C3] - y_ptrs = [y1, y2, y3] - - ####### Run the model ####### - - model = DASH(crypto_prov, hbc_worker) - model.fit(X_ptrs, C_ptrs, y_ptrs) - - # Check dimensions are ok - assert model.coef.shape == torch.Size([M]) - assert model.sigma2.shape == torch.Size([M]) diff --git a/test/torch/linalg/test_operations.py b/test/torch/linalg/test_operations.py deleted file mode 100644 index c5b121ab7e0..00000000000 --- a/test/torch/linalg/test_operations.py +++ /dev/null @@ -1,183 +0,0 @@ -import pytest -import torch -import syft as sy -from syft.frameworks.torch.linalg import inv_sym -from syft.frameworks.torch.linalg import qr -from syft.frameworks.torch.linalg.operations import _norm_mpc -from syft.frameworks.torch.linalg.lr import DASH - - -def test_inv_sym(hook, workers): - """ - Testing inverse of symmetric matrix with MPC - """ - torch.manual_seed(42) # Truncation might not always work so we set the random seed - - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - x = torch.Tensor([[0.4627, 0.8224], [0.8224, 2.4084]]) - - x = x.fix_precision(precision_fractional=6).share(bob, alice, crypto_provider=crypto_prov) - gram = x.matmul(x.t()) - gram_inv = inv_sym(gram) - - gram_inv = gram_inv.get().float_precision() - gram = gram.get().float_precision() - - diff = (gram_inv - gram.inverse()).abs() - assert (diff < 1e-3).all() - - -def test_norm_mpc(hook, workers): - """ - Testing computation of vector norm on an AdditiveSharedTensor - """ - torch.manual_seed(42) # Truncation might not always work so we set the random seed - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - n = 100 - t = torch.randn([n]) - t_sh = t.fix_precision(precision_fractional=6).share(bob, alice, crypto_provider=crypto_prov) - norm_sh = _norm_mpc(t_sh, norm_factor=n ** (1 / 2)) - norm = norm_sh.copy().get().float_precision() - - assert (norm - torch.norm(t)).abs() < 1e-4 - - -def test_qr(hook, workers): - """ - Testing QR decomposition with remote matrix - """ - torch.manual_seed(42) # Truncation might not always work so we set the random seed - - bob = workers["bob"] - n_cols = 5 - n_rows = 10 - t = torch.randn([n_rows, n_cols]) - Q, R = qr(t.send(bob), mode="complete") - Q = Q.get() - R = R.get() - - # Check if Q is orthogonal - I = Q @ Q.t() - assert ((torch.eye(n_rows) - I).abs() < 1e-5).all() - - # Check if R is upper triangular matrix - for col in range(n_cols): - assert ((R[col + 1 :, col]).abs() < 1e-5).all() - - # Check if QR == t - assert ((Q @ R - t).abs() < 1e-5).all() - - # test modes - Q, R = qr(t.send(bob), mode="reduced") - assert Q.shape == (n_rows, n_cols) - assert R.shape == (n_cols, n_cols) - - Q, R = qr(t.send(bob), mode="complete") - assert Q.shape == (n_rows, n_rows) - assert R.shape == (n_rows, n_cols) - - R = qr(t.send(bob), mode="r") - assert R.shape == (n_cols, n_cols) - - -def test_qr_mpc(hook, workers): - """ - Testing QR decomposition with an AdditiveSharedTensor - """ - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - torch.manual_seed(0) # Truncation might not always work so we set the random seed - n_cols = 3 - n_rows = 3 - t = torch.randn([n_rows, n_cols]) - t_sh = t.fix_precision(precision_fractional=6).share(bob, alice, crypto_provider=crypto_prov) - - Q, R = qr(t_sh, norm_factor=3 ** (1 / 2), mode="complete") - Q = Q.get().float_precision() - R = R.get().float_precision() - - # Check if Q is orthogonal - I = Q @ Q.t() - assert ((torch.eye(n_rows) - I).abs() < 1e-2).all() - - # Check if R is upper triangular matrix - for col in range(n_cols - 1): - assert ((R[col + 1 :, col]).abs() < 1e-2).all() - - # Check if QR == t - assert ((Q @ R - t).abs() < 1e-2).all() - - -def test_inv_upper(hook, workers): - - bob = workers["bob"] - alice = workers["alice"] - crypto_prov = workers["james"] - - torch.manual_seed(0) # Truncation might not always work so we set the random seed - n_cols = 3 - n_rows = 3 - R = torch.triu(torch.randn([n_rows, n_cols])) - invR = R.inverse() - - R_sh = R.fix_precision(precision_fractional=6).share(bob, alice, crypto_provider=crypto_prov) - invR_sh = DASH._inv_upper(R_sh) - assert ((invR - invR_sh.get().float_precision()).abs() < 1e-2).all() - - -def test_remote_random_number_generation(hook, workers): - """ - Test random number generation on remote worker machine - """ - - class Model(torch.nn.Module): - def __init__(self): - super(Model, self).__init__() - - def add_randn_like(self, x): - r = torch.randn_like(x) - return x + r - - def get_randint(self, n): - r = torch.rand(n) - return r - - def get_rand(self, n): - r = torch.rand(n) - return r - - def get_randn(self, n): - r = torch.randn(n) - return r - - def get_randperm(self, n): - r = torch.randperm(n) - return r - - alice = workers["alice"] - model = Model().to("cpu").send(alice) - - x = torch.tensor([1.0, 2.0, 3.0, 4.0]).send(alice) - y = model.add_randn_like(x) - - # Check that returned tensor is same size as original - assert len(y.get()) == len(x) - - r = model.get_randint(4) - s = model.get_rand(5) - t = model.get_randn(6) - v = model.get_randperm(7) - - # Check that the returned tensors are the requested size - assert len(r) == 4 - assert len(s) == 5 - assert len(t) == 6 - assert len(v) == 7 diff --git a/test/torch/nn/__init__.py b/test/torch/nn/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/nn/test_conv.py b/test/torch/nn/test_conv.py deleted file mode 100644 index 00034be90fc..00000000000 --- a/test/torch/nn/test_conv.py +++ /dev/null @@ -1,43 +0,0 @@ -import syft.frameworks.torch.nn as nn2 -import torch as th -import torch.nn as nn -import pytest - - -def test_conv2d(): - """ - Test the Conv2d module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = th._C._get_mkldnn_enabled() - th._C._set_mkldnn_enabled(False) - - model2 = nn2.Conv2d(1, 32, 3, bias=True) - - model = nn.Conv2d( - in_channels=1, - out_channels=32, - kernel_size=3, - stride=1, - padding=0, - dilation=1, - groups=1, - bias=True, - padding_mode="zeros", - ) - - model2.weight = model.weight - model2.bias = model.bias - - data = th.rand(10, 1, 28, 28) - - out = model(data) - - out2 = model2(data) - - # Reset mkldnn to the original state - th._C._set_mkldnn_enabled(mkldnn_enabled_init) - - assert th.eq(out, out2).all() diff --git a/test/torch/nn/test_pool.py b/test/torch/nn/test_pool.py deleted file mode 100644 index edfaa3a7062..00000000000 --- a/test/torch/nn/test_pool.py +++ /dev/null @@ -1,33 +0,0 @@ -import syft.frameworks.torch.nn as nn2 -import torch as th -import torch.nn as nn - - -def test_pool2d(): - """ - Test the Pool2d module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - model = nn.Conv2d( - in_channels=1, - out_channels=32, - kernel_size=3, - stride=1, - padding=0, - dilation=1, - groups=1, - bias=True, - padding_mode="zeros", - ) - - pool = nn.AvgPool2d(2) - pool2 = nn2.AvgPool2d(2) - - data = th.rand(10, 1, 8, 8) - - model_out = model(data) - out = pool(model_out) - out2 = pool2(model_out) - - assert th.eq(out, out2).all() diff --git a/test/torch/nn/test_rnn.py b/test/torch/nn/test_rnn.py deleted file mode 100644 index 3e0465cf25e..00000000000 --- a/test/torch/nn/test_rnn.py +++ /dev/null @@ -1,252 +0,0 @@ -import syft.frameworks.torch.nn as nn2 -import torch -import pytest - - -def test_RNNCell(): - """ - Test the RNNCell module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - - test_input = torch.rand(batch_size, input_size) - test_hidden = torch.rand(batch_size, hidden_size) - - # RNNCell implemented in pysyft - rnn_syft = nn2.RNNCell(input_size, hidden_size, True, "tanh") - - # RNNCell implemented in original pytorch - rnn_torch = torch.nn.RNNCell(input_size, hidden_size, True, "tanh") - - # Make sure the weights of both RNNCell are identical - rnn_syft.fc_xh.weight = rnn_torch.weight_ih - rnn_syft.fc_hh.weight = rnn_torch.weight_hh - rnn_syft.fc_xh.bias = rnn_torch.bias_ih - rnn_syft.fc_hh.bias = rnn_torch.bias_hh - - output_syft = rnn_syft(test_input, test_hidden) - output_torch = rnn_torch(test_input, test_hidden) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - assert torch.all(torch.lt(torch.abs(output_syft - output_torch), 1e-6)) - - -def test_GRUCell(): - """ - Test the GRUCell module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - - test_input = torch.rand(batch_size, input_size) - test_hidden = torch.rand(batch_size, hidden_size) - - # GRUCell implemented in pysyft - rnn_syft = nn2.GRUCell(input_size, hidden_size, True) - - # GRUCell implemented in original pytorch - rnn_torch = torch.nn.GRUCell(input_size, hidden_size, True) - - # Make sure the weights of both GRUCell are identical - rnn_syft.fc_xh.weight = rnn_torch.weight_ih - rnn_syft.fc_hh.weight = rnn_torch.weight_hh - rnn_syft.fc_xh.bias = rnn_torch.bias_ih - rnn_syft.fc_hh.bias = rnn_torch.bias_hh - - output_syft = rnn_syft(test_input, test_hidden) - output_torch = rnn_torch(test_input, test_hidden) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - assert torch.all(torch.lt(torch.abs(output_syft - output_torch), 1e-6)) - - -def test_LSTMCell(): - """ - Test the LSTMCell module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - - test_input = torch.rand(batch_size, input_size) - test_hidden_state = torch.rand(batch_size, hidden_size) - test_cell_state = torch.rand(batch_size, hidden_size) - - # LSTMCell implemented in pysyft - rnn_syft = nn2.LSTMCell(input_size, hidden_size, True) - - # LSTMCell implemented in original pytorch - rnn_torch = torch.nn.LSTMCell(input_size, hidden_size, True) - - # Make sure the weights of both LSTMCell are identical - rnn_syft.fc_xh.weight = rnn_torch.weight_ih - rnn_syft.fc_hh.weight = rnn_torch.weight_hh - rnn_syft.fc_xh.bias = rnn_torch.bias_ih - rnn_syft.fc_hh.bias = rnn_torch.bias_hh - - hidden_syft, cell_syft = rnn_syft(test_input, (test_hidden_state, test_cell_state)) - hidden_torch, cell_torch = rnn_torch(test_input, (test_hidden_state, test_cell_state)) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - # Assert the hidden_state and cell_state of both models are identical separately - assert torch.all(torch.lt(torch.abs(hidden_syft - hidden_torch), 1e-6)) - assert torch.all(torch.lt(torch.abs(cell_syft - cell_torch), 1e-6)) - - -def test_RNN(): - """ - Test the RNN module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - num_layers = 1 - seq_len = 8 - - test_input = torch.rand(seq_len, batch_size, input_size) - test_hidden_state = torch.rand(num_layers, batch_size, hidden_size) - - # RNN implemented in pysyft - rnn_syft = nn2.RNN(input_size, hidden_size, num_layers) - - # RNN implemented in original pytorch - rnn_torch = torch.nn.RNN(input_size, hidden_size, num_layers) - - # Make sure the weights of both RNN are identical - rnn_syft.rnn_forward[0].fc_xh.weight = rnn_torch.weight_ih_l0 - rnn_syft.rnn_forward[0].fc_xh.bias = rnn_torch.bias_ih_l0 - rnn_syft.rnn_forward[0].fc_hh.weight = rnn_torch.weight_hh_l0 - rnn_syft.rnn_forward[0].fc_hh.bias = rnn_torch.bias_hh_l0 - - output_syft, hidden_syft = rnn_syft(test_input, test_hidden_state) - output_torch, hidden_torch = rnn_torch(test_input, test_hidden_state) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - # Assert the hidden_state and output of both models are identical separately - assert torch.all(torch.lt(torch.abs(output_syft - output_torch), 1e-6)) - assert torch.all(torch.lt(torch.abs(hidden_syft - hidden_torch), 1e-6)) - - -def test_GRU(): - """ - Test the GRU module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - num_layers = 1 - seq_len = 8 - - test_input = torch.rand(seq_len, batch_size, input_size) - test_hidden_state = torch.rand(num_layers, batch_size, hidden_size) - - # GRU implemented in pysyft - rnn_syft = nn2.GRU(input_size, hidden_size, num_layers) - - # GRU implemented in original pytorch - rnn_torch = torch.nn.GRU(input_size, hidden_size, num_layers) - - # Make sure the weights of both GRU are identical - rnn_syft.rnn_forward[0].fc_xh.weight = rnn_torch.weight_ih_l0 - rnn_syft.rnn_forward[0].fc_xh.bias = rnn_torch.bias_ih_l0 - rnn_syft.rnn_forward[0].fc_hh.weight = rnn_torch.weight_hh_l0 - rnn_syft.rnn_forward[0].fc_hh.bias = rnn_torch.bias_hh_l0 - - output_syft, hidden_syft = rnn_syft(test_input, test_hidden_state) - output_torch, hidden_torch = rnn_torch(test_input, test_hidden_state) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - # Assert the hidden_state and output of both models are identical separately - assert torch.all(torch.lt(torch.abs(output_syft - output_torch), 1e-6)) - assert torch.all(torch.lt(torch.abs(hidden_syft - hidden_torch), 1e-6)) - - -def test_LSTM(): - """ - Test the LSTM module to ensure that it produces the exact same - output as the primary torch implementation, in the same order. - """ - - # Disable mkldnn to avoid rounding errors due to difference in implementation - mkldnn_enabled_init = torch._C._get_mkldnn_enabled() - torch._C._set_mkldnn_enabled(False) - - batch_size = 5 - input_size = 10 - hidden_size = 50 - num_layers = 1 - seq_len = 8 - - test_input = torch.rand(seq_len, batch_size, input_size) - test_hidden_state = torch.rand(num_layers, batch_size, hidden_size) - test_cell_state = torch.rand(num_layers, batch_size, hidden_size) - - # LSTM implemented in pysyft - rnn_syft = nn2.LSTM(input_size, hidden_size, num_layers) - - # LSTM implemented in original pytorch - rnn_torch = torch.nn.LSTM(input_size, hidden_size, num_layers) - - # Make sure the weights of both LSTM are identical - rnn_syft.rnn_forward[0].fc_xh.weight = rnn_torch.weight_ih_l0 - rnn_syft.rnn_forward[0].fc_xh.bias = rnn_torch.bias_ih_l0 - rnn_syft.rnn_forward[0].fc_hh.weight = rnn_torch.weight_hh_l0 - rnn_syft.rnn_forward[0].fc_hh.bias = rnn_torch.bias_hh_l0 - - output_syft, (hidden_syft, cell_syft) = rnn_syft( - test_input, (test_hidden_state, test_cell_state) - ) - output_torch, (hidden_torch, cell_torch) = rnn_torch( - test_input, (test_hidden_state, test_cell_state) - ) - - # Reset mkldnn to the original state - torch._C._set_mkldnn_enabled(mkldnn_enabled_init) - - # Assert the hidden_state, cell_state and output of both models are identical separately - assert torch.all(torch.lt(torch.abs(output_syft - output_torch), 1e-6)) - assert torch.all(torch.lt(torch.abs(hidden_syft - hidden_torch), 1e-6)) - assert torch.all(torch.lt(torch.abs(cell_syft - cell_torch), 1e-6)) diff --git a/test/torch/pointers/__init__.py b/test/torch/pointers/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/pointers/test_callable_pointer.py b/test/torch/pointers/test_callable_pointer.py deleted file mode 100644 index ca4e72a0f7c..00000000000 --- a/test/torch/pointers/test_callable_pointer.py +++ /dev/null @@ -1,88 +0,0 @@ -import torch -from syft.generic.pointers import callable_pointer -from syft.generic.pointers.object_wrapper import ObjectWrapper - - -def test_create_callable_pointer(workers): - alice = workers["alice"] - bob = workers["bob"] - callable_pointer.create_callable_pointer( - id=500, - id_at_location=2, - location=alice, - owner=bob, - tags="tags", - description="description", - register_pointer=True, - ) - - assert len(alice._objects) == 0 - assert len(bob._objects) == 1 - - callable_pointer.create_callable_pointer( - id=501, - id_at_location=2, - location=alice, - owner=bob, - tags="tags", - description="description", - register_pointer=False, - ) - - assert len(alice._objects) == 0 - assert len(bob._objects) == 1 - - -def test_get_obj_callable_pointer(workers): - alice = workers["alice"] - bob = workers["bob"] - - x = torch.tensor(5) - x_ptr = x.send(alice) - - obj_ptr = callable_pointer.create_callable_pointer( - id=1, - id_at_location=x_ptr.id_at_location, - location=alice, - owner=bob, - tags="tags", - description="description", - register_pointer=True, - ) - - assert len(alice._objects) == 1 - assert len(bob._objects) == 1 - - x_get = obj_ptr.get() - - assert len(alice._objects) == 0 - assert len(bob._objects) == 0 - assert x_get == x - - -def test_call_callable_pointer(workers): - def foo(x): - return x + 2 - - alice = workers["alice"] - bob = workers["bob"] - - id_alice = 100 - id_bob = 200 - foo_wrapper = ObjectWrapper(id=id_alice, obj=foo) - - alice.register_obj(foo_wrapper, id_alice) - - foo_ptr = callable_pointer.create_callable_pointer( - id=id_bob, - id_at_location=id_alice, - location=alice, - owner=bob, - tags="tags", - description="description", - register_pointer=True, - ) - - res = foo_ptr(4) - - assert res == 6 diff --git a/test/torch/pointers/test_pointer_plan.py b/test/torch/pointers/test_pointer_plan.py deleted file mode 100644 index 96a663c8dfd..00000000000 --- a/test/torch/pointers/test_pointer_plan.py +++ /dev/null @@ -1,108 +0,0 @@ -import torch as th -import syft as sy - -from syft.generic.pointers.pointer_plan import PointerPlan -from syft.execution.plan import Plan - - -def test_create_pointer_to_plan(hook, workers): - alice, bob, charlie = workers["alice"], workers["bob"], workers["charlie"] - - hook.local_worker.is_client_worker = False - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan(x, state): - (bias,) = state.read() - return x + bias - - plan.send(alice) - id_at_location = plan.id - - plan_ptr = PointerPlan(location=alice, id_at_location=id_at_location) - - x = th.tensor([1.0]).send(alice) - - ptr = plan_ptr(x) - - assert (ptr.get() == th.tensor([2.0])).all() - - hook.local_worker.is_client_worker = True - - -def test_search_plan(hook, workers): - - alice, me = workers["alice"], workers["me"] - me.is_client_worker = False - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan(x, state): - (bias,) = state.read() - return x + bias - - plan.send(alice) - id_at_location = plan.id - - plan_ptr = me.request_search([id_at_location], location=alice)[0] - - assert isinstance(plan_ptr, PointerPlan) - - x = th.tensor([1.0]).send(alice) - ptr = plan_ptr(x) - - assert (ptr.get() == th.tensor([2.0])).all() - - me.is_client_worker = True - - -def test_get_plan(workers): - alice, me = workers["alice"], workers["me"] - me.is_client_worker = False - - @sy.func2plan(args_shape=[(1,)], state=(th.tensor([1.0]),)) - def plan(x, state): - (bias,) = state.read() - return x + bias - - plan.send(alice) - id_at_location = plan.id - plan_ptr = me.request_search([id_at_location], location=alice)[0] - - plan = plan_ptr.get() - - assert isinstance(plan, Plan) - - x = th.tensor([1.0]) - res = plan(x) - - assert (res == th.tensor([2.0])).all() - - me.is_client_worker = True - - -def test_pointer_plan_parameters(workers): - bob, me = workers["bob"], workers["me"] - - me.is_client_worker = False - - class Net(sy.Plan): - def __init__(self): - super(Net, self).__init__() - self.fc1 = th.nn.Linear(2, 1) - - def forward(self, x): - x = self.fc1(x) - return x - - model = Net() - model.build(th.tensor([[0.0, 0.0]])) - model = model.send(bob) - - param_ptrs = model.parameters() - - assert len(param_ptrs) == 2 - - for param_ptr in param_ptrs: - assert param_ptr.is_wrapper - assert isinstance(param_ptr.child, sy.PointerTensor) - - me.is_client_worker = True diff --git a/test/torch/pointers/test_pointer_protocol.py b/test/torch/pointers/test_pointer_protocol.py deleted file mode 100644 index 0e31dcaad17..00000000000 --- a/test/torch/pointers/test_pointer_protocol.py +++ /dev/null @@ -1,158 +0,0 @@ -import torch as th -import syft as sy - -from syft.generic.frameworks.types import FrameworkTensor -from syft.generic.pointers.pointer_protocol import PointerProtocol -from syft.generic.pointers.pointer_tensor import PointerTensor -from syft.execution.protocol import Protocol - - -def _create_inc_protocol(): - @sy.func2plan(args_shape=[(1,)]) - def inc1(x): - return x + 1 - - @sy.func2plan(args_shape=[(1,)]) - def inc2(x): - return x + 1 - - @sy.func2plan(args_shape=[(1,)]) - def inc3(x): - return x + 1 - - protocol = Protocol([("worker1", inc1), ("worker2", inc2), ("worker3", inc3)]) - return protocol - - -def test_create_pointer_to_plan(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - A sends the protocol to the cloud C - B creates a pointer to it on C - B runs remotely the protocol - """ - alice, bob, charlie, james = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - ) - - protocol = _create_inc_protocol() - - protocol.deploy(alice, bob, charlie) - - protocol.send(james) - - id_at_location = protocol.id - protocol_ptr = PointerProtocol(location=james, id_at_location=id_at_location) - - x = th.tensor([1.0]).send(james) - - ptr = protocol_ptr.run(x) - - assert isinstance(ptr, FrameworkTensor) and ptr.is_wrapper - ptr = ptr.get() - assert ( - isinstance(ptr, FrameworkTensor) and ptr.is_wrapper and isinstance(ptr.child, PointerTensor) - ) - - assert (ptr.get() == th.tensor([4.0])).all() - - -def test_search_protocol(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - A sends the protocol to the cloud C - B search C for the protocol - B runs remotely the protocol - """ - alice, bob, charlie, james, me = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - workers["me"], - ) - - protocol = _create_inc_protocol() - - protocol.deploy(alice, bob, charlie) - - protocol.send(james) - id_at_location = protocol.id - - protocol_ptr = me.request_search([id_at_location], location=james)[0] - - x = th.tensor([1.0]).send(james) - - ptr = protocol_ptr.run(x) - - assert isinstance(ptr, FrameworkTensor) and ptr.is_wrapper - ptr = ptr.get() - assert ( - isinstance(ptr, FrameworkTensor) and ptr.is_wrapper and isinstance(ptr.child, PointerTensor) - ) - - assert (ptr.get() == th.tensor([4.0])).all() - - # BONUS: Version with tags - - protocol = _create_inc_protocol() - protocol.tag("my_protocol", "other_tag") - protocol.deploy(alice, bob, charlie) - protocol.send(james) - protocol_ptr = me.request_search("my_protocol", location=james)[0] - x = th.tensor([1.0]).send(james) - ptr = protocol_ptr.run(x) - ptr = ptr.get() - assert (ptr.get() == th.tensor([4.0])).all() - - -def test_get_protocols(workers): - """ - This test validates the following scenario: - A creates a protocol - A deploys it on workers D, E and F - A sends the protocol to the cloud C - B search C for the protocol - B gets the protocol back - B runs the protocol - """ - alice, bob, charlie, james, me = ( - workers["alice"], - workers["bob"], - workers["charlie"], - workers["james"], - workers["me"], - ) - me.is_client_worker = False - - protocol = _create_inc_protocol() - - protocol.deploy(alice, bob, charlie) - - protocol.send(james) - id_at_location = protocol.id - - protocol_ptr = me.request_search([id_at_location], location=james)[0] - - protocol_back = protocol_ptr.get() - - assert isinstance(protocol_back, Protocol) - - x = th.tensor([1.0]) - ptr_charlie = protocol_back.run(x) - assert ( - isinstance(ptr_charlie, FrameworkTensor) - and ptr_charlie.is_wrapper - and isinstance(ptr_charlie.child, PointerTensor) - ) - - assert (ptr_charlie.get() == th.tensor([4.0])).all() - - me.is_client_worker = True diff --git a/test/torch/pointers/test_pointer_tensor.py b/test/torch/pointers/test_pointer_tensor.py deleted file mode 100644 index 9e429d60e05..00000000000 --- a/test/torch/pointers/test_pointer_tensor.py +++ /dev/null @@ -1,479 +0,0 @@ -import torch -import torch as th -import syft - -from syft.frameworks.torch.tensors.interpreters.precision import FixedPrecisionTensor -from syft.generic.pointers.pointer_tensor import PointerTensor -import pytest - - -def test_init(workers): - alice, me = workers["alice"], workers["me"] - pointer = PointerTensor(id=1000, location=alice, owner=me) - pointer.__str__() - - -def test_create_pointer(): - x = torch.Tensor([1, 2]) - x.create_pointer() - - -def test_send_default_garbage_collector_true(workers): - """ - Remote tensor should be garbage collected by default on - deletion of the Pointer tensor pointing to remote tensor - """ - alice = workers["alice"] - - x = torch.Tensor([-1, 2]) - x_ptr = x.send(alice) - assert x_ptr.child.garbage_collect_data - - -def test_send_garbage_collect_data_false(workers): - """ - Remote tensor should be not garbage collected on - deletion of the Pointer tensor pointing to remote tensor - """ - alice = workers["alice"] - - x = torch.Tensor([-1, 2]) - x_ptr = x.send(alice) - x_ptr.garbage_collection = False - assert x_ptr.child.garbage_collect_data == False - - -def test_send_gc_false(workers): - """ - Remote tensor should be not garbage collected on - deletion of the Pointer tensor pointing to remote tensor - """ - alice = workers["alice"] - x = torch.Tensor([-1, 2]) - x_ptr = x.send(alice) - x_ptr.gc = False - assert x_ptr.child.garbage_collect_data == False - assert x_ptr.gc == False, "property GC is not in sync" - assert x_ptr.garbage_collection == False, "property garbage_collection is not in sync" - - -def test_send_gc_true(workers): - """ - Remote tensor by default is garbage collected on - deletion of Pointer Tensor - """ - alice = workers["alice"] - - x = torch.Tensor([-1, 2]) - x_ptr = x.send(alice) - - assert x_ptr.gc == True - - -def test_send_disable_gc(workers): - """Pointer tensor should be not garbage collected.""" - alice = workers["alice"] - - x = torch.Tensor([-1, 2]) - x_ptr = x.send(alice).disable_gc - assert x_ptr.child.garbage_collect_data == False - assert x_ptr.gc == False, "property GC is not in sync" - assert x_ptr.garbage_collection == False, "property garbage_collection is not in sync" - - -def test_send_get(workers): - """Test several send get usages""" - bob = workers["bob"] - alice = workers["alice"] - - # simple send - x = torch.Tensor([1, 2]) - x_ptr = x.send(bob) - x_back = x_ptr.get() - assert (x == x_back).all() - - # send with variable overwriting - x = torch.Tensor([1, 2]) - x = x.send(bob) - x_back = x.get() - assert (torch.Tensor([1, 2]) == x_back).all() - - # double send - x = torch.Tensor([1, 2]) - x_ptr = x.send(bob) - x_ptr_ptr = x_ptr.send(alice) - x_ptr_back = x_ptr_ptr.get() - x_back_back = x_ptr_back.get() - assert (x == x_back_back).all() - - # double send with variable overwriting - x = torch.Tensor([1, 2]) - x = x.send(bob) - x = x.send(alice) - x = x.get() - x_back = x.get() - assert (torch.Tensor([1, 2]) == x_back).all() - - # chained double send - x = torch.Tensor([1, 2]) - x = x.send(bob).send(alice) - x_back = x.get().get() - assert (torch.Tensor([1, 2]) == x_back).all() - - -def test_inplace_send_get(workers): - bob = workers["bob"] - - tensor = torch.tensor([1.0, -1.0, 3.0, 4.0]) - tensor_ptr = tensor.send_(bob) - - assert tensor_ptr.id == tensor.id - assert id(tensor_ptr) == id(tensor) - - tensor_back = tensor_ptr.get_() - - assert tensor_back.id == tensor_ptr.id - assert tensor_back.id == tensor.id - assert id(tensor_back) == id(tensor) - assert id(tensor_back) == id(tensor) - - assert (tensor_back == tensor).all() - - -def test_repeated_send(workers): - """Tests that repeated calls to .send(bob) works gracefully. - Previously garbage collection deleted the remote object - when .send() was called twice. This test ensures the fix still - works.""" - - bob = workers["bob"] - - # create tensor - x = torch.Tensor([1, 2]) - print(x.id) - - # send tensor to bob - x_ptr = x.send(bob) - - # send tensor again - x_ptr = x.send(bob) - - # ensure bob has tensor - assert x.id in bob._objects - - -def test_remote_autograd(workers): - """Tests the ability to backpropagate gradients on a remote - worker.""" - - bob = workers["bob"] - - # TEST: simple remote grad calculation - - # create a tensor - x = torch.tensor([1, 2, 3, 4.0], requires_grad=True) - - # send tensor to bob - x = x.send(bob) - - # do some calculation - y = (x + x).sum() - - # backpropagate on remote machine - y.backward() - - # check that remote gradient is correct - x_grad = bob._objects[x.id_at_location].grad - x_grad_target = torch.ones(4).float() + 1 - assert (x_grad == x_grad_target).all() - - # TEST: Ensure remote grad calculation gets properly serded - - # create tensor - x = torch.tensor([1, 2, 3, 4.0], requires_grad=True).send(bob) - - # compute function - y = x.sum() - - # backpropagate - y.backward() - - # get the gradient created from backpropagation manually - x_grad = bob._objects[x.id_at_location].grad - - # get the entire x tensor (should bring the grad too) - x = x.get() - - # make sure that the grads match - assert (x.grad == x_grad).all() - - -def test_gradient_send_recv(workers): - """Tests that gradients are properly sent and received along - with their tensors.""" - - bob = workers["bob"] - - # create a tensor - x = torch.tensor([1, 2, 3, 4.0], requires_grad=True) - - # create gradient on tensor - x.sum().backward(th.tensor(1.0)) - - # save gradient - orig_grad = x.grad - - # send and get back - t = x.send(bob).get() - - # check that gradient was properly serde - assert (t.grad == orig_grad).all() - - -def test_method_on_attribute(workers): - - bob = workers["bob"] - - # create remote object with children - x = torch.Tensor([1, 2, 3]) - x = syft.LoggingTensor().on(x).send(bob) - - # call method on data tensor directly - x.child.point_to_attr = "child.child" - y = x.add(x) - assert isinstance(y.get(), torch.Tensor) - - # call method on loggingtensor directly - x.child.point_to_attr = "child" - y = x.add(x) - y = y.get() - assert isinstance(y.child, syft.LoggingTensor) - - # # call method on zeroth attribute - # x.child.point_to_attr = "" - # y = x.add(x) - # y = y.get() - # - # assert isinstance(y, torch.Tensor) - # assert isinstance(y.child, syft.LoggingTensor) - # assert isinstance(y.child.child, torch.Tensor) - - # call .get() on pinter to attribute (should error) - x.child.point_to_attr = "child" - try: - x.get() - except syft.exceptions.CannotRequestObjectAttribute as e: - assert True - - -def test_grad_pointer(workers): - """Tests the automatic creation of a .grad pointer when - calling .send() on a tensor with requires_grad==True""" - - bob = workers["bob"] - - x = torch.tensor([1, 2, 3.0], requires_grad=True).send(bob) - y = (x + x).sum() - y.backward() - - assert (bob._objects[x.id_at_location].grad == torch.tensor([2, 2, 2.0])).all() - - -def test_move(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([1, 2, 3, 4, 5]).send(bob) - - assert x.id_at_location in bob._objects - assert x.id_at_location not in alice._objects - - x.move(alice) - - assert x.id_at_location not in bob._objects - assert x.id_at_location in alice._objects - - x = torch.tensor([1.0, 2, 3, 4, 5], requires_grad=True).send(bob) - - assert x.id_at_location in bob._objects - assert x.id_at_location not in alice._objects - - x.move(alice) - - assert x.id_at_location not in bob._objects - assert x.id_at_location in alice._objects - - alice.clear_objects() - bob.clear_objects() - x = torch.tensor([1.0, 2, 3, 4, 5]).send(bob) - x.move(alice) - - assert len(alice._objects) == 1 - - # Test .move on remote objects - - james.clear_objects() - x = th.tensor([1.0]).send(james) - remote_x = james._objects[x.id_at_location] - remote_ptr = remote_x.send(bob) - assert remote_ptr.id in james._objects.keys() - remote_ptr2 = remote_ptr.move(alice) - assert remote_ptr2.id in james._objects.keys() - - -def test_combine_pointers(workers): - """ - Ensure that the sy.combine_pointers works as expected - """ - - bob = workers["bob"] - alice = workers["alice"] - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 2, 3, 4, 5]).send(alice) - - a = x.combine(y) - b = a + a - - c = b.get(sum_results=True) - assert (c == th.tensor([4, 8, 12, 16, 20])).all() - - b = a + a - c = b.get(sum_results=False) - assert len(c) == 2 - assert (c[0] == th.tensor([2, 4, 6, 8, 10])).all - - -def test_remote_to_cpu_device(workers): - """Ensure remote .to cpu works""" - device = torch.device("cpu") - bob = workers["bob"] - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - x.to(device) - - -def test_get_remote_shape(workers): - """Test pointer.shape functionality""" - bob = workers["bob"] - # tensor directly sent: shape stored at sending - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - assert x.shape == torch.Size([5]) - # result of an operation: need to make a call to the remote worker - y = x + x - assert y.shape == torch.Size([5]) - - -def test_remote_function_with_multi_ouput(workers): - """ - Functions like .split return several tensors, registration and response - must be made carefully in this case - """ - bob = workers["bob"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - r_ptr = torch.split(ptr, 2) - assert (r_ptr[0].get() == torch.tensor([1, 2.0])).all() - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - max_value, argmax_idx = torch.max(ptr, 0) - - assert max_value.get().item() == 4.0 - assert argmax_idx.get().item() == 3 - - -def test_raising_error_when_item_func_called(workers): - pointer = PointerTensor(id=1000, location=workers["alice"], owner=workers["me"]) - with pytest.raises(RuntimeError): - pointer.item() - - -def test_fix_prec_on_pointer_tensor(workers): - """ - Ensure .fix_precision() works as expected. - """ - bob = workers["bob"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - - ptr = ptr.fix_precision() - remote_tensor = bob._objects[ptr.id_at_location] - - assert isinstance(ptr.child, PointerTensor) - assert isinstance(remote_tensor.child, FixedPrecisionTensor) - - -def test_fix_prec_on_pointer_of_pointer(workers): - """ - Ensure .fix_precision() works along a chain of pointers. - """ - bob = workers["bob"] - alice = workers["alice"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - ptr = ptr.send(alice) - - ptr = ptr.fix_precision() - - alice_tensor = alice._objects[ptr.id_at_location] - remote_tensor = bob._objects[alice_tensor.id_at_location] - - assert isinstance(ptr.child, PointerTensor) - assert isinstance(remote_tensor.child, FixedPrecisionTensor) - - -def test_float_prec_on_pointer_tensor(workers): - """ - Ensure .float_precision() works as expected. - """ - bob = workers["bob"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - ptr = ptr.fix_precision() - - ptr = ptr.float_precision() - remote_tensor = bob._objects[ptr.id_at_location] - - assert isinstance(ptr.child, PointerTensor) - assert isinstance(remote_tensor, torch.Tensor) - - -def test_float_prec_on_pointer_of_pointer(workers): - """ - Ensure .float_precision() works along a chain of pointers. - """ - bob = workers["bob"] - alice = workers["alice"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - ptr = ptr.send(alice) - ptr = ptr.fix_precision() - - ptr = ptr.float_precision() - - alice_tensor = alice._objects[ptr.id_at_location] - remote_tensor = bob._objects[alice_tensor.id_at_location] - - assert isinstance(ptr.child, PointerTensor) - assert isinstance(remote_tensor, torch.Tensor) - - -def test_registration_of_operation_on_pointer_of_pointer(workers): - """ - Ensure operations along a chain of pointers are registered as expected. - """ - bob = workers["bob"] - alice = workers["alice"] - - tensor = torch.tensor([1, 2, 3, 4.0]) - ptr = tensor.send(bob) - ptr = ptr.send(alice) - ptr_operation = ptr + ptr - - assert len(alice._objects) == 2 - assert len(bob._objects) == 2 diff --git a/test/torch/tensors/__init__.py b/test/torch/tensors/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/torch/tensors/test_additive_shared.py b/test/torch/tensors/test_additive_shared.py deleted file mode 100644 index d85380c0d55..00000000000 --- a/test/torch/tensors/test_additive_shared.py +++ /dev/null @@ -1,942 +0,0 @@ -import copy -import pytest - -import torch -import torch.nn as nn -import torch.nn.functional as F - -import syft -from syft.frameworks.torch.tensors.interpreters.additive_shared import AdditiveSharingTensor - - -def test_wrap(workers): - """ - Test the .on() wrap functionality for AdditiveSharingTensor - """ - - x_tensor = torch.Tensor([1, 2, 3]) - x = AdditiveSharingTensor().on(x_tensor) - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, AdditiveSharingTensor) - assert isinstance(x.child.child, torch.Tensor) - - -def test___str__(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x_sh = torch.tensor([[3, 4]]).share(alice, bob, crypto_provider=james) - assert isinstance(x_sh.__str__(), str) - - -def test_share_get(workers): - - t = torch.tensor([1, 2, 3]) - x = t.share(workers["bob"], workers["alice"], workers["james"]) - - x = x.get() - - assert (x == t).all() - - -def test___bool__(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x_sh = torch.tensor([[3, 4]]).share(alice, bob, crypto_provider=james) - - with pytest.raises(ValueError): - if x_sh: # pragma: no cover - pass - - -def test_share_inplace_consistency(workers): - """Verify that share_ produces the same output then share""" - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x1 = torch.tensor([-1.0]) - x1.fix_precision_().share_(alice, bob, crypto_provider=james) - - x2 = torch.tensor([-1.0]) - x2_sh = x2.fix_precision().share(alice, bob, crypto_provider=james) - - assert (x1 == x2_sh).get().float_prec() - - -def test_clone(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x = torch.tensor([1.2]).fix_precision().share(alice, bob, crypto_provider=james) - original_props = ( - x.id, - x.owner.id, - x.child.id, - x.child.owner.id, - x.child.child.id, - x.child.child.owner.id, - ) - xc = x.clone() - cloned_props = ( - xc.id, - xc.owner.id, - xc.child.id, - xc.child.owner.id, - xc.child.child.id, - xc.child.child.owner.id, - ) - assert original_props == cloned_props - - -def test_virtual_get(workers): - t = torch.tensor([1, 2, 3]) - x = t.share(workers["bob"], workers["alice"], workers["james"]) - - x = x.child.virtual_get() - - assert (x == t).all() - - -def test_non_client_registration(hook, workers): - hook.local_worker.is_client_worker = False - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - x = torch.tensor([-1.0]) - x_sh = x.fix_precision().share(alice, bob, crypto_provider=james) - - assert x_sh.id in hook.local_worker._objects - assert (x_sh == hook.local_worker.get_obj(x_sh.id)).get().float_prec() - hook.local_worker.is_client_worker = True - - -def test_autograd_kwarg(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - t = torch.tensor([1, 2, 3]) - x = t.share(alice, bob, crypto_provider=james, requires_grad=True) - - assert isinstance(x.child, syft.AutogradTensor) - - -def test_send_get(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x_sh = torch.tensor([[3, 4]]).share(alice, bob, crypto_provider=james) - - alice_t_id = x_sh.child.child["alice"].id_at_location - assert alice_t_id in alice._objects - - ptr_x = x_sh.send(james) - ptr_x_id_at_location = ptr_x.id_at_location - assert ptr_x_id_at_location in james._objects - assert alice_t_id in alice._objects - - x_sh_back = ptr_x.get() - assert ptr_x_id_at_location not in james._objects - assert alice_t_id in alice._objects - - x = x_sh_back.get() - assert alice_t_id not in alice._objects - - -def test_add(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # 2 workers - t = torch.tensor([1, 2, 3]) - x = torch.tensor([1, 2, 3]).share(bob, alice) - - y = (x + x).get() - - # 3 workers - assert (y == (t + t)).all() - - t = torch.tensor([1, 2, 3]) - x = torch.tensor([1, 2, 3]).share(bob, alice, james) - - y = (x + x).get() - - # negative numbers - assert (y == (t + t)).all() - - t = torch.tensor([1, -2, 3]) - x = torch.tensor([1, -2, 3]).share(bob, alice, james) - - y = (x + x).get() - - assert (y == (t + t)).all() - - # with fixed precisions - t = torch.tensor([1.0, -2, 3]) - x = torch.tensor([1.0, -2, 3]).fix_prec().share(bob, alice, james) - - y = (x + x).get().float_prec() - - assert (y == (t + t)).all() - - # with FPT>torch.tensor - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - y = t.fix_prec() - - z = (x + y).get().float_prec() - - assert (z == (t + t)).all() - - z = (y + x).get().float_prec() - - assert (z == (t + t)).all() - - # with constant integer - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - c = 4 - - z = (x + c).get().float_prec() - assert (z == (t + c)).all() - - z = (c + x).get().float_prec() - assert (z == (c + t)).all() - - # with constant float - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - c = 4.2 - - z = (x + c).get().float_prec() - assert ((z - (t + c)) < 10e-3).all() - - z = (c + x).get().float_prec() - assert ((z - (c + t)) < 10e-3).all() - - -def test_sub(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # 3 workers - t = torch.tensor([1, 2, 3]) - x = torch.tensor([1, 2, 3]).share(bob, alice, james) - - y = (x - x).get() - - assert (y == (t - t)).all() - - # negative numbers - t = torch.tensor([1, -2, 3]) - x = torch.tensor([1, -2, 3]).share(bob, alice, james) - - y = (x - x).get() - - assert (y == (t - t)).all() - - # with fixed precision - t = torch.tensor([1.0, -2, 3]) - x = torch.tensor([1.0, -2, 3]).fix_prec().share(bob, alice, james) - - y = (x - x).get().float_prec() - - assert (y == (t - t)).all() - - # with FPT>torch.tensor - t = torch.tensor([1.0, -2.0, 3.0]) - u = torch.tensor([4.0, 3.0, 2.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - y = u.fix_prec() - - z = (x - y).get().float_prec() - - assert (z == (t - u)).all() - - z = (y - x).get().float_prec() - - assert (z == (u - t)).all() - - # with constant integer - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - c = 4 - - z = (x - c).get().float_prec() - assert (z == (t - c)).all() - - z = (c - x).get().float_prec() - assert (z == (c - t)).all() - - # with constant float - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - c = 4.2 - - z = (x - c).get().float_prec() - assert ((z - (t - c)) < 10e-3).all() - - z = (c - x).get().float_prec() - assert ((z - (c - t)) < 10e-3).all() - - -def test_mul(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - bob, alice, james, charlie = ( - workers["bob"], - workers["alice"], - workers["james"], - workers["charlie"], - ) - - # 2 workers - t = torch.tensor([1, 2, 3, 4]) - x = t.share(bob, alice, crypto_provider=james) - y = (x * x).get() - - assert (y == (t * t)).all() - - # 3 workers - t = torch.tensor([1, 2, 3, 4]) - x = t.share(bob, alice, charlie, crypto_provider=james) - y = (x * x).get() - - assert (y == (t * t)).all() - - # with fixed precision - x = torch.tensor([1, -2, -3, 4.0]).fix_prec().share(bob, alice, crypto_provider=james) - y = torch.tensor([-1, 2, -3, 4.0]).fix_prec().share(bob, alice, crypto_provider=james) - y = (x * y).get().float_prec() - - assert (y == torch.tensor([-1, -4, 9, 16.0])).all() - - # with non-default fixed precision - t = torch.tensor([1, 2, 3, 4.0]) - x = t.fix_prec(precision_fractional=2).share(bob, alice, crypto_provider=james) - y = (x * x).get().float_prec() - - assert (y == (t * t)).all() - - # with FPT>torch.tensor - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - y = t.fix_prec() - - z = (x * y).get().float_prec() - - assert (z == (t * t)).all() - - -def test_public_mul(workers): - bob, alice, james, charlie = ( - workers["bob"], - workers["alice"], - workers["james"], - workers["charlie"], - ) - - t = torch.tensor([-3.1, 1.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - y = 1 - z = (x * y).get().float_prec() - assert (z == (t * y)).all() - - # 3 workers - t = torch.tensor([-3.1, 1.0]) - x = t.fix_prec().share(alice, bob, charlie, crypto_provider=james) - y = 1 - z = (x * y).get().float_prec() - assert (z == (t * y)).all() - - t = torch.tensor([-3.1, 1.0]) - x = t.fix_prec().share(alice, bob, crypto_provider=james) - y = 0 - z = (x * y).get().float_prec() - assert (z == (t * y)).all() - - t_x = torch.tensor([-3.1, 1]) - t_y = torch.tensor([1.0]) - x = t_x.fix_prec().share(alice, bob, crypto_provider=james) - y = t_y.fix_prec() - z = x * y - z = z.get().float_prec() - assert (z == t_x * t_y).all() - - t_x = torch.tensor([-3.1, 1]) - t_y = torch.tensor([0.0]) - x = t_x.fix_prec().share(alice, bob, crypto_provider=james) - y = t_y.fix_prec() - z = x * y - z = z.get().float_prec() - assert (z == t_x * t_y).all() - - t_x = torch.tensor([-3.1, 1]) - t_y = torch.tensor([0.0, 2.1]) - x = t_x.fix_prec().share(alice, bob, crypto_provider=james) - y = t_y.fix_prec() - z = x * y - z = z.get().float_prec() - assert (z == t_x * t_y).all() - - -def test_div(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # With scalar - t = torch.tensor([[9.0, 12.0], [3.3, 0.0]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - y = (x / 3).get().float_prec() - - assert (y == torch.tensor([[3.0, 4.0], [1.1, 0.0]])).all() - - # With another encrypted tensor of same shape - t1 = torch.tensor([[25, 9], [10, 30]]) - t2 = torch.tensor([[5, 12], [2, 7]]) - x1 = t1.fix_prec().share(bob, alice, crypto_provider=james) - x2 = t2.fix_prec().share(bob, alice, crypto_provider=james) - - y = (x1 / x2).get().float_prec() - assert (y == torch.tensor([[5.0, 0.75], [5.0, 4.285]])).all() - - # With another encrypted single value - t1 = torch.tensor([[25.0, 9], [10, 30]]) - t2 = torch.tensor([5.0]) - x1 = t1.fix_prec().share(bob, alice, crypto_provider=james) - x2 = t2.fix_prec().share(bob, alice, crypto_provider=james) - - y = (x1 / x2).get().float_prec() - assert (y == torch.tensor([[5.0, 1.8], [2.0, 6.0]])).all() - - -def test_pow(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec().share(bob, alice, crypto_provider=james) - y = (x ** 3).get().float_prec() - - assert (y == (m ** 3)).all() - - -def test_operate_with_integer_constants(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - x = torch.tensor([2.0]) - x_sh = x.fix_precision().share(alice, bob, crypto_provider=james) - - r_sh = x_sh + 10 - assert r_sh.get().float_prec() == x + 10 - - r_sh = x_sh - 7 - assert r_sh.get().float_prec() == x - 7 - - r_sh = x_sh * 2 - assert r_sh.get().float_prec() == x * 2 - - r_sh = x_sh / 2 - assert r_sh.get().float_prec() == x / 2 - - -def test_stack(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - t = torch.tensor([1.3, 2]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - res = torch.stack([x, x]).get().float_prec() - - expected = torch.tensor([[1.3000, 2.0000], [1.3000, 2.0000]]) - - assert (res == expected).all() - - -def test_cat(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - t = torch.tensor([[1, 2, 3], [4, 5, 6]]) - x = t.share(bob, alice, crypto_provider=james) - - res0 = torch.cat([x, x], dim=0).get() - res1 = torch.cat([x, x], dim=1).get() - - expected0 = torch.tensor([[1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6]]) - expected1 = torch.tensor([[1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6]]) - - assert (res0 == expected0).all() - assert (res1 == expected1).all() - - # Test when using more tensors - res2 = torch.cat([x, x, x], dim=1).get() - expected2 = torch.tensor([[1, 2, 3, 1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6, 4, 5, 6]]) - - assert (res2 == expected2).all() - - -def test_chunk(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - t = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8]]) - x = t.share(bob, alice, crypto_provider=james) - - res0 = torch.chunk(x, 2, dim=0) - res1 = torch.chunk(x, 2, dim=1) - - expected0 = [torch.tensor([[1, 2, 3, 4]]), torch.tensor([[5, 6, 7, 8]])] - expected1 = [torch.tensor([[1, 2], [5, 6]]), torch.tensor([[3, 4], [7, 8]])] - - assert all([(res0[i].get() == expected0[i]).all() for i in range(2)]) - assert all([(res1[i].get() == expected1[i]).all() for i in range(2)]) - - -def test_roll(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - t = torch.tensor([[1, 2, 3], [4, 5, 6]]) - x = t.share(bob, alice, crypto_provider=james) - - res1 = torch.roll(x, 2) - res2 = torch.roll(x, 2, dims=1) - res3 = torch.roll(x, (1, 2), dims=(0, 1)) - - assert (res1.get() == torch.roll(t, 2)).all() - assert (res2.get() == torch.roll(t, 2, dims=1)).all() - assert (res3.get() == torch.roll(t, (1, 2), dims=(0, 1))).all() - - # With MultiPointerTensor - shifts = torch.tensor(1).send(alice, bob) - res = torch.roll(x, shifts) - - shifts1 = torch.tensor(1).send(alice, bob) - shifts2 = torch.tensor(2).send(alice, bob) - res2 = torch.roll(x, (shifts1, shifts2), dims=(0, 1)) - - assert (res.get() == torch.roll(t, 1)).all() - assert (res2.get() == torch.roll(t, (1, 2), dims=(0, 1))).all() - - -def test_nn_linear(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - t = torch.tensor([[1.0, 2]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - model = nn.Linear(2, 1) - model.weight = nn.Parameter(torch.tensor([[-1.0, 2]])) - model.bias = nn.Parameter(torch.tensor([[-1.0]])) - model.fix_precision().share(bob, alice, crypto_provider=james) - - y = model(x) - - assert y.get().float_prec() == torch.tensor([[2.0]]) - - -def test_matmul(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec().share(bob, alice, crypto_provider=james) - y = (x @ x).get().float_prec() - - assert (y == (m @ m)).all() - - # with FPT>torch.tensor - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec().share(bob, alice, crypto_provider=james) - y = m.fix_prec() - - z = (x @ y).get().float_prec() - - assert (z == (m @ m)).all() - - z = (y @ x).get().float_prec() - - assert (z == (m @ m)).all() - - -def test_mm(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - t = torch.tensor([[1, 2], [3, 4.0]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - - # Using the method - y = (x.mm(x)).get().float_prec() - assert (y == (t.mm(t))).all() - - # Using the function - y = (torch.mm(x, x)).get().float_prec() - assert (y == (torch.mm(t, t))).all() - - # with FPT>torch.tensor - t = torch.tensor([[1, 2], [3, 4.0]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - y = t.fix_prec() - - # Using the method - z = (x.mm(y)).get().float_prec() - assert (z == (t.mm(t))).all() - - # Using the function - z = (torch.mm(x, y)).get().float_prec() - assert (z == (torch.mm(t, t))).all() - - # Using the method - z = (y.mm(x)).get().float_prec() - assert (z == (t.mm(t))).all() - - # Using the function - z = (torch.mm(y, x)).get().float_prec() - assert (z == (torch.mm(t, t))).all() - - -def test_torch_conv2d(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - im = torch.Tensor( - [ - [ - [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]], - [[10.0, 11.0, 12.0], [13.0, 14.0, 15.0], [16.0, 17.0, 18.0]], - ] - ] - ) - w = torch.Tensor( - [ - [[[1.0, 1.0], [1.0, 1.0]], [[2.0, 2.0], [2.0, 2.0]]], - [[[-1.0, -2.0], [-3.0, -4.0]], [[0.0, 0.0], [0.0, 0.0]]], - ] - ) - bias = torch.Tensor([0.0, 5.0]) - - im_shared = im.fix_precision().share(bob, alice, crypto_provider=james) - w_shared = w.fix_precision().share(bob, alice, crypto_provider=james) - bias_shared = bias.fix_precision().share(bob, alice, crypto_provider=james) - - res0 = torch.conv2d(im_shared, w_shared, bias=bias_shared, stride=1).get().float_precision() - res1 = ( - torch.conv2d( - im_shared, - w_shared[:, 0:1].contiguous(), - bias=bias_shared, - stride=2, - padding=3, - dilation=2, - groups=2, - ) - .get() - .float_precision() - ) - - expected0 = torch.conv2d(im, w, bias=bias, stride=1) - expected1 = torch.conv2d( - im, w[:, 0:1].contiguous(), bias=bias, stride=2, padding=3, dilation=2, groups=2 - ) - - assert (res0 == expected0).all() - assert (res1 == expected1).all() - - -def test_fixed_precision_and_sharing(workers): - - bob, alice = (workers["bob"], workers["alice"]) - - t = torch.tensor([1, 2, 3, 4.0]) - x = t.fix_prec().share(bob, alice) - out = x.get().float_prec() - - assert (out == t).all() - - x = t.fix_prec().share(bob, alice) - - y = x + x - - y = y.get().float_prec() - assert (y == (t + t)).all() - - -def test_fixed_precision_and_sharing_on_pointer(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - t = torch.tensor([1, 2, 3, 4.0]) - ptr = t.send(james) - - x = ptr.fix_prec().share(bob, alice) - - y = x + x - - y = y.get().get().float_prec() - assert (y == (t + t)).all() - - -def test_pointer_on_fixed_precision_and_sharing(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - t = torch.tensor([1, 2, 3, 4.0]) - - x = t.fix_prec().share(bob, alice) - x = x.send(james) - - y = x + x - - y = y.get().get().float_prec() - assert (y == (t + t)).all() - - -def test_get_item(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - x = torch.tensor([[3.1, 4.3]]).fix_prec().share(alice, bob, crypto_provider=james) - idx = torch.tensor([0]).send(alice, bob) - - # Operate directly AST[MPT] - assert x.child.child[:, idx.child].get() == torch.tensor([[3100]]) - - # With usual wrappers and FPT - x = torch.tensor([[3, 4]]).share(alice, bob, crypto_provider=james) - idx = torch.tensor([0]).send(alice, bob) - assert x[:, idx].get() == torch.tensor([[3]]) - - -def test_eq(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x == y).get().float_prec() - - x = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([2.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert not (x == y).get().float_prec() - - x = torch.tensor([-3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([-3.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x == y).get().float_prec() - - -def test_comp(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x >= y).get().float_prec() - assert (x <= y).get().float_prec() - assert not (x > y).get().float_prec() - assert not (x < y).get().float_prec() - - x = torch.tensor([-3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([-3.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x >= y).get().float_prec() - assert (x <= y).get().float_prec() - assert not (x > y).get().float_prec() - assert not (x < y).get().float_prec() - - x = torch.tensor([3.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([2.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x >= y).get().float_prec() - assert not (x <= y).get().float_prec() - assert (x > y).get().float_prec() - assert not (x < y).get().float_prec() - - x = torch.tensor([-2.1]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([-3.1]).fix_prec().share(alice, bob, crypto_provider=james) - - assert (x >= y).get().float_prec() - assert not (x <= y).get().float_prec() - assert (x > y).get().float_prec() - assert not (x < y).get().float_prec() - - -def test_max(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([3, 1.0, 2]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - max_value = x.max().get().float_prec() - assert max_value == torch.tensor([3.0]) - - t = torch.tensor([3, 4.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - max_value = x.max().get().float_prec() - assert max_value == torch.tensor([4.0]) - - t = torch.tensor([3, 4.0, 5, 2]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - max_value = x.max().get().float_prec() - assert max_value == torch.tensor([5.0]) - - -def test_argmax(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([3, 1.0, 2]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - idx = x.argmax().get().float_prec() - assert idx == torch.tensor([0.0]) - - t = torch.tensor([3, 4.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - idx = x.argmax().get().float_prec() - assert idx == torch.tensor([1.0]) - - t = torch.tensor([3, 4.0, 5, 2]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - idx = x.argmax().get().float_prec() - assert idx == torch.tensor([2.0]) - - # no dim= - t = torch.tensor([[1, 2.0, 4], [3, 9.0, 2.0]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - ids = x.argmax().get().float_prec() - assert ids.long() == torch.argmax(t) - - # dim=1 - t = torch.tensor([[1, 2.0, 4], [3, 1.0, 2.0]]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - ids = x.argmax(dim=1).get().float_prec() - assert (ids.long() == torch.argmax(t, dim=1)).all() - - -def test_mod(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([21]).share(bob, alice, crypto_provider=james) - assert t.child.mod(8).get() % 8 == torch.tensor([5]) - assert t.child.mod(-8).get() % -8 == torch.tensor([-3]) - - t = torch.tensor([-21]).share(bob, alice, crypto_provider=james) - assert t.child.mod(8).get() % 8 == torch.tensor([3]) - assert t.child.mod(-8).get() % -8 == torch.tensor([-5]) - - assert (t.child % 8).get() % 8 == torch.tensor([3]) - - -def test_torch_sum(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([[1, 2, 4], [8, 5, 6]]) - x = t.share(alice, bob, crypto_provider=james) - - s = torch.sum(x).get() - s_dim = torch.sum(x, 0).get() - s_dim2 = torch.sum(x, (0, 1)).get() - s_keepdim = torch.sum(x, 1, keepdim=True).get() - - assert (s == torch.sum(t)).all() - assert (s_dim == torch.sum(t, 0)).all() - assert (s_dim2 == torch.sum(t, (0, 1))).all() - assert (s_keepdim == torch.sum(t, 1, keepdim=True)).all() - - -def test_torch_mean(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - base = 10 - prec_frac = 4 - - t = torch.tensor([[1.0, 2.5], [8.0, 5.5]]) - x = t.fix_prec(base=base, precision_fractional=prec_frac).share( - alice, bob, crypto_provider=james - ) - - s = torch.mean(x).get().float_prec() - s_dim = torch.mean(x, 0).get().float_prec() - s_dim2 = torch.mean(x, (0, 1)).get().float_prec() - s_keepdim = torch.mean(x, 1, keepdim=True).get().float_prec() - - assert (s == torch.tensor(4.25)).all() - assert (s_dim == torch.tensor([4.5, 4.0])).all() - assert (s_dim2 == torch.tensor(4.25)).all() - assert (s_keepdim == torch.tensor([[1.75], [6.75]])).all() - - -def test_torch_dot(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0]).fix_prec().share(alice, bob, crypto_provider=james) - y = torch.tensor([3.0, 3.0, 3.0, 3.0, 3.0]).fix_prec().share(alice, bob, crypto_provider=james) - - assert torch.dot(x, y).get().float_prec() == 45 - - -def test_unbind(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([21, 17]).share(bob, alice, crypto_provider=james).child - - x0, x1 = torch.unbind(x) - - assert x0.get() == torch.tensor(21) - assert x1.get() == torch.tensor(17) - - -def test_handle_func_command(workers): - """ - Just to show that handle_func_command works - Even if torch.abs should be hooked to return a correct value - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([-21]).share(bob, alice, crypto_provider=james).child - _ = torch.abs(t).get() - - -def test_init_with_no_crypto_provider(workers): - alice, bob = workers["alice"], workers["bob"] - - x = torch.tensor([21, 17]).share(bob, alice).child - - assert x.crypto_provider.id == syft.hook.local_worker.id - - -def test_zero_refresh(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - t = torch.tensor([2.2, -1.0]) - x = t.fix_prec().share(bob, alice, crypto_provider=james) - - x_sh = x.child.child - assert (x_sh.zero().get() == torch.zeros(*t.shape).long()).all() - - x = t.fix_prec().share(bob, alice, crypto_provider=james) - x_copy = t.fix_prec().share(bob, alice, crypto_provider=james) - x_r = x.refresh() - - assert (x_r.get().float_prec() == x_copy.get().float_prec()).all() - - x = t.fix_prec().share(bob, alice, crypto_provider=james) - x_r = x.refresh() - - assert ((x_r / 2).get().float_prec() == t / 2).all() - - -def test_cnn_model(workers): - torch.manual_seed(121) # Truncation might not always work so we set the random seed - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - class Net(nn.Module): - def __init__(self): - super(Net, self).__init__() - self.conv1 = nn.Conv2d(1, 20, 5, 1) - self.conv2 = nn.Conv2d(20, 50, 5, 1) - self.fc1 = nn.Linear(4 * 4 * 50, 500) - self.fc2 = nn.Linear(500, 10) - - def forward(self, x): - # TODO: uncomment maxpool2d operations - # once it is supported with smpc. - x = F.relu(self.conv1(x)) - # x = F.max_pool2d(x, 2, 2) - x = F.relu(self.conv2(x)) - # x = F.max_pool2d(x, 2, 2) - x = x.view(-1, 4 * 4 * 50) - x = F.relu(self.fc1(x)) - x = self.fc2(x) - return x - - model = Net() - sh_model = copy.deepcopy(model).fix_precision().share(alice, bob, crypto_provider=james) - - data = torch.zeros((1, 1, 28, 28)) - sh_data = torch.zeros((1, 1, 28, 28)).fix_precision().share(alice, bob, crypto_provider=james) - - assert torch.allclose(sh_model(sh_data).get().float_prec(), model(data), atol=1e-2) - - -def test_correct_tag_and_description_after_send(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - x = torch.tensor([1, 2, 3]).share(alice, bob, james) - x.tags = ["tag_additive_test1", "tag_additive_test2"] - x.description = "description_additive_test" - - pointer_x = x.send(alice) - - assert alice.search("tag_additive_test1") - assert alice.search("tag_additive_test2") - assert alice.search("description_additive_test") diff --git a/test/torch/tensors/test_autograd.py b/test/torch/tensors/test_autograd.py deleted file mode 100644 index fde0def68c7..00000000000 --- a/test/torch/tensors/test_autograd.py +++ /dev/null @@ -1,778 +0,0 @@ -import pytest -import torch -import torch.nn as nn -import torch.nn.functional as F -import torch.optim as optim -import syft - -from syft.frameworks.torch.tensors.interpreters.autograd import AutogradTensor -from syft.generic.pointers.pointer_tensor import PointerTensor - - -def test_wrap(): - """ - Test the .on() wrap functionality for AutogradTensor - """ - - x_tensor = torch.Tensor([1, 2, 3]) - x = AutogradTensor().on(x_tensor) - - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, AutogradTensor) - assert isinstance(x.child.child, torch.Tensor) - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__", "__mul__", "__matmul__"]) -@pytest.mark.parametrize("backward_one", [True, False]) -def test_backward_for_binary_cmd_with_autograd(cmd, backward_one): - """ - Test .backward() on local tensors wrapped in an AutogradTensor - (It is useless but this is the most basic example) - """ - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape) - ones = syft.AutogradTensor().on(ones) - c.backward(ones if backward_one else None) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.child.grad == a_torch.grad).all() - assert (b.child.grad == b_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__iadd__", "__isub__"]) -def test_backward_for_inplace_binary_cmd_with_autograd(cmd): - - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - c = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - c = syft.AutogradTensor().on(c) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - c_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - r = a * b - getattr(r, cmd)(c) - r_torch = a_torch * b_torch - getattr(r_torch, cmd)(c_torch) - - ones = torch.ones(r.shape) - ones = syft.AutogradTensor().on(ones) - r.backward(ones) - r_torch.backward(torch.ones(r_torch.shape)) - - assert (a.child.grad == a_torch.grad).all() - assert (b.child.grad == b_torch.grad).all() - assert (c.child.grad == c_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__"]) -@pytest.mark.parametrize( - "shapes", - [ - ((2,), (2,)), - ((5, 3, 2), (5, 1, 2)), - ((3, 2), (5, 3, 2)), - ((3, 1), (5, 3, 2)), - ((3, 2), (5, 1, 2)), - ], -) -def test_backward_for_binary_cmd_with_inputs_of_different_dim_and_autograd(cmd, shapes): - """ - Test .backward() on local tensors wrapped in an AutogradTensor - (It is useless but this is the most basic example) - """ - a_shape, b_shape = shapes - a = torch.ones(a_shape, requires_grad=True) - b = torch.ones(b_shape, requires_grad=True) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - - a_torch = torch.ones(a_shape, requires_grad=True) - b_torch = torch.ones(b_shape, requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape) - ones = syft.AutogradTensor().on(ones) - c.backward(ones) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.child.grad == a_torch.grad).all() - assert (b.child.grad == b_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__", "__mul__", "__matmul__"]) -@pytest.mark.parametrize("backward_one", [True, False]) -def test_backward_for_remote_binary_cmd_with_autograd(workers, cmd, backward_one): - """ - Test .backward() on remote tensors using explicit wrapping - with an Autograd Tensor. - """ - alice = workers["alice"] - - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True).send(alice) - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True).send(alice) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape).send(alice) - ones = syft.AutogradTensor().on(ones) - c.backward(ones if backward_one else None) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.grad.get() == a_torch.grad).all() - assert (b.grad.get() == b_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__iadd__", "__isub__"]) -def test_backward_for_remote_inplace_binary_cmd_with_autograd(workers, cmd): - alice = workers["alice"] - - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True).send(alice) - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True).send(alice) - c = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True).send(alice) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - c = syft.AutogradTensor().on(c) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - c_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - r = a * b - getattr(r, cmd)(c) - r_torch = a_torch * b_torch - getattr(r_torch, cmd)(c_torch) - - ones = torch.ones(r.shape).send(alice) - ones = syft.AutogradTensor().on(ones) - r.backward(ones) - r_torch.backward(torch.ones(r_torch.shape)) - - assert (a.grad.get() == a_torch.grad).all() - assert (b.grad.get() == b_torch.grad).all() - assert (c.grad.get() == c_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__", "__mul__", "__matmul__"]) -def test_backward_for_remote_binary_cmd_local_autograd(workers, cmd): - """ - Test .backward() on remote tensors using implicit wrapping - with an Autograd Tensor. - - Distinguish the current use of: - a = torch.tensor([[3., 2], [-1, 2]], requires_grad=True) - a.send(alice, local_autograd=True) - - instead of the previous: - a = torch.tensor([[3., 2], [-1, 2]], requires_grad=True).send(alice) - a = syft.AutogradTensor().on(a) - """ - alice = workers["alice"] - - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - a = a.send(alice, local_autograd=True) - b = b.send(alice, local_autograd=True) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape).send(alice) - ones = syft.AutogradTensor().on(ones) - c.backward(ones) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.grad.get() == a_torch.grad).all() - assert (b.grad.get() == b_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["sqrt", "asin", "sin", "sinh", "tanh", "sigmoid"]) -def test_backward_for_remote_unary_cmd_local_autograd(workers, cmd): - """ - Test .backward() on unary methods on remote tensors using - implicit wrapping - """ - alice = workers["alice"] - - a = torch.tensor([0.3, 0.2, 0], requires_grad=True) - a = a.send(alice, local_autograd=True) - - a_torch = torch.tensor([0.3, 0.2, 0], requires_grad=True) - - c = getattr(a, cmd)() - c_torch = getattr(a_torch, cmd)() - - ones = torch.ones(c.shape).send(alice) - ones = syft.AutogradTensor().on(ones) - c.backward(ones) - c_torch.backward(torch.ones_like(c_torch)) - - # Have to do .child.grad here because .grad doesn't work on Wrappers yet - assert (a.grad.get() == a_torch.grad).all() - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__", "__mul__", "__matmul__"]) -@pytest.mark.parametrize("backward_one", [True, False]) -def test_backward_for_fix_prec_binary_cmd_with_autograd(cmd, backward_one): - """ - Test .backward() on Fixed Precision Tensor for a single operation - """ - a = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True).fix_prec() - b = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True).fix_prec() - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape).fix_prec() - ones = syft.AutogradTensor().on(ones) - c.backward(ones if backward_one else None) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.grad.float_prec() == a_torch.grad).all() - assert (b.grad.float_prec() == b_torch.grad).all() - - -def test_backward_for_linear_model_on_fix_prec_params_with_autograd(): - """ - Test .backward() on Fixed Precision parameters with mixed operations - """ - x = torch.tensor([[1.0, 2], [1.0, 2]]).fix_prec() - target = torch.tensor([[1.0], [1.0]]).fix_prec() - model = nn.Linear(2, 1) - model.weight = nn.Parameter(torch.tensor([[-1.0, 2]])) - model.bias = nn.Parameter(torch.tensor([-1.0])) - model.fix_precision() - - x = syft.AutogradTensor().on(x) - target = syft.AutogradTensor().on(target) - model.weight = syft.AutogradTensor().on(model.weight) - model.bias = syft.AutogradTensor().on(model.bias) - - output = model(x) - loss = ((output - target) ** 2).sum() - one = torch.ones(loss.shape).fix_prec() - one = syft.AutogradTensor().on(one) - loss.backward(one) - - weight_grad = model.weight.grad.float_precision() - bias_grad = model.bias.grad.float_precision() - - x = torch.tensor([[1.0, 2], [1.0, 2]]) - target = torch.tensor([[1.0], [1.0]]) - model = nn.Linear(2, 1) - model.weight = nn.Parameter(torch.tensor([[-1.0, 2]])) - model.bias = nn.Parameter(torch.tensor([-1.0])) - - output = model(x) - loss = ((output - target) ** 2).sum() - - one = torch.ones(loss.shape) - loss.backward(one) - assert (model.weight.grad == weight_grad).all() - assert (model.bias.grad == bias_grad).all() - - -@pytest.mark.parametrize("cmd", ["__add__", "__sub__", "__mul__", "__matmul__"]) -@pytest.mark.parametrize("backward_one", [True, False]) -def test_backward_for_additive_shared_binary_cmd_with_autograd(workers, cmd, backward_one): - """ - Test .backward() on Additive Shared Tensor for a single operation - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - a = ( - torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - b = ( - torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - - c = getattr(a, cmd)(b) - c_torch = getattr(a_torch, cmd)(b_torch) - - ones = torch.ones(c.shape).fix_prec().share(alice, bob, crypto_provider=james) - ones = syft.AutogradTensor().on(ones) - c.backward(ones if backward_one else None) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.grad.get().float_prec() == a_torch.grad).all() - assert (b.grad.get().float_prec() == b_torch.grad).all() - - -@pytest.mark.parametrize("backward_one", [True, False]) -def test_backward_for_additive_shared_div_with_autograd(workers, backward_one): - """ - Test .backward() on Additive Shared Tensor for division with an integer - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - a = ( - torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - b = 2 - - a = syft.AutogradTensor().on(a) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = 2 - - c = a / b - c_torch = a_torch / b_torch - - ones = torch.ones(c.shape).fix_prec().share(alice, bob, crypto_provider=james) - ones = syft.AutogradTensor().on(ones) - c.backward(ones if backward_one else None) - c_torch.backward(torch.ones(c_torch.shape)) - - assert (a.grad.get().float_prec() == a_torch.grad).all() - - -def test_addmm_backward_for_additive_shared_with_autograd(workers): - """ - Test .backward() on Additive Shared Tensor for addmm - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - a = ( - torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - b = ( - torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - c = ( - torch.tensor([[2.0, 2], [0, 1]], requires_grad=True) - .fix_prec() - .share(alice, bob, crypto_provider=james) - ) - - a = syft.AutogradTensor().on(a) - b = syft.AutogradTensor().on(b) - c = syft.AutogradTensor().on(c) - - a_torch = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - b_torch = torch.tensor([[1.0, 2], [3, 2]], requires_grad=True) - c_torch = torch.tensor([[2.0, 2], [0, 1]], requires_grad=True) - - r = torch.addmm(c, a, b) - r_torch = torch.addmm(c_torch, a_torch, b_torch) - - ones = torch.ones(r.shape).fix_prec().share(alice, bob, crypto_provider=james) - ones = syft.AutogradTensor().on(ones) - r.backward(ones) - r_torch.backward(torch.ones(r_torch.shape)) - - assert (a.grad.get().float_prec() == a_torch.grad).all() - assert (b.grad.get().float_prec() == b_torch.grad).all() - assert (c.grad.get().float_prec() == c_torch.grad).all() - - -def test_relu_backward_or_additive_shared_with_autograd(workers): - """ - Test .backward() on Additive Shared Tensor for F.relu - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - data = torch.tensor([[-1, -0.1], [1, 0.1]], requires_grad=True) - data = data.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True) - loss = F.relu(data) - loss.backward() - expected = torch.tensor([[0.0, 0], [1, 1]]) - assert (data.grad.get().float_prec() == expected).all() - - -def test_backward_for_linear_model_on_additive_shared_with_autograd(workers): - """ - Test .backward() on Additive Shared tensors with mixed operations - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - x = torch.tensor([[1.0, 2], [1.0, 2]]).fix_prec().share(bob, alice, crypto_provider=james) - target = torch.tensor([[1.0], [1.0]]).fix_prec().share(bob, alice, crypto_provider=james) - model = nn.Linear(2, 1) - model.weight = nn.Parameter(torch.tensor([[-1.0, 2]])) - model.bias = nn.Parameter(torch.tensor([-1.0])) - model.fix_precision().share(bob, alice, crypto_provider=james) - - x = syft.AutogradTensor().on(x) - target = syft.AutogradTensor().on(target) - model.weight = syft.AutogradTensor().on(model.weight) - model.bias = syft.AutogradTensor().on(model.bias) - - output = model(x) - loss = ((output - target) ** 2).sum() - one = torch.ones(loss.shape).fix_prec().share(bob, alice, crypto_provider=james) - one = syft.AutogradTensor().on(one) - loss.backward(one) - - weight_grad = model.weight.grad.get().float_precision() - bias_grad = model.bias.grad.get().float_precision() - - x = torch.tensor([[1.0, 2], [1.0, 2]]) - target = torch.tensor([[1.0], [1.0]]) - model = nn.Linear(2, 1) - model.weight = nn.Parameter(torch.tensor([[-1.0, 2]])) - model.bias = nn.Parameter(torch.tensor([-1.0])) - - output = model(x) - loss = ((output - target) ** 2).sum() - - one = torch.ones(loss.shape) - loss.backward(one) - assert (model.weight.grad == weight_grad).all() - assert (model.bias.grad == bias_grad).all() - - -def test_share_with_requires_grad(workers): - """ - Test calling fix_precision and share(requires_grad=True) on tensors and model - """ - bob, alice, charlie, crypto_provider = ( - workers["bob"], - workers["alice"], - workers["charlie"], - workers["james"], - ) - - t = torch.Tensor([3.0]) - t = t.fix_precision() - t = t.share(alice, bob, crypto_provider=crypto_provider, requires_grad=True) - - assert t.is_wrapper and isinstance(t.child, AutogradTensor) - - t = t.get() - - assert t.is_wrapper and isinstance(t.child, AutogradTensor) - - t = t.float_prec() - - assert t == torch.Tensor([3.0]) - - -def test_remote_share_with_requires_grad(workers): - """ - Test calling fix_precision and share(requires_grad=True) on pointers - to tensors and model - """ - bob, alice, charlie, crypto_provider = ( - workers["bob"], - workers["alice"], - workers["charlie"], - workers["james"], - ) - - t = torch.Tensor([3]) - t = t.send(charlie) - t = t.fix_precision() - t = t.share(alice, bob, crypto_provider=crypto_provider, requires_grad=True) - t = t.get() - - assert isinstance(t.child, AutogradTensor) - - t = torch.Tensor([3]) - t = t.fix_precision() - t = t.send(charlie) - t = t.share(alice, bob, crypto_provider=crypto_provider, requires_grad=True) - t = t.get() - - assert isinstance(t.child, AutogradTensor) - - model = nn.Linear(2, 1) - model.send(charlie) - model.fix_precision() - model.share(alice, bob, crypto_provider=crypto_provider, requires_grad=True) - model.get() - - assert isinstance(model.weight.child, AutogradTensor) - - # See Issue #2546 - - # model = nn.Linear(2, 1) - # model.fix_precision() - # model.send(charlie) - # model.share(alice, bob, crypto_provider=crypto_provider, requires_grad=True) - # model.get() - # - # assert isinstance(model.weight.child, AutogradTensor) - - -def test_encrypted_training_with_linear_model(workers): - """ - Test a minimal example of encrypted training using nn.Linear - """ - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - # A Toy Dataset - data = ( - torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]]) - .fix_prec() - .share(bob, alice, crypto_provider=james) - ) - target = ( - torch.tensor([[0], [0], [1], [1.0]]).fix_prec().share(bob, alice, crypto_provider=james) - ) - - # A Toy Model - model = nn.Linear(2, 1).fix_precision().share(bob, alice, crypto_provider=james) - - data = syft.AutogradTensor().on(data) - target = syft.AutogradTensor().on(target) - model.weight = syft.AutogradTensor().on(model.weight) - model.bias = syft.AutogradTensor().on(model.bias) - - def train(): - # Training Logic - # Convert the learning rate to fixed precision - opt = optim.SGD(params=model.parameters(), lr=0.1).fix_precision() - - for iter in range(10): - - # 1) erase previous gradients (if they exist) - opt.zero_grad() - - # 2) make a prediction - pred = model(data) - - # 3) calculate how much we missed - loss = ((pred - target) ** 2).sum() - - # 4) figure out which weights caused us to miss - loss.backward() - - # 5) change those weights - opt.step() - - return loss - - loss = train() - - assert loss.child.child.child.virtual_get() < 500 - - -def test_get_float_prec_on_autograd_tensor(workers): - bob, alice, james = workers["bob"], workers["alice"], workers["james"] - - x = torch.tensor([0.1, 1.0]) - x2 = syft.AutogradTensor().on(x.fix_prec()) - assert (x2.float_precision() == x).all() - - x = torch.tensor([1, 2]) - x2 = x.share(bob, alice, crypto_provider=james) - x2 = syft.AutogradTensor().on(x2) - assert (x2.get() == x).all() - - x = torch.tensor([0.1, 1.0]) - x2 = x.fix_precision() - x2 = x2.share(bob, alice, crypto_provider=james, requires_grad=True) - assert (x2.get().float_precision() == x).all() - - -def test_serialize_deserialize_autograd_tensor(workers): - # let's try to send an autogradTensor to a remote location and get it back - alice = workers["alice"] - - random_tensor = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - assert isinstance(random_tensor, torch.Tensor) - - remote_tensor = random_tensor.send(alice, local_autograd=True) - assert isinstance(remote_tensor.child, syft.AutogradTensor) - - local_tensor = remote_tensor.get() - assert isinstance(local_tensor, torch.Tensor) - - # check if the tensor sent is equal to the tensor got from the remote version - assert torch.all(torch.eq(local_tensor, random_tensor)) - - -def test_types_auto_remote_tensors(workers): - alice = workers["alice"] - bob = workers["bob"] - - random_tensor = torch.tensor([[3.0, 2], [-1, 2]], requires_grad=True) - assert isinstance(random_tensor, torch.Tensor) - - remote_tensor_auto = random_tensor.send(alice, local_autograd=True) - assert isinstance(remote_tensor_auto.child, syft.AutogradTensor) - - remote_tensor_remote = remote_tensor_auto.send(bob) - assert isinstance(remote_tensor_remote, torch.Tensor) - - assert type(remote_tensor_auto) == type(remote_tensor_remote) - - -def test_train_remote_autograd_tensor(workers): - # Training procedure to train an input model, be it remote or local - - def train(model_input, data_input, target_input, remote=False): - opt = optim.SGD(params=model_input.parameters(), lr=0.1) - loss_previous = 99999999999 # just a very big number - for iter in range(10): - # 1) erase previous gradients (if they exist) - opt.zero_grad() - # 2) make a prediction - predictions = model_input(data_input) - # 3) calculate how much we missed - loss = ((predictions - target_input) ** 2).sum() - # check for monotonic decrease of the loss - - if remote == True: - # Remote loss monotonic decrease - loss_val_local = loss.copy().get().item() - assert loss_val_local < loss_previous - loss_previous = loss_val_local - - else: - # Local loss monotonic decrease - loss_val_local = loss.item() - assert loss_val_local < loss_previous - loss_previous = loss_val_local - - # 4) Figure out which weights caused us to miss - loss.backward() - # 5) change those weights - opt.step() - return (loss, model_input) - - alice = workers["alice"] - - # Some Toy Data - data_local = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]]) - target_local = torch.tensor([[0], [0], [1], [1.0]]) - - # Toy local model - model_local = nn.Linear(2, 1) - - # Local training - loss_local, model_local_trained = train(model_local, data_local, target_local, remote=False) - - # Remote training, setting autograd for the data and the targets - data_remote = data_local.send(alice, local_autograd=True) - assert isinstance(data_remote.child, syft.AutogradTensor) - assert isinstance(data_remote.child.child, PointerTensor) - - target_remote = target_local.send(alice, local_autograd=True) - assert isinstance(target_remote.child, syft.AutogradTensor) - assert isinstance(target_remote.child.child, PointerTensor) - - model_remote = model_local.send(alice, local_autograd=True) - assert isinstance(model_remote.weight.child, syft.AutogradTensor) - assert isinstance(model_remote.weight.child.child, PointerTensor) - - assert type(model_remote) == type(model_local) - - loss_remote, model_remote_trained = train(model_remote, data_remote, target_remote, remote=True) - - # let's check if the local version and the remote version have the same weight - assert torch.all( - torch.eq( - model_local_trained.weight.copy().get().data, model_remote.weight.copy().get().data - ) - ) - - -def test_train_without_requires_grad(workers): - def train(enc_model, enc_data, enc_target): - optimizer = torch.optim.SGD(enc_model.parameters(), lr=0.1).fix_precision() - - for i in range(1): - optimizer.zero_grad() - enc_pred = enc_model(enc_data).squeeze(1) - l = (((enc_pred - enc_target) ** 2)).sum().refresh() - l.backward() - optimizer.step() - - return enc_model.weight.copy().get().data - - alice = workers["alice"] - bob = workers["bob"] - james = workers["james"] - - x_1 = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(torch.float) - y_1 = torch.tensor([0, 0, 1, 1]).to(torch.float) - - enc_data_1 = x_1.fix_precision().share(alice, bob, crypto_provider=james, requires_grad=True) - enc_target_1 = y_1.fix_precision().share(alice, bob, crypto_provider=james, requires_grad=True) - - model_1 = torch.nn.Linear(2, 1) - model_2 = torch.nn.Linear(2, 1) - - # Make sure both networks have the same initial values for the parameters - for param_model_2, param_model_1 in zip(model_2.parameters(), model_1.parameters()): - param_model_2.data = param_model_1.data - - enc_model_1 = model_1.fix_precision().share( - alice, bob, crypto_provider=james, requires_grad=True - ) - - model_weights_1 = train(enc_model_1, enc_data_1, enc_target_1) - - # Prepare for new train - bob.clear_objects() - alice.clear_objects() - james.clear_objects() - - enc_model_2 = model_2.fix_precision().share( - alice, bob, crypto_provider=james, requires_grad=True - ) - - # Without requires_grad - x_2 = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(torch.float) - y_2 = torch.tensor([0, 0, 1, 1]).to(torch.float) - - enc_data_2 = x_2.fix_precision().share(alice, bob, crypto_provider=james) - enc_target_2 = y_2.fix_precision().share(alice, bob, crypto_provider=james) - - model_weights_2 = train(enc_model_2, enc_data_2, enc_target_2) - - # Check the weights for the two models - assert torch.all(torch.eq(model_weights_1, model_weights_2)) diff --git a/test/torch/tensors/test_crt_precision.py b/test/torch/tensors/test_crt_precision.py deleted file mode 100644 index 9efb4f5c9f2..00000000000 --- a/test/torch/tensors/test_crt_precision.py +++ /dev/null @@ -1,130 +0,0 @@ -import torch -import syft - - -def test__str__(): - t = torch.tensor([[3, 9], [4, 1]]) - crt = t.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - assert isinstance(crt.__str__(), str) - - -def test_eq(): - t_a = torch.tensor([[3, 9], [4, 1]]) - t_b = torch.tensor([[3, 9], [4, 1]]) - t_c = torch.tensor([[2, 9], [4, 2]]) - - crt_a = t_a.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - crt_b = t_b.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - crt_c = t_c.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - eq_ab = (crt_a == crt_b).float_precision() - eq_ac = (crt_a == crt_c).float_precision() - - assert (eq_ab == torch.tensor([[1.0, 1.0], [1.0, 1.0]])).all() - assert (eq_ac == torch.tensor([[0.0, 1.0], [1.0, 0.0]])).all() - - -def test__neg__(): - t = torch.tensor([[1, -3], [3, -2]]) - crt = t.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - neg = -crt - - assert (neg.float_precision() == torch.tensor([[-1.0, 3.0], [-3.0, 2.0]])).all() - - -def test_add(): - t_a = torch.tensor([[1, 2], [3, -4]]) - t_b = torch.tensor([[1, -3], [3, -2]]) - - crt_a = t_a.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - crt_b = t_b.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - result = crt_a + crt_b - - assert (result.float_precision() == torch.tensor([[2.0, -1.0], [6.0, -6.0]])).all() - - # With scalars - result = crt_a + 1 - - assert (result.float_precision() == torch.tensor([[2.0, 3.0], [4.0, -3.0]])).all() - - -def test_sub(): - t_a = torch.tensor([[1, 2], [5, -4]]) - t_b = torch.tensor([[1, -3], [3, -2]]) - - crt_a = t_a.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - crt_b = t_b.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - result = crt_a - crt_b - - assert (result.float_precision() == torch.tensor([[0.0, 5.0], [2.0, -2.0]])).all() - - # With scalars - result_a = crt_a - 1 - result_b = 1 - crt_a - - assert (result_a.float_precision() == torch.tensor([[0.0, 1.0], [4.0, -5.0]])).all() - assert (result_b.float_precision() == torch.tensor([[0.0, -1.0], [-4.0, 5.0]])).all() - - -def test_mul(): - t_a = torch.tensor([[1, -2], [3, -2]]) - t_b = torch.tensor([[1, 2], [3, -2]]) - - crt_a = t_a.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - crt_b = t_b.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - result = crt_a * crt_b - - assert (result.float_precision() == torch.tensor([[1.0, -4.0], [9.0, 4.0]])).all() - - # With scalar - result = 3 * crt_a - - assert (result.float_precision() == torch.tensor([[3.0, -6.0], [9.0, -6.0]])).all() - - -def test_send_and_get(workers): - alice, bob = (workers["alice"], workers["bob"]) - - t = torch.tensor([1, 2]) - crt = t.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - to_alice = crt.send(alice) - to_alice_id = to_alice.id_at_location - - assert to_alice_id in alice._objects - - to_bob_to_alice = to_alice.send(bob) - to_bob_to_alice_id = to_bob_to_alice.id_at_location - - assert to_alice_id in alice._objects - assert to_bob_to_alice_id in bob._objects - - to_alice_back = to_bob_to_alice.get() - - assert to_bob_to_alice_id not in bob._objects - assert to_alice_id in alice._objects - - t_back = to_alice_back.get() - - assert to_alice_id not in alice._objects - - eq = (t_back == crt).float_precision() - assert (eq == torch.tensor([1.0, 1.0])).all() - - -def test_share_and_get(workers): - alice, bob, james = (workers["alice"], workers["bob"], workers["james"]) - - t = torch.tensor([1, 2]) - crt = t.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - copy = t.fix_precision(field_type="int100", precision_fractional=2, storage="crt") - - shared = crt.share(alice, bob, crypto_provider=james) - back = shared.get() - - assert (back.float_precision() == copy.float_precision()).all() diff --git a/test/torch/tensors/test_gc.py b/test/torch/tensors/test_gc.py deleted file mode 100644 index 036077572a1..00000000000 --- a/test/torch/tensors/test_gc.py +++ /dev/null @@ -1,207 +0,0 @@ -"""All the tests relative to garbage collection of all kinds of remote or local tensors""" -import time - -import torch - -from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor -from syft.workers.websocket_server import WebsocketServerWorker -from syft.workers.websocket_client import WebsocketClientWorker - -# TESTING POINTERS - - -def test_explicit_garbage_collect_pointer(workers): - """Tests whether deleting a PointerTensor garbage collects the remote object too""" - bob = workers["bob"] - - # create tensor - x = torch.Tensor([1, 2]) - - # send tensor to bob - x_ptr = x.send(bob) - - # ensure bob has tensor - assert x.id in bob._objects - - # delete pointer to tensor, which should - # automatically garbage collect the remote - # object on Bob's machine - del x_ptr - - # ensure bob's object was garbage collected - assert x.id not in bob._objects - - -def test_explicit_garbage_collect_double_pointer(workers): - """Tests whether deleting a pointer to a pointer garbage collects - the remote object too""" - - alice, bob = workers["alice"], workers["bob"] - - # create tensor - x = torch.Tensor([1, 2]) - - # send tensor to bob and then pointer to alice - x_ptr = x.send(bob) - x_ptr_ptr = x_ptr.send(alice) - - # ensure bob has tensor - assert x.id in bob._objects - - # delete pointer to pointer to tensor, which should automatically - # garbage collect the remote object on Bob's machine - del x_ptr_ptr - - # ensure bob's object was garbage collected - assert x.id not in bob._objects - # ensure alice's object was garbage collected - assert x_ptr.id not in workers["alice"]._objects - - # Chained version - x = torch.Tensor([1, 2]) - x_id = x.id - - # send tensor to bob and then pointer to alice - # overwriting variable names at sending in the test, is on purpose, - # to be sure nothing weird happens when people do this - x = x.send(bob).send(alice) - - # ensure bob has tensor - assert x_id in bob._objects - # delete pointer to pointer to tensor - del x - # ensure bob's object was garbage collected - assert x_id not in bob._objects - - -def test_implicit_garbage_collection_pointer(workers): - """Tests whether GCing a PointerTensor GCs the remote object too.""" - bob = workers["bob"] - - # create tensor - x = torch.Tensor([1, 2]) - - # send tensor to bob - x_ptr = x.send(bob) - - # ensure bob has tensor - assert x.id in bob._objects - - # delete pointer to tensor, which should - # automatically garbage collect the remote - # object on Bob's machine - x_ptr = "asdf" - - # ensure bob's object was garbage collected - assert x.id not in bob._objects - - -def test_implicit_garbage_collect_double_pointer(workers): - """Tests whether GCing a pointer to a pointer garbage collects - the remote object too""" - - alice, bob = workers["alice"], workers["bob"] - - # create tensor - x = torch.Tensor([1, 2]) - - # send tensor to bob and then pointer to alice - x_ptr = x.send(bob) - x_ptr_ptr = x_ptr.send(alice) - - # ensure bob has tensor - assert x.id in bob._objects - # ensure alice has tensor - assert x_ptr.id in alice._objects - - # delete pointer to pointer to tensor, which should automatically - # garbage collect the remote object on Bob's machine - x_ptr_ptr = "asdf" - - # ensure bob's object was garbage collected - assert x.id not in bob._objects - # ensure alice's object was garbage collected - assert x_ptr.id not in alice._objects - - # Chained version - x = torch.Tensor([1, 2]) - x_id = x.id - # send tensor to bob and then pointer to alice - # overwriting variable names at sending in the test, is on purpose, - # to be sure nothing weird happens when people do this - x = x.send(bob).send(alice) - - # ensure bob has tensor - assert x_id in bob._objects - - # delete pointer to pointer to tensor - x = "asdf" - - # ensure bob's object was garbage collected - assert x_id not in bob._objects - - -# TESTING IN PLACE METHODS - - -def test_inplace_method_on_pointer(workers): - bob = workers["bob"] - - tensor = torch.tensor([[1.0, 2], [4.0, 2]]) - pointer = tensor.send(bob) - pointer.add_(pointer) - tensor_back = pointer.get() - assert (tensor * 2 == tensor_back).all() - - -# TESTING LOGGING TENSORS - - -def test_explicit_garbage_collect_logging_on_pointer(workers): - """ - Tests whether deleting a LoggingTensor on a PointerTensor - garbage collects the remote object too - """ - bob = workers["bob"] - - x = torch.Tensor([1, 2]) - x_id = x.id - - x = x.send(bob) - x = LoggingTensor().on(x) - assert x_id in bob._objects - - del x - - assert x_id not in bob._objects - - -def test_implicit_garbage_collect_logging_on_pointer(workers): - """ - Tests whether GCing a LoggingTensor on a PointerTensor - garbage collects the remote object too - """ - bob = workers["bob"] - - x = torch.Tensor([1, 2]) - x_id = x.id - - x = x.send(bob) - x = LoggingTensor().on(x) - assert x_id in bob._objects - - x = "open-source" - assert x_id not in bob._objects - - -def test_websocket_garbage_collection(hook, start_remote_worker): - server, remote_proxy = start_remote_worker(id="ws_gc", hook=hook, port=8555) - - sample_data = torch.tensor([1, 2, 3, 4]) - sample_ptr = sample_data.send(remote_proxy) - - _ = sample_ptr.get() - assert sample_data not in remote_proxy._objects - - remote_proxy.close() - server.terminate() diff --git a/test/torch/tensors/test_large_precision.py b/test/torch/tensors/test_large_precision.py deleted file mode 100644 index 6eabf814f60..00000000000 --- a/test/torch/tensors/test_large_precision.py +++ /dev/null @@ -1,308 +0,0 @@ -import pytest - -import torch - -from syft.frameworks.torch.tensors.interpreters.large_precision import LargePrecisionTensor - - -def test_wrap(workers): - """ - Test the .on() wrap functionality for LargePrecisionTensor - """ - x_tensor = torch.Tensor([1, 2, 3]) - x = LargePrecisionTensor().on(x_tensor) - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, LargePrecisionTensor) - assert isinstance(x.child.child, torch.Tensor) - - -def test_fix_prec(workers): - x = torch.tensor([1.5, 2.0, 3.0]) - enlarged = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -def test_2d_tensors(workers): - x = torch.tensor([[1.5, 2.0, 3.0], [4.5, 5.0, 6.0]]) - enlarged = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -def test_3d_tensors(workers): - x = torch.tensor([[[1.5, 2.0, 3.0]], [[4.5, 5.0, 6.0]], [[7.0, 8.0, 9.0]]]) - enlarged = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -def test_negative_numbers(workers): - x = torch.tensor([[[-1.5, 2.0, 3.0]], [[4.5, 5.0, 6.0]], [[7.0, 8.0, 9.0]]]) - enlarged = x.fix_prec( - base=10, internal_type=torch.int16, precision_fractional=128, verbose=True - ) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -def test_add_multiple_dimensions(workers): - x = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.5, 5.0, -3.0]]]) - y = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.5, 5.0, 6.0]]]) - lpt1 = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - lpt2 = y.fix_prec(internal_type=torch.int16, precision_fractional=128) - expected = torch.tensor([[[-3.0, -4.0, -6.0]], [[9.0, 10.0, 3.0]]]) - result = lpt1 + lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_add_negative_values(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([-90000000000000010.0]) - expected = torch.tensor([-90000000000000000.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 + lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_add(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([20.0]) - expected = torch.tensor([30.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 + lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_iadd(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([20.0]) - expected = torch.tensor([30.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1.add_(lpt2) - assert torch.all(torch.eq(expected, lpt1.float_precision())) - - -def test_add_different_dims(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([100000.0]) - x2 = torch.tensor([20.0]) - expected = torch.tensor([100020.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 + lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_mul(): - internal_type = torch.int16 - precision_fractional = 32 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([20.0]) - expected = torch.tensor([200.0]) - expected.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 * lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_imul(): - internal_type = torch.int16 - precision_fractional = 32 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([20.0]) - expected = torch.tensor([200.0]) - expected.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1.mul_(lpt2) - assert torch.all(torch.eq(expected, lpt1.float_precision())) - - -def test_mul_multiple_dims(): - internal_type = torch.int16 - precision_fractional = 32 - x = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.0, 5.0, -3.0]]]) - y = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.0, 5.0, 6.0]]]) - expected = torch.tensor([[[2.25, 4.0, 9.0]], [[16.0, 25.0, -18.0]]]) - expected.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1 = x.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = y.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 * lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_concat_ops(): - internal_type = torch.int16 - precision_fractional = 32 - x = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.0, 5.0, -3.0]]]) - y = torch.tensor([[[-1.5, -2.0, -3.0]], [[4.0, 5.0, 6.0]]]) - z = torch.tensor([[[-1.0, -2.0, 2.5]], [[4.0, -5.0, 7.5]]]) - expected = torch.tensor([[[1.25, 2.0, 11.5]], [[20.0, 20.0, -10.5]]]) - expected.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt_x = x.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt_y = y.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt_z = z.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = (lpt_x * lpt_y) + lpt_z - - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_uint8_representation(workers): - x = torch.tensor([[1.5, 2.0, 3.0], [4.5, 5.0, 6.0]]) - enlarged = x.fix_prec(internal_type=torch.uint8, precision_fractional=128) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -def test_sub(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([90000000000000010.0]) - expected = torch.tensor([-90000000000000000.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 - lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -def test_isub(): - internal_type = torch.int16 - precision_fractional = 128 - x1 = torch.tensor([10.0]) - x2 = torch.tensor([90000000000000010.0]) - expected = torch.tensor([-90000000000000000.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt1.sub_(lpt2) - assert torch.all(torch.eq(expected, lpt1.float_precision())) - - -def test_diff_dims_in_same_tensor(): - internal_type = torch.int16 - precision_fractional = 128 - x = torch.tensor([2000.0, 1.0]) - lpt_x = x.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - restored = lpt_x.float_precision() - assert torch.all(torch.eq(x, restored)) - - -def test_mod(): - internal_type = torch.int16 - precision_fractional = 128 - expected = torch.tensor([6.0, 3.0]) - x1 = torch.tensor([6.0, 12.0]) - x2 = torch.tensor([9.0]) - lpt1 = x1.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - lpt2 = x2.fix_prec(internal_type=internal_type, precision_fractional=precision_fractional) - result = lpt1 % lpt2 - assert torch.all(torch.eq(expected, result.float_precision())) - - -test_data = [ - (torch.tensor([1]), torch.tensor([1.0])), - (torch.tensor([1.0]), torch.tensor([1.0])), - (torch.tensor([2000.0, 1.0]), torch.tensor([2000.0, 1.0])), - (torch.tensor([2000.0, 1]), torch.tensor([2000.0, 1.0])), - (torch.tensor([-2000.0]), torch.tensor([-2000.0])), - (torch.tensor([-2000.0, -50]), torch.tensor([-2000.0, -50.0])), - (torch.tensor([-2000.0, 50]), torch.tensor([-2000.0, 50.0])), - ( - torch.tensor([[-2000.0, 50], [1000.5, -25]]), - torch.tensor([[-2000.0, 50.0], [1000.5, -25.0]]), - ), - (torch.tensor([-2000.0123458910]), torch.tensor([-2000.0123458910])), - (torch.tensor([2000.0123458910]), torch.tensor([2000.0123458910])), -] - - -@pytest.mark.parametrize("x, expected", test_data) -def test_types(x, expected): - enlarged = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(expected, restored)) - - -@pytest.mark.parametrize("x, expected", test_data) -def test_share_and_get(workers, x, expected): - alice, bob, james = (workers["alice"], workers["bob"], workers["james"]) - - enlarged = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - expected = expected.fix_prec(internal_type=torch.int16, precision_fractional=128) - - shared = enlarged.share(alice, bob, crypto_provider=james) - - result = shared.get().float_precision() - - assert (expected.float_precision() == result).all() - - -def test_share_add(workers): - alice, bob, james = (workers["alice"], workers["bob"], workers["james"]) - - x = torch.tensor([5.0]) - expected = x + x - - x = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - x_shared = x.share(alice, bob, crypto_provider=james) - - y = (x_shared + x_shared).get().float_precision() - - assert torch.all(torch.eq(expected, y)) - - -def test_share_sub(workers): - alice, bob, james = (workers["alice"], workers["bob"], workers["james"]) - - x = torch.tensor([5.0]) - expected = x - x - - x = x.fix_prec(internal_type=torch.int16, precision_fractional=128) - x_shared = x.share(alice, bob, crypto_provider=james) - - y = (x_shared - x_shared).get().float_precision() - - assert torch.all(torch.eq(expected, y)) - - -def test_storage(): - x = torch.tensor([1.0, 2.0, 3.0]) - enlarged = x.fix_prec(storage="large") - restored = enlarged.float_precision() - # And now x and restored must be the same - assert torch.all(torch.eq(x, restored)) - - -# def test_share_mul(workers): -# alice, bob, james = (workers["alice"], workers["bob"], workers["james"]) -# -# x = torch.tensor([5.0]) -# expected = x * x -# -# x = x.fix_prec(internal_type=torch.int16, precision_fractional=128) -# x_shared = x.share(alice, bob, crypto_provider=james) -# -# # TODO -# # This is tricky. The multiplication of the shares in the workers will not yield the expected results -# # because they have the original number decomposed into parts. -# y = (x_shared * x_shared).get().float_precision() -# -# assert torch.all(torch.eq(expected, y)) diff --git a/test/torch/tensors/test_logging.py b/test/torch/tensors/test_logging.py deleted file mode 100644 index 8f828994ba4..00000000000 --- a/test/torch/tensors/test_logging.py +++ /dev/null @@ -1,147 +0,0 @@ -import pytest -import torch -import torch.nn.functional as F - -from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor - - -def test_wrap(): - """ - Test the .on() wrap functionality for LoggingTensor - """ - - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, LoggingTensor) - assert isinstance(x.child.child, torch.Tensor) - - -def test_overwritten_method_on_log_chain(): - """ - Test method call on a chain including a log tensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - y = x.add(x) - - assert (y.child.child == x_tensor.add(x_tensor)).all() - - y = x.child.manual_add(x.child) - - assert (y.child == x_tensor.add(x_tensor)).all() - - -def test_method_on_log_chain(): - """ - Test method call on a chain including a log tensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - y = x.mul(x) - - assert (y.child.child == x_tensor.mul(x_tensor)).all() - - -@pytest.mark.parametrize("attr", ["relu", "celu", "elu"]) -def test_hook_module_functional_on_log_chain(attr): - """ - Test torch function call on a chain including a log tensor - """ - - attr = getattr(F, attr) - x = torch.Tensor([1, -1, 3, 4]) - expected = attr(x) - - x_log = LoggingTensor().on(x) - res_log = attr(x_log) - res = res_log.child.child - - assert (res == expected).all() - - -def test_function_on_log_chain(): - """ - Test torch function call on a chain including a log tensor - """ - - x = LoggingTensor().on(torch.Tensor([1, -1, 3])) - y = F.relu(x) - - assert (y.child.child == torch.Tensor([1, 0, 3])).all() - - -def test_send_get_log_chain(workers): - """ - Test sending and getting back a chain including a logtensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - x_ptr = x.send(workers["bob"]) - x_back = x_ptr.get() - - assert (x_back.child.child == x_tensor).all() - - -def test_inplace_send_get_log_chain(workers): - """ - Test sending and getting back a chain including a logtensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - x_ptr = x.send_(workers["bob"]) - x_back = x_ptr.get_() - - assert (x_back.child.child == x_tensor).all() - - -def test_remote_method_on_log_chain(workers): - """ - Test remote method call on a chain including a log tensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - x_ptr = x.send(workers["bob"]) - y_ptr = F.relu(x_ptr) - y = y_ptr.get() - - assert (y.child.child == F.relu(x_tensor)).all() - - -def test_remote_function_on_log_chain(workers): - """ - Test remote function call on a chain including a log tensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - x_ptr = x.send(workers["bob"]) - y_ptr = x_ptr.add(x_ptr) - y = y_ptr.get() - - assert (y.child.child == x_tensor.add(x_tensor)).all() - - -def test_print_log_chain(): - """ - Test sending and getting back a chain including a logtensor - """ - - # Build a long chain tensor Wrapper>LoggingTensor>TorchTensor - x_tensor = torch.Tensor([1, 2, 3]) - x = LoggingTensor().on(x_tensor) - - assert isinstance(x.__str__(), str) - assert isinstance(x.__repr__(), str) diff --git a/test/torch/tensors/test_multi_pointer.py b/test/torch/tensors/test_multi_pointer.py deleted file mode 100644 index 18d94d45bba..00000000000 --- a/test/torch/tensors/test_multi_pointer.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -import torch as th -import syft as sy - -from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor -from syft.generic.pointers.multi_pointer import MultiPointerTensor - - -def test_multi_pointers(workers): - """ - Ensure that the sy.combine_pointers works as expected - """ - - bob = workers["bob"] - alice = workers["alice"] - - a = th.tensor([1, 2, 3, 4, 5]).send(bob, alice) - - b = a + a - - c = b.get(sum_results=True) - assert (c == th.tensor([4, 8, 12, 16, 20])).all() - - b = a + a - c = b.get(sum_results=False) - assert len(c) == 2 - assert (c[0] == th.tensor([2, 4, 6, 8, 10])).all - - # test default sum pointer state - b = a + a - c = b.get() - assert len(c) == 2 - assert (c[0] == th.tensor([2, 4, 6, 8, 10])).all - - -def test_dim(workers): - bob = workers["bob"] - alice = workers["alice"] - - a = th.tensor([1, 2, 3, 4, 5]).send(bob, alice) - - assert a.dim() == 1 - - -def test_simplify(workers): - bob = workers["bob"] - alice = workers["alice"] - - a = th.tensor([1, 2, 3, 4, 5]).send(bob, alice) - ser = sy.serde.serialize(a) - detail = sy.serde.deserialize(ser).child - assert isinstance(detail, MultiPointerTensor) - for key in a.child.child: - assert key in detail.child diff --git a/test/torch/tensors/test_native.py b/test/torch/tensors/test_native.py deleted file mode 100644 index b07da868711..00000000000 --- a/test/torch/tensors/test_native.py +++ /dev/null @@ -1,214 +0,0 @@ -import pytest -import torch -from torch import nn -import torch.nn.functional as F -from syft.generic.pointers.pointer_tensor import PointerTensor -from syft.exceptions import InvalidTensorForRemoteGet -import syft - - -def test___str__(workers): - bob = workers["bob"] - tensor = torch.Tensor([1, 2, 3, 4]) - assert isinstance(tensor.__str__(), str) - - tensor_ptr = tensor.send(bob) - assert isinstance(tensor_ptr.__str__(), str) - - -def test___repr__(workers): - bob = workers["bob"] - - tensor = torch.Tensor([1, 2, 3, 4]) - assert isinstance(tensor.__repr__(), str) - - tensor_ptr = tensor.send(bob) - assert isinstance(tensor_ptr.__repr__(), str) - - tensor = torch.Tensor([1, 2, 3, 4]).tag("#my_tag").describe("This is a description") - assert isinstance(tensor.__repr__(), str) - - -def test_overload_reshape(): - tensor = torch.Tensor([1, 2, 3, 4]) - tensor_reshaped = tensor.reshape((2, 2)) - tensor_matrix = torch.Tensor([[1.0, 2.0], [3.0, 4.0]]) - assert (tensor_reshaped == tensor_matrix).all() - - -def test_owner_default(hook): - tensor = torch.Tensor([1, 2, 3, 4, 5]) - assert tensor.owner == hook.local_worker - - -def test_create_pointer(hook, workers): - bob = workers["bob"] - - tensor = torch.Tensor([1, 2, 3, 4, 5]) - - ptr = tensor.create_pointer( - location=bob, id_at_location=1, register=False, owner=hook.local_worker, ptr_id=2 - ) - - assert ptr.owner == hook.local_worker - assert ptr.location == bob - assert ptr.id_at_location == 1 - assert ptr.id == 2 - - ptr2 = tensor.create_pointer(owner=hook.local_worker) - assert isinstance(ptr2.__str__(), str) - assert isinstance(ptr2.__repr__(), str) - - -def test_create_pointer_defaults(workers): - bob = workers["bob"] - - tensor = torch.Tensor([1, 2, 3, 4, 5]) - - ptr = tensor.create_pointer(location=bob) - - assert ptr.owner == tensor.owner - assert ptr.location == bob - - -def test_get(workers): - bob = workers["bob"] - - tensor = torch.rand(5, 3) - pointer = tensor.send(bob) - - assert type(pointer.child) == PointerTensor - assert (pointer.get() == tensor).all() - - -def test_invalid_remote_get(workers): - bob = workers["bob"] - - tensor = torch.rand(5, 3) - pointer = tensor.send(bob) - with pytest.raises(InvalidTensorForRemoteGet): - pointer.remote_get() - - -def test_remote_get(hook, workers): - me = workers["me"] - bob = workers["bob"] - alice = workers["alice"] - - x = torch.tensor([1, 2, 3, 4, 5]) - ptr_ptr_x = x.send(bob).send(alice) - - assert ptr_ptr_x.owner == me - assert ptr_ptr_x.location == alice - assert x.id in bob._objects - - assert len(bob._objects) == 1 - assert len(alice._objects) == 1 - - ptr_ptr_x.remote_get() - - assert len(bob._objects) == 0 - assert len(alice._objects) == 1 - - -def test_remote_send(hook, workers): - me = workers["me"] - bob = workers["bob"] - alice = workers["alice"] - - x = torch.tensor([1, 2, 3, 4, 5]) - ptr_ptr_x = x.send(bob).remote_send(alice) - - assert ptr_ptr_x.owner == me - assert ptr_ptr_x.location == bob - assert x.id in alice._objects - - y = torch.tensor([1, 2, 3, 4, 5]) - ptr_y = y.send(bob).remote_send(alice, change_location=True) - - assert ptr_y.owner == me - assert ptr_y.location == alice - assert y.id in alice._objects - - -def test_copy(): - tensor = torch.rand(5, 3) - coppied_tensor = tensor.copy() - assert (tensor == coppied_tensor).all() - assert tensor is not coppied_tensor - - -def test_size(): - tensor = torch.rand(5, 3) - assert tensor.size() == torch.Size([5, 3]) - assert tensor.size() == tensor.shape - assert tensor.size(0) == tensor.shape[0] - - -# Compare local dim with the remote one -def test_dim(workers): - tensor_local = torch.randn(5, 3) - tensor_remote = tensor_local.send(workers["alice"]) - - assert tensor_local.dim() == tensor_remote.dim() - - -def test_does_not_require_large_precision(): - x = torch.tensor([[[-1.5, 2.0, 30000000000.0]], [[4.5, 5.0, 6.0]], [[7.0, 8.0, 9.0]]]) - base = 10 - prec_fractional = 3 - max_precision = 62 - assert not x._requires_large_precision(max_precision, base, prec_fractional) - - -def test_requires_large_precision(): - x = torch.tensor([[[-1.5, 2.0, 30000000000.0]], [[4.5, 5.0, 6.0]], [[7.0, 8.0, 9.0]]]) - base = 10 - prec_fractional = 256 - max_precision = 62 - assert x._requires_large_precision(max_precision, base, prec_fractional) - - -def test_roll(workers): - x = torch.tensor([1.0, 2.0, 3, 4, 5]) - expected = torch.roll(x, -1) - - index = torch.tensor([-1.0]) - result = torch.roll(x, index) - - assert (result == expected).all() - - -def test_complex_model(workers): - hook = syft.TorchHook(torch) - bob = workers["bob"] - tensor_local = torch.rand(1, 1, 32, 32) - tensor_remote = tensor_local.send(bob) - - ## Instantiating a model with multiple layer types - class Net(nn.Module): - def __init__(self): - super(Net, self).__init__() - self.conv1 = nn.Conv2d(1, 6, 5) - self.conv2 = nn.Conv2d(6, 16, 5) - self.fc1 = nn.Linear(16 * 5 * 5, 120) - self.fc2 = nn.Linear(120, 84) - self.fc3 = nn.Linear(84, 10) - - def forward(self, x): - out = self.conv1(x) - out = F.relu(out) - out = F.max_pool2d(out, 2) - out = F.relu(self.conv2(out)) - out = F.avg_pool2d(out, 2) - out = out.view(out.shape[0], -1) - out = F.relu(self.fc1(out)) - out = F.relu(self.fc2(out)) - out = self.fc3(out) - return out - - model_net = Net() - model_net.send(bob) - - ## Forward on the remote model - pred = model_net(tensor_remote) diff --git a/test/torch/tensors/test_numpy.py b/test/torch/tensors/test_numpy.py deleted file mode 100644 index cad946de6c0..00000000000 --- a/test/torch/tensors/test_numpy.py +++ /dev/null @@ -1,90 +0,0 @@ -import pytest -import torch as th -import numpy as np -import syft as sy - - -def test_numpy_add(): - """ - Test basic NumpyTensor addition - """ - - x = sy.NumpyTensor(numpy_tensor=[[1, 2, 3, 4]]) - y = x + x - assert (y.child.child == np.array([2, 4, 6, 8])).all() - - -def test_numpy_subtract(): - """ - Test basic NumpyTensor subtraction - """ - - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x - x - assert (y.child.child == np.array([0, 0, 0, 0])).all() - - -def test_numpy_multiply(): - """ - Test basic NumpyTensor multiplication - """ - - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x * x - assert (y.child.child == np.array([1, 4, 9, 16])).all() - - -def test_numpy_divide(): - """ - Test basic NumpyTensor division - """ - - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x / x - assert (y.child.child == np.array([1, 1, 1, 1])).all() - - -def test_numpy_dot(): - """ - Test basic NumpyTensor dot product - """ - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x.dot(x.transpose()) - assert (y.child.child == np.array([[30]])).all() - - -def test_numpy_mm(): - """ - Test basic NumpyTensor matrix multiply - """ - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x.mm(x.transpose()) - assert (y.child.child == np.array([[30]])).all() - - -def test_numpy_mm2(): - """ - Test @ based NumpyTensor matrix multiply - """ - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x @ (x.transpose()) - assert (y.child.child == np.array([[30]])).all() - - -def test_numpy_transpose(): - """ - Test basic NumpyTensor transpose - """ - x = sy.NumpyTensor(numpy_tensor=np.array([[1, 2, 3, 4]])) - y = x.transpose(0, 1) - assert (y.child.child == np.array([[1], [2], [3], [4]])).all() - - -def test_numpy_casting(): - """ - This tests the ability to cast a data tensor to a tensor chain - with an underlying Numpy representation. - """ - - out = th.tensor([1, 2, 23, 4]).numpy_tensor() - assert (out.child.child == np.array([1, 2, 23, 4])).all() diff --git a/test/torch/tensors/test_paillier.py b/test/torch/tensors/test_paillier.py deleted file mode 100644 index 70837643475..00000000000 --- a/test/torch/tensors/test_paillier.py +++ /dev/null @@ -1,168 +0,0 @@ -import pytest -import torch -import syft as sy - - -def test_encrypt_and_decrypt(): - """ - Test the basic paillier encrypt/decrypt functionality - """ - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y = x.decrypt(pri) - - assert (x_tensor == y).all() - - -def test_encrypted_encrypted_add(): - """ - Test addition of two encrypted values - """ - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y = (x + x).decrypt(pri) - - assert ((x_tensor + x_tensor) == y).all() - - -def test_encrypted_decrypted_add(): - """ - Test addition of an encryptd and decrypted value - """ - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y = (x + x_tensor).decrypt(pri) - - assert ((x_tensor + x_tensor) == y).all() - - -def test_decrypted_encrypted_add(): - """ - Test the addition of a decrypted and encrypted value - """ - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y = (x_tensor + x).decrypt(pri) - - assert ((x_tensor + x_tensor) == y).all() - - -def test_encrypted_encrypted_sub(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x - y).decrypt(pri) - - assert ((x_tensor - y_tensor) == z).all() - - -def test_encrypted_decrypted_sub(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x - y_tensor).decrypt(pri) - - assert ((x_tensor - y_tensor) == z).all() - - -def test_decrypted_encrypted_sub(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x_tensor - y).decrypt(pri) - - assert ((x_tensor - y_tensor) == z).all() - - -def test_encrypted_decrypted_mul(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x * y_tensor).decrypt(pri) - - assert ((x_tensor * y_tensor) == z).all() - - -def test_decrypted_encrypted_mul(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x_tensor * y).decrypt(pri) - - assert ((x_tensor * y_tensor) == z).all() - - -def test_encrypted_decrypted_matmul(): - - pub, pri = sy.keygen() - - x_tensor = torch.tensor([1, 2, 3]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.tensor([2, 2, 2]) - y = y_tensor.encrypt(pub) - - z = (x.mm(y_tensor)).decrypt(pri) - - assert (z == 12).all() - - -def test_decrypted_encrypted_matmul(): - - pub, pri = sy.keygen() - - x_tensor = torch.Tensor([[1, 2, 3]]) - x = x_tensor.encrypt(pub) - - y_tensor = torch.Tensor([[2], [2], [2]]) - y = y_tensor.encrypt(pub) - - z = (x_tensor.mm(y)).decrypt(pri) - - assert ((x_tensor.mm(y_tensor)) == z).all() diff --git a/test/torch/tensors/test_parameter.py b/test/torch/tensors/test_parameter.py deleted file mode 100644 index 247707f84f2..00000000000 --- a/test/torch/tensors/test_parameter.py +++ /dev/null @@ -1,82 +0,0 @@ -import torch -import torch.nn as nn -from torch.nn import Parameter - - -def test_param_on_pointer(workers): - tensor = torch.tensor([1.0, -1.0, 3.0, 4.0]) - ptr = tensor.send(workers["bob"]) - param = Parameter(ptr) - local_param = param.get() - - assert (local_param.data == tensor).all() - - -def test_param_send_get(workers): - tensor = torch.tensor([1.0, -1.0, 3.0, 4.0]) - param = Parameter(data=tensor.clone()) - param_ptr = param.send(workers["bob"]) - param_back = param_ptr.get() - - assert (param_back.data == tensor).all() - - -def test_param_inplace_send_get(workers): - tensor = torch.tensor([1.0, -1.0, 3.0, 4.0]) - param = Parameter(data=tensor.clone()) - param_ptr = param.send_(workers["bob"]) - - assert param_ptr.id == param.id - assert id(param_ptr) == id(param) - - param_back = param_ptr.get_() - - assert param_back.id == param_ptr.id - assert param_back.id == param.id - assert id(param_back) == id(param_ptr) - assert id(param_back) == id(param) - - assert (param_back.data == tensor).all() - - -def test_param_double_send_get(workers): - tensor = torch.tensor([[1.0, 1]]) - param = Parameter(tensor) - - param = param.send(workers["bob"]).send(workers["alice"]) - param = param.get().get() - - assert (param.data == tensor).all() - - -def test_param_remote_binary_method(workers): - tensor = torch.tensor([1.0, -1.0, 3.0, 4.0]) - param = Parameter(data=tensor.clone()) - param_ptr = param.send(workers["bob"]) - param_double_ptr = param_ptr + param_ptr - param_double_back = param_double_ptr.get() - double_tensor = tensor + tensor - - assert (param_double_back.data == double_tensor).all() - - -def test_local_param_in_nn_module_linear(): - model = nn.Linear(2, 1) - tensor = torch.tensor([1.0, -1.0]) - res = model(tensor) - - -def test_remote_param_in_nn_module_linear(workers): - model = nn.Linear(2, 1, bias=False) - tensor = torch.tensor([1.0, -1.0]) - model_ptr = model.send(workers["bob"]) - tensor_ptr = tensor.send(workers["bob"]) - res_ptr = model_ptr(tensor_ptr) - res = res_ptr.get() - - model = nn.Linear(2, 1) - tensor = torch.tensor([1.0, -1.0]) - model_ptr = model.send(workers["bob"]) - tensor_ptr = tensor.send(workers["bob"]) - res_ptr = model_ptr(tensor_ptr) - res = res_ptr.get() diff --git a/test/torch/tensors/test_polynomial.py b/test/torch/tensors/test_polynomial.py deleted file mode 100644 index cfc565b6cad..00000000000 --- a/test/torch/tensors/test_polynomial.py +++ /dev/null @@ -1,152 +0,0 @@ -# import torch -# import numpy as np - -# from syft.frameworks.torch.tensors.interpreters.polynomial import PolynomialTensor - - -# def test_sigmoid(): -# -# poly_tensor = PolynomialTensor() -# -# # x = torch.tensor(np.linspace(-3, 3, 10), dtype=torch.double) -# -# expected = torch.tensor( -# [0.0337, 0.0886, 0.1759, 0.2921, 0.4283, 0.5717, 0.7079, 0.8241, 0.9114, 0.9663] -# ) -# -# -# # allclose function to compare the expected values and approximations with fixed precision -# # result = poly_tensor.get_val("sigmoid", x) -# -# # assert torch.abs(expected - expected).max()[0] < 1e-03 -# _ = (expected - expected).max() -# print(_) -# assert True - -# -# def test_exp(): -# -# poly_tensor = PolynomialTensor() -# -# x = torch.tensor(np.linspace(-3, 3, 10), dtype=torch.double) -# -# expected = torch.tensor( -# [0.0498, 0.0970, 0.1889, 0.3679, 0.7165, 1.1176, 2.9503, 5.1088, 10.2501, 20.2955], -# dtype=torch.double, -# ) -# -# # allclose function to compare the expected values and approximations with fixed precision -# result = poly_tensor.get_val("exp", x) -# assert torch.allclose(expected, result, atol=1e-03) -# -# -# def test_tanh(): -# -# # Test if tanh approximation works as expected -# -# poly_tensor = PolynomialTensor() -# -# x = torch.tensor(np.linspace(-3, 3, 10), dtype=torch.double) -# -# expected = torch.tensor( -# [-0.9937, -0.9811, -0.9329, -0.7596, -0.3239, 0.3239, 0.7596, 0.9329, 0.9811, 0.9937], -# dtype=torch.double, -# ) -# -# result = poly_tensor.get_val("tanh", x) -# -# # allclose function to compare the expected values and approximations with fixed precision -# assert torch.allclose(expected, result, atol=1e-03) -# -# -# def test_interpolate(): -# -# # Test if interpolation function works as expected by verifying an approximation of exponential function -# -# expected = torch.tensor([1.2220, 2.9582, 7.1763, 20.3064, 54.4606], dtype=torch.double) -# -# poly_tensor = PolynomialTensor() -# -# f1 = poly_tensor.interpolate((lambda x: np.exp(x)), np.linspace(0, 10, 50)) -# -# assert torch.allclose(expected, torch.tensor(f1(torch.tensor([0, 1, 2, 3, 4]))), 1e-04) -# -# -# def test_custom_function(): -# poly_tensor = PolynomialTensor() -# poly_tensor.add_function( -# "Custom", 10, [[0, 10, 100, 10, poly_tensor.fit_function]], lambda x: x + 2 -# ) -# -# assert round(poly_tensor.get_val("Custom", 3)) == 5 -# assert round(poly_tensor.get_val("Custom", 6)) == 8 -# -# -# def test_random_function(): -# -# x = torch.tensor(np.linspace(-3, 3, 10), dtype=torch.double) -# poly_tensor = PolynomialTensor(function=lambda x: x * 2) -# scaled_result = poly_tensor.get_val("exp", x.clone()) -# -# poly_tensor = PolynomialTensor() -# original_result = poly_tensor.get_val("exp", x) -# -# assert torch.all(torch.eq(scaled_result, torch.mul(original_result, 2))) -# -# -# def test_log_function(): -# -# # Test if log approximation works as expected -# -# poly_tensor = PolynomialTensor() -# -# x = torch.tensor(np.linspace(1, 10, 10), dtype=torch.double) -# -# expected = torch.tensor( -# [ -# 3.7160e-04, -# 6.9319e-01, -# 1.0986e00, -# 1.3863e00, -# 1.6096e00, -# 1.7932e00, -# 1.9526e00, -# 2.1056e00, -# 2.2835e00, -# 2.5537e00, -# ], -# dtype=torch.double, -# ) -# -# result = poly_tensor.get_val("log", x.clone()) -# -# # allclose function to compare the expected values and approximations with fixed precision -# assert torch.allclose(expected, result, atol=1e-03) -# -# -# def test_exp_taylor(): -# -# expected = torch.tensor( -# [-0.1076, 0.0664, 0.1852, 0.3677, 0.7165, 1.3956, 2.7180, 5.2867, 10.2325, 19.5933], -# dtype=torch.double, -# ) -# poly_tensor = PolynomialTensor() -# x = torch.tensor(np.linspace(-3, 3, 10), dtype=torch.double) -# result = poly_tensor.exp(x) -# -# # allclose function to compare the expected values and approximations with fixed precision -# assert torch.allclose(expected, result, atol=1e-03) -# -# -# def test_sigmoid_taylor(): -# -# expected = torch.tensor( -# [0.1000, 0.1706, 0.2473, 0.3392, 0.4447, 0.5553, 0.6608, 0.7527, 0.8294, 0.9000], -# dtype=torch.double, -# ) -# poly_tensor = PolynomialTensor() -# x = torch.tensor(np.linspace(-2, 2, 10), dtype=torch.double) -# result = poly_tensor.sigmoid(x) -# -# # allclose function to compare the expected values and approximations with fixed precision -# assert torch.allclose(expected, result, atol=1e-03) diff --git a/test/torch/tensors/test_precision.py b/test/torch/tensors/test_precision.py deleted file mode 100644 index 51dff30e6fe..00000000000 --- a/test/torch/tensors/test_precision.py +++ /dev/null @@ -1,630 +0,0 @@ -import pytest -import torch -import torch.nn as nn -import torch.nn.functional as F - -from syft.frameworks.torch.tensors.interpreters.precision import FixedPrecisionTensor - - -def test_wrap(workers): - """ - Test the .on() wrap functionality for LoggingTensor - """ - - x_tensor = torch.Tensor([1, 2, 3]) - x = FixedPrecisionTensor().on(x_tensor) - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, FixedPrecisionTensor) - assert isinstance(x.child.child, torch.Tensor) - - -@pytest.mark.parametrize("parameter", [False, True]) -def test_encode_decode(workers, parameter): - x = torch.tensor([0.1, 0.2, 0.3]) - if parameter: - x = nn.Parameter(x) - x = x.fix_prec() - assert (x.child.child == torch.LongTensor([100, 200, 300])).all() - x = x.float_prec() - - assert (x == torch.tensor([0.1, 0.2, 0.3])).all() - - -def test_fix_prec_registration(hook): - with hook.local_worker.registration_enabled(): - x = torch.tensor([1.0]) - x_fpt = x.fix_precision() - - assert hook.local_worker.get_obj(x.id) == x - - -def test_inplace_encode_decode(workers): - - x = torch.tensor([0.1, 0.2, 0.3]) - x.fix_prec_() - assert (x.child.child == torch.LongTensor([100, 200, 300])).all() - x.float_prec_() - - assert (x == torch.tensor([0.1, 0.2, 0.3])).all() - - x = torch.tensor([3.0]).fix_precision() - assert x.float_prec_().is_wrapper is False - - -def test_fix_prec_inplace_registration(hook): - - with hook.local_worker.registration_enabled(): - x = torch.tensor([1.0]) - x.fix_precision_() - assert hook.local_worker.get_obj(x.id) == torch.tensor([1.0]).fix_precision() - - -@pytest.mark.parametrize("method", ["t", "matmul"]) -@pytest.mark.parametrize("parameter", [False, True]) -def test_methods_for_linear_module(method, parameter): - """ - Test all the methods used in the F.linear functions - """ - if parameter: - tensor = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])) - else: - tensor = torch.tensor([[1.0, 2], [3, 4]]) - fp_tensor = tensor.fix_precision() - if method != "t": - fp_result = getattr(fp_tensor, method)(fp_tensor) - result = getattr(tensor, method)(tensor) - else: - fp_result = getattr(fp_tensor, method)() - result = getattr(tensor, method)() - - assert (result == fp_result.float_precision()).all() - - -def test_torch_add(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # Method syntax - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - y = x + x - - assert (y.child.child == torch.LongTensor([200, 400, 600])).all() - y = y.float_prec() - - assert (y == torch.tensor([0.2, 0.4, 0.6])).all() - - # Function syntax - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - y = torch.add(x, x) - - assert (y.child.child == torch.LongTensor([200, 400, 600])).all() - y = y.float_prec() - - assert (y == torch.tensor([0.2, 0.4, 0.6])).all() - - # With negative numbers - x = torch.tensor([-0.1, -0.2, 0.3]).fix_prec() - y = torch.tensor([0.4, -0.5, -0.6]).fix_prec() - - z = torch.add(x, y).float_prec() - - assert (z == torch.tensor([0.3, -0.7, -0.3])).all() - - # When overflow occurs - x = torch.tensor([10.0, 20.0, 30.0]).fix_prec(field=1e4, precision_fractional=2) - y = torch.add(x, x) - y = torch.add(y, y).float_prec() - - assert (y == torch.tensor([40.0, -20.0, 20.0])).all() - - # with AdditiveSharingTensor - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec() - y = t.fix_prec().share(bob, alice, crypto_provider=james) - - z = torch.add(x, y).get().float_prec() - assert (z == torch.add(t, t)).all() - - z = torch.add(y, x).get().float_prec() - assert (z == torch.add(t, t)).all() - - # with constant integer - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec() - c = 4 - - z = (x + c).float_prec() - assert (z == (t + c)).all() - - z = (c + x).float_prec() - assert (z == (c + t)).all() - - # with constant float - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec() - c = 4.2 - - z = (x + c).float_prec() - assert ((z - (t + c)) < 10e-3).all() - - z = (c + x).float_prec() - assert ((z - (c + t)) < 10e-3).all() - - -def test_torch_add_(): - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - y = x.add_(x) - - assert (y.child.child == torch.LongTensor([200, 400, 600])).all() - y = y.float_prec() - - assert (y == torch.tensor([0.2, 0.4, 0.6])).all() - - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - lr = torch.tensor(0.5).fix_prec() - - y = x.add_(lr, x) - - assert (y.child.child == torch.LongTensor([150, 300, 450])).all() - y = y.float_prec() - - assert (y == torch.tensor([0.15, 0.3, 0.45])).all() - - -def test_torch_sub(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - x = torch.tensor([0.5, 0.8, 1.3]).fix_prec() - y = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - z = torch.sub(x, y) - - assert (z.child.child == torch.LongTensor([400, 600, 1000])).all() - z = z.float_prec() - - assert (z == torch.tensor([0.4, 0.6, 1.0])).all() - - # with AdditiveSharingTensor - tx = torch.tensor([1.0, -2.0, 3.0]) - ty = torch.tensor([0.1, 0.2, 0.3]) - x = tx.fix_prec() - y = ty.fix_prec().share(bob, alice, crypto_provider=james) - - z1 = torch.sub(y, x).get().float_prec() - z2 = torch.sub(x, y).get().float_prec() - - assert (z1 == torch.sub(ty, tx)).all() - assert (z2 == torch.sub(tx, ty)).all() - - # with constant integer - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec() - c = 4 - - z = (x - c).float_prec() - assert (z == (t - c)).all() - - z = (c - x).float_prec() - assert (z == (c - t)).all() - - # with constant float - t = torch.tensor([1.0, -2.0, 3.0]) - x = t.fix_prec() - c = 4.2 - - z = (x - c).float_prec() - assert ((z - (t - c)) < 10e-3).all() - - z = (c - x).float_prec() - assert ((z - (c - t)) < 10e-3).all() - - -def test_torch_sub_(): - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - y = x.sub_(x) - - assert (y.child.child == torch.LongTensor([0, 0, 0])).all() - y = y.float_prec() - - assert (y == torch.tensor([0, 0, 0.0])).all() - - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - lr = torch.tensor(0.5).fix_prec() - - y = x.sub_(lr, x) - - assert (y.child.child == torch.LongTensor([50, 100, 150])).all() - y = y.float_prec() - - assert (y == torch.tensor([0.05, 0.1, 0.15])).all() - - -def test_torch_mul(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # mul with non standard fix precision - x = torch.tensor([2.113]).fix_prec(precision_fractional=2) - - y = torch.mul(x, x) - - assert y.child.child == torch.LongTensor([445]) - assert y.child.precision_fractional == 2 - - y = y.float_prec() - - assert y == torch.tensor([4.45]) - - # Mul with negative numbers - x = torch.tensor([2.113]).fix_prec() - y = torch.tensor([-0.113]).fix_prec() - - z = torch.mul(x, y) - - assert z.child.precision_fractional == 3 - - z = z.float_prec() - assert z == torch.tensor([-0.2380]) - - x = torch.tensor([11.0]).fix_prec(field=2 ** 16, precision_fractional=2) - y = torch.mul(x, x).float_prec() - - assert y == torch.tensor([121.0]) - - # mixing + and * - x = torch.tensor([2.113]).fix_prec() - y = torch.tensor([-0.113]).fix_prec() - z = torch.mul(x, y + y) - - assert z.child.precision_fractional == 3 - - z = z.float_prec() - - assert z == torch.tensor([-0.4770]) - - # with AST - t = torch.tensor([1.0, -2.0, 3.0]) - u = torch.tensor([1.0, -2.0, -3.0]) - x = t.fix_prec() - y = u.fix_prec().share(bob, alice, crypto_provider=james) - - z = torch.mul(x, y).get().float_prec() - - assert (z == torch.mul(t, u)).all() - - -def test_torch_div(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - # With scalar - x = torch.tensor([[9.0, 25.42], [3.3, 0.0]]).fix_prec() - y = torch.tensor([[3.0, 6.2], [3.3, 4.7]]).fix_prec() - - z = torch.div(x, y).float_prec() - - assert (z == torch.tensor([[3.0, 4.1], [1.0, 0.0]])).all() - - # With negative numbers - x = torch.tensor([[-9.0, 25.42], [-3.3, 0.0]]).fix_prec() - y = torch.tensor([[3.0, -6.2], [-3.3, 4.7]]).fix_prec() - - z = torch.div(x, y).float_prec() - - assert (z == torch.tensor([[-3.0, -4.1], [1.0, 0.0]])).all() - - # AST divided by FPT - x = torch.tensor([[9.0, 25.42], [3.3, 0.0]]).fix_prec().share(bob, alice, crypto_provider=james) - y = torch.tensor([[3.0, 6.2], [3.3, 4.7]]).fix_prec() - - z = torch.div(x, y).get().float_prec() - - assert (z == torch.tensor([[3.0, 4.1], [1.0, 0.0]])).all() - - -def test_inplace_operations(): - a = torch.tensor([5.0, 6.0]).fix_prec() - b = torch.tensor([2.0]).fix_prec() - - a /= b - assert (a.float_prec() == torch.tensor([2.5, 3.0])).all() - - a *= b - assert (a.float_prec() == torch.tensor([5.0, 6.0])).all() - - a += b - assert (a.float_prec() == torch.tensor([7.0, 8.0])).all() - - a -= b - assert (a.float_prec() == torch.tensor([5.0, 6.0])).all() - - -def test_torch_pow(): - - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec() - y = (x ** 3).float_prec() - - assert (y == (m ** 3)).all() - - -def test_torch_matmul(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec() - y = torch.matmul(x, x).float_prec() - - assert (y == torch.matmul(m, m)).all() - - # with AST - m = torch.tensor([[1, 2], [3, 4.0]]) - x = m.fix_prec() - y = m.fix_prec().share(bob, alice, crypto_provider=james) - - z = (x @ y).get().float_prec() - - assert (z == torch.matmul(m, m)).all() - - -def test_torch_addmm(): - weight = nn.Parameter(torch.tensor([[1.0, 2], [4.0, 2]])).fix_precision() - inputs = nn.Parameter(torch.tensor([[1.0, 2]])).fix_precision() - bias = nn.Parameter(torch.tensor([1.0, 2])).fix_precision() - - fp_result = torch.addmm(bias, inputs, weight) - - assert (fp_result.float_precision() == torch.tensor([[10.0, 8.0]])).all() - - -def test_torch_dot(workers): - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0]).fix_prec() - y = torch.tensor([3.0, 3.0, 3.0, 3.0, 3.0]).fix_prec() - - assert torch.dot(x, y).float_prec() == 45 - - -def test_torch_inverse_approx(workers): - """ - Test the approximate inverse with different tolerance depending on - the precision_fractional considered - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - fix_prec_tolerance = {3: 1 / 100, 4: 1 / 100, 5: 1 / 100} - - for prec_frac, tolerance in fix_prec_tolerance.items(): - for t in [ - torch.tensor([[0.4, -0.1], [-0.4, 2.0]]), - torch.tensor([[1, -0.6], [0.4, 4.0]]), - torch.tensor([[1, 0.2], [0.4, 4.0]]), - ]: - t_sh = t.fix_precision(precision_fractional=prec_frac).share( - alice, bob, crypto_provider=james - ) - r_sh = t_sh.inverse() - r = r_sh.get().float_prec() - t = t.inverse() - diff = (r - t).abs().max() - norm = (r + t).abs().max() / 2 - - assert (diff / (tolerance * norm)) < 1 - - -def test_torch_exp_approx(workers): - """ - Test the approximate exponential with different tolerance depending on - the precision_fractional considered - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - fix_prec_tolerance = {3: 20 / 100, 4: 5 / 100, 5: 5 / 100} - - for prec_frac, tolerance in fix_prec_tolerance.items(): - cumsum = torch.zeros(5) - for i in range(10): - t = torch.tensor([0.0, 1, 2, 3, 4]) - t_sh = t.fix_precision(precision_fractional=prec_frac).share( - alice, bob, crypto_provider=james - ) - r_sh = t_sh.exp() - r = r_sh.get().float_prec() - t = t.exp() - diff = (r - t).abs() - norm = (r + t) / 2 - cumsum += diff / (tolerance * norm) - - cumsum /= 10 - assert (cumsum < 1).all() - - -def test_torch_sigmoid_approx(workers): - """ - Test the approximate sigmoid with different tolerance depending on - the precision_fractional considered - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - - fix_prec_tolerance_by_method = { - "exp": {3: 6 / 100, 4: 1 / 100, 5: 1 / 100}, - "maclaurin": {3: 7 / 100, 4: 15 / 100, 5: 15 / 100}, - } - - for method, fix_prec_tolerance in fix_prec_tolerance_by_method.items(): - for prec_frac, tolerance in fix_prec_tolerance.items(): - t = torch.tensor(range(-10, 10)) * 0.5 - t_sh = t.fix_precision(precision_fractional=prec_frac).share( - alice, bob, crypto_provider=james - ) - r_sh = t_sh.sigmoid(method=method) - r = r_sh.get().float_prec() - t = t.sigmoid() - diff = (r - t).abs().max() - norm = (r + t).abs().max() / 2 - - assert (diff / (tolerance * norm)) < 1 - - -def test_torch_log_approx(workers): - """ - Test the approximate logarithm with different tolerance depending on - the precision_fractional considered - """ - alice, bob, james = workers["alice"], workers["bob"], workers["james"] - fix_prec_tolerance = {3: 100 / 100, 4: 3 / 100, 5: 2 / 100} - - for prec_frac, tolerance in fix_prec_tolerance.items(): - cumsum = torch.zeros(9) - for i in range(10): - t = torch.tensor([0.1, 0.5, 2, 5, 10, 20, 50, 100, 250]) - t_sh = t.fix_precision(precision_fractional=prec_frac).share( - alice, bob, crypto_provider=james - ) - r_sh = t_sh.log() - r = r_sh.get().float_prec() - t = t.log() - diff = (r - t).abs() - norm = (r + t) / 2 - cumsum += diff / (tolerance * norm) - - cumsum /= 10 - assert (cumsum.abs() < 1).all() - - -def test_torch_conv2d(workers): - bob, alice, james = (workers["bob"], workers["alice"], workers["james"]) - im = torch.Tensor( - [ - [ - [[0.5, 1.0, 2.0], [3.5, 4.0, 5.0], [6.0, 7.5, 8.0]], - [[10.0, 11.0, 12.0], [13.0, 14.5, 15.0], [16.0, 17.5, 18.0]], - ] - ] - ) - w = torch.Tensor( - [ - [[[0.0, 3.0], [1.5, 1.0]], [[2.0, 2.0], [2.5, 2.0]]], - [[[-0.5, -1.0], [-2.0, -1.5]], [[0.0, 0.0], [0.0, 0.5]]], - ] - ) - bias = torch.Tensor([-1.3, 15.0]) - - im_fp = im.fix_precision() - w_fp = w.fix_precision() - bias_fp = bias.fix_precision() - - res0 = torch.conv2d(im_fp, w_fp, bias=bias_fp, stride=1).float_precision() - res1 = torch.conv2d( - im_fp, w_fp[:, 0:1].contiguous(), bias=bias_fp, stride=2, padding=3, dilation=2, groups=2 - ).float_precision() - - expected0 = torch.conv2d(im, w, bias=bias, stride=1) - expected1 = torch.conv2d( - im, w[:, 0:1].contiguous(), bias=bias, stride=2, padding=3, dilation=2, groups=2 - ) - - assert (res0 == expected0).all() - assert (res1 == expected1).all() - - -def test_torch_nn_functional_linear(): - tensor = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])).fix_prec() - weight = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])).fix_prec() - - result = F.linear(tensor, weight).float_prec() - - expected = torch.tensor([[5.0, 11.0], [11.0, 25.0]]) - - assert (result == expected).all() - - tensor = nn.Parameter(torch.tensor([[1.0, -2], [3, 4]])).fix_prec() - weight = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])).fix_prec() - - result = F.linear(tensor, weight).float_prec() - - expected = torch.tensor([[-3.0, -5], [11.0, 25.0]]) - - assert (result == expected).all() - - tensor = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])).fix_prec(precision_fractional=2) - weight = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])).fix_prec(precision_fractional=2) - - result = F.linear(tensor, weight).float_prec() - - expected = torch.tensor([[5.0, 11.0], [11.0, 25.0]]) - - assert (result == expected).all() - - -def test_operate_with_integer_constants(): - x = torch.tensor([1.0]) - x_fp = x.fix_precision() - - r_fp = x_fp + 10 - r = r_fp.float_precision() - assert r == x + 10 - - r_fp = x_fp - 7 - r = r_fp.float_precision() - assert r == x - 7 - - r_fp = x_fp * 2 - assert r_fp.float_precision() == x * 2 - - r_fp = x_fp / 5 - assert r_fp.float_precision() == x / 5 - - -def test_fixed_precision_and_sharing(workers): - - bob, alice = (workers["bob"], workers["alice"]) - - x = torch.tensor([1, 2, 3, 4.0]).fix_prec().share(bob, alice) - out = x.get().float_prec() - - assert (out == torch.tensor([1, 2, 3, 4.0])).all() - - x = torch.tensor([1, 2, 3, 4.0]).fix_prec().share(bob, alice) - - y = x + x - - y = y.get().float_prec() - assert (y == torch.tensor([2, 4, 6, 8.0])).all() - - -def test_get_preserves_attributes(workers): - bob, alice = (workers["bob"], workers["alice"]) - - x = torch.tensor([1, 2, 3, 4.0]).fix_prec(precision_fractional=1).share(bob, alice) - out = x.get().float_prec() - - assert (out == torch.tensor([1, 2, 3, 4.0])).all() - - -def test_comp(): - x = torch.tensor([3.1]).fix_prec() - y = torch.tensor([3.1]).fix_prec() - - assert (x >= y).float_prec() - assert (x <= y).float_prec() - assert not (x > y).float_prec() - assert not (x < y).float_prec() - - x = torch.tensor([3.1]).fix_prec() - y = torch.tensor([2.1]).fix_prec() - - assert (x >= y).float_prec() - assert not (x <= y).float_prec() - assert (x > y).float_prec() - assert not (x < y).float_prec() - - x = torch.tensor([2.1]).fix_prec() - y = torch.tensor([3.1]).fix_prec() - - assert not (x >= y).float_prec() - assert (x <= y).float_prec() - assert not (x > y).float_prec() - assert (x < y).float_prec() diff --git a/test/torch/tensors/test_private.py b/test/torch/tensors/test_private.py deleted file mode 100644 index 11f9178ca43..00000000000 --- a/test/torch/tensors/test_private.py +++ /dev/null @@ -1,331 +0,0 @@ -import pytest -import torch -import torch.nn as nn -import torch.nn.functional as F - -from syft.frameworks.torch.tensors.interpreters.private import PrivateTensor -from syft.exceptions import GetNotPermittedError -from syft.exceptions import SendNotPermittedError - - -def test_wrap(): - """ - Test the .on() wrap functionality for LoggingTensor - """ - - x_tensor = torch.Tensor([1, 2, 3]) - x = PrivateTensor().on(x_tensor) - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, PrivateTensor) - assert isinstance(x.child.child, torch.Tensor) - - -def test_native_private_tensor_method(): - """ - Test native's private_tensor method. - """ - x_tensor = torch.Tensor([1, 2, 3]) - private_x = x_tensor.private_tensor(allowed_users=("testing")) - assert isinstance(private_x, torch.Tensor) - assert isinstance(private_x.child, PrivateTensor) - assert isinstance(private_x.child.child, torch.Tensor) - - -def test_allow_method(): - """ - Test native's private_tensor method. - """ - - x_tensor = torch.Tensor([1, 2, 3]) - - # User credentials mockup - class UserAuthMockup(object): - def __init__(self, login, password): - self.login = login - self.password = password - - def __eq__(self, other): - if isinstance(other, UserAuthMockup): - return self.login == other.login and self.__password == other.password - - allowed_user = UserAuthMockup("user", "password") - second_allowed_user = UserAuthMockup("second_user", "password") - unallowed_user = UserAuthMockup("example", "password") - - private_x = x_tensor.private_tensor(allowed_users=(allowed_user, second_allowed_user)) - assert private_x.allow(allowed_user) - assert private_x.allow(second_allowed_user) - assert not private_x.allow(unallowed_user) - - -def test_send_method(workers): - bob = workers["bob"] - x_tensor = torch.tensor([4, 5, 6, 7, 8]) - - private_x = x_tensor.private_tensor(allowed_users=("User")) - - # Try to call send() without credentials - with pytest.raises(SendNotPermittedError): - private_x.send(bob) - - # Try to call send() with wrong credentials - with pytest.raises(SendNotPermittedError): - private_x.send(user="unallowed_user") - - # Try to call send() with allowed credentails - private_x_pointer = private_x.send(bob, user="User") - - -def test_get_method(workers): - bob = workers["bob"] - x_tensor = torch.Tensor([1, 2, 3]) - - private_x = x_tensor.private_tensor(allowed_users=("User")) - - private_x_pointer = private_x.send(bob, user="User") - - # Try to call get() without credentials - with pytest.raises(GetNotPermittedError): - private_x_pointer.get() - - # Try to call get() with wrong credentials - with pytest.raises(GetNotPermittedError): - private_x_pointer.get(user="UnregisteredUser") - - # Try to call get() with allowed credentials - result = private_x_pointer.get(user="User") - - -def test_private_tensor_registration(hook): - with hook.local_worker.registration_enabled(): - x = torch.tensor([1.0]) - private_x = x.private_tensor(allowed_users=("User")) - - assert hook.local_worker.get_obj(x.id) == x - - -def test_allowed_to_get(): - x = torch.tensor([1, 2, 3, 4, 5, 6]) - assert x.allow("User") # Public tensors always return true. - - private_x = x.private_tensor(allowed_users=("User")) - - assert private_x.allow("User") # It Returns true to previously registered user. - assert not private_x.allow("AnotherUser") # It Returns False to non previously registered user. - - -def test_add_method(): - t = torch.tensor([0.1, 0.2, 0.3]) - x = t.private_tensor(allowed_users=("User")) - - y = x + x - - # Test if it preserves the wraper stack - assert isinstance(x, torch.Tensor) - assert isinstance(x.child, PrivateTensor) - assert isinstance(x.child.child, torch.Tensor) - - assert x.allow("User") # Test if it preserves the parent user credentials. - - -@pytest.mark.parametrize("method", ["t", "matmul"]) -@pytest.mark.parametrize("parameter", [False, True]) -def test_methods_for_linear_module(method, parameter): - """ - Test all the methods used in the F.linear functions - """ - if parameter: - tensor = nn.Parameter(torch.tensor([[1.0, 2], [3, 4]])) - else: - tensor = torch.tensor([[1.0, 2], [3, 4]]) - fp_tensor = tensor.fix_precision() - - # ADD Private Tensor at wrapper stack - private_fp_tensor = fp_tensor.private_tensor(allowed_users=("User")) # ADD Private Layer - - if method != "t": - fp_result = getattr(private_fp_tensor, method)(private_fp_tensor) - result = getattr(tensor, method)(tensor) - else: - fp_result = getattr(private_fp_tensor, method)() - result = getattr(tensor, method)() - - assert (result == fp_result.float_precision()).all() - - -def test_torch_add(): - x = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - - y = torch.add(x, x) - - assert (y.child.child.child == torch.LongTensor([200, 400, 600])).all() - - y_fp = y.float_prec() - - assert (y_fp == torch.tensor([0.2, 0.4, 0.6])).all() - - # Test if it preserves the parent user credentials. - assert y.allow("User") - assert not y.allow("NonRegisteredUser") - - # With negative numbers - x = torch.tensor([-0.1, -0.2, 0.3]).fix_prec() - y = torch.tensor([0.4, -0.5, -0.6]).fix_prec() - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("UserCredential")) - y = y.private_tensor(allowed_users=("UserCredential")) - - z = torch.add(x, y) - z_fp = z.float_prec() - - assert (z_fp == torch.tensor([0.3, -0.7, -0.3])).all() - - # Test if it preserves the parent user credentials. - assert z.allow("UserCredential") - assert not z.allow("NonRegisteredUser") - - # When overflow occurs - x = torch.tensor([10.0, 20.0, 30.0]).fix_prec(field=1e4, precision_fractional=2) - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("UserCredential")) - - y = torch.add(x, x) - y = torch.add(y, y) - y_fp = y.float_prec() - - assert (y_fp == torch.tensor([40.0, -20.0, 20.0])).all() - - -def test_torch_sub(): - x = torch.tensor([0.5, 0.8, 1.3]).fix_prec() - y = torch.tensor([0.1, 0.2, 0.3]).fix_prec() - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - y = y.private_tensor(allowed_users=("User")) - - z = torch.sub(x, y) - - # Test if it preserves the parent user credentials. - assert z.allow("User") - assert not z.allow("NonRegisteredUser") - - assert (z.child.child.child == torch.LongTensor([400, 600, 1000])).all() - z_fp = z.float_prec() - - assert (z_fp == torch.tensor([0.4, 0.6, 1.0])).all() - - -def test_torch_mul(): - # mul with non standard fix precision - x = torch.tensor([2.113]).fix_prec(precision_fractional=2) - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - - y = torch.mul(x, x) - - assert y.child.child.child == torch.LongTensor([445]) - assert y.child.child.precision_fractional == 2 - - # Test if it preserves the parent user credentials. - assert y.allow("User") - assert not y.allow("NonRegisteredUser") - - y = y.float_prec() - - assert y == torch.tensor([4.45]) - - # Mul with negative numbers - x = torch.tensor([2.113]).fix_prec() - y = torch.tensor([-0.113]).fix_prec() - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - y = y.private_tensor(allowed_users=("User")) - - z = torch.mul(x, y) - - assert z.child.child.precision_fractional == 3 - - # Test if it preserves the parent user credentials. - assert z.allow("User") - assert not z.allow("NonRegisteredUser") - - z = z.float_prec() - assert z == torch.tensor([-0.2380]) - - x = torch.tensor([11.0]).fix_prec(field=2 ** 16, precision_fractional=2) - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - - y = torch.mul(x, x) - - y = y.float_prec() - - assert y == torch.tensor([121.0]) - - # mixing + and * - x = torch.tensor([2.113]).fix_prec() - y = torch.tensor([-0.113]).fix_prec() - - # ADD Private Tensor at wrapper stack - x = x.private_tensor(allowed_users=("User")) - y = y.private_tensor(allowed_users=("User")) - - z = torch.mul(x, y + y) - z = z.float_prec() - - assert z == torch.tensor([-0.4770]) - - -def test_operate_with_integer_constants(): - x = torch.tensor([1.0]) - x_fp = x.fix_precision() - - # PrivateTensor at wrapper stack. - x_fp = x_fp.private_tensor(allowed_users=("User")) - - # ADD - r_fp = x_fp + 10 - - # Test if it preserves the parent user credentials. - assert r_fp.allow("User") - assert not r_fp.allow("NonRegisteredUser") - - r = r_fp.float_precision() - assert r == x + 10 - - # SUB - r_fp = x_fp - 7 - - # Test if it preserves the parent user credentials. - assert r_fp.allow("User") - assert not r_fp.allow("NonRegisteredUser") - - r = r_fp.float_precision() - assert r == x - 7 - - # MUL - r_fp = x_fp * 2 - - # Test if it preserves the parent user credentials. - assert r_fp.allow("User") - assert not r_fp.allow("NonRegisteredUser") - - assert r_fp.float_precision() == x * 2 - - # DIV - r_fp = x_fp / 5 - - # Test if it preserves the parent user credentials. - assert r_fp.allow("User") - assert not r_fp.allow("NonRegisteredUser") - - assert r_fp.float_precision() == x / 5 diff --git a/test/torch/tensors/test_tensor.py b/test/torch/tensors/test_tensor.py deleted file mode 100644 index cdc5c7ee1d1..00000000000 --- a/test/torch/tensors/test_tensor.py +++ /dev/null @@ -1,9 +0,0 @@ -import torch -import syft - - -def test_init(): - hook = syft.TorchHook(torch, verbose=True) - tensor_extension = torch.Tensor() - assert tensor_extension.id is not None - assert tensor_extension.owner is not None diff --git a/test/torch/test_federated_learning.py b/test/torch/test_federated_learning.py deleted file mode 100644 index f812d422422..00000000000 --- a/test/torch/test_federated_learning.py +++ /dev/null @@ -1,110 +0,0 @@ -"""All the tests relative to garbage collection of all kinds of remote or local tensors""" - -import syft as sy -import torch - -hook = sy.TorchHook(torch) -from torch import nn -from torch import optim - - -class TestFederatedLearning(object): - def setUp(self): - hook = sy.TorchHook(torch, verbose=True) - - self.me = hook.local_worker - self.me.is_client_worker = True - - instance_id = str(sy.ID_PROVIDER.pop()) - bob = sy.VirtualWorker(id=f"bob{instance_id}", hook=hook, is_client_worker=False) - alice = sy.VirtualWorker(id=f"alice{instance_id}", hook=hook, is_client_worker=False) - james = sy.VirtualWorker(id=f"james{instance_id}", hook=hook, is_client_worker=False) - - bob.add_workers([alice, james]) - alice.add_workers([bob, james]) - james.add_workers([bob, alice]) - - self.hook = hook - - self.bob = bob - self.alice = alice - self.james = james - - # A Toy Dataset - data = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1.0]], requires_grad=True) - target = torch.tensor([[0], [0], [1], [1.0]], requires_grad=True) - - # get pointers to training data on each worker by - # sending some training data to bob and alice - data_bob = data[0:2] - target_bob = target[0:2] - - data_alice = data[2:] - target_alice = target[2:] - - data_bob = data_bob.send(bob) - data_alice = data_alice.send(alice) - target_bob = target_bob.send(bob) - target_alice = target_alice.send(alice) - - # organize pointers into a list - self.datasets = [(data_bob, target_bob), (data_alice, target_alice)] - - # POINTERS - - def test_toy_federated_learning(self): - - self.setUp() - - # Initialize A Toy Model - model = nn.Linear(2, 1) - - # Training Logic - opt = optim.SGD(params=model.parameters(), lr=0.1) - for iter in range(20): - - # NEW) iterate through each worker's dataset - for data, target in self.datasets: - # NEW) send model to correct worker - model.send(data.location) - - # 1) erase previous gradients (if they exist) - opt.zero_grad() - - # 2) make a prediction - pred = model(data) - - # 3) calculate how much we missed - loss = ((pred - target) ** 2).sum() - - # 4) figure out which weights caused us to miss - loss.backward() - - # 5) change those weights - opt.step() - - # get model (with gradients) - model.get() - - # 6) print our progress - print(loss.get()) # NEW) slight edit... need to call .get() on loss - - -def test_lstm(workers): - bob = workers["bob"] - lstm = nn.LSTM(3, 3) - inputs = torch.randn(5, 1, 3) - hidden = (torch.randn(1, 1, 3), torch.randn(1, 1, 3)) # clean out hidden state - out, hidden = lstm(inputs, hidden) - assert out.shape == torch.Size([5, 1, 3]) - lstm = nn.LSTM(3, 3) - lstm.send(bob) - inputs = torch.randn(5, 1, 3).send(bob) - hidden = ( - torch.randn(1, 1, 3).send(bob), - torch.randn(1, 1, 3).send(bob), - ) # clean out hidden state - # out, hidden = lstm(inputs, hidden) - # This test will pass once the .size() method is implemented for - # remote tensors - # assert out.shape == torch.Size([5, 1, 3]) diff --git a/test/torch/test_functions.py b/test/torch/test_functions.py deleted file mode 100644 index f7a56042788..00000000000 --- a/test/torch/test_functions.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest -import torch as th -import syft as sy - -from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor - - -def test_combine_pointers(workers): - """ - Ensure that the sy.combine_pointers works as expected - """ - - bob = workers["bob"] - alice = workers["alice"] - - x = th.tensor([1, 2, 3, 4, 5]).send(bob) - y = th.tensor([1, 2, 3, 4, 5]).send(alice) - - a = sy.combine_pointers(*[x, y]) - b = a + a - - c = b.get(sum_results=True) - assert (c == th.tensor([4, 8, 12, 16, 20])).all() - - b = a + a - c = b.get(sum_results=False) - assert len(c) == 2 - assert (c[0] == th.tensor([2, 4, 6, 8, 10])).all diff --git a/test/torch/test_hook.py b/test/torch/test_hook.py deleted file mode 100644 index ca822efa327..00000000000 --- a/test/torch/test_hook.py +++ /dev/null @@ -1,412 +0,0 @@ -"""Tests relative to verifying the hook process behaves properly.""" -import pytest -import torch -import torch.nn as nn -import torch.nn.functional as F - -import syft -from syft.generic.pointers.pointer_tensor import PointerTensor - -from syft.exceptions import RemoteObjectFoundError - - -def test___init__(hook): - assert torch.torch_hooked - assert hook.torch.__version__ == torch.__version__ - - -def test_torch_attributes(): - with pytest.raises(RuntimeError): - syft.framework._command_guard("false_command") - - assert syft.framework._is_command_valid_guard("torch.add") - assert not syft.framework._is_command_valid_guard("false_command") - - syft.framework._command_guard("torch.add", get_native=False) - - -def test_worker_registration(hook, workers): - boris = syft.VirtualWorker(id="boris", hook=hook, is_client_worker=False) - - workers["me"].add_workers([boris]) - worker = workers["me"].get_worker(boris) - - assert boris == worker - - -def test_pointer_found_exception(workers): - ptr_id = syft.ID_PROVIDER.pop() - pointer = PointerTensor(id=ptr_id, location=workers["alice"], owner=workers["me"]) - - try: - raise RemoteObjectFoundError(pointer) - except RemoteObjectFoundError as err: - err_pointer = err.pointer - assert isinstance(err_pointer, PointerTensor) - assert err_pointer.id == ptr_id - - -def test_build_get_child_type(): - from syft.generic.frameworks.hook.hook_args import build_rule - from syft.generic.frameworks.hook.hook_args import build_get_tensor_type - - x = torch.Tensor([1, 2, 3]) - args = (x, [[1, x]]) - rule = build_rule(args) - - get_child_type_function = build_get_tensor_type(rule) - tensor_type = get_child_type_function(args) - - assert tensor_type == torch.Tensor - - -@pytest.mark.parametrize("attr", ["abs"]) -def test_get_pointer_unary_method(attr, workers): - x = torch.Tensor([1, 2, 3]) - native_method = getattr(x, f"native_{attr}") - expected = native_method() - - x_ptr = x.send(workers["bob"]) - method = getattr(x_ptr, attr) - res_ptr = method() - res = res_ptr.get() - - assert (res == expected).all() - - -@pytest.mark.parametrize("attr", ["add", "mul"]) -def test_get_pointer_binary_method(attr, workers): - x = torch.Tensor([1, 2, 3]) - native_method = getattr(x, f"native_{attr}") - expected = native_method(x) - - x_ptr = x.send(workers["bob"]) - method = getattr(x_ptr, attr) - res_ptr = method(x_ptr) - res = res_ptr.get() - - assert (res == expected).all() - - -@pytest.mark.parametrize("attr", ["abs"]) -def test_get_pointer_to_pointer_unary_method(attr, workers): - x = torch.Tensor([1, 2, 3]) - native_method = getattr(x, f"native_{attr}") - expected = native_method() - - x_ptr = x.send(workers["bob"]).send(workers["alice"]) - method = getattr(x_ptr, attr) - res_ptr = method() - res = res_ptr.get().get() - - assert (res == expected).all() - - -@pytest.mark.parametrize("attr", ["add", "mul"]) -def test_get_pointer_to_pointer_binary_method(attr, workers): - x = torch.Tensor([1, 2, 3]) - native_method = getattr(x, f"native_{attr}") - expected = native_method(x) - - x_ptr = x.send(workers["bob"]).send(workers["alice"]) - method = getattr(x_ptr, attr) - res_ptr = method(x_ptr) - res = res_ptr.get().get() - - assert (res == expected).all() - - -@pytest.mark.parametrize("attr", ["relu", "celu", "elu"]) -def test_hook_module_functional(attr, workers): - attr = getattr(F, attr) - x = torch.Tensor([1, -1, 3, 4]) - expected = attr(x) - - x_ptr = x.send(workers["bob"]) - res_ptr = attr(x_ptr) - res = res_ptr.get() - - assert (res == expected).all() - - -@pytest.mark.parametrize("attr", ["relu", "celu", "elu"]) -def test_functional_same_in_both_imports(attr): - """This function tests that the hook modifies the behavior of - torch.nn.function regardless of the import namespace - """ - fattr = getattr(F, attr) - tattr = getattr(torch.nn.functional, attr) - x = torch.Tensor([1, -1, 3, 4]) - - assert (fattr(x) == tattr(x)).all() - - -def test_hook_tensor(workers): - x = torch.tensor([1.0, -1.0, 3.0, 4.0], requires_grad=True) - x.send(workers["bob"]) - x = torch.tensor([1.0, -1.0, 3.0, 4.0], requires_grad=True)[0:2] - x_ptr = x.send(workers["bob"]) - assert hasattr(x_ptr, "child") - - -def test_properties(): - x = torch.Tensor([1, -1, 3, 4]) - assert x.is_wrapper is False - - -def test_signature_cache_change(): - """Tests that calls to the same method using a different - signature works correctly. We cache signatures in the - hook.build_unwrap_args_from_function dictionary but sometimes they - are incorrect if we use the same method with different - parameter types. So, we need to test to make sure that - this cache missing fails gracefully. This test tests - that for the .div(tensor) .div(int) method.""" - - x = torch.Tensor([1, 2, 3]) - y = torch.Tensor([1, 2, 3]) - - z = x.div(y) - z = x.div(2) - z = x.div(y) - - assert True - - -def test_parameter_hooking(): - """Test custom nn.Module and parameter auto listing in m.parameters()""" - - class MyLayer(torch.nn.Module): - def __init__(self): - super().__init__() - self.some_params = torch.nn.Parameter(torch.tensor([5.0])) - - m = MyLayer() - out = list(m.parameters()) - - assert len(out) == 1 - assert out[0] == m.some_params - - -def test_torch_module_hook(workers): - """Tests sending and getting back torch nn module like nn.Linear""" - model = nn.Linear(2, 1) - model_ptr = model.send(workers["bob"]) - model_back = model_ptr.get() - - bias = model_back.bias - model_back.fix_precision() - model_back.float_precision() - assert (bias == model_back.bias).all() - - -def test_functional_hook(): - x = torch.tensor([[1, 2], [3, 4]]) - y = torch.einsum("ij,jk->ik", x, x) - assert (y == torch.tensor([[7, 10], [15, 22]])).all() - - -def test_hook_args_and_cmd_signature_malleability(): - """Challenge the hook_arg module with methods used with different signatures""" - a = syft.LoggingTensor().on(torch.tensor([1.0, 2])) - b = syft.LoggingTensor().on(torch.tensor([1.0, 2])) - - r1 = a + b - assert (r1 == syft.LoggingTensor().on(torch.tensor([2.0, 4]))).all() - - r2 = a + 1 - assert (r2 == syft.LoggingTensor().on(torch.tensor([2.0, 3]))).all() - - r3 = a + b - assert (r3 == syft.LoggingTensor().on(torch.tensor([2.0, 4]))).all() - - -def test_torch_func_signature_without_tensor(): - """The hook on the args of torch commands should work even if the args - don't contain any tensor""" - x = torch.as_tensor((0.1307,), dtype=torch.float32, device="cpu") - assert (x == torch.tensor([0.1307])).all() - - -def test_RNN_grad_set_backpropagation(workers): - """Perform backpropagation at a remote worker and check if the gradient updates - and properly computed within the model""" - - alice = workers["alice"] - - class RNN(nn.Module): - def __init__(self, input_size, hidden_size, output_size): - super(RNN, self).__init__() - self.hidden_size = hidden_size - self.i2h = nn.Linear(input_size + hidden_size, hidden_size) - self.i2o = nn.Linear(input_size + hidden_size, output_size) - self.softmax = nn.LogSoftmax(dim=1) - - def forward(self, input, hidden): - combined = torch.cat((input, hidden), 1) - hidden = self.i2h(combined) - output = self.i2o(combined) - output = self.softmax(output) - return output, hidden - - def initHidden(self): - return torch.zeros(1, self.hidden_size) - - # let's initialize a simple RNN - n_hidden = 128 - n_letters = 57 - n_categories = 18 - - rnn = RNN(n_letters, n_hidden, n_categories) - - # Let's send the model to alice, who will be responsible for the tiny computation - alice_model = rnn.copy().send(alice) - - # Simple input for the Recurrent Neural Network - input_tensor = torch.zeros(size=(1, 57)) - # Just set a random category for it - input_tensor[0][20] = 1 - alice_input = input_tensor.copy().send(alice) - - label_tensor = torch.randint(low=0, high=(n_categories - 1), size=(1,)) - alice_label = label_tensor.send(alice) - - hidden_layer = alice_model.initHidden() - alice_hidden_layer = hidden_layer.send(alice) - # Forward pass into the NN and its hidden layers, notice how it goes sequentially - output, alice_hidden_layer = alice_model(alice_input, alice_hidden_layer) - criterion = nn.NLLLoss() - loss = criterion(output, alice_label) - # time to backpropagate... - loss.backward() - - # now let's get the model and check if its parameters are indeed there - model_got = alice_model.get() - - learning_rate = 0.005 - - # If the gradients are there, then the backpropagation did indeed complete successfully - for param in model_got.parameters(): - # param.grad.data would raise an exception in case it is none, - # so we better check it beforehand - assert param.grad.data is not None - param.data.add_(-learning_rate, param.grad.data) - - -def test_local_remote_gradient_clipping(workers): - """ - Real test case of gradient clipping for the remote and - local parameters of an RNN - """ - alice = workers["alice"] - - class RNN(nn.Module): - def __init__(self, input_size, hidden_size, output_size): - super(RNN, self).__init__() - self.hidden_size = hidden_size - self.i2h = nn.Linear(input_size + hidden_size, hidden_size) - self.i2o = nn.Linear(input_size + hidden_size, output_size) - self.softmax = nn.LogSoftmax(dim=1) - - def forward(self, input, hidden): - combined = torch.cat((input, hidden), 1) - hidden = self.i2h(combined) - output = self.i2o(combined) - output = self.softmax(output) - return output, hidden - - def initHidden(self): - return torch.zeros(1, self.hidden_size) - - # let's initialize a simple RNN - n_hidden = 128 - n_letters = 57 - n_categories = 18 - - rnn = RNN(n_letters, n_hidden, n_categories) - - # Let's send the model to alice, who will be responsible for the tiny computation - alice_model = rnn.copy().send(alice) - - # Simple input for the Recurrent Neural Network - input_tensor = torch.zeros(size=(1, 57)) - # Just set a random category for it - input_tensor[0][20] = 1 - alice_input = input_tensor.copy().send(alice) - - label_tensor = torch.randint(low=0, high=(n_categories - 1), size=(1,)) - alice_label = label_tensor.send(alice) - - hidden_layer = alice_model.initHidden() - alice_hidden_layer = hidden_layer.send(alice) - # Forward pass into the NN and its hidden layers, notice how it goes sequentially - output, alice_hidden_layer = alice_model(alice_input, alice_hidden_layer) - criterion = nn.NLLLoss() - loss = criterion(output, alice_label) - # time to backpropagate... - loss.backward() - - # Remote gradient clipping - remote_parameters = alice_model.parameters() - total_norm_remote = nn.utils.clip_grad_norm_(remote_parameters, 2) - - # Local gradient clipping - local_alice_model = alice_model.get() - local_parameters = local_alice_model.parameters() - total_norm_local = nn.utils.clip_grad_norm_(local_parameters, 2) - - # Is the output of the remote gradient clipping version equal to - # the output of the local gradient clipping version? - assert total_norm_remote.get() == total_norm_local - - -# Input: None -# Output: a local PyTorch tensor with .grad attribute set to [4.5, 4.5, 4.5, 4.5] -# These operations were taken from this tutorial: -# https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html -def produce_tensor_with_grad(): - x = torch.ones(2, 2, requires_grad=True) - a = torch.randn(2, 2) - a = (a * 3) / (a - 1) - a.requires_grad_(True) - b = (a * a).sum() - y = x + 2 - z = y * y * 3 - out = z.mean() - # backward function is used for computing the gradient of the tensor 'x' - out.backward() - - return x - - -def test_remote_gradient_clipping(workers): - """ Vanishing gradient test over - gradients of a remote tensor - """ - alice = workers["alice"] - local_tensor = produce_tensor_with_grad() - remote_tensor = local_tensor.send(alice) - # initially, remote_tensor.grad is [4.5, 4.5, 4.5, 4.5] - # Method operates in place - nn.utils.clip_grad_norm_(remote_tensor, 2) - tensor_comparison_grad = torch.Tensor([[4.5, 4.5], [4.5, 4.5]]) - tensor_comp_grad_remote = tensor_comparison_grad.send(alice) - # Has the gradient decreased w.r.t. the initial value (i.e. was it clipped)? - smaller_tensor_check_remote = remote_tensor.grad < tensor_comp_grad_remote - - assert 1 == smaller_tensor_check_remote.all().copy().get().item() - - -def test_local_gradient_clipping(): - """ Vanishing gradient test over - gradients of a local tensor - """ - local_tensor = produce_tensor_with_grad() - # initially, local_tensor.grad is [4.5, 4.5, 4.5, 4.5] - # Method operates in place - nn.utils.clip_grad_norm_(local_tensor, 2) - tensor_comparison_grad = torch.Tensor([[4.5, 4.5], [4.5, 4.5]]) - # Has the gradient decreased w.r.t. the initial value (i.e. was it clipped)? - smaller_tensor_check = local_tensor.grad < tensor_comparison_grad - - assert 1 == smaller_tensor_check.all().item() diff --git a/test/workers/__init__.py b/test/workers/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/workers/test_base.py b/test/workers/test_base.py deleted file mode 100644 index 12d239e1721..00000000000 --- a/test/workers/test_base.py +++ /dev/null @@ -1,126 +0,0 @@ -import pytest -import time - -import syft as sy -import torch as th -from unittest import mock -from types import MethodType - -from syft.workers.websocket_client import WebsocketClientWorker -from syft.workers.websocket_server import WebsocketServerWorker - - -def test_create_already_existing_worker(hook): - # Shares tensor with bob - bob = sy.VirtualWorker(hook, "bob") - x = th.tensor([1, 2, 3]).send(bob) - - # Recreates bob and shares a new tensor - bob = sy.VirtualWorker(hook, "bob") - y = th.tensor([2, 2, 2]).send(bob) - - # Recreates bob and shares a new tensor - bob = sy.VirtualWorker(hook, "bob") - z = th.tensor([2, 2, 10]).send(bob) - - # Both workers should be the same, so the following operation should be valid - _ = x + y * z - - -def test_clear_object_for_worker_created_with_pre_existing_id(hook): - - worker = sy.VirtualWorker(hook, id="worker") - worker.clear_objects() - - ptr = th.tensor([1, 2, 3]).send(worker) - - assert len(worker._known_workers[worker.id]._objects) == len(worker._objects) - assert len(worker._objects) == 1 - - # create worker with pre-existing id - worker = sy.VirtualWorker(hook, id="worker") - worker.clear_objects() - - assert len(worker._known_workers[worker.id]._objects) == len(worker._objects) - assert len(worker._objects) == 0 - - ptr = th.tensor([1, 2, 3]).send(worker) - - assert len(worker._known_workers[worker.id]._objects) == len(worker._objects) - assert len(worker._objects) == 1 - - -def test_create_already_existing_worker_with_different_type(hook, start_proc): - # Shares tensor with bob - bob = sy.VirtualWorker(hook, "bob") - _ = th.tensor([1, 2, 3]).send(bob) - - kwargs = {"id": "fed1", "host": "localhost", "port": 8765, "hook": hook} - server = start_proc(WebsocketServerWorker, **kwargs) - - time.sleep(0.1) - - # Recreates bob as a different type of worker - kwargs = {"id": "bob", "host": "localhost", "port": 8765, "hook": hook} - with pytest.raises(RuntimeError): - bob = WebsocketClientWorker(**kwargs) - - server.terminate() - - -def test_execute_command_self(hook): - sy.VirtualWorker.mocked_function = MethodType( - mock.Mock(return_value="bob_mocked_function"), sy.VirtualWorker - ) - - bob = sy.VirtualWorker(hook, "bob") - x = th.tensor([1, 2, 3]).send(bob) - - message = bob.create_message_execute_command( - command_name="mocked_function", command_owner="self" - ) - - serialized_message = sy.serde.serialize(message) - - response = bob._recv_msg(serialized_message) - response = sy.serde.deserialize(response) - - assert response == "bob_mocked_function" - - bob.mocked_function.assert_called() - - -def test_enable_registration_with_ctx(hook): - assert hook.local_worker.is_client_worker == True - with hook.local_worker.registration_enabled(): - hook.local_worker.is_client_worker == False - assert hook.local_worker.is_client_worker == True - - -def test_send_command_whitelist(hook, workers): - bob = workers["bob"] - whitelisted_methods = { - "torch": {"tensor": [1, 2, 3], "rand": (2, 3), "randn": (2, 3), "zeros": (2, 3)} - } - - for framework, methods in whitelisted_methods.items(): - attr = getattr(bob.remote, framework) - - for method, inp in methods.items(): - x = getattr(attr, method)(inp) - - if "rand" not in method: - assert (x.get() == getattr(th, method)(inp)).all() - - -def test_send_command_not_whitelisted(hook, workers): - bob = workers["bob"] - - method_not_exist = "openmind" - - for framework in bob.remote.frameworks: - if framework in dir(bob.remote): - attr = getattr(bob.remote, framework) - - with pytest.raises(AttributeError): - getattr(attr, method_not_exist) diff --git a/test/workers/test_virtual.py b/test/workers/test_virtual.py deleted file mode 100644 index c844717b0a6..00000000000 --- a/test/workers/test_virtual.py +++ /dev/null @@ -1,279 +0,0 @@ -from time import time -from unittest.mock import patch - -import pytest -import torch - -import syft as sy -from syft import serde -from syft.generic.pointers.object_wrapper import ObjectWrapper -from syft.messaging.message import ObjectMessage -from syft.messaging.message import ObjectRequestMessage -from syft.workers.virtual import VirtualWorker - -from syft.exceptions import GetNotPermittedError -from syft.exceptions import ObjectNotFoundError - - -def test_send_msg(): - """Tests sending a message with a specific ID - - This is a simple test to ensure that the BaseWorker interface - can properly send/receive a message containing a tensor. - """ - - # get pointer to local worker - me = sy.torch.hook.local_worker - - # pending time to simulate lantency (optional) - me.message_pending_time = 0.1 - - # create a new worker (to send the object to) - worker_id = sy.ID_PROVIDER.pop() - bob = VirtualWorker(sy.torch.hook, id=f"bob{worker_id}") - - # initialize the object and save it's id - obj = torch.Tensor([100, 100]) - obj_id = obj.id - - # Send data to bob - start_time = time() - me.send_msg(ObjectMessage(obj), bob) - elapsed_time = time() - start_time - - # ensure that object is now on bob's machine - assert obj_id in bob._objects - # ensure that object was sent 0.1 secs later - assert abs(elapsed_time - me.message_pending_time) < 0.1 - - -def test_send_msg_using_tensor_api(): - """Tests sending a message with a specific ID - - This is a simple test to ensure that the high level tensor .send() - method correctly sends a message to another worker. - """ - - # create worker to send object to - worker_id = sy.ID_PROVIDER.pop() - bob = VirtualWorker(sy.torch.hook, id=f"bob{worker_id}") - - # create a tensor to send (default on local_worker) - obj = torch.Tensor([100, 100]) - - # save the object's id - obj_id = obj.id - - # send the object to Bob (from local_worker) - _ = obj.send(bob) - - # ensure tensor made it to Bob - assert obj_id in bob._objects - - -def test_recv_msg(): - """Tests the recv_msg command with 2 tests - - The first test uses recv_msg to send an object to alice. - - The second test uses recv_msg to request the object - previously sent to alice.""" - - # TEST 1: send tensor to alice - - # create a worker to send data to - worker_id = sy.ID_PROVIDER.pop() - alice = VirtualWorker(sy.torch.hook, id=f"alice{worker_id}") - - # create object to send - obj = torch.Tensor([100, 100]) - - # create/serialize message - message = ObjectMessage(obj) - bin_msg = serde.serialize(message) - - # have alice receive message - alice.recv_msg(bin_msg) - - # ensure that object is now in alice's registry - assert obj.id in alice._objects - - # Test 2: get tensor back from alice - - # Create message: Get tensor from alice - message = ObjectRequestMessage((obj.id, None, "")) - - # serialize message - bin_msg = serde.serialize(message) - - # call receive message on alice - resp = alice.recv_msg(bin_msg) - - obj_2 = sy.serde.deserialize(resp) - - # assert that response is correct type - assert type(resp) == bytes - - # ensure that the object we receive is correct - assert obj_2.id == obj.id - - -def tests_worker_convenience_methods(): - """Tests send and get object methods on BaseWorker - - This test comes in two parts. The first uses the simple - BaseWorker.send_obj and BaseWorker.request_obj to send a - tensor to Alice and to get the worker back from Alice. - - The second part shows that the same methods work between - bob and alice directly. - """ - - me = sy.torch.hook.local_worker - worker_id = sy.ID_PROVIDER.pop() - bob = VirtualWorker(sy.torch.hook, id=f"bob{worker_id}") - worker_id = sy.ID_PROVIDER.pop() - alice = VirtualWorker(sy.torch.hook, id=f"alice{worker_id}") - obj = torch.Tensor([100, 100]) - - # Send data to alice - me.send_obj(obj, alice) - - # Get data from alice - resp_alice = me.request_obj(obj.id, alice) - - assert (resp_alice == obj).all() - - obj2 = torch.Tensor([200, 200]) - - # Set data on self - bob.set_obj(obj2) - - # Get data from self - resp_bob_self = bob.get_obj(obj2.id) - - assert (resp_bob_self == obj2).all() - - # Get data from bob as alice - resp_bob_alice = alice.request_obj(obj2.id, bob) - - assert (resp_bob_alice == obj2).all() - - -def test_search(): - worker_id = sy.ID_PROVIDER.pop() - bob = VirtualWorker(sy.torch.hook, id=f"bob{worker_id}") - - x = ( - torch.tensor([1, 2, 3, 4, 5]) - .tag("#fun", "#mnist") - .describe("The images in the MNIST training dataset.") - .send(bob) - ) - - y = ( - torch.tensor([1, 2, 3, 4, 5]) - .tag("#not_fun", "#cifar") - .describe("The images in the MNIST training dataset.") - .send(bob) - ) - - z = ( - torch.tensor([1, 2, 3, 4, 5]) - .tag("#fun", "#boston_housing") - .describe("The images in the MNIST training dataset.") - .send(bob) - ) - - a = ( - torch.tensor([1, 2, 3, 4, 5]) - .tag("#not_fun", "#boston_housing") - .describe("The images in the MNIST training dataset.") - .send(bob) - ) - - assert len(bob.search("#fun")) == 2 - assert len(bob.search("#mnist")) == 1 - assert len(bob.search("#cifar")) == 1 - assert len(bob.search("#not_fun")) == 2 - assert len(bob.search(["#not_fun", "#boston_housing"])) == 1 - - -def test_obj_not_found(workers): - """Test for useful error message when trying to call a method on - a tensor which does not exist on a worker anymore.""" - - bob = workers["bob"] - - x = torch.tensor([1, 2, 3, 4, 5]).send(bob) - - bob._objects = {} - - with pytest.raises(ObjectNotFoundError): - y = x + x - - -def test_get_not_permitted(workers): - bob = workers["bob"] - x = torch.tensor([1, 2, 3, 4, 5]).send(bob) - with patch.object(torch.Tensor, "allow") as mock_allowed_to_get: - mock_allowed_to_get.return_value = False - with pytest.raises(GetNotPermittedError): - x.get() - mock_allowed_to_get.assert_called_once() - - -def test_spinup_time(hook): - """Tests to ensure that virtual workers intialized with 10000 data points - load in under 0.05 seconds. This is needed to ensure that virtual workers - spun up inside web frameworks are created quickly enough to not cause timeout errors""" - data = [] - for i in range(10000): - data.append(torch.Tensor(5, 5).random_(100)) - start_time = time() - dummy = sy.VirtualWorker(hook, id="dummy", data=data) - end_time = time() - assert (end_time - start_time) < 0.1 - - -def test_send_jit_scriptmodule(hook, workers): # pragma: no cover - bob = workers["bob"] - - @torch.jit.script - def foo(x): - return x + 2 - - foo_wrapper = ObjectWrapper(obj=foo, id=99) - foo_ptr = hook.local_worker.send(foo_wrapper, bob) - - res = foo_ptr(torch.tensor(4)) - assert res == torch.tensor(6) - - -def test_send_command_whitelist(hook, workers): - bob = workers["bob"] - whitelisted_methods = { - "torch": {"tensor": [1, 2, 3], "rand": (2, 3), "randn": (2, 3), "zeros": (2, 3)} - } - - for framework, methods in whitelisted_methods.items(): - attr = getattr(bob.remote, framework) - - for method, inp in methods.items(): - x = getattr(attr, method)(inp) - - if "rand" not in method: - assert (x.get() == getattr(torch, method)(inp)).all() - - -def test_send_command_not_whitelisted(hook, workers): - bob = workers["bob"] - - method_not_exist = "openmind" - - for framework in bob.remote.frameworks: - if framework in dir(bob.remote): - attr = getattr(bob.remote, framework) - - with pytest.raises(AttributeError): - getattr(attr, method_not_exist) diff --git a/test/workers/test_websocket_worker.py b/test/workers/test_websocket_worker.py deleted file mode 100644 index ac656beb370..00000000000 --- a/test/workers/test_websocket_worker.py +++ /dev/null @@ -1,342 +0,0 @@ -import io -from os.path import exists, join -import time -from socket import gethostname -from OpenSSL import crypto, SSL -import pytest -import torch -import syft as sy -from syft.generic.frameworks.hook import hook_args -from syft.frameworks.torch.fl import utils - -from syft.workers.websocket_client import WebsocketClientWorker -from syft.workers.websocket_server import WebsocketServerWorker - -from test.conftest import instantiate_websocket_client_worker - - -PRINT_IN_UNITTESTS = False - - -@pytest.mark.parametrize("secure", [True, False]) -def test_websocket_worker_basic(hook, start_proc, secure, tmpdir): - """Evaluates that you can do basic tensor operations using - WebsocketServerWorker in insecure and secure mode.""" - - def create_self_signed_cert(cert_path, key_path): - # create a key pair - k = crypto.PKey() - k.generate_key(crypto.TYPE_RSA, 1024) - - # create a self-signed cert - cert = crypto.X509() - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(1000) - cert.set_pubkey(k) - cert.sign(k, "sha1") - - # store keys and cert - open(cert_path, "wb").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) - open(key_path, "wb").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k)) - - kwargs = { - "id": "secure_fed" if secure else "not_secure_fed", - "host": "localhost", - "port": 8766, - "hook": hook, - } - - if secure: - # Create cert and keys - cert_path = tmpdir.join("test.crt") - key_path = tmpdir.join("test.key") - create_self_signed_cert(cert_path, key_path) - kwargs["cert_path"] = cert_path - kwargs["key_path"] = key_path - - process_remote_worker = start_proc(WebsocketServerWorker, **kwargs) - - time.sleep(0.1) - x = torch.ones(5) - - if secure: - # unused args - del kwargs["cert_path"] - del kwargs["key_path"] - - kwargs["secure"] = secure - remote_proxy = instantiate_websocket_client_worker(**kwargs) - - x = x.send(remote_proxy) - y = x + x - y = y.get() - - assert (y == torch.ones(5) * 2).all() - - del x - - remote_proxy.close() - time.sleep(0.1) - remote_proxy.remove_worker_from_local_worker_registry() - process_remote_worker.terminate() - - -def test_websocket_workers_search(hook, start_remote_worker): - """Evaluates that a client can search and find tensors that belong - to another party""" - # Args for initializing the websocket server and client - server, remote_proxy = start_remote_worker(id="fed2", hook=hook, port=8767) - - # Sample tensor to store on the server - sample_data = torch.tensor([1, 2, 3, 4]).tag("#sample_data", "#another_tag") - _ = sample_data.send(remote_proxy) - - # Search for the tensor located on the server by using its tag - results = remote_proxy.search(["#sample_data", "#another_tag"]) - - assert results - assert results[0].owner.id == "me" - assert results[0].location.id == "fed2" - - # Search multiple times should still work - results = remote_proxy.search(["#sample_data", "#another_tag"]) - - assert results - assert results[0].owner.id == "me" - assert results[0].location.id == "fed2" - - remote_proxy.close() - time.sleep(0.1) - remote_proxy.remove_worker_from_local_worker_registry() - server.terminate() - - -def test_list_objects_remote(hook, start_remote_worker): - server, remote_proxy = start_remote_worker(id="fed-list-objects", hook=hook, port=8765) - remote_proxy.clear_objects() - - x = torch.tensor([1, 2, 3]).send(remote_proxy) - - res = remote_proxy.list_objects_remote() - - x = torch.tensor([1, 2, 3]).send(remote_proxy) - - res = remote_proxy.list_objects_remote() - res_dict = eval(res.replace("tensor", "torch.tensor")) - assert len(res_dict) == 1 - - y = torch.tensor([4, 5, 6]).send(remote_proxy) - res = remote_proxy.list_objects_remote() - res_dict = eval(res.replace("tensor", "torch.tensor")) - assert len(res_dict) == 2 - - # delete x before terminating the websocket connection - del x - del y - time.sleep(0.1) - remote_proxy.close() - time.sleep(0.1) - remote_proxy.remove_worker_from_local_worker_registry() - server.terminate() - - -def test_objects_count_remote(hook, start_remote_worker): - server, remote_proxy = start_remote_worker(id="fed-count-objects", hook=hook, port=8764) - remote_proxy.clear_objects() - - x = torch.tensor([1, 2, 3]).send(remote_proxy) - - nr_objects = remote_proxy.objects_count_remote() - assert nr_objects == 1 - - y = torch.tensor([4, 5, 6]).send(remote_proxy) - nr_objects = remote_proxy.objects_count_remote() - assert nr_objects == 2 - - x.get() - nr_objects = remote_proxy.objects_count_remote() - assert nr_objects == 1 - - # delete remote object before terminating the websocket connection - del y - time.sleep(0.1) - remote_proxy.close() - time.sleep(0.1) - remote_proxy.remove_worker_from_local_worker_registry() - server.terminate() - - -def test_clear_objects_remote(hook, start_remote_worker): - server, remote_proxy = start_remote_worker(id="fed-clear-objects", hook=hook, port=8769) - - x = torch.tensor([1, 2, 3]).send(remote_proxy, garbage_collect_data=False) - y = torch.tensor(4).send(remote_proxy, garbage_collect_data=False) - - nr_objects = remote_proxy.objects_count_remote() - assert nr_objects == 2 - - remote_proxy.clear_objects_remote() - nr_objects = remote_proxy.objects_count_remote() - assert nr_objects == 0 - - remote_proxy.close() - remote_proxy.remove_worker_from_local_worker_registry() - server.terminate() - - -def test_connect_close(hook, start_remote_worker): - server, remote_proxy = start_remote_worker(id="fed-connect-close", hook=hook, port=8770) - - x = torch.tensor([1, 2, 3]) - x_ptr = x.send(remote_proxy) - - assert remote_proxy.objects_count_remote() == 1 - - remote_proxy.close() - - time.sleep(0.1) - - remote_proxy.connect() - - assert remote_proxy.objects_count_remote() == 1 - - x_val = x_ptr.get() - assert (x_val == x).all() - - remote_proxy.close() - remote_proxy.remove_worker_from_local_worker_registry() - - time.sleep(0.1) - - server.terminate() - - -def test_websocket_worker_multiple_output_response(hook, start_remote_worker): - """Evaluates that you can do basic tensor operations using - WebsocketServerWorker.""" - server, remote_proxy = start_remote_worker(id="socket_multiple_output", hook=hook, port=8771) - - x = torch.tensor([1.0, 3, 2]) - x = x.send(remote_proxy) - - p1, p2 = torch.sort(x) - x1, x2 = p1.get(), p2.get() - - assert (x1 == torch.tensor([1.0, 2, 3])).all() - assert (x2 == torch.tensor([0, 2, 1])).all() - - x.get() # retrieve remote object before closing the websocket connection - - remote_proxy.close() - server.terminate() - - -def test_send_command_whitelist(hook, start_remote_worker): - server, remote_proxy = start_remote_worker( - id="worker_call_api_good_methods", hook=hook, port=8772 - ) - whitelisted_methods = { - "torch": {"tensor": [1, 2, 3], "rand": (2, 3), "randn": (2, 3), "zeros": (2, 3)} - } - - for framework, methods in whitelisted_methods.items(): - attr = getattr(remote_proxy.remote, framework) - - for method, inp in methods.items(): - x = getattr(attr, method)(inp) - - if "rand" not in method: - assert (x.get() == getattr(torch, method)(inp)).all() - - remote_proxy.close() - server.terminate() - - -def test_send_command_not_whitelisted(hook, start_remote_worker): - server, remote_proxy = start_remote_worker( - id="worker_call_api_bad_method", hook=hook, port=8773 - ) - - method_not_exist = "openmind" - - for framework in remote_proxy.remote.frameworks: - if framework in dir(remote_proxy.remote): - attr = getattr(remote_proxy.remote, framework) - with pytest.raises(AttributeError): - getattr(attr, method_not_exist) - - remote_proxy.close() - server.terminate() - - -@pytest.mark.skip -def test_evaluate(hook, start_proc): # pragma: no cover - - sy.local_worker.clear_objects() - sy.generic.frameworks.hook.hook_args.hook_method_args_functions = {} - sy.generic.frameworks.hook.hook_args.hook_method_response_functions = {} - sy.generic.frameworks.hook.hook_args.get_tensor_type_functions = {} - sy.generic.frameworks.hook.hook_args.register_response_functions = {} - - data, target = utils.iris_data_partial() - - dataset = sy.BaseDataset(data=data, targets=target) - - kwargs = {"id": "evaluate_remote", "host": "localhost", "port": 8790, "hook": hook} - dataset_key = "iris" - # TODO: check why unit test sometimes fails when WebsocketServerWorker is started from the unit test. Fails when run after test_federated_client.py - # process_remote_worker = start_proc(WebsocketServerWorker, dataset=(dataset, dataset_key), verbose=True, **kwargs) - - remote_proxy = instantiate_websocket_client_worker(**kwargs) - - def loss_fn(pred, target): - return torch.nn.functional.cross_entropy(input=pred, target=target) - - class Net(torch.nn.Module): - def __init__(self): - super(Net, self).__init__() - self.fc1 = torch.nn.Linear(4, 3) - - torch.nn.init.xavier_normal_(self.fc1.weight) - - def forward(self, x): - x = torch.nn.functional.relu(self.fc1(x)) - return x - - model_untraced = Net() - model = torch.jit.trace(model_untraced, data) - loss_traced = torch.jit.trace(loss_fn, (torch.tensor([[0.3, 0.5, 0.2]]), torch.tensor([1]))) - - pred = model(data) - loss_before = loss_fn(target=target, pred=pred) - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Loss: {}".format(loss_before)) - - # Create and send train config - train_config = sy.TrainConfig( - batch_size=4, - model=model, - loss_fn=loss_traced, - model_id=None, - loss_fn_id=None, - optimizer_args=None, - epochs=1, - ) - train_config.send(remote_proxy) - - result = remote_proxy.evaluate( - dataset_key=dataset_key, return_histograms=True, nr_bins=3, return_loss=True - ) - - len_dataset = result["nr_predictions"] - hist_target = result["histogram_target"] - - if PRINT_IN_UNITTESTS: # pragma: no cover - print("Evaluation result before training: {}".format(result)) - - assert len_dataset == 30 - assert (hist_target == [10, 10, 10]).all() - - remote_proxy.close() - remote_proxy.remove_worker_from_local_worker_registry() - # process_remote_worker.terminate() diff --git a/test/workers/test_worker.py b/test/workers/test_worker.py deleted file mode 100644 index 3d333b61f6a..00000000000 --- a/test/workers/test_worker.py +++ /dev/null @@ -1,53 +0,0 @@ -import pytest -import torch - -import syft as sy -from syft.workers.virtual import VirtualWorker - -from syft.exceptions import WorkerNotFoundException - - -def test___init__(): - hook = sy.TorchHook(torch) - - tensor = torch.tensor([1, 2, 3, 4]) - - worker_id = sy.ID_PROVIDER.pop() - alice_id = f"alice{worker_id}" - alice = VirtualWorker(hook, id=alice_id) - worker_id = sy.ID_PROVIDER.pop() - bob = VirtualWorker(hook, id=f"bob{worker_id}") - worker_id = sy.ID_PROVIDER.pop() - charlie = VirtualWorker(hook, id=f"charlie{worker_id}") - worker_id = sy.ID_PROVIDER.pop() - dawson = VirtualWorker(hook, id=f"dawson{worker_id}", data=[tensor]) - - # Ensure adding data on signup functionality works as expected - assert tensor.owner == dawson - - assert bob.get_worker(alice_id).id == alice.id - assert bob.get_worker(alice).id == alice.id - assert bob.get_worker(charlie).id == charlie.id - - bob.get_worker("the_unknown_worker") - - bob.add_worker(alice) - - -def test_get_unknown_worker(): - - hook = sy.TorchHook(torch) - - bob = VirtualWorker(hook, id="bob") - charlie = VirtualWorker(hook, id="charlie") - - # if an unknown string or id representing a worker is given it fails - with pytest.raises(WorkerNotFoundException): - bob.get_worker("the_unknown_worker", fail_hard=True) - - with pytest.raises(WorkerNotFoundException): - bob.get_worker(1, fail_hard=True) - - # if an instance of virtual worker is given it doesn't fail - assert bob.get_worker(charlie).id == charlie.id - assert charlie.id in bob._known_workers