Split Learning
O aprendizado dividido separa uma rede neural em uma camada de corte, para que os clientes mantenham os dados brutos e as camadas iniciais, enquanto um servidor treina o restante usando as ativações.
O aprendizado dividido é um método colaborativo de treinamento distribuído que divide uma rede neural em uma camada de corte escolhida, entre o proprietário dos dados (o cliente) e um servidor. O cliente executa as camadas anteriores ao corte com seus dados privados e envia apenas as ativações resultantes, às vezes chamadas de dados fragmentados; o servidor executa as camadas restantes, calcula a perda e envia de volta o gradiente na camada de corte para que o cliente atualize suas camadas. Os dados de treinamento brutos nunca saem do cliente, e nenhum dos lados mantém o modelo inteiro. Otkrist Gupta e Ramesh Raskar, do MIT Media Lab, apresentaram o método em outubro de 2018 no artigo Aprendizado distribuído de redes neurais profundas entre vários agentes. Em dezembro de 2018, o grupo publicou o artigo seguinte, Split Learning for Health, que propôs configurações para que hospitais com diferentes tipos de dados de pacientes, como exames para análise de imagens médicas, treinassem modelos em conjunto sem compartilhar registros brutos.
Como funciona o aprendizado dividido#
Cada etapa de treinamento atravessa o corte duas vezes: as ativações vão do cliente ao servidor durante a passagem direta, e o gradiente da perda em relação a essas ativações retorna durante a retropropagação. Como a regra da cadeia precisa apenas desse gradiente para continuar, as atualizações do cliente são idênticas às do treinamento do modelo não dividido. Uma simulação em processo único com PyTorch mostra a troca:
import torch
from torch import nn
torch.manual_seed(0)
client = nn.Sequential(nn.Linear(784, 256), nn.ReLU()) # camadas anteriores ao corte, junto aos dados privados
server = nn.Sequential(nn.Linear(256, 10)) # camadas posteriores ao corte
images, labels = torch.randn(32, 784), torch.randint(0, 10, (32,))
# Cliente: passagem direta até a camada de corte; depois, enviar apenas as ativações
activations = client(images)
received = activations.detach().requires_grad_()
# Servidor: concluir a passagem direta e retropropagar até o corte; depois, enviar esse gradiente de volta
nn.functional.cross_entropy(server(received), labels).backward()
# Cliente: continuar a retropropagação a partir do gradiente recebido
activations.backward(received.grad)
split_grad = client[0].weight.grad.clone()
# A mesma etapa no modelo não dividido fornece gradientes idênticos ao cliente
client.zero_grad()
nn.functional.cross_entropy(server(client(images)), labels).backward()
print("Same client gradients as unsplit training:", torch.equal(split_grad, client[0].weight.grad))A saída é Same client gradients as unsplit training: True. Em seguida, cada lado atualiza seu próprio otimizador. Com vários clientes, o protocolo original os treina em sequência, e cada cliente recebe os pesos mais recentes do lado cliente deixados pelo cliente anterior.
A configuração muda conforme o que precisa permanecer privado. A configuração básica acima envia os rótulos ao servidor; uma configuração em U também mantém as últimas camadas e os rótulos no cliente; e uma configuração vertical atende organizações que têm características diferentes dos mesmos registros:
Aprendizado dividido vs. aprendizado federado#
O aprendizado federado também mantém os dados nas máquinas dos proprietários, mas cada cliente treina uma cópia completa do modelo e envia atualizações dos pesos para serem calculadas em média. O aprendizado dividido envia ativações e gradientes, em vez disso, por isso os clientes precisam de muito menos capacidade computacional e nunca mantêm o modelo completo. A comunicação aumenta com a quantidade de dados, não com o tamanho do modelo, e os clientes treinam um após o outro, em vez de em paralelo. O aprendizado SplitFed, proposto por Chandra Thapa e colegas em 2020, combina as duas abordagens ao executar em paralelo as camadas do lado cliente e calculá-las em média no estilo federado.
O aprendizado dividido vertical também atende ao setor financeiro, no qual um banco e um parceiro com características diferentes dos mesmos clientes treinam um modelo, como no tutorial de marketing bancário da SecretFlow, sem trocar dados privados. O paralelismo de pipeline também divide uma rede por profundidade, mas entre GPUs de um único cluster confiável, para que um modelo grande caiba na memória.
Riscos à privacidade#
As ativações e os gradientes ainda contêm informações sobre os dados. É possível inverter as ativações das primeiras camadas para recuperar imagens reconhecíveis e, quando o servidor mantém os rótulos, os gradientes enviados de volta podem revelá-los ao cliente. Na ACM CCS 2021, Dario Pasquini, Giuseppe Ateniese e Massimo Bernaschi demonstraram que um servidor malicioso pode sequestrar o treinamento por meio dos gradientes enviados, direcionando as camadas do cliente para uma configuração que permite ao servidor reconstruir entradas privadas. As defesas adicionam ruído com privacidade diferencial, penalizam a quantidade de informações da entrada revelada pelas ativações ou detectam gradientes incomuns, cada uma com algum custo em precisão. As implantações combinam o aprendizado dividido com controles de segurança de dados, como autenticação e transporte criptografado, pois o próprio protocolo só rege o que atravessa o corte.
Como escolher a camada de corte#
O corte define o equilíbrio entre a computação no cliente, o tráfego e a exposição: um corte inicial exige menos computação do cliente, mas envia ativações grandes que ainda se parecem com a entrada, enquanto um corte posterior envia mapas de características mais abstratos, mas exige mais do hardware do cliente, o que é importante para dispositivos de AI de borda. As conexões de atalho complicam a escolha, porque é preciso enviar todos os tensores que atravessam o corte. Cortar o Ultralytics YOLO26 depois do seu backbone exige enviar três mapas de características, pois a configuração do modelo encaminha as saídas das camadas 4, 6 e 10 para o pescoço. Para o YOLO26n em imgsz=640, elas contêm 1.126.400 valores, quase tantos quanto os 1.228.800 da imagem de entrada.










