Aprendizado de máquina com Spark MLlib

Aprendizado de máquina com Spark MLlib

1. Visão geral

Neste tutorial, vamos entender como aproveitarApache Spark MLlib para desenvolver produtos de aprendizado de máquina. Vamos desenvolver um produto de aprendizado de máquina simples com Spark MLlib para demonstrar os conceitos principais.

2. Um breve resumo do aprendizado de máquina

O aprendizado de máquina épart of a broader umbrella known as Artificial Intelligence. O aprendizado de máquina refere-se aostudy of statistical models to solve specific problems com padrões e inferências. Esses modelos são "treinados" para o problema específico por meio de dados de treinamento extraídos do espaço do problema.

Veremos o que exatamente esta definição implica ao seguirmos nosso exemplo.

2.1. Categorias de aprendizado de máquina

Podemos amplamentecategorize machine learning into supervised and unsupervised categorias com base na abordagem. Existem outras categorias também, mas nos limitaremos a estas duas:

  • Aprendizagem supervisionadaworks with a set of data that contains both the inputs and the desired output - por exemplo, um conjunto de dados contendo várias características de uma propriedade e a receita de aluguel esperada. O aprendizado supervisionado é dividido em duas grandes subcategorias, denominadas classificação e regressão:

    • Os algoritmos de classificação estão relacionados à saída categórica, como se uma propriedade está ocupada ou não

    • Os algoritmos de regressão estão relacionados a um intervalo de saída contínuo, como o valor de uma propriedade

  • Aprendizagem não supervisionada, por outro lado,works with a set of data which only have input values. Ele funciona tentando identificar a estrutura inerente nos dados de entrada. Por exemplo, encontrar diferentes tipos de consumidores por meio de um conjunto de dados de seu comportamento de consumo.

2.2. Fluxo de trabalho de aprendizado de máquina

O aprendizado de máquina é realmente uma área interdisciplinar de estudo. Requer conhecimento do domínio comercial, estatística, probabilidade, álgebra linear e programação. Como isso pode ser claramente opressor,it’s best to approach this in an orderly fashion, o que normalmente chamamos de fluxo de trabalho de aprendizado de máquina:

image

Como podemos ver, todo projeto de aprendizado de máquina deve começar com uma declaração de problema claramente definida. Isso deve ser seguido por uma série de etapas relacionadas aos dados que podem potencialmente responder ao problema.

Em seguida, normalmente selecionamos um modelo que analisa a natureza do problema. Isso é seguido por uma série de treinamento e validação de modelo, conhecido como ajuste fino do modelo. Finalmente, testamos o modelo em dados não vistos anteriormente e o implantamos na produção, se satisfatório.

3. O que é o Spark MLlib?

Spark MLlib éa module on top of Spark Core that provides machine learning primitives como APIs. O aprendizado de máquina geralmente lida com uma grande quantidade de dados para o treinamento do modelo.

A estrutura básica de computação do Spark é um grande benefício. Além disso, o MLlib fornece a maioria dos populares algoritmos de aprendizado de máquina e estatísticos. Isso simplifica bastante a tarefa de trabalhar em um projeto de aprendizado de máquina em larga escala.

4. Aprendizado de máquina com MLlib

Agora temos contexto suficiente no aprendizado de máquina e como o MLlib pode ajudar nesse empreendimento. Vamos começar com nosso exemplo básico de implementação de um projeto de aprendizado de máquina com Spark MLlib.

Se nos lembrarmos de nossa discussão sobre o fluxo de trabalho de aprendizado de máquina, devemos começar com uma declaração do problema e depois passar para os dados. Felizmente para nós, escolheremos o “hello world” do aprendizado de máquina,Iris Dataset. Este é um conjunto de dados rotulado multivariado, composto por comprimento e largura de sépalas e pétalas de diferentes espécies de íris.

Isso nos dá o objetivo do problema:can we predict the species of an Iris from the length and width of its sepal and petal?

4.1. Definindo as dependências

Primeiro, temos que definir o seguintedependency in Maven para extrair as bibliotecas relevantes:


    org.apache.spark
    spark-mllib_2.11
    2.4.3
    provided

E precisamos inicializar o SparkContext para trabalhar com as APIs do Spark:

SparkConf conf = new SparkConf()
  .setAppName("Main")
  .setMaster("local[2]");
