O Deep Learning agora está em Java

Não gosta de Java? Sim, você não sabe cozinhar! Mani Sarkar nos convida a familiarizar-se com a ferramenta Valohai, que permite realizar pesquisas de modelos em Java.



Isenção de responsabilidade do tradutor
Espero que não seja uma publicação publicitária. Eu não sou afiliado com Valohai. Acabei de traduzir o artigo ao qual refiro o link. Se desajeitado traduzido - pontapé no PM. Se necessário, posso excluir links e mencionar outros recursos externos. Obrigado pela sua compreensão.

1. Introdução


Há algum tempo, deparei-me com um serviço em nuvem chamado Valohai, e fiquei satisfeito com a interface do usuário e a simplicidade do design e layout. Pedi o serviço de um dos membros de Valohai e recebi uma versão demo. Antes disso, escrevi um pipeline simples usando o GNU Parallel, JavaScript, Python e Bash - e outro que usa apenas o GNU Parallel e Bash.

Também pensei em usar ferramentas de gerenciamento de tarefas / fluxo de trabalho prontas para uso, como Jenkins X, Jenkins Pipeline, Concourse ou Airflow, mas por várias razões, decidi não usar.

Notei que muitos exemplos e documentação de Valohai são baseados em Python e R e em suas respectivas estruturas e bibliotecas. Decidi não perder a oportunidade e quero corrigir a falta de exemplos e documentação.

Valohai me incentivou a implementar algo usando a famosa biblioteca Java chamada DL4J - Deep Learning for Java .

Minha primeira experiência com Valohai causou uma boa impressão em mim depois de sentir o design, o layout e o fluxo de trabalho. Os criadores já levaram em consideração vários aspectos dos fluxos de trabalho do desenvolvedor e da infraestrutura. Em nosso mundo, o processo de desenvolvimento de infraestrutura é controlado principalmente pelas equipes de DevOps ou SysOps, e conhecemos as nuances e pontos negativos associados a ele.

Do que precisamos e como?


Em qualquer projeto de aprendizado de máquina, existem dois componentes importantes (do ponto de vista de alto nível) - um código que funcionará com o modelo e um código que funcionará com a infraestrutura, na qual todo o ciclo de vida do projeto será executado.

Obviamente, haverá etapas e componentes necessários antes, durante e depois, mas para simplificar, digamos, precisamos de código e infraestrutura.

Código


Para o código, escolhi um exemplo complexo usando o DL4J, este é um projeto MNist com um conjunto de treinamento de 60.000 imagens e um conjunto de testes de 10.000 imagens de dígitos manuscritos. Este conjunto de dados está disponível na biblioteca DL4J (como Keras).

Antes de começar, é recomendável que você dê uma olhada no código-fonte que usaremos. A principal classe Java é chamada org.deeplearning4j.feedforward.mnist.MLPMnistSingleLayerRunner .

A infraestrutura


Decidimos tentar o exemplo de Java usando Valohai como nossa infraestrutura para realizar experimentos (treinamento e avaliação de modelos). O Valohai reconhece os repositórios git e se conecta diretamente a eles, permitindo que executemos nosso código independentemente da plataforma ou idioma - portanto, veremos como ele funciona. Isso também significa que, se você usar GitOps ou Infraestrutura como código, tudo funcionará para você também.

Para fazer isso, precisamos apenas de uma conta em Valohai. Depois de criar uma conta gratuita, obtemos acesso a várias instâncias de várias configurações. Para o que gostaríamos de fazer, o Free-Tier é mais que suficiente.

Deep Learning para Java e Valohai


Forneceremos todas as dependências da imagem do Docker e a usaremos para compilar nosso aplicativo Java, treinar o modelo e avaliá-lo na plataforma Valohai usando um simples arquivo valohai.yaml localizado na pasta raiz do repositório do projeto.

Deep Learning para Java: DL4J


A parte mais simples. Não precisamos fazer muito, basta coletar o frasco e carregar o conjunto de dados no contêiner do Docker. Temos uma imagem pré-criada do Docker que contém todas as dependências necessárias para criar um aplicativo Java. Colocamos essa imagem no Docker Hub e você pode encontrá-la pesquisando dl4j-mnist-single-layer (usaremos uma tag especial conforme definida no arquivo YAML). Decidimos usar o GraalVM 19.1.1 como nosso ambiente Java de compilação e tempo de execução para este projeto, e ele é incorporado à imagem do Docker.

