Back-End

5 dez, 2018

Aprendizado de Máquina de Escala na Uber com Michelangelo – Parte 03

100 visualizações
Publicidade

Daremos sequência agora, à última parte do artigo sobre aprendizado de máquina de escala com Michelangelo.

Velocidade do desenvolvedor do modelo

A criação de sistemas de ML impactantes é uma ciência e requer muitas iterações para acertar. A velocidade da iteração afeta a maneira como o ML se expande em toda a organização e o nível de produtividade de uma equipe em determinado problema.

Uma alta prioridade para a equipe de Michelangelo é permitir que as equipes de ciência de dados sejam mais rápidas. Quanto mais rápido formos, mais experimentos podemos realizar, mais hipóteses podemos testar, melhores resultados podemos obter.

O diagrama abaixo mostra como pensamos sobre o processo de desenvolvimento de ML padrão e os diferentes ciclos de feedback dentro deles. Estamos constantemente pensando sobre esse processo e apertando esses loops para que seja mais fácil e rápido fazer ciência de dados iterativa e ágil.

Figura 4: O fluxo de trabalho de um projeto de aprendizado de máquina. Definir um problema, criar protótipos de uma solução, produzir a solução e medir o impacto da solução é o fluxo de trabalho principal. Os ciclos ao longo do fluxo de trabalho representam as muitas iterações de coleta de feedback necessárias para aperfeiçoar a solução e concluir o projeto.

A “velocidade zero a um” ou a “velocidade de tempo para valor” de Michelangelo é fundamental para a forma como o ML se espalha pela Uber.

Para novos casos de uso, nos concentramos em reduzir a barreira à entrada, ajustando o fluxo de trabalho inicial para pessoas com diferentes habilidades e tendo um fluxo otimizado para obter um modelo básico pronto e em funcionamento com bons padrões.

Para projetos existentes, observamos a velocidade de iteração, que determina a velocidade com que os cientistas de dados podem iterar e obter feedback sobre seus novos modelos ou recursos, seja em um teste off-line ou em um experimento on-line.

Alguns princípios provaram ser muito úteis para permitir que as equipes se desenvolvam rapidamente:

1 – Resolva o problema de dados para que os cientistas de dados não precisem resolvê-lo.

  • Lidar com acesso a dados, integração, gerenciamento de recursos e pipelines pode desperdiçar uma grande quantidade de tempo de um cientista de dados. A loja de recursos e os pipelines de recursos de Michelangelo são essenciais para resolver muitas dores de cabeça de cientistas de dados.

2 – Automatize ou forneça ferramentas poderosas para acelerar fluxos comuns.

3 – Torne o processo de implantação rápido e mágico.

  • Michelangelo esconde os detalhes da implantação e monitoramento de modelos e pipelines de dados na produção, com um único clique na interface do usuário.

4 – Deixe o usuário usar as ferramentas que eles adoram com pouca sujeira/cruft – “Vá até o cliente”.

  • Michelangelo permite o desenvolvimento interativo em Python, notebooks, CLIs e inclui interfaces de usuário para gerenciar sistemas e registros de produção.

5 – Ativar colaboração e reutilização.

  • Novamente, a loja de recursos de Michelangelo é fundamental para permitir que as equipes reutilizem importantes recursos preditivos já identificados e construídos por outras equipes.

6 – Guie o usuário por meio de um fluxo de trabalho estruturado.

Indo para o cliente: Notebooks e Python

Quando Michelangelo começou, os casos de uso mais urgentes e de maior impacto foram alguns problemas de escala muito alta, o que nos levou a construir em torno do Apache Spark (para processamento de dados em larga escala e treinamento de modelo) e Java (para baixa latência, alta taxa de serviço on-line).

Essa estrutura funcionou bem para o treinamento de produção e implantação de muitos modelos, mas deixou muito a desejar em termos de sobrecarga, flexibilidade e facilidade de uso, especialmente durante a prototipagem e experimentação iniciais.

Para fornecer maior flexibilidade, facilidade de uso e velocidade de iteração, estamos movendo os principais fluxos de trabalho de construção de modelos para o DSW da Uber. O DSW fornece acesso flexível e fácil à infraestrutura de dados da Uber e computa recursos em uma interface natural de notebook.

Sua integração com nossos clusters de nuvem e GPU no local permite a rápida criação de protótipos de modelos de ML prontos para Michelangelo em um ambiente de notebook e a fácil economia desses modelos em Michelangelo para implantação e serviço escalonado.

Estamos fazendo a transição para usar o DSW como a principal interface de exploração e prototipagem de modelos para Michelangelo.