JavaSparkContext sc = new JavaSparkContext(conf);

4.2. Carregando os dados

Primeiramente, devemos fazer o download dos dados, que estão disponíveis como um arquivo de texto no formato CSV. Então temos que carregar esses dados no Spark:

String dataFile = "data\\iris.data";
JavaRDD data = sc.textFile(dataFile);

O Spark MLlib oferece vários tipos de dados, locais e distribuídos, para representar os dados de entrada e os rótulos correspondentes. O mais simples dos tipos de dados éVector:

JavaRDD inputData = data
  .map(line -> {
      String[] parts = line.split(",");
      double[] v = new double[parts.length - 1];
      for (int i = 0; i < parts.length - 1; i++) {
          v[i] = Double.parseDouble(parts[i]);
      }
      return Vectors.dense(v);
});

Observe que incluímos apenas os recursos de entrada aqui, principalmente para realizar análises estatísticas.

Um exemplo de treinamento normalmente consiste em vários recursos de entrada e um rótulo, representado pela classeLabeledPoint:

Map map = new HashMap<>();
map.put("Iris-setosa", 0);
map.put("Iris-versicolor", 1);
map.put("Iris-virginica", 2);

JavaRDD labeledData = data
  .map(line -> {
      String[] parts = line.split(",");
      double[] v = new double[parts.length - 1];
      for (int i = 0; i < parts.length - 1; i++) {
          v[i] = Double.parseDouble(parts[i]);
      }
      return new LabeledPoint(map.get(parts[parts.length - 1]), Vectors.dense(v));
});

Nosso rótulo de saída no conjunto de dados é textual, significando as espécies de Iris. Para alimentar isso em um modelo de aprendizado de máquina, precisamos convertê-lo em valores numéricos.

4.3. Análise exploratória de dados

A análise exploratória dos dados envolve a análise dos dados disponíveis. Agora,machine learning algorithms are sensitive towards data quality, portanto, dados de qualidade mais alta têm melhores perspectivas de entregar o resultado desejado.

Os objetivos típicos da análise incluem remover anomalias e detectar padrões. Isso alimenta as etapas críticas da engenharia de recursos para obter recursos úteis a partir dos dados disponíveis.

Nosso conjunto de dados, neste exemplo, é pequeno e bem formado. Portanto, não temos que nos entregar a muitas análises de dados. O Spark MLlib, no entanto, está equipado com APIs para oferecer um insight.

Vamos começar com algumas análises estatísticas simples:

MultivariateStatisticalSummary summary = Statistics.colStats(inputData.rdd());
System.out.println("Summary Mean:");
System.out.println(summary.mean());
System.out.println("Summary Variance:");
System.out.println(summary.variance());
System.out.println("Summary Non-zero:");
System.out.println(summary.numNonzeros());

Aqui, estamos observando a média e a variação dos recursos que temos. Isso é útil para determinar se precisamos executar a normalização de recursos. Éuseful to have all features on a similar scale. Também estamos anotando valores diferentes de zero, que podem afetar adversamente o desempenho do modelo.

Aqui está a saída para nossos dados de entrada:

Summary Mean:
[5.843333333333332,3.0540000000000003,3.7586666666666666,1.1986666666666668]
Summary Variance:
[0.6856935123042509,0.18800402684563744,3.113179418344516,0.5824143176733783]
Summary Non-zero:
[150.0,150.0,150.0,150.0]

Outra métrica importante a ser analisada é a correlação entre os recursos nos dados de entrada:

Matrix correlMatrix = Statistics.corr(inputData.rdd(), "pearson");
System.out.println("Correlation Matrix:");
System.out.println(correlMatrix.toString());

Ahigh correlation between any two features suggests they are not adding any incremental valuee um deles podem ser descartados. Aqui está como nossos recursos são correlacionados:

Correlation Matrix:
1.0                   -0.10936924995064387  0.8717541573048727   0.8179536333691672
-0.10936924995064387  1.0                   -0.4205160964011671  -0.3565440896138163
0.8717541573048727    -0.4205160964011671   1.0                  0.9627570970509661
0.8179536333691672    -0.3565440896138163   0.9627570970509661   1.0

4.4. Dividindo os dados

Se recordarmos nossa discussão sobre o fluxo de trabalho de aprendizado de máquina, isso envolve várias iterações de treinamento e validação de modelos, seguidas de testes finais.