Quando o uber jar é chamado na linha de comando, criamos a classe MLPMnistSingleLayerRunner, que nos diz a ação pretendida, dependendo dos parâmetros passados ​​para:

public static void main(String[] args) throws Exception { MLPMnistSingleLayerRunner mlpMnistRunner = new MLPMnistSingleLayerRunner(); JCommander.newBuilder() .addObject(mlpMnistRunner) .build() .parse(args); mlpMnistRunner.execute(); } 

Os parâmetros passados ​​para o uber jar são aceitos por essa classe e processados ​​pelo método execute ().

Podemos criar um modelo usando o parâmetro --action train e avaliar o modelo criado usando o parâmetro --action assessment passado para o aplicativo Java.

As principais partes do aplicativo Java que fazem esse trabalho podem ser encontradas nas duas classes Java mencionadas nas seções abaixo.

Modelo de treinamento


Ligar

 ./runMLPMnist.sh --action train --output-dir ${VH_OUTPUTS_DIR} or java -Djava.library.path="" \ -jar target/MLPMnist-1.0.0-bin.jar \ --action train --output-dir ${VH_OUTPUTS_DIR} 

Este comando cria um modelo chamado mlpmnist-single-layer.pb na pasta especificada pelo parâmetro --output-dir passado no início da execução. Do ponto de vista de Valohai, ele deve ser colocado em $ {VH_OUTPUTS_DIR}, o que fazemos (consulte o arquivo valohai.yaml ).

Para o código fonte, consulte a classe MLPMNistSingleLayerTrain.java .

Avaliação do Modelo


Ligar

 ./runMLPMnist.sh --action evaluate --input-dir ${VH_INPUTS_DIR}/model or java -Djava.library.path="" \ -jar target/MLPMnist-1.0.0-bin.jar \ --action evaluate --input-dir ${VH_INPUTS_DIR}/model 

Supõe-se que o modelo (criado durante a fase de treinamento) com o nome mlpmnist-single-layer.pb esteja presente na pasta especificada no parâmetro --input-dir passado quando o aplicativo foi chamado.

Para o código-fonte, consulte a classe MLPMNistSingleLayerEvaluate.java .

Espero que esta breve ilustração esclareça como funciona um aplicativo Java que ensina e avalia um modelo.

Isso é tudo o que é exigido de nós, mas não hesite em brincar com o restante das fontes (juntamente com os scripts README.md e bash) e satisfazer sua curiosidade e compreensão de como isso é feito!

Valohai


O Valohai nos permite vincular livremente nosso tempo de execução, código e conjunto de dados, como você pode ver na estrutura do arquivo YAML abaixo. Assim, vários componentes podem se desenvolver independentemente um do outro. Consequentemente, apenas os componentes de montagem e tempo de execução são embalados em nosso contêiner Docker.

Em tempo de execução, coletamos o Uber JAR em um contêiner do Docker, carregamos em algum armazenamento interno ou externo e usamos a outra etapa de execução para carregar o Uber JAR e o conjunto de dados do armazenamento (ou outro local) para iniciar o treinamento. Assim, as duas etapas de execução são desconectadas; por exemplo, podemos compilar um frasco uma vez e concluir centenas de etapas de treinamento em um único frasco. Como os ambientes de montagem e tempo de execução não precisam ser alterados com tanta frequência, podemos armazená-los em cache e o código, conjuntos de dados e modelos podem ser acessados ​​dinamicamente no tempo de execução.

valohai.yaml
A principal parte da integração do nosso projeto Java com a infraestrutura Valohai é determinar a ordem das etapas de Execução no arquivo valohai.yaml localizado na raiz da pasta do seu projeto. Nosso valohai.yaml é assim:

 --- - step: name: Build-dl4j-mnist-single-layer-java-app image: neomatrix369/dl4j-mnist-single-layer:v0.5 command: - cd ${VH_REPOSITORY_DIR} - ./buildUberJar.sh - echo "~~~ Copying the build jar file into ${VH_OUTPUTS_DIR}" - cp target/MLPMnist-1.0.0-bin.jar ${VH_OUTPUTS_DIR}/MLPMnist-1.0.0.jar - ls -lash ${VH_OUTPUTS_DIR} environment: aws-eu-west-1-g2-2xlarge - step: name: Run-dl4j-mnist-single-layer-train-model image: neomatrix369/dl4j-mnist-single-layer:v0.5 command: - echo "~~~ Unpack the MNist dataset into ${HOME} folder" - tar xvzf ${VH_INPUTS_DIR}/dataset/mlp-mnist-dataset.tgz -C ${HOME} - cd ${VH_REPOSITORY_DIR} - echo "~~~ Copying the build jar file from ${VH_INPUTS_DIR} to current location" - cp ${VH_INPUTS_DIR}/dl4j-java-app/MLPMnist-1.0.0.jar . - echo "~~~ Run the DL4J app to train model based on the the MNist dataset" - ./runMLPMnist.sh {parameters} inputs: - name: dl4j-java-app description: DL4J Java app file (jar) generated in the previous step 'Build-dl4j-mnist-single-layer-java-app' - name: dataset default: https://github.com/neomatrix369/awesome-ai-ml-dl/releases/download/mnist-dataset-v0.1/mlp-mnist-dataset.tgz description: MNist dataset needed to train the model parameters: - name: --action pass-as: '--action {v}' type: string default: train description: Action to perform ie train or evaluate - name: --output-dir pass-as: '--output-dir {v}' type: string default: /valohai/outputs/ description: Output directory where the model will be created, best to pick the Valohai output directory environment: aws-eu-west-1-g2-2xlarge - step: name: Run-dl4j-mnist-single-layer-evaluate-model image: neomatrix369/dl4j-mnist-single-layer:v0.5 command: - cd ${VH_REPOSITORY_DIR} - echo "~~~ Copying the build jar file from ${VH_INPUTS_DIR} to current location" - cp ${VH_INPUTS_DIR}/dl4j-java-app/MLPMnist-1.0.0.jar . - echo "~~~ Run the DL4J app to evaluate the trained MNist model" - ./runMLPMnist.sh {parameters} inputs: - name: dl4j-java-app description: DL4J Java app file (jar) generated in the previous step 'Build-dl4j-mnist-single-layer-java-app' - name: model description: Model file generated in the previous step 'Run-dl4j-mnist-single-layer-train-model' parameters: - name: --action pass-as: '--action {v}' type: string default: evaluate description: Action to perform ie train or evaluate - name: --input-dir pass-as: '--input-dir {v}' type: string default: /valohai/inputs/model description: Input directory where the model created by the previous step can be found created environment: aws-eu-west-1-g2-2xlarge 

Como o Build-dl4j-mnist-single-layer-java-app funciona


No arquivo YAML, vemos que definimos essa etapa, primeiro usando a imagem do Docker e, em seguida, executando o script para criar o Uber JAR. Nossa imagem do docker possui personalização das dependências do ambiente de construção (por exemplo, GraalVM JDK, Maven etc.) para criar um aplicativo Java. Não fornecemos nenhuma entrada ou parâmetro, pois esta é a fase de montagem. Quando a compilação for bem-sucedida, copiamos o uber jar chamado MLPMnist-1.0.0-bin.jar (nome original) para a pasta / valohai / outputs (representada como $ {VH_OUTPUTS_DIR}). Tudo nesta pasta é salvo automaticamente no armazenamento do seu projeto, por exemplo, na lixeira do AWS S3. Por fim, definimos nosso trabalho para a AWS.

Nota
A conta gratuita do Valohai não tem acesso à rede a partir do contêiner do Docker (isso está desativado por padrão); entre em contato com o suporte para ativar esta opção (eu tive que fazer o mesmo); caso contrário, não conseguiremos baixar o Maven e outras dependências durante a montagem.

Como o modelo Run-dl4j-mnist-single-layer-train-train funciona


A semântica da definição é semelhante à etapa anterior, exceto que especificamos duas entradas: uma para o uber jar (MLPMnist-1.0.0.jar) e a outra para o conjunto de dados (descompactado na pasta $ {HOME} /. Deeplearning4j). Passaremos dois parâmetros - --action train e --output-dir / valohai / outputs. O modelo criado nesta etapa é construído em / valohai / outputs / model (representado como $ {VH_OUTPUTS_DIR} / model).

Nota
Nos campos de entrada na guia Execução da interface da web Valohai, podemos selecionar a saída das execuções anteriores usando o número da execução, ou seja, nº 1 ou nº 2, além de usar o dado: // ou http: / URLs /, inserir algumas letras do nome do arquivo também ajuda a pesquisar a lista inteira.

Como o Run-dl4j-mnist-single-layer -valu-model funciona


Novamente, esta etapa é semelhante à etapa anterior, exceto que passaremos dois parâmetros - action assessment e --input-dir / valohai / inputs / model. Além disso, indicamos novamente na entrada: as seções definidas no arquivo YAML com o nome dl4j-java-app e model sem o padrão para os dois. Isso nos permitirá selecionar o uber jar e o modelo que queremos avaliar - que foi criado usando a etapa Run-dl4j-mnist-single-layer-train-model-model usando a interface da web.

Espero que isso explique as etapas no arquivo de definição acima, mas se você precisar de mais ajuda, fique à vontade para visualizar a documentação e os tutoriais .

Interface Web Valohai


Após receber a conta, podemos efetuar login e continuar criando o projeto com o nome mlpmnist-single-layer e associar git repo github.com/valohai/mlpmnist-dl4j-example ao projeto e salvar o projeto.

Agora você pode concluir a etapa e ver como fica!

Construir um aplicativo Java DL4J


Vá para a guia "Execução" na interface da web e copie a execução existente ou crie uma nova usando o botão [Criar execução]. Todos os parâmetros padrão necessários serão preenchidos. Selecione Etapa Build-dl4j-mnist-single-layer-java-app.

Para o ambiente, selecionei AWS eu-west-1 g2.2xlarge e cliquei no botão [Criar execução] na parte inferior da página para ver o início da execução.



Modelo de treinamento


Vá para a guia "Execução" na interface da web e faça o mesmo da etapa anterior e selecione Executar-dl4j-mnist-modelo de trem de camada única. Você precisará selecionar o aplicativo Java (basta inserir jar no campo) criado na etapa anterior. O conjunto de dados já foi preenchido previamente usando o arquivo valohai.yaml:



Clique em [Criar execução] para iniciar.



Você verá o resultado no console:

 [<--- snipped --->] 11:17:05 ======================================================================= 11:17:05 LayerName (LayerType) nIn,nOut TotalParams ParamsShape 11:17:05 ======================================================================= 11:17:05 layer0 (DenseLayer) 784,1000 785000 W:{784,1000}, b:{1,1000} 11:17:05 layer1 (OutputLayer) 1000,10 10010 W:{1000,10}, b:{1,10} 11:17:05 ----------------------------------------------------------------------- 11:17:05 Total Parameters: 795010 11:17:05 Trainable Parameters: 795010 11:17:05 Frozen Parameters: 0 11:17:05 ======================================================================= [<--- snipped --->] 

Modelos criados podem ser encontrados na guia "Saídas" da guia principal "Execução" durante e após a execução:



Você pode observar vários artefatos na subguia Saídas. Isso ocorre porque mantemos pontos de controle no final de cada era. Vejamos isso nos logs:

 [<--- snipped --->] 11:17:14 odolCheckpointListener - Model checkpoint saved: epoch 0, iteration 469, path: /valohai/outputs/checkpoint_0_MultiLayerNetwork.zip [<--- snipped --->] 

O ponto de verificação contém o estado do modelo em três arquivos:

 configuration.json coefficients.bin updaterState.bin 

Modelo de treinamento. Metadados


Você deve ter notado essas entradas nos logs de execução:

 [<--- snipped --->] 11:17:05 {"epoch": 0, "iteration": 0, "score (loss function)": 2.410047} 11:17:07 {"epoch": 0, "iteration": 100, "score (loss function)": 0.613774} 11:17:09 {"epoch": 0, "iteration": 200, "score (loss function)": 0.528494} 11:17:11 {"epoch": 0, "iteration": 300, "score (loss function)": 0.400291} 11:17:13 {"epoch": 0, "iteration": 400, "score (loss function)": 0.357800} 11:17:14 odolCheckpointListener - Model checkpoint saved: epoch 0, iteration 469, path: /valohai/outputs/checkpoint_0_MultiLayerNetwork.zip [<--- snipped --->] 

