Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
225 commits
Select commit Hold shift + click to select a range
8240cf1
Merge pull request #2317 from OpenMined/dev
robert-wagner Jun 27, 2019
b9fdfb7
Merge pull request #2330 from OpenMined/dev
robert-wagner Jul 9, 2019
044038c
Update Master (#2438)
robert-wagner Aug 2, 2019
4840f5b
added new custom message types, but no change in functionality yet
iamtrask Aug 7, 2019
34cef68
Added unit tests for CommandMessage, ObjectMessage, and ObjectRequset…
iamtrask Aug 7, 2019
db87a0d
added tests for GetShapeMessage and ForceObjectDeleteMessage
iamtrask Aug 7, 2019
2a236b9
balck
iamtrask Aug 7, 2019
061acd4
formatting
iamtrask Aug 7, 2019
81ee55b
__getitem__ should return none if the item doesn't exist
iamtrask Aug 7, 2019
087c499
bugfix with todo for pointer.is_none
iamtrask Aug 7, 2019
9e8eded
test isnone message
iamtrask Aug 7, 2019
02a4841
black
iamtrask Aug 7, 2019
0a54bec
formatting
iamtrask Aug 7, 2019
0c603d5
added searchmessage with test
iamtrask Aug 7, 2019
ee05fcd
black
iamtrask Aug 7, 2019
8f6d3e2
todos
iamtrask Aug 7, 2019
4dd8b9b
black
iamtrask Aug 7, 2019
e6c0ff4
added faster detailer and simplifier for CommandMessage
iamtrask Aug 7, 2019
6f37b9b
black
iamtrask Aug 7, 2019
92bb928
fixed comments
iamtrask Aug 7, 2019
282504b
fixed init
iamtrask Aug 7, 2019
8002f09
black
iamtrask Aug 7, 2019
2e325fe
removed unnecessary comment
iamtrask Aug 7, 2019
8501ec0
cleanup request from bobby
iamtrask Aug 7, 2019
f49ae95
added _get_msg utility function
iamtrask Aug 8, 2019
5674104
added compress and decompress to serde init
iamtrask Aug 8, 2019
78555aa
Merge branch 'dev' into custom_message_types
robert-wagner Aug 8, 2019
d1fe2fa
Add type checking for messages
iamtrask Aug 8, 2019
d675d57
Merge branch 'custom_message_types' of github.com:OpenMined/PySyft in…
iamtrask Aug 8, 2019
3d9df12
run black
iamtrask Aug 8, 2019
91b3a9a
Fix a typo
iamtrask Aug 14, 2019
4eb1767
Add documentation to message.py
iamtrask Aug 15, 2019
24ea741
Fix test
iamtrask Aug 15, 2019
199b816
Fix test_force_object_delete_message
iamtrask Aug 15, 2019
c788667
Fix test_get_shape_message
iamtrask Aug 15, 2019
e29fb75
Fix test_obj_req_message
iamtrask Aug 15, 2019
2ac6950
Fix test_obj_message
iamtrask Aug 15, 2019
c2130d3
Fix test_cmd_message
iamtrask Aug 15, 2019
3fb1dcc
Run black
iamtrask Aug 15, 2019
4fad0a5
Run black
iamtrask Aug 15, 2019
33f03cd
Add documentation to Message class
iamtrask Aug 15, 2019
15bcdd4
Add TODO
iamtrask Aug 15, 2019
e2d47a9
Add inline documentation for CommandMessage
iamtrask Aug 15, 2019
d3b33bf
Fix error in docs
iamtrask Aug 15, 2019
85fc9ba
Typo in CommandMessage docs
iamtrask Aug 15, 2019
e43c55a
Add documentation for ObjectMessage
iamtrask Aug 15, 2019
fe6888c
Add documentation for ObjectRequestMessage
iamtrask Aug 15, 2019
0e660ed
Add documentation for IsNoneMessage
iamtrask Aug 15, 2019
78481cf
Change messaging import strategy in serde.py
iamtrask Aug 15, 2019
d19f04b
Access Message.contents as property
iamtrask Aug 15, 2019
1b9e699
Merge branch 'dev' into custom_message_types
iamtrask Aug 15, 2019
ac3c2ff
Run 'black syft'
iamtrask Aug 15, 2019
d666cc6
Fix typo in several todos 'detalier' -> 'detailer'
iamtrask Aug 15, 2019
3232401
Finish IsNoneMessage documentation
iamtrask Aug 15, 2019
b69c4a1
Change tensor_tuple to msg_tuple
iamtrask Aug 15, 2019
431b0fe
Document GetShapeMessage type
iamtrask Aug 15, 2019
0646ca4
Document ForceObjectDeleteMessage type
iamtrask Aug 15, 2019
7561791
Document SearchMessage type
iamtrask Aug 15, 2019
1173ae8
Add Github issues for each TODO
iamtrask Aug 15, 2019
c89a4f6
Add 'syft/messaging/promise.py'
iamtrask Aug 15, 2019
9409912
Merge branch 'dev' into promise
iamtrask Aug 15, 2019
29a2d0d
Init generic Promise object with schema and docs
iamtrask Aug 15, 2019
55aaefc
Run 'black syft'
iamtrask Aug 15, 2019
0485438
Merge branch 'promise' of github.com:OpenMined/PySyft into promise
iamtrask Aug 15, 2019
3b27821
Create TODO for misplaced files/classes
iamtrask Aug 15, 2019
b38fe6e
Add simplify and detail to Promise
iamtrask Aug 15, 2019
a489e01
Add Promise to messaging/__init__.py
iamtrask Aug 15, 2019
56a5a6f
Add __str__ and __repr__ to Promise
iamtrask Aug 15, 2019
0a62f71
Add attribute to Promise to store its future object
iamtrask Aug 15, 2019
fa7f1e6
Move default plans argument to initializer body
iamtrask Aug 15, 2019
4f4487f
Init PromiseTensor
iamtrask Aug 15, 2019
90ac4c5
Run 'black syft'
iamtrask Aug 15, 2019
4ae26d8
Merge branch 'dev' into promise
hereismari Aug 16, 2019
ddc1599
merge with mastr
iamtrask Aug 17, 2019
c010016
Fix strange merge
iamtrask Aug 17, 2019
4cd5eb1
Run and
iamtrask Aug 17, 2019
0398fba
Merge branch 'promise' of github.com:OpenMined/PySyft into promise
iamtrask Aug 17, 2019
f32a179
Merge branch 'dev' of github.com:OpenMined/PySyft into promise
iamtrask Aug 17, 2019
ec430eb
Fix multi-inheritance for PromisTensor
iamtrask Aug 17, 2019
a520d80
Cleanup extra reference code
iamtrask Aug 17, 2019
f72bd81
Run 'black syft'
iamtrask Aug 17, 2019
956178f
Init PromiseTensor example using __add__
iamtrask Aug 17, 2019
8057846
Remove Promise when fulfilled
iamtrask Aug 17, 2019
01508f3
Remove Promise when fulfilled
iamtrask Aug 17, 2019
1e0c52b
Fix typing issue in wrappers
iamtrask Aug 17, 2019
9cfffad
Fix .torch_type() when self.child is dict
iamtrask Aug 17, 2019
e61c5bc
Add TODO and link to Github Issue
iamtrask Aug 17, 2019
f39c8a5
Run 'black syft'
iamtrask Aug 17, 2019
3724538
Add ways to create promises more conveniently
iamtrask Aug 17, 2019
8ba5904
Reorder methods in promise.py
iamtrask Aug 17, 2019
a3f58a2
Clean up
iamtrask Aug 17, 2019
fb971e9
Remove print statement
iamtrask Aug 17, 2019
de1b8e3
Add type information
iamtrask Aug 17, 2019
766160e
Remove commented out code
iamtrask Aug 17, 2019
e0eb207
Store input/output shape info on Plans
iamtrask Aug 17, 2019
a442a2b
Store input/output shape info on Plans
iamtrask Aug 17, 2019
f7fd828
Fix bad merge
iamtrask Aug 19, 2019
0461087
Merge branch 'dev' of github.com:OpenMined/PySyft into promise
iamtrask Aug 19, 2019
4f434b5
Generate __add__ dynamically
iamtrask Aug 19, 2019
dbbf200
Make PointerTensor.method logic work with varible # of args
iamtrask Aug 19, 2019
e5f73d0
Make PointerTensor.method logic work with varible # of args
iamtrask Aug 19, 2019
d85ad4c
Hook Promises for addition, multiplication, and division automagically
iamtrask Aug 19, 2019
23e0341
Hook all methods in PromiseTensor
iamtrask Aug 19, 2019
eba0e77
Add automatic support for .grad on promise tensors
iamtrask Aug 19, 2019
efaa4b9
Add simplify and detail to PromiseTensor
iamtrask Aug 19, 2019
51fcf04
checkpoint
iamtrask Aug 20, 2019
0dbabad
Fix merge conflicts
iamtrask Aug 21, 2019
19d988b
Merge branch 'dev' of github.com:OpenMined/PySyft into promise
iamtrask Aug 21, 2019
9ebc6c0
Fix imports from previous merge
iamtrask Aug 21, 2019
3fc2296
Fix typo
iamtrask Aug 21, 2019
c7fab93
Remove print statements
iamtrask Aug 21, 2019
da4cfc8
Change Plan.readable_plan type from tuple to list
iamtrask Aug 21, 2019
c84f6fe
Remove print statements
iamtrask Aug 21, 2019
19209b6
Improve __str__ for PromiseTensor to be more informative
iamtrask Aug 21, 2019
115d92d
Create PromiseTensor.send()
iamtrask Aug 21, 2019
bd3bf86
Create PromiseTensor.send()
iamtrask Aug 21, 2019
c84b533
Add owner to PointerTensor
iamtrask Aug 21, 2019
a89b847
Enable plans across multiple workers
iamtrask Aug 21, 2019
0fac765
Run 'black syft'
iamtrask Aug 21, 2019
2234c03
Merge branch 'dev' of github.com:OpenMined/PySyft into promise
iamtrask Aug 21, 2019
a3355a6
merge
iamtrask Aug 23, 2019
b8007c8
Simplify wrapper management and fix keep() id bug
iamtrask Aug 23, 2019
66b2c50
Remove print statement
iamtrask Aug 23, 2019
29e49d6
Add a comment:
iamtrask Aug 23, 2019
98d06c5
Add a comment:
iamtrask Aug 23, 2019
fe2da29
Checkpoint to share code with Theo.
iamtrask Aug 23, 2019
6b42dd4
added has_args_fulfilled method to plan
Sep 9, 2019
80f4c36
Merge remote-tracking branch 'upstream/dev' into promises_jason
Sep 9, 2019
7a8228c
fixed imports after merge
Sep 9, 2019
8df13f9
remove def from loop
Sep 10, 2019
8763509
operations can be done between promise and non-promise
Sep 10, 2019
0a3ddf7
Merge branch 'dev' into promises_jason
hereismari Sep 10, 2019
4493ffd
pointer tensors can forward keep method
Sep 11, 2019
dde0e95
started to add first tests for PromiseTensors
Sep 12, 2019
99a3b1d
can send promises
Sep 12, 2019
6fc9cef
black
Sep 12, 2019
e948471
remove doubled line
Sep 12, 2019
ee481c5
use value to get the result of a promise
Sep 12, 2019
73ad4f3
can do remote operations on promises
Sep 12, 2019
141a174
set local_worker.is_client_worker to False in tests needing it
Sep 12, 2019
e889625
set is_kept to true when promise kept
Sep 13, 2019
f58cff4
can do operations with scalar
Sep 13, 2019
5aec32e
fix cast scalars to tensors when building plans for operations
Sep 14, 2019
fabf47e
prepare to have buffer for promise objects
Sep 14, 2019
9ebb9c3
output of promises is bufferized
Sep 15, 2019
dd5a357
black
Sep 15, 2019
67e3af3
.wrap() hack to fix test
Sep 15, 2019
164f083
test for result buffer
Sep 15, 2019
b6e742a
Remove code related to the create_send_plan method
Sep 15, 2019
daf7ef2
Removed code related to the obj_id2promise_id dict
Sep 15, 2019
7ad284d
tests for plans with promises
Sep 16, 2019
0767de6
Merge branch 'dev' into promises_jason
Jasopaum Sep 17, 2019
614ae26
always use ids instead of objects
Sep 16, 2019
e5490dd
Fixed operations on PromiseTensors
Sep 17, 2019
f636361
Remove obj_id attribute from Promise
Sep 17, 2019
16b8ee1
Plan attribute promised_args is dict
Sep 17, 2019
a9386a7
remove commented line
Sep 17, 2019
984055c
fix problem of ids in plans
Sep 17, 2019
0bbb38f
collection of arguments a bit clearer
Sep 17, 2019
c6d3d75
added function to setup plans with promises
Sep 17, 2019
67cb85a
tests for promises on plans
Sep 17, 2019
f601062
black
Sep 17, 2019
30f28b4
added some doc
Sep 18, 2019
69bd722
removed attribute promised_args for plans
Sep 18, 2019
50b83ec
a bit of comments
Sep 18, 2019
a09c78a
setup_plan_with_promises closer to normal __call__ now
Sep 18, 2019
d5f5a2c
Merge branch 'dev' into promises_jason
hereismari Sep 18, 2019
659eccc
removed comment
Sep 18, 2019
1ea2b47
Check if plan waiting for promise on same worker
Jasopaum Sep 22, 2019
cf5ade2
call setup_plan_with_promises under the hood
Jasopaum Sep 22, 2019
8aaea1c
usage of plan with similar to classic plans
Jasopaum Sep 22, 2019
8d4257e
black
Jasopaum Sep 23, 2019
4143951
Merge branch 'dev' into promises_jason
Jasopaum Sep 23, 2019
e720f07
return result when using keep on wrapper
Jasopaum Sep 25, 2019
4322eae
some cleaning according to Theo's review
Jasopaum Sep 25, 2019
ff3903c
remove tests mixing promises and remote computations
Jasopaum Sep 25, 2019
dbaf27c
rm code dealing with promises on remote workers
Jasopaum Sep 25, 2019
7398dab
use shape instead of _shape
Jasopaum Sep 25, 2019
2543f0a
checkout websocket client example from upstream
Sep 25, 2019
377542d
black
Sep 25, 2019
d5ffa19
remove id attribute for abstract Promise
Sep 25, 2019
6201466
remove unnecessary cast to list
Sep 25, 2019
b8b4d78
rm change to tuto from PR
Sep 25, 2019
9971c4f
set is_client_worker back to True at the end of promises tests
Jasopaum Sep 26, 2019
8eb10e7
Merge branch 'dev' into promises_jason
Jasopaum Oct 3, 2019
158f4f4
Merge remote-tracking branch 'upstream/dev' into promises_jason
Jasopaum Oct 14, 2019
439f70e
direct re-alignment with plans
Jasopaum Oct 9, 2019
8914fb7
added attributes to serde
Jasopaum Oct 9, 2019
2dc80e0
fix because of id problem
Jasopaum Oct 9, 2019
43448d5
method to simply send __call__ to plan when applied to PointerPlan
Jasopaum Oct 14, 2019
8c2c082
Merge branch 'dev' into promises_jason
robert-wagner Oct 14, 2019
b0b58fd
black
Jasopaum Oct 14, 2019
bb9f7cc
rm comments saying move to generic folder
Jasopaum Oct 14, 2019
77051ed
added implementation of remote_send
Jasopaum Oct 14, 2019
b1b89c9
start making protocols work with promises
Jasopaum Oct 15, 2019
e8f31f5
test for protocol with promises
Jasopaum Oct 15, 2019
c4b875f
black
Jasopaum Oct 15, 2019
073b6ab
doc for build protocol with promises
Jasopaum Oct 15, 2019
bc165a7
Merge branch 'dev' into promises_jason
Jasopaum Oct 15, 2019
b4ea663
Merge branch 'dev' into promises_jason
Jasopaum Oct 16, 2019
1bf721e
cleaning
Jasopaum Oct 16, 2019
ad0fe55
fix output_shape property for plan
Jasopaum Oct 16, 2019
20e53ad
precise some comments for review
Jasopaum Oct 16, 2019
a8308c9
clean call pointed plan on pointed promises
Jasopaum Oct 16, 2019
706dd56
can run protocol with 2 consecutive plans on same worker
Jasopaum Oct 18, 2019
f22ab47
some cleaning according to review
Jasopaum Oct 19, 2019
a295168
Merge branch 'dev' into promises_jason
Jasopaum Oct 19, 2019
f0293e7
put promise_out_id in plan's procedure
Jasopaum Oct 19, 2019
07e2ede
distribute plans on workers for protocols where ids match exactly
Jasopaum Oct 20, 2019
f818a0c
Merge branch 'dev' into promises_jason
Jasopaum Oct 20, 2019
d09c053
Merge branch 'dev' into promises_jason
iamtrask Oct 21, 2019
90d9656
detail and simplify for promise abstract method
Jasopaum Oct 22, 2019
a329b5d
Merge branch 'master' into promises_jason
LaRiffle Oct 31, 2019
4d57256
Merge branch 'master' into promises_jason
Jasopaum Nov 25, 2019
9663af2
fix for serde refactor
Jasopaum Nov 25, 2019
3ee7ed2
black
Jasopaum Nov 25, 2019
543f0d0
clean according to review
Jasopaum Nov 25, 2019
d990da2
black
Jasopaum Nov 25, 2019
1aeaf0b
can change location of pointer when remote_send
Jasopaum Nov 26, 2019
47033ff
tests for remote_send
Jasopaum Nov 26, 2019
8907cf3
clean comment
Jasopaum Nov 27, 2019
e46baff
docstring for PromiseTensor arguments
Jasopaum Nov 29, 2019
45d6ec0
remove unused argument from PromiseTensor constructor
Jasopaum Dec 2, 2019
6f48943
Merge branch 'master' into promises_jason
iamtrask Dec 2, 2019
d59bc10
black
Jasopaum Dec 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions syft/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from syft.messaging.plan import Plan
from syft.messaging.plan import func2plan
from syft.messaging.plan import method2plan
from syft.messaging.promise import Promise

# Import Worker Types
from syft.workers.virtual import VirtualWorker
Expand All @@ -67,6 +68,7 @@
from syft.frameworks.torch.tensors.interpreters.autograd import AutogradTensor
from syft.frameworks.torch.tensors.interpreters.precision import FixedPrecisionTensor
from syft.frameworks.torch.tensors.interpreters.large_precision import LargePrecisionTensor
from syft.frameworks.torch.tensors.interpreters.promise import PromiseTensor
from syft.generic.pointers.pointer_plan import PointerPlan
from syft.generic.pointers.pointer_protocol import PointerProtocol
from syft.generic.pointers.pointer_tensor import PointerTensor
Expand Down
103 changes: 103 additions & 0 deletions syft/frameworks/torch/hook/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import syft
from syft.generic.frameworks.hook import hook_args
from syft.generic.frameworks.hook.hook import FrameworkHook
from syft.generic.tensor import AbstractTensor
from syft.generic.frameworks.remote import Remote
from syft.frameworks.torch.tensors.interpreters.autograd import AutogradTensor
from syft.frameworks.torch.tensors.interpreters.native import TorchTensor
from syft.frameworks.torch.tensors.interpreters.promise import PromiseTensor
from syft.frameworks.torch.tensors.interpreters.paillier import PaillierTensor
from syft.frameworks.torch.tensors.decorators.logging import LoggingTensor
from syft.frameworks.torch.tensors.interpreters.precision import FixedPrecisionTensor
Expand All @@ -26,6 +28,7 @@
from syft.workers.base import BaseWorker
from syft.workers.virtual import VirtualWorker
from syft.messaging.plan import Plan
from syft.messaging.promise import Promise

from syft.exceptions import route_method_exception
from syft.exceptions import TensorsNotCollocatedException
Expand Down Expand Up @@ -168,6 +171,9 @@ def __init__(
# Add all hooked tensor methods to LargePrecisionTensor tensor
self._hook_syft_tensor_methods(LargePrecisionTensor)

# Add all hooked tensor methods to PromiseTensor
self._hook_promise_tensor()

# Hook the tensor constructor function
self._hook_tensor()

Expand Down Expand Up @@ -504,6 +510,103 @@ def overloaded_attr(self, *args, **kwargs):

return overloaded_attr

def _hook_promise_tensor(hook_self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to hook the promise tensor? Why can't we just define all the methods directly in the PromiseTensor class? The class resides within PySyft, so why don't we define the methods as for example DoubleTensor there? It doesn't seem to rely on the DoubleTensor being hooked before defining the method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Methods like DoubleTensor were in the file where the class is defined before but I was asked in some comments to move them here ^^
For the other methods, I think this file was supposed to be where this kind of method generation happen but maybe not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that sounds like a contradiction. I'd like to hear the opinion of @LaRiffle and @robert-wagner 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Historically PromiseTensor has always been a little bit of an exception because of the way it works. I'm ok with this for now.


methods_to_hook = hook_self.to_auto_overload[torch.Tensor]

def generate_method(method_name):
def method(self, *args, **kwargs):

arg_shapes = list([self.shape])
arg_ids = list([self.id])

# Convert scalar arguments to tensors to be able to use them with plans
args = list(args)
for ia in range(len(args)):
if not isinstance(args[ia], (torch.Tensor, AbstractTensor)):
args[ia] = torch.tensor(args[ia])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised that this is needed: you can usually use scalars with torch operation:
A cmd like th.tensor([1.]) + 1 will (unless I'm wrong) be serialized and store the 1 as a scalar

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand it will make your next call to .shape fail, but you can test there if it has a shape

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to be able to use plans with scalar arguments.
I don't think it works to call a plan for which some arguments are Python integers, for instance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it does now :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often will we use plans with scalar arguments? If this this an edge case we can remove this an leave it for another PR with a TODO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it depends on the use case: for NN stuff maybe it's not needed but for crypto protocols, it might be more often (I'm not a crypto expert though).
And the problem is that we need the arg to have an id so that we can find it back. Or we can just store the scalar value and use it instead of an id but this needs some changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can "just store the scalar value" in the plan, it looks like it works from what I've seen

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think it's easier to change the scalars to tensors because this way, I can store and retrieve them from the worker when needed (when the promises are fulfilled). I can't see how to do that with scalars (but maybe it's just me :))


for arg in args:
arg_shapes.append(arg.shape)

@syft.func2plan(arg_shapes)
def operation_method(self, *args, **kwargs):
return getattr(self, method_name)(*args, **kwargs)

self.plans.add(operation_method.id)
for arg in args:
if isinstance(arg, PromiseTensor):
arg.plans.add(operation_method.id)

operation_method.procedure.update_args(
[self, *args], operation_method.procedure.result_ids
)

promise_out = PromiseTensor(
owner=self.owner,
shape=operation_method.output_shape,
tensor_type=self.obj_type,
plans=set(),
)
operation_method.procedure.promise_out_id = promise_out.id

if operation_method.owner != self.owner:
operation_method.send(self.owner)
else: # otherwise object not registered on local worker
operation_method.owner.register_obj(operation_method)

return promise_out

return method

for method_name in methods_to_hook:
setattr(PromiseTensor, method_name, generate_method(method_name))

def FloatTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.FloatTensor", *args, **kwargs).wrap()

setattr(Promise, "FloatTensor", FloatTensor)

def DoubleTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.DoubleTensor", *args, **kwargs).wrap()

setattr(Promise, "DoubleTensor", DoubleTensor)

def HalfTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.HalfTensor", *args, **kwargs).wrap()

setattr(Promise, "HalfTensor", HalfTensor)

def ByteTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.ByteTensor", *args, **kwargs).wrap()

setattr(Promise, "ByteTensor", ByteTensor)

def CharTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.CharTensor", *args, **kwargs).wrap()

setattr(Promise, "CharTensor", CharTensor)

def ShortTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.ShortTensor", *args, **kwargs).wrap()

setattr(Promise, "ShortTensor", ShortTensor)

def IntTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.IntTensor", *args, **kwargs).wrap()

setattr(Promise, "IntTensor", IntTensor)

def LongTensor(shape, *args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.LongTensor", *args, **kwargs).wrap()

setattr(Promise, "LongTensor", LongTensor)

def BoolTensor(shape, args, **kwargs):
return PromiseTensor(shape, tensor_type="torch.BoolTensor", *args, **kwargs).wrap()

setattr(Promise, "BoolTensor", BoolTensor)

def _hook_tensor(hook_self):
"""Hooks the function torch.tensor()
We need to do this seperately from hooking the class because internally
Expand Down
1 change: 1 addition & 0 deletions syft/frameworks/torch/tensors/interpreters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

24 changes: 24 additions & 0 deletions syft/frameworks/torch/tensors/interpreters/native.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from syft.generic.frameworks.hook import hook_args
from syft.generic.frameworks.overload import overloaded
from syft.frameworks.torch.tensors.interpreters.crt_precision import _moduli_for_fields
from syft.frameworks.torch.tensors.interpreters.promise import PromiseTensor
from syft.frameworks.torch.tensors.interpreters.paillier import PaillierTensor
from syft.generic.frameworks.types import FrameworkTensor
from syft.generic.tensor import AbstractTensor
Expand Down Expand Up @@ -583,6 +584,10 @@ def move(self, location):
self.child.owner.register_obj(self)
return self

def remote_send(self, location, change_location=False):
self.child.remote_send(location, change_location)
return self

def attr(self, attr_name):
""""""

Expand Down Expand Up @@ -814,6 +819,25 @@ def combine(self, *pointers):

return syft.combine_pointers(*ps)

def keep(self, obj):
""" Call .keep() on self's child if the child is a Promise (otherwise an error is raised).
.keep() is used to fulfill a promise with a value.
"""
return self.child.keep(obj)

def value(self):
""" Call .value() on self's child if the child is a Promise (otherwise an error is raised).
.value() is used to retrieve the oldest unused value the promise was kept with.
"""
return self.child.value()

def torch_type(self):

if isinstance(self, torch.Tensor) and not self.is_wrapper:
return self.type()
else:
return self.child.torch_type()

def encrypt(self, public_key):
"""This method will encrypt each value in the tensor using Paillier
homomorphic encryption.
Expand Down
110 changes: 110 additions & 0 deletions syft/frameworks/torch/tensors/interpreters/promise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import syft as sy
from syft.workers.abstract import AbstractWorker
import weakref

from syft.generic.tensor import AbstractTensor
from syft.generic.tensor import initialize_tensor
from syft.messaging.promise import Promise
from syft.generic.frameworks.hook import hook_args


class PromiseTensor(AbstractTensor, Promise):
def __init__(
self, shape, owner=None, id=None, tensor_type=None, plans=None, tags=None, description=None,
):
"""Initializes a PromiseTensor

Args:
shape: the shape that should have the tensors keeping the promise.
owner: an optional BaseWorker object to specify the worker on which
the tensor is located.
id: an optional string or integer id of the PromiseTensor.
tensor_type: the type that should have the tensors keeping the promise.
plans: the ids of the plans waiting for the promise to be kept. When the promise is
kept, all the plans corresponding to these ids will be executed if the other
promises they were waiting for are also kept.
tags: an optional set of hashtags corresponding to this tensor
which this tensor should be searchable for.
description: an optional string describing the purpose of the
tensor.
"""

if owner is None:
owner = sy.local_worker

# constructors for AbstractTensor and Promise
AbstractTensor.__init__(self, id=id, owner=owner, tags=tags, description=description)
Promise.__init__(self, owner=owner, obj_type=tensor_type, plans=plans)

self._shape = shape

del self.child

def torch_type(self):
return self.obj_type

@property
def shape(self):
return self._shape

@property
def grad(self):
return None
# if not hasattr(self, "_grad"):
# self._grad = PromiseTensor(shape=self._shape, tensor_type=self.torch_type()).wrap()
#
# return self._grad

def __str__(self):
return f"[PromiseTensor({self.owner.id}:{self.id}) -future-> {self.obj_type.split('.')[-1]} -blocking-> {len(self.plans)} plans]"

def __repr__(self):
return self.__str__()

@staticmethod
def simplify(worker: AbstractWorker, tensor: "PromiseTensor") -> tuple:
"""Takes the attributes of a FixedPrecisionTensor and saves them in a tuple.

Args:
tensor: a FixedPrecisionTensor.

Returns:
tuple: a tuple holding the unique attributes of the fixed precision tensor.
"""

return (
sy.serde._simplify(worker, tensor.id),
sy.serde._simplify(worker, tensor.shape),
sy.serde._simplify(worker, tensor.obj_type),
sy.serde._simplify(worker, tensor.plans),
)

@staticmethod
def detail(worker: AbstractWorker, tensor_tuple: tuple) -> "PromiseTensor":
"""
This function reconstructs a FixedPrecisionTensor given it's attributes in form of a tuple.
Args:
worker: the worker doing the deserialization
tensor_tuple: a tuple holding the attributes of the FixedPrecisionTensor
Returns:
FixedPrecisionTensor: a FixedPrecisionTensor
Examples:
shared_tensor = detail(data)
"""

id, shape, tensor_type, plans = tensor_tuple

id = sy.serde._detail(worker, id)
shape = sy.serde._detail(worker, shape)
tensor_type = sy.serde._detail(worker, tensor_type)
plans = sy.serde._detail(worker, plans)

tensor = PromiseTensor(
owner=worker, id=id, shape=shape, tensor_type=tensor_type, plans=plans
)

return tensor


### Register the tensor with hook_args.py ###
hook_args.default_register_tensor(PromiseTensor)
3 changes: 2 additions & 1 deletion syft/generic/object_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ObjectStorage:
"""

def __init__(self):
# This is the collection of objects being stored.
self._objects = {}

def register_obj(self, obj: object, obj_id: Union[str, int] = None):
Expand Down Expand Up @@ -103,7 +104,7 @@ def force_rm_obj(self, remote_key: Union[str, int]):
"""
if remote_key in self._objects:
obj = self._objects[remote_key]
if hasattr(obj, "child") and obj.child is not None:
if hasattr(obj, "child") and hasattr(obj.child, "garbage_collect_data"):
obj.child.garbage_collect_data = True
del self._objects[remote_key]

Expand Down
44 changes: 44 additions & 0 deletions syft/generic/pointers/pointer_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,22 @@ def move(self, location):
ptr.garbage_collect_data = False
return ptr

def remote_send(self, destination, change_location=False):
""" Request the worker where the tensor being pointed to belongs to send it to destination.
For instance, if C holds a pointer, ptr, to a tensor on A and calls ptr.remote_send(B),
C will hold a pointer to a pointer on A which points to the tensor on B.
If change_location is set to True, the original pointer will point to the moved object.
Considering the same example as before with ptr.remote_send(B, change_location=True):
C will hold a pointer to the tensor on B. We may need to be careful here because this pointer
will have 2 references pointing to it.
"""
args = (destination,)
kwargs = {"inplace": True}
self.owner.send_command(message=("send", self, args, kwargs), recipient=self.location)
if change_location:
self.location = destination
return self

def remote_get(self):
self.owner.send_command(message=("mid_get", self, (), {}), recipient=self.location)
return self
Expand Down Expand Up @@ -369,6 +385,34 @@ def share(self, *args, **kwargs):

return response

def keep(self, *args, **kwargs):
"""
Send a command to remote worker to keep a promise

Returns:
A pointer to a Tensor
"""

# Send the command
command = ("keep", self, args, kwargs)

response = self.owner.send_command(self.location, command)

return response

def value(self, *args, **kwargs):
"""
Send a command to remote worker to get the result generated by a promise.

Returns:
A pointer to a Tensor
"""
command = ("value", self, args, kwargs)

response = self.owner.send_command(self.location, command)

return response

def share_(self, *args, **kwargs):
"""
Send a command to remote worker to additively share inplace a tensor
Expand Down
1 change: 1 addition & 0 deletions syft/messaging/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading