Pysyft: Re-work Protocols to incorporate Actions, Placeholders, Roles, and Executions

Created on 4 Feb 2020  Â·  7Comments  Â·  Source: OpenMined/PySyft

We propose a new way of building Protocol on top of Plan using PlaceHolder.

Example of protocol

@sy.protocol(alice=RoleWorker())
def foo(x):
    y = x - 1
    y_ptr = y.send(alice)
    z_ptr = y_ptr.abs()
    return z_ptr

Standard workflow:

# build constructs a tape of logs for each RoleWorker
foo.build(th.Tensor([-1]))

print(foo.plans)
#>out  {'local': Plan1, 'alice': Plan2}

foo_deployed = foo.deploy(local=james, alice=bob)

res = foo_deployed.run(th.tensor([1.5]))
print(res)
#>out ptr to bob with remote value=0.5

# redeploy: basically copy and instantiate the Roles
foo_deployed2 = foo.deploy(local=andrew, alice=dan)

protocol.build will create a tape of log on each Role involved (these Role are like a worker that exist just for the build)(note that a local Role is created implicitly in addition to alice). Each tape will become a plan. Each Plan will be composed of a list of Operation or ObjectMessage exclusively. More precisely sending a tensor A -> B will add a ObjectMessage in tape of A. Calling now get()from A on a remote pointer to B will add a ObjectMessage on tape B to get the tensor back. (same strategy for move). During the build, ie when the tracing is on, ie when the tapes are recording, the owner of Placeholders (which is one of the Role worker involved) used in the Operation as arguments is used to determine in which tape goes the operation, and defines the owner of the return placeholders.