Para que isso aconteça,we have to split our training data into training, validation, and test sets. Para manter as coisas simples, vamos pular a parte de validação. Então, vamos dividir nossos dados em conjuntos de treinamento e teste:

JavaRDD[] splits = parsedData.randomSplit(new double[] { 0.8, 0.2 }, 11L);
JavaRDD trainingData = splits[0];
JavaRDD testData = splits[1];

4.5. Treinamento do modelo

Então, chegamos a um estágio em que analisamos e preparamos nosso conjunto de dados. Tudo o que resta é alimentar isso em um modelo e começar a mágica! Bem, é mais fácil falar do que fazer. Precisamos escolher um algoritmo adequado para o nosso problema - lembre-se das diferentes categorias de aprendizado de máquina das quais falamos anteriormente.

Não é difícil entender queour problem fits into classification within the supervised category. Agora, existem alguns algoritmos disponíveis para uso nesta categoria.

O mais simples deles é regressão logística (não deixe a palavra regressão nos confundir; é, afinal, um algoritmo de classificação):

LogisticRegressionModel model = new LogisticRegressionWithLBFGS()
  .setNumClasses(3)
  .run(trainingData.rdd());

Aqui, estamos usando um classificador de três classes com memória limitada BFGS. Os detalhes deste algoritmo estão além do escopo deste tutorial, mas este é um dos mais usados.

4.6. Avaliação do Modelo

Lembre-se de que o treinamento do modelo envolve várias iterações, mas para simplificar, usamos apenas uma única passagem aqui. Agora que treinamos nosso modelo, é hora de testar isso no conjunto de dados de teste:

JavaPairRDD predictionAndLabels = testData
  .mapToPair(p -> new Tuple2<>(model.predict(p.features()), p.label()));
MulticlassMetrics metrics = new MulticlassMetrics(predictionAndLabels.rdd());
double accuracy = metrics.accuracy();
System.out.println("Model Accuracy on Test Data: " + accuracy);

Agora, como medimos a eficácia de um modelo? Existemseveral metrics that we can use, but one of the simplest is Accuracy. Simplificando, precisão é uma proporção entre o número correto de previsões e o número total de previsões. Aqui está o que podemos alcançar em uma única execução do nosso modelo:

Model Accuracy on Test Data: 0.9310344827586207

Observe que isso varia um pouco de execução para execução devido à natureza estocástica do algoritmo.

No entanto, a precisão não é uma métrica muito eficaz em alguns domínios problemáticos. Outromore sophisticated metrics are Precision and Recall (F1 Score), ROC Curve, and Confusion Matrix.

4.7. Salvando e carregando o modelo

Por fim, geralmente precisamos salvar o modelo treinado no sistema de arquivos e carregá-lo para previsão nos dados de produção. Isso é trivial no Spark:

model.save(sc, "model\\logistic-regression");
LogisticRegressionModel sameModel = LogisticRegressionModel
  .load(sc, "model\\logistic-regression");
Vector newData = Vectors.dense(new double[]{1,1,1,1});
double prediction = sameModel.predict(newData);
System.out.println("Model Prediction on New Data = " + prediction);

Então, estamos salvando o modelo no sistema de arquivos e carregando-o de volta. Após o carregamento, o modelo pode ser usado imediatamente para prever a saída em novos dados. Aqui está uma amostra de previsão sobre novos dados aleatórios:

Model Prediction on New Data = 2.0

5. Além do exemplo primitivo

Embora o exemplo a seguir tenhamos abordado o fluxo de trabalho de um projeto de aprendizado de máquina em geral, ele deixa muitos pontos sutis e importantes. Embora não seja possível discuti-los em detalhes aqui, certamente podemos passar por alguns dos mais importantes.

O Spark MLlib por meio de suas APIs tem amplo suporte em todas essas áreas.

5.1. Seleção de modelo

A seleção de modelos geralmente é uma das tarefas complexas e críticas. Treinar um modelo é um processo complicado e é muito melhor fazer em um modelo que estamos mais confiantes de que produzirá os resultados desejados.

Embora a natureza do problema possa nos ajudar a identificar a categoria de algoritmo de aprendizado de máquina a ser escolhido, não é um trabalho totalmente realizado. Dentro de uma categoria como a classificação, como vimos anteriormente,there are often many possible different algorithms and their variations to choose from.

