Parte 2: Servindo o Modelo de forma segura com Syft Keras

Agora que você tem um modelo treinado com Keras normal, está pronto para servir algumas previsões privadas. Podemos fazer isso usando o Syft Keras.

Para proteger e servir esse modelo, precisaremos de três TFEWorkers (servidores). Isso ocorre porque o TF Encrypted por debaixo dos panos usa uma técnica de criptografia chamada multi-party computation (MPC). A idéia é dividir os pesos do modelo e dados de entrada em partições, depois enviar uma parte de cada valor para os diferentes servidores. A propriedade-chave é que, se você observar a parte recebida em um servidor, ele não revelará nada sobre o valor original (dados de entrada ou pesos do modelo).

Definiremos um modelo Syft Keras como fizemos no notebook anterior. No entanto, há um truque: antes de instanciar esse modelo, executaremos hook = sy.KerasHook(tf.keras). Isso adicionará três novos métodos importantes à classe Sequencial Keras:

  • share: protegerá seu modelo via compartilhamento secreto; por padrão, ele usará o protocolo SecureNN do TF Encrypted para compartilhar seu modelo em segredo entre cada um dos três TFEWorkers. Mais importante, isso adicionará a capacidade de fornecer previsões sobre dados criptografados.
  • serve: esta função irá lançar uma fila para servir, de modo que os TFEWorkers pode aceitar pedidos de previsão sobre o modelo seguro de clientes externos.
  • shutdown_workers: depois de fornecer previsões particulares, você pode desligar o modelo executando esta função. Ele o instruirá a encerrar os processos do servidor manualmente, se você optar por gerenciar manualmente cada worker.

Se você quiser saber mais sobre o MPC, pode ler este excelente blog.


In [ ]:
import numpy as np
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import AveragePooling2D, Conv2D, Dense, Activation, Flatten, ReLU, Activation

import syft as sy
hook = sy.KerasHook(tf.keras)

Modelo

Como você pode ver, definimos quase exatamente o mesmo modelo de antes, exceto que fornecemos um batch_input_shape. Isso permite que o TF Encrypted otimize melhor os cálculos seguros através de formas predefinidas de tensores. Para esta demonstração MNIST, enviaremos dados de entrada com a forma (1, 28, 28, 1). Também retornamos o logit em vez de softmax porque essa operação é complexa para executar usando MPC e não precisamos dela para atender a solicitações de previsão.


In [ ]:
num_classes = 10
input_shape = (1, 28, 28, 1)

In [ ]:
model = Sequential()

model.add(Conv2D(10, (3, 3), batch_input_shape=input_shape))
model.add(AveragePooling2D((2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(AveragePooling2D((2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(AveragePooling2D((2, 2)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(num_classes, name="logit"))

Carregando pesos pré-treinados

Com a função load_weights, você pode carregar facilmente os pesos que você salvou anteriormente após treinar seu modelo.


In [ ]:
pre_trained_weights = 'short-conv-mnist.h5'
model.load_weights(pre_trained_weights)

Lançando os workers

Vamos agora criar TFEWorkers (alice,bob e carol) exigidos pelo TF Encrypted para realizar previsões privadas. Para cada TFEWorker, você apenas precisa especificar um host. Em seguida, fazemos combinar esses workers em um cluster.

Esses trabalhadores executam um servidor TensorFlow, que você pode gerenciar manualmente (AUTO = False) ou pedir aos workers que gerenciem para você (AUTO = True). Se optar por gerenciá-los manualmente, você será instruído a executar um comando de terminal no dispositivo host de cada trabalhador após chamar cluster.start() abaixo. Se todos os workers estiverem hospedados em um único dispositivo (por exemplo, localhost), você poderá escolher que o Syft gerencie automaticamente o servidor TensorFlow do worker.


In [ ]:
AUTO = False

alice = sy.TFEWorker(host='localhost:4000', auto_managed=AUTO)
bob = sy.TFEWorker(host='localhost:4001', auto_managed=AUTO)
carol = sy.TFEWorker(host='localhost:4002', auto_managed=AUTO)

cluster = sy.TFECluster(alice, bob, carol)
cluster.start()

Proteja o modelo, compartilhando os pesos

Graças ao sy.KerasHook (tf.keras), você pode chamar o método share para transformar seu modelo em um modelo TF Encrypted Keras.

Se você pediu para gerenciar manualmente os servidores acima, essa etapa não será concluída até que todos tenham sido iniciados. Observe que seu firewall pode solicitar que o Python aceite a conexão de entrada.


In [ ]:
model.share(cluster)

Servindo o modelo

Perfeito! Agora, chamando model.serve, seu modelo está pronto para fornecer algumas previsões privadas. Você pode definir num_requests para definir um limite para o número de requisições de previsões atendidas pelo modelo; se não especificado, o modelo será servido até ser interrompido.


In [ ]:
model.serve(num_requests=3)

Você está pronto para ir para o notebook Parte 13c para fazer requisições de algumas previsões privadas.

Hora da limpeza!

Quando o limite de suas requisições for totalmente utilizado, o modelo não estará mais disponível para atender requisições, mas ainda será compartilhado em segredo entre os três workers acima. Você pode matar os workers executando a célula abaixo.

Parabéns por concluir a Parte 13b: Classificação segura com Syft Keras e TFE!


In [ ]:
model.stop()
cluster.stop()

if not AUTO:
    process_ids = !ps aux | grep '[p]ython -m tf_encrypted.player --config' | awk '{print $2}'
    for process_id in process_ids:
        !kill {process_id}
        print("Process ID {id} has been killed.".format(id=process_id))

In [ ]: