One place for hosting & domains

      Construir

      Como Construir uma Rede Neural para Reconhecer Dígitos Manuscritos com o TensorFlow


      Introdução

      Redes neurais são usadas como um método de deep learning ou aprendizado profundo, um dos vários subcampos da inteligência artificial. Elas foram propostas pela primeira vez há cerca de 70 anos como uma tentativa de simular a maneira como o cérebro humano funciona, embora de uma forma muito mais simplificada. Os “neurônios” individuais são conectados em camadas, com pesos designados para determinar como o neurônio responde quando os sinais são propagados pela rede. Anteriormente, as redes neurais eram limitadas no número de neurônios que elas eram capazes de simular e, portanto, a complexidade do aprendizado que podiam alcançar. Mas nos últimos anos, devido aos avanços no desenvolvimento de hardware, pudemos construir redes muito profundas e treiná-las em enormes datasets ou conjuntos de dados para obter avanços na inteligência de máquinas.

      Essas inovações permitiram que as máquinas correspondessem e excedessem as capacidades dos humanos em realizar certas tarefas. Uma dessas tarefas é o reconhecimento de objetos. Embora as máquinas tenham sido historicamente incapazes de corresponder à visão humana, avanços recentes em deep learning tornaram possível construir redes neurais capazes de reconhecer objetos, rostos, textos e até mesmo emoções.

      Neste tutorial, você implementará uma pequena subseção de reconhecimento de objeto recognition—digit. Utilizando o TensorFlow, uma biblioteca Python open-source desenvolvida pelos laboratórios do Google Brain para pesquisa em deep learning, você pegará imagens desenhadas à mão dos números de 0 a 9 e construirá e treinará uma rede neural para reconhecer e prever o rótulo correto para o dígito exibido.

      Embora você não precise de experiência prévia em deep learning prático ou de uso do TensorFlow para acompanhar este tutorial, vamos assumir alguma familiaridade com termos e conceitos de machine learning, como treinamento e testes, recursos e rótulos, otimização e avaliação. Você pode aprender mais sobre esses conceitos em Uma Introdução ao Machine Learning.

      Pré-requisitos

      Para completar esse tutorial, você vai precisar de:

      Passo 1 — Configurando o Projeto

      Antes de desenvolver o programa de reconhecimento, você precisará instalar algumas dependências e criar um espaço de trabalho para armazenar seus arquivos.

      Usaremos um ambiente virtual do Python 3 para gerenciar as dependências do nosso projeto. Crie um novo diretório para o seu projeto e navegue até o novo diretório:

      • mkdir tensorflow-demo
      • cd tensorflow-demo

      Execute os seguintes comandos para configurar o ambiente virtual para este tutorial:

      • python3 -m venv tensorflow-demo
      • source tensorflow-demo/bin/activate

      Em seguida, instale as bibliotecas que você usará neste tutorial. Usaremos versões específicas dessas bibliotecas criando um arquivo requirements.txt no diretório do projeto, que especifica o requisito e a versão que precisamos. Crie o arquivo requirements.txt:

      Abra o arquivo em seu editor de textos e adicione as seguintes linhas para especificar as bibliotecas Image, NumPy, e TensorFlow e suas versões:

      requirements.txt

      image==1.5.20
      numpy==1.14.3
      tensorflow==1.4.0
      

      Salve o arquivo e saia do editor. Em seguida instale estas bibliotecas com o seguinte comando:

      • pip install -r requirements.txt

      Com as dependências instaladas, podemos começar a trabalhar no nosso projeto.

      Passo 2 — Importando o Dataset MNIST

      O dataset que estaremos utilizando neste tutorial é chamado de dataset MNIST, e ele é um clássico na comunidade de machine learning. Este dataset é composto de imagens de dígitos manuscritos, com 28x28 pixels de tamanho. Aqui estão alguns exemplos dos dígitos incluídos no dataset:

      Vamos criar um programa Python para trabalhar com este dataset. Usaremos um arquivo para todo o nosso trabalho neste tutorial. Crie um novo arquivo chamado main.py:

      Agora abra este arquivo no editor de textos de sua preferência e adicione esta linha de código ao arquivo para importar a biblioteca do TensorFlow:

      main.py

      import tensorflow as tf
      

      Adicione as seguintes linhas de código ao seu arquivo para importar o dataset MNIST e armazenar os dados da imagem na variável mnist:

      main.py

      from tensorflow.examples.tutorials.mnist import input_data
      mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # y labels are oh-encoded
      

      Ao ler os dados, estamos usando one-hot-encoding para representar os rótulos (o dígito real desenhado, por exemplo "3") das imagens. O one-hot-encoding utiliza um vetor de valores binários para representar valores numéricos ou categóricos. Como nossos rótulos são para os dígitos de 0 a 9, o vetor contém dez valores, um para cada dígito possível. Um desses valores é definido como 1, para representar o dígito nesse índice do vetor, e o restante é difinido como 0. Por exemplo, o dígito 3 é representado usando o vetor [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]. Como o valor no índice 3 está armazenado como 1, o vetor representa o dígito 3.

      Para representar as imagens, os 28x28 pixels são achatados em um vetor 1D com 784 pixels de tamanho. Cada um dos 784 pixels que compõem a imagem é armazenado como um valor entre 0 e 255. Isso determina a escala de cinza do pixel, pois nossas imagens são apresentadas apenas em preto e branco. Portanto, um pixel preto é representado por 255 e um pixel branco por 0, com os vários tons de cinza em algum lugar entre eles.

      Podemos usar a variável mnist para descobrir o tamanho do dataset que acabamos de importar. Observando os num_examples para cada um dos três subconjuntos, podemos determinar que o dataset foi dividido em 55.000 imagens para treinamento, 5000 para validação e 10.000 para teste. Adicione as seguintes linhas ao seu arquivo:

      main.py

      
      n_train = mnist.train.num_examples # 55,000
      n_validation = mnist.validation.num_examples # 5000
      n_test = mnist.test.num_examples # 10,000
      

      Agora que temos nossos dados importados, é hora de pensar sobre a rede neural.

      Passo 3 — Definindo a Arquitetura da Rede Neural

      A arquitetura da rede neural refere-se a elementos como o número de camadas na rede, o número de unidades em cada camada e como as unidades são conectadas entre as camadas. Como as redes neurais são vagamente inspiradas no funcionamento do cérebro humano, aqui o termo unidade é usado para representar o que seria biologicamente um neurônio. Assim como os neurônios transmitem sinais pelo cérebro, as unidades tomam alguns valores das unidades anteriores como entrada, realizam uma computação e, em seguida, transmitem o novo valor como saída para outras unidades. Essas unidades são colocadas em camadas para formar a rede, iniciando no mínimo com uma camada para entrada de valores e uma camada para valores de saída. O termo hidden layer ou camada oculta é usado para todas as camadas entre as camadas de entrada e saída, ou seja, aquelas "ocultas" do mundo real.

      Arquiteturas diferentes podem produzir resultados drasticamente diferentes, já que o desempenho pode ser pensado como uma função da arquitetura entre outras coisas, como os parâmetros, os dados e a duração do treinamento.

      Adicione as seguintes linhas de código ao seu arquivo para armazenar o número de unidades por camada nas variáveis globais. Isso nos permite alterar a arquitetura de rede em um único lugar e, no final do tutorial, você pode testar por si mesmo como diferentes números de camadas e unidades afetarão os resultados de nosso modelo:

      main.py

      
      n_input = 784   # input layer (28x28 pixels)
      n_hidden1 = 512 # 1st hidden layer
      n_hidden2 = 256 # 2nd hidden layer
      n_hidden3 = 128 # 3rd hidden layer
      n_output = 10   # output layer (0-9 digits)
      

      O diagrama a seguir mostra uma visualização da arquitetura que projetamos, com cada camada totalmente conectada às camadas adjacentes:

      O termo "deep neural network" ou rede neural profunda se relaciona com o número de camadas ocultas, com "superficial" geralmente significando apenas uma camada oculta e "profunda", referindo-se a várias camadas ocultas. Fornecidos dados de treinamento suficientes, uma rede neural superficial com um número suficiente de unidades deve teoricamente ser capaz de representar qualquer função que uma rede neural profunda possa. Mas é mais eficiente computacionalmente usar uma rede neural profunda menor para realizar a mesma tarefa que exigiria uma rede superficial com exponencialmente mais unidades ocultas. Redes neurais superficiais também freqüentemente encontram overfitting, onde a rede essencialmente memoriza os dados de treinamento que viu e não é capaz de generalizar o conhecimento para novos dados. É por isso que as redes neurais profundas são mais comumente usadas: as várias camadas entre os dados brutos de entrada e o rótulo de saída permitem que a rede aprenda recursos em vários níveis de abstração, tornando a própria rede mais capaz de generalizar.

      Outros elementos da rede neural que precisam ser definidos aqui são os hiperparâmetros. Ao contrário dos parâmetros que serão atualizados durante o treinamento, esses valores são definidos inicialmente e permanecem constantes durante todo o processo. No seu arquivo, defina as seguintes variáveis e valores:

      main.py

      
      learning_rate = 1e-4
      n_iterations = 1000
      batch_size = 128
      dropout = 0.5
      

      A taxa de aprendizado, learningrate, representa o quanto os parâmetros serão ajustados em cada etapa do processo de aprendizado. Esses ajustes são um componente-chave do treinamento: depois de cada passagem pela rede, ajustamos os pesos ligeiramente para tentar reduzir a perda. Taxas de aprendizado maiores podem convergir mais rapidamente, mas também têm o potencial de ultrapassar os valores ideais à medida que são atualizados. O número de iterações, niterations, refere-se a quantas vezes passamos pela etapa de treinamento e o tamanho do lote ou batch_size se refere a quantos exemplos de treinamento estamos usando em cada etapa. A variável dropout representa um limiar no qual eliminamos algumas unidades aleatoriamente. Estaremos usando dropout em nossa última camada oculta para dar a cada unidade 50% de chance de ser eliminada em cada etapa de treinamento. Isso ajuda a evitar o overfitting.

      Agora já definimos a arquitetura de nossa rede neural e os hiperparâmetros que impactam o processo de aprendizagem. O próximo passo é construir a rede como um gráfico do TensorFlow.

      Passo 4 — Construindo o Gráfico do TensorFlow

      Para construir nossa rede, vamos configurará-la como um gráfico computacional para o TensorFlow executar. O conceito central do TensorFlow é o tensor, uma estrutura de dados semelhante a uma matriz ou lista inicializada, manipulada à medida que passa pelo gráfico e atualizada através do processo de aprendizado.

      Começaremos definindo três tensores como placeholders ou marcadores de posição, que são tensores nos quais alimentaremos os valores posteriormente. Adicione o seguinte ao seu arquivo:

      main.py

      
      X = tf.placeholder("float", [None, n_input])
      Y = tf.placeholder("float", [None, n_output])
      keep_prob = tf.placeholder(tf.float32) ^
      

      O único parâmetro que precisa ser especificado em sua declaração é o tamanho dos dados os quais estaremos alimentando. Para X usamos um formato [None, 784], onde None representa qualquer quantidade, pois estaremos alimentando em um número indefinido de imagens de 784 pixels. O formato de Y é [None, 10] pois iremos usá-lo para um número indefinido de saídas de rótulo, com 10 classes possíveis. O tensor keep_prob é usado para controlar a taxa de dropout, e nós o inicializamos como um placeholder ao invés de uma variável imutável porque queremos usar o mesmo tensor tanto para treinamento (quando dropout é definido para 0.5) quanto para testes (quando dropout é definido como 1.0).

      Os parâmetros que a rede atualizará no processo de treinamento são os valores weight e bias, portanto, precisamos definir um valor inicial em vez de um placeholder vazio. Esses valores são essencialmente onde a rede faz seu aprendizado, pois são utilizados nas funções de ativação dos neurônios, representando a força das conexões entre as unidades.

      Como os valores são otimizados durante o treinamento, podemos defini-los para zero por enquanto. Mas o valor inicial realmente tem um impacto significativo na precisão final do modelo. Usaremos valores aleatórios de uma distribuição normal truncada para os pesos. Queremos que eles estejam próximos de zero, para que possam se ajustar em uma direção positiva ou negativa, e um pouco diferente, para que gerem erros diferentes. Isso garantirá que o modelo aprenda algo útil. Adicione estas linhas:

      main.py

      
      weights = {
          'w1': tf.Variable(tf.truncated_normal([n_input, n_hidden1], stddev=0.1)),
          'w2': tf.Variable(tf.truncated_normal([n_hidden1, n_hidden2], stddev=0.1)),
          'w3': tf.Variable(tf.truncated_normal([n_hidden2, n_hidden3], stddev=0.1)),
          'out': tf.Variable(tf.truncated_normal([n_hidden3, n_output], stddev=0.1)),
      }
      

      Para o bias ou tendência, usamos um pequeno valor constante para garantir que os tensores se ativem nos estágios iniciais e, portanto, contribuam para a propagação. Os pesos e tensores de bias são armazenados em objetos de dicionário para facilitar o acesso. Adicione este código ao seu arquivo para definir cada bias:

      main.py

      
      biases = {
          'b1': tf.Variable(tf.constant(0.1, shape=[n_hidden1])),
          'b2': tf.Variable(tf.constant(0.1, shape=[n_hidden2])),
          'b3': tf.Variable(tf.constant(0.1, shape=[n_hidden3])),
          'out': tf.Variable(tf.constant(0.1, shape=[n_output]))
      }
      

      Em seguida, configure as camadas da rede definindo as operações que manipularão os tensores. Adicione estas linhas ao seu arquivo:

      main.py

      
      layer_1 = tf.add(tf.matmul(X, weights['w1']), biases['b1'])
      layer_2 = tf.add(tf.matmul(layer_1, weights['w2']), biases['b2'])
      layer_3 = tf.add(tf.matmul(layer_2, weights['w3']), biases['b3'])
      layer_drop = tf.nn.dropout(layer_3, keep_prob)
      output_layer = tf.matmul(layer_3, weights['out']) + biases['out']
      

      Cada camada oculta executará a multiplicação da matriz nas saídas da camada anterior e os pesos da camada atual e adicionará o bias a esses valores. Na última camada oculta, aplicaremos uma operação de eliminação usando nosso valor keep_prob de 0.5.

      O passo final na construção do gráfico é definir a função de perda que queremos otimizar. Uma escolha popular da função de perda nos programas do TensorFlow é a cross-entropy ou entropia cruzada, também conhecida como log-loss, que quantifica a diferença entre duas distribuições de probabilidade (as predições e os rótulos). Uma classificação perfeita resultaria em uma entropia cruzada de 0, com a perda completamente minimizada.

      Também precisamos escolher o algoritmo de otimização que será usado para minimizar a função de perda. Um processo denominado otimização gradiente descendente é um método comum para encontrar o mínimo (local) de uma função, tomando etapas iterativas ao longo do gradiente em uma direção negativa (descendente). Existem várias opções de algoritmos de otimização de gradiente descendente já implementados no TensorFlow, e neste tutorial vamos usar o otimizador Adam. Isso se estende à otimização de gradiente descendente usando o momento para acelerar o processo através do cálculo de uma média exponencialmente ponderada dos gradientes e usando isso nos ajustes. Adicione o seguinte código ao seu arquivo:

      main.py

      
      cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=output_layer))
      train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
      

      Agora acabamos de definir a rede e a construímos com o TensorFlow. O próximo passo é alimentar os dados através do gráfico para treiná-los e, em seguida, testar se realmente aprendeu alguma coisa.

      Passo 5 — Treinando e Testando

      O processo de treinamento envolve alimentar o dataset de treinamento através do gráfico e otimizar a função de perda. Toda vez que a rede itera um lote de mais imagens de treinamento, ela atualiza os parâmetros para reduzir a perda, a fim de prever com mais precisão os dígitos exibidos. O processo de teste envolve a execução do nosso dataset de teste através do gráfico treinado e o acompanhamento do número de imagens que são corretamente previstas, para que possamos calcular a precisão.

      Antes de iniciar o processo de treinamento, definiremos nosso método de avaliação da precisão para que possamos imprimi-lo em mini-lotes de dados enquanto treinamos. Estas declarações impressas nos permitem verificar que, da primeira iteração até a última, a perda diminui e a precisão aumenta; elas também nos permitem rastrear se executamos ou não repetições suficientes para alcançar um resultado consistente e ideal:

      main.py

      correct_pred = tf.equal(tf.argmax(output_layer, 1), tf.argmax(Y, 1))
      accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
      

      Em correct_pred, usamos a função arg_max para comparar quais imagens estão sendo previstas corretamente observando output_layer (predições) e Y (labels), e usamos a função equal para retornar isso como uma lista de Booleanos. Podemos, então, converter essa lista em floats e calcular a média para obter uma pontuação total da precisão.

      Agora estamos prontos para inicializar uma sessão para executar o gráfico. Nesta sessão, vamos alimentar a rede com nossos exemplos de treinamento e, uma vez treinados, alimentamos o mesmo gráfico com novos exemplos de teste para determinar a precisão do modelo. Adicione as seguintes linhas de código ao seu arquivo:

      main.py

      
      init = tf.global_variables_initializer()
      sess = tf.Session()
      sess.run(init)
      

      A essência do processo de treinamento em deep learning é otimizar a função de perda. Aqui, pretendemos minimizar a diferença entre os rótulos previstos das imagens e os rótulos verdadeiros das imagens. O processo envolve quatro etapas que são repetidas para um número definido de iterações:

      Em cada etapa de treinamento, os parâmetros são ligeiramente ajustados para tentar reduzir a perda para a próxima etapa. À medida que o aprendizado avança, devemos ver uma redução na perda e, eventualmente, podemos parar de treinar e usar a rede como um modelo para testar nossos novos dados.

      Adicione este código ao arquivo:

      main.py

      
      # train on mini batches
      for i in range(n_iterations):
          batch_x, batch_y = mnist.train.next_batch(batch_size)
          sess.run(train_step, feed_dict={X: batch_x, Y: batch_y, keep_prob:dropout})
      
          # print loss and accuracy (per minibatch)
          if i%100==0:
              minibatch_loss, minibatch_accuracy = sess.run([cross_entropy, accuracy], feed_dict={X: batch_x, Y: batch_y, keep_prob:1.0})
              print("Iteration", str(i), "t| Loss =", str(minibatch_loss), "t| Accuracy =", str(minibatch_accuracy))
      

      Após 100 iterações de cada etapa de treinamento em que alimentamos um mini-lote de imagens através da rede, imprimimos a perda e a precisão desse lote. Observe que não devemos esperar uma perda decrescente e uma precisão crescente aqui, pois os valores são por lote, não para o modelo inteiro. Usamos mini-lotes de imagens em vez de alimentá-las individualmente para acelerar o processo de treinamento e permitir que a rede veja vários exemplos diferentes antes de atualizar os parâmetros.

      Quando o treinamento estiver concluído, podemos executar a sessão nas imagens de teste. Desta vez estamos usando uma taxa de dropout keep_prob de 1.0 para garantir que todas as unidades estejam ativas no processo de teste.

      Adicione este código ao arquivo:

      main.py

      
      test_accuracy = sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob:1.0})
      print("nAccuracy on test set:", test_accuracy)
      

      Agora é hora de executar nosso programa e ver com que precisão nossa rede neural pode reconhecer esses dígitos manuscritos. Salve o arquivo main.py e execute o seguinte comando no terminal para executar o script:

      Você verá uma saída semelhante à seguinte, embora os resultados individuais de perda e precisão possam variar um pouco:

      Output

      Iteration 0 | Loss = 3.67079 | Accuracy = 0.140625 Iteration 100 | Loss = 0.492122 | Accuracy = 0.84375 Iteration 200 | Loss = 0.421595 | Accuracy = 0.882812 Iteration 300 | Loss = 0.307726 | Accuracy = 0.921875 Iteration 400 | Loss = 0.392948 | Accuracy = 0.882812 Iteration 500 | Loss = 0.371461 | Accuracy = 0.90625 Iteration 600 | Loss = 0.378425 | Accuracy = 0.882812 Iteration 700 | Loss = 0.338605 | Accuracy = 0.914062 Iteration 800 | Loss = 0.379697 | Accuracy = 0.875 Iteration 900 | Loss = 0.444303 | Accuracy = 0.90625 Accuracy on test set: 0.9206

      Para tentar melhorar a precisão do nosso modelo, ou para saber mais sobre o impacto dos hiperparâmetros de ajuste, podemos testar o efeito de alterar a taxa de aprendizado, o limite de dropout, o tamanho do lote e o número de iterações. Também podemos alterar o número de unidades em nossas camadas ocultas e alterar a quantidade das próprias camadas ocultas, para ver como diferentes arquiteturas aumentam ou diminuem a precisão do modelo.

      Para demonstrar que a rede está realmente reconhecendo as imagens desenhadas à mão, vamos testá-la em uma única imagem nossa.

      Primeiro, faça o download dessa amostra de imagem de teste ou abra um editor gráfico e crie sua própria imagem de 28x28 pixels de um dígito.

      Abra o arquivo main.py no seu editor e adicione as seguintes linhas de código ao topo do arquivo para importar duas bibliotecas necessárias para a manipulação de imagens.

      main.py

      
      import numpy as np
      from PIL import Image
      ...
      

      Em seguida, no final do arquivo, adicione a seguinte linha de código para carregar a imagem de teste do dígito manuscrito:

      main.py

      
      img = np.invert(Image.open("test_img.png").convert('L')).ravel()
      

      A função open da bibliotecaImage carrega a imagem de teste como um array 4D contendo os três canais de cores RGB e a transparência Alpha. Esta não é a mesma representação que usamos anteriormente ao ler o dataset com o TensorFlow, portanto, precisamos fazer algum trabalho extra para corresponder ao formato.

      Primeiro, usamos a função convert com o parâmetro L para reduzir a representação 4D RGBA para um canal de cor em escala de cinza. Aarmazenamos isso como um array numpy e o invertemos usando np.invert, porque a matriz atual representa o preto como 0 e o branco como 255, porém, precisamos do oposto. Finalmente, chamamos ravel para achatar o array.

      Agora que os dados da imagem estão estruturados corretamente, podemos executar uma sessão da mesma forma que anteriormente, mas desta vez apenas alimentando uma imagem única para teste. Adicione o seguinte código ao seu arquivo para testar a imagem e imprimir o rótulo de saída.

      [labe main.py]
      prediction = sess.run(tf.argmax(output_layer,1), feed_dict={X: [img]})
      print ("Prediction for test image:", np.squeeze(prediction))
      

      A função np.squeeze é chamada na predição para retornar o único inteiro da matriz (ou seja, para ir de [2] para 2). A saída resultante demonstra que a rede reconheceu essa imagem como o dígito 2.

      Output

      Prediction for test image: 2

      Você pode tentar testar a rede com imagens mais complexas - dígitos que se parecem com outros dígitos, por exemplo, ou dígitos que foram mal desenhados ou desenhados incorretamente - para ver como ela se sai.

      Conclusão

      Neste tutorial você treinou com sucesso uma rede neural para classificar o dataset MNIST com cerca de 92% de precisão e testou em uma imagem sua. O estado da arte em pesquisa atual alcança cerca de 99% neste mesmo problema, usando arquiteturas de rede mais complexas envolvendo camadas convolucionais. Elas usam a estrutura 2D da imagem para melhor representar o conteúdo, ao contrário do nosso método que achata todos os pixels em um vetor de 784 unidades. Você pode ler mais sobre esse tópico no website do TensorFlow, e ver os documentos de pesquisa detalhando os resultados mais precisos no wesite do MNIST.

      Agora que você sabe como construir e treinar uma rede neural, pode tentar usar essa implementação em seus próprios dados ou testá-la em outros datasets populares, como o Google StreetView House Numbers, ou o dataset CIFAR-10 para um reconhecimento de imagem mais genérico.

      Por Ellie Birbeck



      Source link

      Como Construir um Classificador de Machine Learning em Python com Scikit-learn


      Introdução

      Machine learning ou Aprendizado de máquina é um campo de pesquisa em ciência da computação, inteligência artificial, e estatística. O foco do Machine Learning é treinar algoritmos para aprender padrões e fazer previsões a partir de dados. Machine learning é especialmente valioso porque ele nos leva a utilizar computadores para automatizar o processo de tomada de decisões.

      Você encontrará aplicações de Machine learning em todos os lugares. Netflix e Amazon usam machine learning para fazer novas recomendações de produtos. Bancos usam machine learning para detectar atividades fraudulentas em transações de cartões de crédito, e empresas de assistência à saúde estão começando a usar machine learning para monitorar, avaliar e diagnosticar pacientes.

      Neste tutorial vamos implementar um algoritmo simples de machine learning em Python utilizando Scikit-learn, uma ferramenta de machine learning para Python. Usando um banco de dados de informações sobre tumores de câncer de mama, iremos usar um classificador Naive Bayes (NB) que prevê se um tumor é maligno ou benigno.

      No final deste tutorial, você saberá como construir o seu próprio modelo de machine learning em Python.

      Pré-requisitos

      Para completar este tutorial, você precisará de:

      Passo 1 — Importando o Scikit-learn

      Vamos começar instalando o módulo Python Scikit-learn, um das melhores e mais bem documentadas bibliotecas de machine learning para Python.

      Para começar com nosso projeto de codificação, vamos ativar nosso ambiente de programação Python 3. Certifique-se de estar no diretório onde o seu ambiente está localizado, e execute o seguinte comando:

      Com seu ambiente de programação ativado, verifique se o módulo Scikit-learn já está instalado:

      • python -c "import sklearn"

      Se o sklearn estiver instalado, este comando irá completar sem erros. Se ele não estiver instalado, você verá a seguinte mensagem de erro:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ImportError: No module named 'sklearn'

      A mensagem de erro indica que o módulo sklearn não está instalado, então baixe o biblioteca usando o pip:

      • pip install scikit-learn[alldeps]

      Quando a instalação estiver concluída, inicie o Jupyter Notebook:

      No Jupyter, crie um novo Python Notebook chamado ML Tutorial. Na primeira célula do Notebook, importe o módulo sklearn.

      ML Tutorial

      
      import sklearn
      
      

      Seu notebook deve se parecer com a figura a seguir:

      Agora que temos o sklearn importado em nosso notebook, podemos começar a trabalhar com o dataset para o nosso modelo de machine learning.

      Passo 2 — Importando o Dataset do Scikit-learn

      O dataset com o qual estaremos trabalhando neste tutorial é o Breast Cancer Wisconsin Diagnostic Database. O dataset inclui várias informações sobre tumores de câncer de mama, bem como rótulos de classificação como malignos ou benignos. O dataset tem 569 instâncias, ou dados, sobre 569 tumores e inclui informações sobre 30 atributos, ou características, tais como o raio do tumor, textura, suavidade, e área.

      Utilizando este dataset, construiremos um modelo de machine learning para utilizar as informações sobre tumores para prever se um tumor é maligno ou benigno.

      O Scikit-learn vem instalado com vários datasets que podemos carregar no Python, e o dataset que queremos está incluído. Importe e carregue o dataset:

      ML Tutorial

      
      ...
      
      from sklearn.datasets import load_breast_cancer
      
      # Carregar o dataset
      data = load_breast_cancer()
      
      

      A variável data representa um objeto Python que funciona como um dicionário. As chaves importantes do dicionário a considerar são os nomes dos rótulos de classificação (target_names), os rótulos reais (target), os nomes de atributo/característica (feature_names), e os atributos (data).

      Atributos são uma parte crítica de qualquer classificador. Os atributos capturam características importantes sobre a natureza dos dados. Dado o rótulo que estamos tentando prever (tumor maligno versus benigno), os possíveis atributos úteis incluem o tamanho, raio, e a textura do tumor.

      Crie novas variáveis para cada conjunto importante de informações e atribua os dados:

      ML Tutorial

      
      ...
      
      # Organizar nossos dados
      label_names = data['target_names']
      labels = data['target']
      feature_names = data['feature_names']
      features = data['data']
      
      

      Agora temos listas para cada conjunto de informações. Para entender melhor nosso conjunto de dados, vamos dar uma olhada em nossos dados imprimindo nossos rótulos de classe, o primeiro rótulo da instância de dados, nossos nomes de características, e os valores das características para a primeira instância de dados.

      ML Tutorial

      
      ...
      
      # Olhando para os nossos dados
      print(label_names)
      print(labels[0])
      print(feature_names[0])
      print(features[0])
      
      

      Você verá os seguintes resultados se você executar o código:

      Como mostra a imagem, nossos nomes de classes são malignant and benign (maligno e benigno), que são então mapeados para valores binários de 0 e 1, onde 0 representa tumores malignos e 1 representa tumores benignos. Portanto, nossa primeira instância de dados é um tumor maligno cujo raio médio é 1.79900000e+01.

      Agora que temos nossos dados carregados, podemos trabalhar com eles para construir nosso classificador de machine learning.

      Passo 3 — Organizando Dados em Conjuntos

      Para avaliar o desempenho de um classificador, você deve sempre testar o modelo em dados não visualizados. Portanto, antes da construção de um modelo, divida seus dados em duas partes: um conjunto de treinamento e um conjunto de testes.

      Você usa o conjunto de testes para treinar e avaliar o modelo durante o estágio de desenvolvimento. Então você usa o modelo treinado para fazer previsões no conjunto de testes não visualizado. Essa abordagem lhe dá uma noção do desempenho e robustez do modelo.

      Felizmente, o sklearn tem uma função chamada train_test_split(), que divide seus dados nesses conjuntos. Importe a função e em seguida utilize-a para dividir os dados:

      ML Tutorial

      
      ...
      
      from sklearn.model_selection import train_test_split
      
      # Dividir nossos dados
      train, test, train_labels, test_labels = train_test_split(features,
                                                                labels,
                                                                test_size=0.33,
                                                                random_state=42)
      
      

      A função divide aleatoriamente os dados usando o parâmetro test_size. Neste exemplo, agora temos um conjunto de testes (test) que representa 33% do dataset original. Os dados restantes (train) formam então os dados de treinamento. Também temos os respectivos rótulos para ambas as variáveis train/test, ou seja, train_labels e test_labels.

      Agora podemos passar para o treinamento do nosso primeiro modelo.

      Passo 4 — Construindo e Avaliando o Modelo

      Existem muitos modelos para machine learning, e cada modelo tem seus pontos fortes e fracos. Neste tutorial, vamos nos concentrar em um algoritmo simples que geralmente funciona bem em tarefas de classificação binária, a saber Naive Bayes (NB).

      Primeiro, importe o módulo GaussianNB. Em seguida inicialize o modelo com a função GaussianNB(), depois treine o modelo, ajustando-o aos dados usando gnb.fit():

      ML Tutorial

      
      ...
      
      from sklearn.naive_bayes import GaussianNB
      
      # Inicializar nosso classificador
      gnb = GaussianNB()
      
      # Treinar nosso classificador
      model = gnb.fit(train, train_labels)
      
      

      Depois de treinarmos o modelo, podemos usar o modelo treinado para fazer previsões no nosso conjunto de teste, o que fazemos utilizando a função predict(). A função predict() retorna uma matriz de previsões para cada instância de dados no conjunto de testes. Podemos então, imprimir nossas previsões para ter uma ideia do que o modelo determinou.

      Utilize a função predict() com o conjunto test e imprima os resultados:

      ML Tutorial

      
      ...
      
      # Fazer previsões
      preds = gnb.predict(test)
      print(preds)
      
      

      Execute o código e você verá os seguintes resultados:

      Como você vê na saída do Jupyter Notebook, a função predict() retornou uma matriz de 0s e 1s que representa nossos valores previstos para a classe tumor (maligno vs. benigno).

      Agora que temos nossas previsões, vamos avaliar o desempenho do nosso classificador.

      Passo 5 — Avaliando a Precisão do Modelo

      Usando a matriz de rótulos de classe verdadeira, podemos avaliar a precisão dos valores previstos do nosso modelo comparando as duas matrizes (test_labels vs. preds). Utilizaremos a função accuracy_score() do sklearn para determinar a precisão do nosso classificador de machine learning.

      ML Tutorial

      
      ...
      
      from sklearn.metrics import accuracy_score
      
      # Avaliar a precisão
      print(accuracy_score(test_labels, preds))
      
      

      Você verá os seguintes resultados:

      Como você vê na saída, o classificador NB é 94.15% preciso. Isso significa que 94,15 porcento do tempo o classificador é capaz de fazer a previsão correta se o tumor é maligno ou benigno. Esses resultados sugerem que nosso conjunto de características de 30 atributos são bons indicadores da classe do tumor.

      Você construiu com sucesso seu primeiro classificador de machine learning. Vamos reorganizar o código colocando todas as declarações import no topo do Notebook ou script. A versão final do código deve ser algo assim:

      ML Tutorial

      
      from sklearn.datasets import load_breast_cancer
      from sklearn.model_selection import train_test_split
      from sklearn.naive_bayes import GaussianNB
      from sklearn.metrics import accuracy_score
      
      # Carregar o dataset
      data = load_breast_cancer()
      
      # Organizar nossos dados
      label_names = data['target_names']
      labels = data['target']
      feature_names = data['feature_names']
      features = data['data']
      
      # Olhando para os nossos dados
      print(label_names)
      print('Class label = ', labels[0])
      print(feature_names)
      print(features[0])
      
      # Dividir nossos dados
      train, test, train_labels, test_labels = train_test_split(features,
                                                                labels,
                                                                test_size=0.33,
                                                                random_state=42)
      
      # Inicializar nosso classificador
      gnb = GaussianNB()
      
      # Treinar nosso classificador
      model = gnb.fit(train, train_labels)
      
      # Fazer previsões
      preds = gnb.predict(test)
      print(preds)
      
      # Avaliar a precisão
      print(accuracy_score(test_labels, preds))
      
      

      Agora você pode continuar trabalhando com seu código para ver se consegue fazer com que seu classificador tenha um desempenho ainda melhor. Você pode experimentar com diferentes subconjuntos de características ou mesmo tentar algoritmos completamente diferentes. Confira o website do Scikit-learn para mais ideias sobre machine learning.

      Conclusão

      Neste tutorial, você aprendeu como construir um classificador de machine learning em Python. Agora você pode carregar dados, organizar dados, treinar, prever e avaliar classificadores de machine learning em Python usando o Scikit-learn. Os passos deste tutorial devem ajudá-lo a facilitar o processo de trabalhar com seus próprios dados no Python.

      Traduzido Por Fernando Pimenta



      Source link

      Como Construir Imagens Docker e Hospedar um Repositório de Imagens Docker com o GitLab


      Introdução

      A containerização está rapidamente se tornando o método de empacotamento e deploy de aplicações mais aceito nos ambientes de nuvem. A padronização que ele fornece, juntamente com sua eficiência de recursos (quando comparado a máquinas virtuais completas) e flexibilidade, o tornam um grande facilitador da moderna mentalidade DevOps. Muitas estratégias interessantes de deployment, orquestração e monitoramento nativas para nuvem tornam-se possíveis quando suas aplicações e microsserviços são totalmente containerizados.

      Os containers Docker são de longe os tipos mais comuns de container atualmente. Embora os repositórios públicos de imagem do Docker como o Docker Hub estejam repletos de imagens de software opensource containerizado que você pode fazer um docker pull hoje, para código privado você precisará pagar um serviço para construir e armazenar suas imagens, ou executar seu próprio software para fazer isso.

      O GitLab Community Edition é um pacote de software auto-hospedado que fornece hospedagem de repositório Git, acompanhamento de projetos, serviços de CI/CD, e um registro de imagem Docker, entre outros recursos. Neste tutorial vamos utilizar o serviço de integração contínua do GitLab para construir imagens Docker a partir de uma aplicação de exemplo em Node.js. Estas imagens serão então testadas e carregadas para o nosso próprio registro privado do Docker.

      Pré-requisitos

      Antes de começarmos, precisamos configurar um servidor GitLab seguro, e um GitLab CI runner para executar tarefas de integração contínua. As seções abaixo fornecerão links e maiores detalhes.

      Um Servidor Gitlab Protegido com SSL

      Para armazenar nosso código fonte, executar tarefas de CI/CD, e hospedar um registro Docker, precisamos de uma instância do GitLab instalada em um servidor Ubuntu 16.04. Atualmente, o GitLab recomenda um servidor com pelo menos 2 núcleos de CPU e 4GB de RAM. Adicionalmente, iremos proteger o servidor com certificados SSL do Let’s Encrypt. Para fazer isto, precisaremos de um nome de domínio apontando para o servidor.

      Você pode completar esses pré-requisitos com os seguintes tutoriais:

      Um GitLab CI Runner

      O tutorial Como configurar pipelines de integração contínua com o GitLab CI no Ubuntu 16.04 fornecerá uma visão geral do serviço de CI ou integração contínua do GitLab e mostrará como configurar um CI runner para processar jobs. Vamos construir isso em cima da aplicação de demonstração e da infraestrutura do runner criados neste tutorial.

      Passo 1 — Configurando um GitLab CI Runner Privilegiado

      No pré-requisito do tutorial de integração contínua com o GitLab, configuramos um GitLab runner utilizando sudo gitlab-runner register e seu processo de configuração interativo. Este runner é capaz de executar builds e testes de software dentro de containers Docker isolados.

      Entretanto, para se construir imagens Docker, nosso runner precisa de acesso total ao próprio serviço do Docker. A maneira recomendada de se configurar isto é utilizar a imagem docker-in-docker oficial do Docker para executar os jobs. Isto requer conceder ao runner um modo de execução privileged ou privilegiado. Portanto, criaremos um segundo runner com este modo ativado.

      Nota: Conceder ao runner o modo privileged basicamente desativa todas as vantagens de segurança da utilização de containers. Infelizmente, os outros métodos de ativar runners compatíveis com o Docker também carregam implicações de segurança semelhantes. Por favor, veja a documentação oficial do GitLab no Docker Build para aprender mais sobre as diferentes opções de runners e qual é a melhor para a sua situação.

      Como existem implicações de segurança para a utilização de runner privilegiado, vamos criar um runner específico do projeto que aceitará somente jobs de Docker em nosso projeto hello_hapi (Os administradores de GitLab sempre podem adicionar manualmente esse runner a outros projetos posteriormente). A partir da página do nosso projeto hello_hapi, clique em Settings na parte inferior do menu à esquerda, em seguida clique em CI/CD no sub-menu:

      Agora, clique no botão Expand ao lado da seção de configurações de Runners:

      Haverá algumas informações sobre como configurar um Specific Runner, incluindo um token de registro. Tome nota desse token. Quando o utilizamos para registrar um novo runner, o runner será bloqueado apenas para este projeto.

      Estando nesta página, clique no botão Disable shared Runners. Queremos ter certeza de que nossos jobs de Docker sempre executarão em nosso runner privilegiado. Se um runner compartilhado não privilegiado estivesse disponível, o GitLab pode optar por utilizá-lo, o que resultaria em erros de build.

      Faça o login no servidor que possui o seu CI runner atual. Se você não tiver uma máquina já configurada com os runners, volte e complete a seção Installing the GitLab CI Runner Service do tutorial de pré-requisitos antes de continuar.

      Agora, execute o seguinte comando para configurar o runner privilegiado específico do projeto:

      • sudo gitlab-runner register -n
      • --url https://gitlab.example.com/
      • --registration-token seu-token
      • --executor docker
      • --description "docker-builder"
      • --docker-image "docker:latest"
      • --docker-privileged

      Output

      Registering runner... succeeded runner=61SR6BwV Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

      Certifique-se de substituir suas próprias informações. Nós definimos todas as opções do nosso runner na linha de comando em vez de usar os prompts interativos, porque os prompts não nos permitem especificar o modo --docker-privileged.

      Agora o seu runner está configurado, registrado e executando. Para verificar, volte ao seu navegador. Clique no ícone de chave inglesa na barra de menu principal do GitLab, em seguida clique em Runners no menu à esquerda. Seus runners serão listados:

      Agora que temos um runner capaz de criar imagens do Docker, vamos configurar um registro privado do Docker para carregar imagens para ele.

      Passo 2 — Configurando o Registro Docker do GitLab

      Configurar seu próprio registro do Docker permite que você envie e extraia imagens de seu próprio servidor privado, aumentando a segurança e reduzindo as dependências do seu fluxo de trabalho em serviços externos.

      O GitLab irá configurar um registro Docker privado com apenas algumas atualizações de configuração. Primeiro vamos configurar a URL onde o registro irá residir. Depois, iremos (opcionalmente) configurar o registro para usar um serviço de armazenamento de objetos compatível com S3 para armazenar seus dados.

      Faça SSH em seu servidor GitLab, depois abra o arquivo de configuração do GitLab:

      • sudo nano /etc/gitlab/gitlab.rb

      Role para baixo até a seção Container Registry settings. Vamos descomentar a linha registry_external_url e configurá-la para o nosso host GitLab com a porta número 5555:

      /etc/gitlab/gitlab.rb

      
      registry_external_url 'https://gitlab.example.com:5555'
      

      A seguir, adicione as duas linhas seguintes para dizer ao registro onde encontrar nossos certificados Let’s Encrypt:

      /etc/gitlab/gitlab.rb

      
      registry_nginx['ssl_certificate'] = "/etc/letsencrypt/live/gitlab.example.com/fullchain.pem"
      registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/gitlab.example.com/privkey.pem"
      

      Salve e feche o arquivo, depois reconfigure o GitLab:

      • sudo gitlab-ctl reconfigure

      Output

      . . . gitlab Reconfigured!

      Atualize o firewall para pemitir tráfego para a porta do registro:

      Agora mude para outra máquina com o Docker instalado e efetue o login no registro Docker privado. Se você não tiver o Docker no seu computador de desenvolvimento local, você pode usar qualquer servidor configurado para executar seus jobs do GitLab CI, já que ele tem o Docker instalado:

      • docker login gitlab.example.com:5555

      Você será solicitado para inserir o seu nome de usuário e senha. Use suas credenciais do GitLab para efetuar login.

      Output

      Login Succeeded

      Sucesso! O registro está configurado e funcionando. Atualmente, ele armazenará arquivos no sistema de arquivos local do servidor GitLab. Se você quiser usar um serviço de armazenamento de objetos, continue com esta seção. Se não, pule para o Passo 3.

      Para configurar um backend de armazenamento de objetos para o registro, precisamos saber as seguintes informações sobre o nosso serviço de armazenamento de objetos:

      • Access Key

      • Secret Key

      • Region (us-east-1) por exemplo, se estiver usando Amazon S3, ou Region Endpoint se estiver usando um serviço compatível com S3 (https://nyc.digitaloceanspaces.com)

      • Nome do Bucket

      Se você estiver usando o DigitalOcean Spaces, você pode descobrir como configurar um novo Space e obter as informações acima lendo Como Criar um Space e uma Chave de API na DigitalOcean.

      Quando você tiver suas informações sobre o amazenamento de objetos, abra o arquivo de configuração do GitLab:

      • sudo nano /etc/gitlab/gitlab.rb

      Novamente, role até a seção de registro do container. Procure pelo bloco registry['storage'], descomente o bloco e atualize-o para o seguinte, novamente certificando-se de substituir suas próprias informações, quando apropriado:

      /etc/gitlab/gitlab.rb

      
      registry['storage'] = {
        's3' => {
          'accesskey' => 'sua-key',
          'secretkey' => 'seu-secret',
          'bucket' => 'seu-bucket-name',
          'region' => 'nyc3',
          'regionendpoint' => 'https://nyc3.digitaloceanspaces.com'
        }
      }
      

      Se você estiver uando Amazon S3, você precisa apenas da region e não do regionendpoint. Se estiver usando um serviço S3 compatível, como o Spaces, você irá precisar do regionendpoint. Neste caso, region na verdade não configura nada e o valor que você digita não importa, mas ainda precisa estar presente e não em branco.

      Salve e feche o arquivo.

      Nota: Atualmente, há um bug em que o registro será encerrado após trinta segundos se seu bucket de armazenamento de objetos estiver vazio. Para evitar isso, coloque um arquivo no seu bucket antes de executar a próxima etapa. Você poderá removê-lo mais tarde, após o registro ter adicionado seus próprios objetos.

      Se você estiver usando o Spaces da DigitalOcean, você pode arrastar e soltar um arquivo para carregá-lo usando a interface do Painel de Controle.

      Reconfigure o GitLab mais uma vez:

      • sudo gitlab-ctl reconfigure

      Em sua outra máquina Docker, efetue login no registro novamente para ter certeza de que tudo está bem:

      • docker login gitlab.example.com:5555

      Você deve receber uma mensagem de Login Succeeded.

      Agora que temos nosso registro do Docker configurado, vamos atualizar a configuração de CI da nossa aplicação para criar e testar nossa app, e enviar as imagens Docker para o nosso registro privado.

      Passo 3 — Atualizando o gitlab-ci.yaml e Construindo uma Imagem Docker

      Nota: Se você não concluiu o artigo de pré-requisito do GitLab CI você precisará copiar o repositório de exemplo para o seu servidor GitLab. Siga a seção Copying the Example Repository From GitHub para fazer isto.

      Para que possamos fazer o building de nossa app no Docker, precisamos atualizar o arquivo .gitlab-ci.yml. Você pode editar este arquivo diretamente no GitLab clicando na página principal do projeto, e depois no botão Edit. Alternativamente, você poderia clonar o repositório para a sua máquina local, editar o arquivo, e então fazer um git push nele de volta para o GitLab. Isso ficaria assim:

      • git clone git@gitlab.example.com:sammy/hello_hapi.git
      • cd hello_hapi
      • # edit the file w/ your favorite editor
      • git commit -am "updating ci configuration"
      • git push

      Primeiro, exclua tudo no arquivo, depois cole nele a seguinte configuração:

      .gitlab-ci.yml

      
      image: docker:latest
      services:
      - docker:dind
      
      stages:
      - build
      - test
      - release
      
      variables:
        TEST_IMAGE: gitlab.example.com:5555/sammy/hello_hapi:$CI_COMMIT_REF_NAME
        RELEASE_IMAGE: gitlab.example.com:5555/sammy/hello_hapi:latest
      
      before_script:
        - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN gitlab.example.com:5555
      
      build:
        stage: build
        script:
          - docker build --pull -t $TEST_IMAGE .
          - docker push $TEST_IMAGE
      
      test:
        stage: test
        script:
          - docker pull $TEST_IMAGE
          - docker run $TEST_IMAGE npm test
      
      release:
        stage: release
        script:
          - docker pull $TEST_IMAGE
          - docker tag $TEST_IMAGE $RELEASE_IMAGE
          - docker push $RELEASE_IMAGE
        only:
          - master
      

      Certifique-se de atualizar os URLs e nomes de usuários realçados com suas próprias informações e, em seguida, salve com o botão Commit changes no GitLab. Se você está atualizando o arquivo fora do GitLab, confirme as mudanças e faça git push de volta no GitLab.

      Este novo arquivo de configuração diz ao GitLab para usar a imagem mais recente do docker (image: docker:latest) e vinculá-la ao serviço docker-in-docker (docker:dind). Então, ele define os estágios de build, test, e release. O estágio de build cria a imagem do Docker usando o Dockerfile fornecido pelo repositório, em seguida o carrega para o nosso registro de imagens Docker. Se isso for bem sucedido, o estágio test vai baixar a imagem que acabamos de construir e executar o comando npm test dentro dele. Se o estágio test for bem sucedido, o estágio release irá lançar a imagem, irá colocar uma tag como hello_hapi:latest e irá retorná-la ao registro.

      Dependendo do seu fluxo de trabalho, você também pode adicionar mais estágios test, ou mesmo estágios deploy que levam o aplicativo para um ambiente de preparação ou produção.

      A atualização do arquivo de configuração deve ter acionado um novo build. Volte ao projeto hello_hapi no GitLab e clique no indicador de status do CI para o commit:

      Na página resultante, você pode clicar em qualquer um dos estágios para ver seu progresso:

      Eventualmente, todas as etapas devem indicar que eles foram bem sucedidos, mostrando ícones com a marca de verificação em verde. Podemos encontrar as imagens Docker que acabaram de ser construídas clicando no item Registry no menu à esquerda:

      Se você clicar no pequeno ícone "document" ao lado do nome da imagem, ele copiará o comando apropriado docker pull ... para a sua área de transferência. Você pode então baixar e executar sua imagem:

      • docker pull gitlab.example.com:5555/sammy/hello_hapi:latest
      • docker run -it --rm -p 3000:3000 gitlab.example.com:5555/sammy/hello_hapi:latest

      Output

      > hello@1.0.0 start /usr/src/app > node app.js Server running at: http://56fd5df5ddd3:3000

      A imagem foi baixada do registro e iniciada em um container. Mude para o seu navegador e conecte-se ao aplicativo na porta 3000 para testar. Neste caso, estamos executando o container em nossa máquina local, assim podemos acessá-la via localhost na seguinte URL:

      http://localhost:3000/hello/test
      

      Output

      Hello, test!

      Sucesso! Você pode parar o container com CTRL-C. A partir de agora, toda vez que enviarmos um novo código para a ramificação master do nosso repositório, vamos construir e testar automaticamente uma nova imagem hello_hapi: latest.

      Conclusão

      Neste tutorial, configuramos um novo GitLab runner para criar imagens do Docker, criamos um regisro privado do Docker para armazená-las, e atualizamos um app Node.js para ser construído e testado dentro de containers Docker.

      Para aprender mais sobre os vários componentes utilizados nesta configuração, você pode ler a documentação oficial do GitLab CE, GitLab Container Registry, e do Docker.

      Por Brian Boucheron



      Source link