Para suportar a mesma modelagem escalável em um ambiente de notebook que sempre fornecemos por meio de nossa UI, lançamos (internamente por enquanto, mas esperamos abrir o código fonte brevemente) um conjunto de bibliotecas que estendem o Spark para fornecer um conjunto de componentes Estimator, Transformer e do Pipeline personalizados que expõem interfaces para lote, streaming/fluxo e pontuação baseada em solicitação/resposta (o último não está disponível na versão padrão do Spark).

Esses componentes podem ser montados usando o PySpark e, em seguida, enviados para Michelangelo para implantação e exibição/serviço usando nosso sistema de serviço Java puro. Isso reúne grande parte da facilidade de uso do Python com a escala do Spark e do Java.

A modelagem Python simples é vantajosa para simplicidade e acesso a um ecossistema mais rico de ML e kits de ferramentas de dados. Para resolver isso, recentemente expandimos o Michelangelo para servir qualquer tipo de modelo Python de qualquer fonte para um suporte de modelagem mais flexível.

Os usuários constroem seus modelos em notebooks DSW (ou outro ambiente Python preferido) e usam o PyML SDK de Michelangelo para empacotar e carregar o modelo e as dependências para Michelangelo para armazenamento, implantação e serviço (tanto em lote quanto online).

Velocidade com aprendizado profundo

O fluxo de trabalho de desenvolvimento para modelos de aprendizagem profunda geralmente tem requisitos diferentes dos outros fluxos de trabalho de desenvolvimento de ML.

Os desenvolvedores normalmente escrevem códigos de treinamento muito mais detalhados e exigem recursos de computação especializados (GPUs). Nos concentramos muito em tornar esse processo suave e rápido no ano passado.

Michelangelo agora tem ótimas ferramentas para provisionar e executar trabalhos de treinamento em diferentes máquinas de GPU, tanto nos centros de dados da Uber quanto em várias nuvens públicas.

Os modelos de produção TensorFlow são atendidos a partir de nossa infraestrutura de serviço de modelo Michelangelo de alta escala existente (que agora está integrada ao TensorFlow Serving) ou do nosso sistema PyML.

Temos ferramentas especializadas para ajudar os modeladores a acompanhar seus experimentos e desenvolvimentos, mas uma vez que um modelo é salvo em Michelangelo, ele é tratado como qualquer outro modelo no sistema.

Acelerando o desenvolvimento de modelos com o AutoTune

O AutoTune é uma nova ferramenta de otimização como serviço de uso geral da Uber. Ele foi integrado ao Michelangelo para permitir que os modeladores utilizem facilmente os algoritmos de otimização Bayesianos de caixa preta de última geração para pesquisar mais eficientemente um conjunto ideal de hiperparâmetros.

Ele serve como uma nova alternativa recomendada para os algoritmos de pesquisa menos sofisticados que temos oferecido em Michelangelo até o momento. Isso significa modelos mais precisos na mesma quantidade de tempo de treinamento ou menos tempo de treinamento para chegar a um modelo de alta qualidade.

Modularidade e ofertas em camadas

Uma das tensões encontradas durante o desenvolvimento de Michelangelo estava entre fornecer suporte de ponta a ponta para os fluxos de trabalho de ML mais comuns e, ao mesmo tempo, fornecer a flexibilidade para suportar os menos comuns.

Originalmente, nossos componentes de plataforma e infraestrutura foram combinados em um único sistema. À medida que nossos sistemas se tornavam mais sofisticados e os problemas que resolvíamos se tornavam mais variados e complexos, crescia a demanda por mais flexibilidade, extensibilidade e experiências de desenvolvimento específicas de domínio além do que uma plataforma monolítica poderia oferecer.

Conseguimos resolver alguns desses problemas por meio das equipes de bridge/pontes, conforme descrito acima. Mas algumas equipes queriam misturar e combinar partes de Michelangelo com seus próprios componentes em novos fluxos de trabalho.

Outras equipes precisavam de ferramentas de desenvolvimento especializadas para seus casos de uso, mas não fazia sentido criar essas ferramentas do zero.

Fizemos algumas mudanças importantes na arquitetura de Michelangelo para alavancar nossos sistemas existentes tanto quanto possível, enquanto evoluímos com os requisitos crescentes conforme o ML amadurecia em toda a empresa:

Também descobrimos que, para alguns domínios de problemas, experiências de desenvolvimento especializadas são úteis.

Isso pode ser tão simples quanto fluxos de trabalho pré-construídos para aplicar e avaliar modelos de previsão ou pode ser algo mais personalizado, como uma ferramenta interativa de aprendizado e rotulagem criada para um aplicativo específico de visão computacional.

Queremos apoiar todos esses casos de uso, permitindo que os desenvolvedores de plataformas aproveitem a infraestrutura subjacente de Michelangelo.