Steps:

  • Create Role which should have the same function with workers as the placeholder for tensors
  • Add a tracing functionality on tensor.send: it should in particular record the origin and target Roles.
  • Create a trace log (or _tape_) per worker. (_One issue here is that it's often hard to know on which worker an operation is running when dealing with virtual workers_)
  • Build plans under the hook when calling protocol.build, from the trace with multiple tapes
  • After building tensor.send corresponds to a remote instantiation of a placeholder.
  • Placeholder should know which Operation they are involved in, so that when it's instantiated, either from local or remote command, it can trigger the Operation depending on it, provided that all the placeholder in this Operation have been instantiated.

More examples:

Function

@sy.protocol(
     alice=RoleWorker(state=(nn.Linear(2, 3), )), 
     bob=RoleWorker(state=(nn.Linear(3, 2), ))
)
def foo(x, bias):
    """
    The arguments are not necessarily local, here `bias` is a pointer to alice
    """
    x = (x - x.mean())/x.std()
    x = x.send(alice) 
    fc1, = alice.state.read()
    x = fc1(x) # computation is done on alice
    x += bias
    x = x.move(bob)
    fc2, = bob.state.read()
    x = fc2(x) # computation is done on bob
    x = x.get()
    return F.log_softmax(x, dim=0) # computation is done on the "local worker"

Class

This configuration is not well defined

alice, bob  = RoleWorker(),  RoleWorker()
class Net(sy.Protocol):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(2, 3)
        self.fc2 = nn.Linear(3, 2).send(alice)
        self.fc3 = nn.Linear(2, 1).send(bob)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = x.send(alice)
        x = F.relu(self.fc2(x))
        x = x.move(bob)
        x = self.fc3(x)
        return F.log_softmax(x, dim=0)

Tensors created remotely

@sy.protocol(alice=RoleWorker())
def foo(x):
    y =x.send(alice)
    z = y.abs()
    noise, = alice.torch.randint(0, 10,  (1,))
    return z + noise

Here, we could create the tensor "remotely" by using worker.torch.<gen_func>: the Operation logged would be in the tape of Alice

Concerns

  • The ability for a PlaceHolder to point to Operations and to trigger them is very close to what we expect from Promise. There's gonna be a sticking point here. To clarify this point, the tape of Operations for a given worker wouldn't not be executed in sequential order as we did with Plan, but in an async and eager way, where each time all the placeholders needed for an op are instantiated, the op is executed.
  • The notion of _tape_ is confusing because of this possibly asynchronous execution.
  • it's in particular almost impossible to know in which tape to record torch functions creating tensors from nowhere (like torch.ones), but maybe we should handle correctly the new syntax worker.torch.ones [this is not the top priority right now]
  • The exact moment where RoleWorker are defined is not clear: it should be only at the build like we do with PlaceHolders
  • Because we need to record the worker doing the Operation of the origin and target when sending a tensor, our tape will differ a bit from what we currently have for simple plans, to add this extra information.
  • There might be better syntax to define Protocols
Status Type Type

Most helpful comment

From a conversation with @Jasopaum, we're planning to start working on this and have a preliminary checklist of steps forward to get us started:

  • [ ] Extract ComputationAction from OperationMessage
  • [ ] Create Action base class
  • [ ] Create CommunicationAction class
  • [ ] Create a Role class (possibly w/ a worker inside?)
  • [ ] Create a Protocol class (w/ building and tracing like Plans)
  • [ ] Partition the trace logs into separate roles
  • [ ] Send Roles to workers
  • [ ] Add the ability to execute Actions from Protocol Roles on workers
  • [ ] Create an Execution abstraction to capture state (inputs, outputs, intermediate results, etc.)
  • [ ] Add protocol id and execution id fields to message classes
  • [ ] Update worker's message dispatch to take ids into account

All 7 comments

This is a neat idea! I can definitely see it working, particularly with the worker.torch syntax.

Definitely interesting - but there are a few features missing from the prototype above.

# Secure aggregation protocol
worker1 = sy.VirtualWorker(hook=hook, id="worker1")
worker2 = sy.VirtualWorker(hook=hook, id="worker2")
worker3 = sy.VirtualWorker(hook=hook, id="worker3")

worker1_model = worker1.Promise.Model()
worker2_model = worker2.Promise.Model()
worker3_model = worker3.Promise.Model()

worker1_shares = worker1_model.share(worker1, worker2, worker3)
worker2_shares = worker2_model.share(worker1, worker2, worker3)
worker3_shares = worker3_model.share(worker1, worker2, worker3)

new_model_shares = (worker1_shares + worker2_shares + worker3_shares) / 3

new_model_shares["worker1"].declare_output()
new_model_shares["worker2"].declare_output()
new_model_shares["worker3"].declare_output()
secure_aggregation_protocol = sy.Protocol(worker1, worker2, worker3)
  • Would we still be able to declare separate inputs and outputs corresponding to each worker?
  • Would we still be able to indicate type information for inputs and outputs?
  • Optional: Could .we call .deploy() multiple times?
  • Can you show this example involving coordinating between multiple workers? Right now the plan only specifies 1 worker and "local" is implied.
  • Is it possible to specify that a worker should create a tensor of their own (as opposed to it being an input... i.e. torch.zeros(2,3))
  • Let's make an example requiring multiple inputs from multiple different actors which are submitted asynchronously.

To be clear - I like the interface you propose as an option. I think that yours is an interesting STATIC graph API whereas the one I proposed is a DYNAMIC graph API which can be converted into a static graph. We should support both.

I extended my example to answer some of your questions, I agree this is STATIC for the moment, but it's quite easy to turn to DYNAMIC: activate the tracing mode, do whatever you want, close the trace and pickup the tapes to build a protocol.

From a conversation with @Jasopaum, we're planning to start working on this and have a preliminary checklist of steps forward to get us started:

  • [ ] Extract ComputationAction from OperationMessage
  • [ ] Create Action base class
  • [ ] Create CommunicationAction class
  • [ ] Create a Role class (possibly w/ a worker inside?)
  • [ ] Create a Protocol class (w/ building and tracing like Plans)
  • [ ] Partition the trace logs into separate roles
  • [ ] Send Roles to workers
  • [ ] Add the ability to execute Actions from Protocol Roles on workers
  • [ ] Create an Execution abstraction to capture state (inputs, outputs, intermediate results, etc.)
  • [ ] Add protocol id and execution id fields to message classes
  • [ ] Update worker's message dispatch to take ids into account

Can't wait to see progress on this one!

On Mon, Mar 2, 2020 at 5:12 PM Karl Higley notifications@github.com wrote:

From a conversation with @Jasopaum https://github.com/Jasopaum, we're
planning to start working on this and have a preliminary checklist of steps
forward to get us started:

  • Extract ComputationAction from OperationMessage
  • Create Action base class
  • Create CommunicationAction class
  • Create a Role class (possibly w/ a worker inside?)
  • Create a Protocol class (w/ building and tracing like Plans)
  • Partition the trace logs into separate roles
  • Send Roles to workers
  • Add the ability to execute Actions from Protocol Roles on workers
  • Create an Execution abstraction to capture state (inputs, outputs,
    intermediate results, etc.)
  • Add protocol id and execution id fields to message classes
  • Update worker's message dispatch to take ids into account

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/OpenMined/PySyft/issues/3008?email_source=notifications&email_token=ABBAZEQYFG6FAYZUCLH26TTRFPSHBA5CNFSM4KP3P7M2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENQEH7Q#issuecomment-593511422,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ABBAZEXSLIPMUHZHWTUYXTTRFPSHBANCNFSM4KP3P7MQ
.

@iamtrask See #3132.

This issue has been marked stale because it has been open 30 days with no activity. Leave a comment or remove the stale label to unmark it. Otherwise, this will be closed in 7 days.

Was this page helpful?
0 / 5 - 0 ratings