Esses dados permitem que a Valohai obtenha esses valores (no formato JSON) que serão usados ​​para criar as métricas que podem ser vistas durante e após a execução na guia Metadados adicionais na guia principal Execuções:



Conseguimos fazer isso conectando a classe ValohaiMetadataCreator ao modelo, para que Valohai se refira a essa classe durante o treinamento. No caso desta classe, derivamos várias épocas, o número de iterações e Score (valor da função de perda). Aqui está um trecho de código da classe:

 public void iterationDone(Model model, int iteration, int epoch) { if (printIterations <= 0) printIterations = 1; if (iteration % printIterations == 0) { double score = model.score(); System.out.println(String.format( "{\"epoch\": %d, \"iteration\": %d, \"score (loss function)\": %f}", epoch, iteration, score) ); } } 

Avaliação do Modelo


Depois que o modelo foi criado com sucesso na etapa anterior, ele deve ser avaliado. Criamos uma nova execução da mesma maneira que antes, mas desta vez selecione a etapa Run-dl4j-mnist-single-layer -valu-model. Precisamos selecionar o aplicativo Java (MLPMnist-1.0.0.jar) e o modelo criado (mlpmnist-single-layer.pb) novamente antes de iniciar a execução (como mostrado abaixo):



Após selecionar o modelo desejado como entrada, clique no botão [Criar execução]. Ele será executado mais rápido que o anterior e veremos o seguinte resultado:



Vimos que nosso "mundo olá" levou a um modelo cuja precisão é de cerca de 97%, com base em um conjunto de dados de teste. A matriz de confusão ajuda a encontrar casos em que um dígito foi previsto incorretamente como outro dígito.

A questão permanece (e fora do escopo deste post) - quão bom é o modelo quando confrontado com dados reais?

Para clonar um repositório git, eis o que você precisa fazer:

  $ git clone https://github.com/valohai/mlpmnist-dl4j-example 

Em seguida, precisamos vincular nosso projeto Valohai, criado através da interface da web na seção acima, com o projeto armazenado em nossa máquina local (a que acabamos de clonar). Execute os seguintes comandos para fazer isso:

 $ cd mlpmnist-dl4j-example $ vh project --help ### to see all the project-specific options we have for Valohai $ vh project link 

Você será mostrado algo como isto:

 [ 1] mlpmnist-single-layer ... Which project would you like to link with /path/to/mlpmnist-dl4j-example? Enter [n] to create a new project.: 

Selecione 1 (ou aquele que combina com você) e você deverá ver esta mensagem:

 Success! Linked /path/to/mlpmnist-dl4j-example to mlpmnist-single-layer. 

Mais uma coisa, antes de prosseguir, verifique se o seu projeto Valohai está sincronizado com o projeto git mais recente, fazendo o seguinte:

  $ vh project fetch 



Agora podemos concluir as etapas da CLI com:

  $ vh exec run Build-dl4j-mnist-single-layer-java-app 

Após a execução, podemos verificar com:

 $ vh exec info $ vh exec logs $ vh exec watch 

Conclusão


Como vimos, é muito conveniente trabalhar com DL4J e Valohai juntos. Além disso, podemos desenvolver os vários componentes que compõem nossos experimentos (pesquisa), ou seja, o ambiente de compilação / tempo de execução, o código e o conjunto de dados e integrá-los ao nosso projeto.

Os modelos de amostra usados ​​nesta postagem são uma boa maneira de começar a criar projetos mais complexos. E você pode usar a interface da Web ou da linha de comando para fazer seu trabalho com o Valohai. Com a CLI, você também pode integrá-lo às suas instalações e scripts (ou mesmo aos trabalhos CRON ou CI / CD).

Além disso, é claro que, se estou trabalhando em um projeto relacionado à AI / ML / DL, não preciso me preocupar em criar e manter um pipeline de ponta a ponta (o que muitos outros tiveram que fazer no passado).

Referências

  1. O projeto mlpmnist-dl4j-examples no GitHub
  2. Recursos impressionantes de AI / ML / DL
  3. Recursos Java AI / ML / DL
  4. Recursos de Deep Learning e DL4J

Obrigado pela atenção!

Source: https://habr.com/ru/post/pt469405/


All Articles