Para resolver esses problemas, estamos no processo de decompor a infraestrutura de Michelangelo em uma camada de infraestrutura explícita e disponibilizar essa infraestrutura para que as equipes aproveitem para construir plataformas mais especializadas, por exemplo, para NLP ou Visão.

Feito isso, teremos dois grupos de clientes: os construtores de modelos que usam a plataforma Michelangelo para construir e implantar modelos e os construtores de sistemas de ML que usam os componentes de infraestrutura de Michelangelo para construir soluções sob medida ou plataformas mais especializadas.

Principais lições aprendidas

Construindo Michelangelo e ajudando a escalar o aprendizado de máquina em toda a Uber nos últimos três anos, nos fez aprender muito com nossos sucessos e fracassos. Em alguns casos, acertamos na primeira vez, mas com mais frequência, foram necessárias algumas iterações para descobrir o que funciona melhor para nós.

  • Deixe que os desenvolvedores usem as ferramentas que desejarem. Esta é uma área que nos levou várias iterações ao longo de muitos anos para descobrir a abordagem correta. Quando começamos Michelangelo, nos concentramos primeiro nos casos de uso de maior escala, porque era onde poderíamos ter o maior impacto. Embora o foco inicial em fluxos de trabalho baseados em Scala, configuração e interface do usuário nos permitisse oferecer suporte a casos de uso de alta escala, ele nos afastou das interfaces programáticas maduras e bem documentadas com as quais os desenvolvedores de modelos já são proficientes. Como o trabalho de modelagem é muito iterativo, acabou sendo importante se concentrar na velocidade do desenvolvedor (e, portanto, ciclos de iteração rápidos), juntamente com alta escalabilidade. Chegamos a uma solução híbrida onde oferecemos uma opção de alta escala que é um pouco mais difícil de usar e um sistema de menor escala que é muito fácil de usar.
  • Os dados são a parte mais difícil do ML e a peça mais importante para acertar. Os modeladores passam a maior parte do tempo selecionando e transformando recursos no tempo de treinamento e, em seguida, construindo os pipelines para fornecer esses recursos aos modelos de produção. Dados quebrados são a causa mais comum de problemas nos sistemas de ML de produção. Na Uber, nossa loja de recursos aborda muitos desses problemas, permitindo que os modeladores compartilhem facilmente recursos de alta qualidade, implantem automaticamente os pipelines de produção desses recursos e os monitorem ao longo do tempo. Depois que os recursos são definidos, também podemos aproveitar as ferramentas de monitoramento de qualidade de dados da Uber para garantir que os dados do recurso estejam corretos ao longo do tempo.
  • Pode ser necessário um esforço significativo para que os componentes comerciais e de código aberto funcionem bem em escala. O Apache Spark e o Cassandra são projetos populares e maduros de código aberto; no entanto, levou mais de um ano de esforço sustentado em cada caso para fazê-los funcionar de forma confiável na escala da Uber. Tivemos desafios semelhantes com kits de ferramentas comerciais que tentamos desde o início e acabamos abandonando.
  • Desenvolva iterativamente com base no feedback do usuário, com a visão de longo prazo em mente. Quando construímos Michelangelo, quase sempre trabalhamos de perto com as equipes de clientes em novas capacidades. Nós resolveríamos bem o problema para uma equipe primeiro e, uma vez que ela estivesse sendo executada com sucesso na produção, nós generalizaríamos para o restante da empresa. Esse processo garantiu que as soluções que construímos fossem realmente usadas Isso também ajudou a manter a equipe engajada e a liderança solidária, porque eles tiveram um impacto constante. Ao mesmo tempo, é importante reservar algum tempo para apostas de longo prazo que os usuários podem não ver em seu horizonte. Por exemplo, começamos a trabalhar em ferramentas de aprendizagem profunda bem antes de haver demanda real; se tivéssemos esperado, teríamos chegado tarde demais. ML em tempo real é um desafio para acertar. A maioria das ferramentas de dados existentes é criada para ETL offline ou streaming on-line. Não existem ótimas ferramentas – ainda! – que abordem os recursos online/offline híbridos (lote, streaming e RPC) exigidos pelos sistemas ML em tempo real. Isso continua sendo uma grande área de foco para nós da Uber como parte de nossa loja de recursos.

A jornada está apenas começando e ainda há muito a fazer. Este é um espaço em evolução e haverá muito mais lições para aprender. Se você estiver interessado em enfrentar desafios de aprendizado de máquina que ultrapassem os limites de escala, considere a possibilidade de se candidatar a um cargo em nossa equipe!

***

Este artigo é do Uber Engineering. Ele foi escrito por Jeremy Hermann e Mike Del Balso. A tradução foi feita pela Redação iMasters com autorização. Você pode conferir o original em: https://eng.uber.com/scaling-michelangelo/