Frequentementethe best course of action is quick prototyping on a much smaller set of data. Uma biblioteca como o Spark MLlib facilita muito o trabalho de prototipagem rápida.

5.2. Ajuste do parâmetro de modelo

Um modelo típico consiste em recursos, parâmetros e hiperparâmetros. Recursos são o que alimentamos no modelo como dados de entrada. Parâmetros do modelo são variáveis ​​aprendidas pelo modelo durante o processo de treinamento. Dependendo do modelo,there are certain additional parameters that we have to set based on experience and adjust iteratively. Estes são chamados de hiper-parâmetros do modelo.

Por exemplo, a taxa de aprendizado é um hiperparâmetro típico em algoritmos baseados em descida por gradiente. A taxa de aprendizado controla a rapidez com que os parâmetros são ajustados durante os ciclos de treinamento. Isso deve ser definido adequadamente para que o modelo aprenda efetivamente a um ritmo razoável.

Embora possamos começar com um valor inicial desses hiperparâmetros com base na experiência, precisamos executar a validação do modelo e ajustá-los manualmente iterativamente.

5.3. Desempenho do modelo

Um modelo estatístico, enquanto está sendo treinado, éprone to overfitting and underfitting, both causing poor model performance. A falta de ajuste refere-se ao caso em que o modelo não seleciona os detalhes gerais suficientemente dos dados. Por outro lado, o ajuste excessivo acontece quando o modelo também começa a captar ruído dos dados.

Existem vários métodos para evitar os problemas de ajuste insuficiente e excessivo, que geralmente são empregados em conjunto. Por exemplo,to counter overfitting, the most employed techniques include cross-validation and regularization. Da mesma forma, para melhorar a falta de ajuste, podemos aumentar a complexidade do modelo e aumentar o tempo de treinamento.

O Spark MLlib tem suporte fantástico para a maioria dessas técnicas, como regularização e validação cruzada. De fato, a maioria dos algoritmos tem suporte padrão para eles.

6. Spark MLlib em comparação

Embora o Spark MLlib seja uma biblioteca bastante poderosa para projetos de aprendizado de máquina, certamente não é a única para o trabalho. Existem várias bibliotecas disponíveis em diferentes linguagens de programação com suporte variado. Veremos alguns dos mais populares aqui.

6.1. Tensorflow/Keras

Tensorflow é umlibrary for dataflow and differentiable programming, widely employed for machine learning applications de código aberto. Junto com sua abstração de alto nível,Keras, é uma ferramenta de escolha para aprendizado de máquina. Eles são escritos principalmente em Python e C ++ e usados ​​principalmente em Python. Ao contrário do Spark MLlib, ele não possui presença poliglota.

6.2. Theano

Theano é outrolibrary for manipulating and evaluating mathematical expressions de código aberto baseado em Python - por exemplo, expressões baseadas em matriz, que são comumente usadas em algoritmos de aprendizado de máquina. Ao contrário do Spark MLlib, o Theano é novamente usado principalmente em Python. Keras, no entanto, pode ser usado junto com um back-end Theano.

6.3. CNTK

Microsoft Cognitive Toolkit (CNTK) é uma * estrutura de aprendizagem profunda escrita em C que descreve as etapas computacionais por meio de um gráfico direcionado *. Ele pode ser usado em programas Python e C e é usado principalmente no desenvolvimento de redes neurais. Há um back-end Keras baseado em CNTK disponível para uso que fornece a abstração intuitiva familiar.

7. Conclusão

Para resumir, neste tutorial, abordamos os conceitos básicos de aprendizado de máquina, incluindo diferentes categorias e fluxos de trabalho. Examinamos o básico do Spark MLlib como uma biblioteca de aprendizado de máquina disponível para nós.

Além disso, desenvolvemos um aplicativo simples de aprendizado de máquina com base no conjunto de dados disponível. Implementamos algumas das etapas mais comuns no fluxo de trabalho de aprendizado de máquina em nosso exemplo.

Também passamos por algumas das etapas avançadas de um projeto típico de aprendizado de máquina e como o Spark MLlib pode ajudá-lo. Por fim, vimos algumas das bibliotecas alternativas de aprendizado de máquina disponíveis para uso.

Como sempre, o código pode ser encontradoover on GitHub.