Dois anos parecem uma eternidade no mundo do software. Nos últimos dois anos, vimos uma ascensão meteórica da mídia social, a transformação em commodity da computação em cluster em grande escala (graças a empresas como Amazon e RackSpace) e um crescimento de grandes proporções nos dados e na nossa habilidade de interpretá-los. E faz dois anos desde que Introducing Apache Mahout" foi publicado pela primeira vez no developerWorks. Desde então, a comunidade Mahout — e a base de código e recursos do projeto — cresceu significativamente. Mahout também viu uma adoção significativa pelas grandes e pequenas empresas ao redor do mundo.
No meu artigo anterior sobre Mahout, apresentei muitos dos conceitos de aprendizado de máquina e os fundamentos do uso do conjunto de algoritmos do Mahout. Os conceitos apresentados ainda são válidos, mas o conjunto de algoritmos mudou de maneira bastante significativa. Em vez de passar pelos fundamentos mais uma vez, este artigo foca no status atual do Mahout e em como escalar o Mahout por meio de um cluster de computador usando o serviço EC2 da Amazon e um conjunto de dados composto de 7 milhões de documentos de email. Para uma revisão dos fundamentos, consulte os Recursos, especialmente o livro Mahout in Action . Ainda, irei presumir um conhecimento básico sobre o Apache Hadoop e o paradigma de Redução de Mapa.(Consulte Recursos para mais informações sobre Hadoop.)
O Mahout percorreu um longo caminho em um curto período. Embora o foco do projeto ainda esteja no que gosto de chamar de os "três Cs" — filtragem Colaborativa (recomendadores), armazenamento em Cluster e Classificação — o projeto também adicionou outros recursos. Destacarei algumas das principais expansões e melhorias em duas áreas: algoritmos essenciais (implementações) para aprendizado de máquina e infraestrutura de suporte, incluindo ferramentas de entrada/saída, pontos de integração com outras bibliotecas e mais exemplos para referência. Observe, porém, que esse status não é completo. Além disso, o espaço limitado deste artigo significa que posso oferecer somente algumas frases sobre cada uma das melhorias. Incentivo os leitores a buscar mais informações lendo a seção News do website do Mahout e as notas sobre a liberação para cada uma dos releases do Mahout.
Algoritmos, algoritmos, algoritmos
Depois de tentar solucionar problemas de aprendizado de máquina por um tempo, percebe-se rapidamente que nenhum algoritmo é adequado para todas as situações. Assim, o Mahout adicionou várias implementações novas. A Tabela 1 contém minha seleção das novas implementações algorítmicas mais significativas no Mahout, bem como alguns casos de uso de exemplo. Colocarei alguns desses algoritmos em funcionamento mais adiante neste artigo.
Tabela 1. Novos algoritmos no Mahout
| Algoritmo | Breve descrição | Caso de uso |
|---|---|---|
| Regressão logística, solucionada pelo Stochastic Gradient Descent (SGD) | Classificador sequencial simples e extremamente rápido com capacidade de aprendizado on-line em ambientes exigentes | Recomendação de anúncios a usuários, classificação de texto em categorias |
| Hidden Markov Models (HMM) | Implementações sequenciais e paralelas do clássico algoritmo de classificação para modelar processos do mundo real quando o processo de geração subjacente é desconhecido | Identificação de texto de parte do discurso; reconhecimento de discurso |
| Singular Value Decomposition (SVD) | Projetada para reduzir o ruído em grandes matrizes, tornando-as menores e mais fáceis de trabalhar | Como um precursor ao armazenamento em cluster, recomendadores e classificação para realizar a seleção de recurso automaticamente |
| Armazenamento em cluster Dirichlet | Abordagem com base em modelo ao armazenamento em cluster que determina a associação de acordo com se os dados se ajustam ao modelo subjacente | Útil quando os dados têm sobreposição ou hierarquia |
| Armazenamento em cluster espectral | Família de abordagens similares que usam uma abordagem com base em gráfico para determinar a associação do cluster | Como todos os algoritmos de armazenamento em cluster, útil para explorar conjuntos de dados grandes e não vistos |
| Armazenamento em cluster Minhash | Usa uma estratégia de hashing para agrupar itens similares, produzindo, assim, os clusters | Igual a outras abordagens de armazenamento em cluster |
| Diversas melhorias de recomendador | Coocorrências distribuídas, SVD, mínimos quadrados alternados | Sites de namoro, e-commerce, recomendações de filmes ou livros |
| Disposições | Implementação de disposições ativadas para redução de mapa | Localização de frases estatisticamente interessantes em texto |
O Mahout também adicionou vários algoritmos matemáticos de nível baixo (consulte o pacote de matemática) que os usuários podem considerar úteis. Muitos deles são usados pelos algoritmos descritos na Tabela 1, mas são projetados para serem de uso geral e, assim, podem ser adequados às suas necessidades.
Melhorando e expandindo a infraestrutura do Mahout
Conforme mais pessoas usam um projeto de software livre e trabalham para fazer o código do projeto funcionar com o seu código, mais a infraestrutura é preenchida. Para o Mahout, essa evolução levou a diversas melhorias. A mais importante é uma interface de linha de comando muito aprimorada e consistente, que torna mais fácil enviar e executar tarefas localmente e no Apache Hadoop. Esse novo script está localizado no diretório bin dentro do diretório de nível superior do Mahout (ao qual me referirei como $MAHOUT_HOME a partir de agora). (Consulte a barra lateral linha de comando do Mahout .)
Dois componentes principais de qualquer biblioteca de aprendizado de máquina são uma biblioteca de matemática confiável e um pacote de coleções eficiente. A biblioteca de matemática (localizada no módulo de matemática sob $MAHOUT_HOME) fornece uma ampla variedade de funcionalidades — desde estruturas de dados representando vetores, matrizes e operadores relacionados para manipulá-los até ferramentas para gerar números aleatórios e estatísticas úteis, como a probabilidade de log (consulte os Recursos). A biblioteca de coleções do Mahout consiste em estruturas de dados similares àquelas fornecidas por coleções Java (Map, List, entre outras), exceto que têm suporte nativo para primitivas Java como int, float e double em das suas contrapartes Object de Integer, Float e Double. Isso é importante porque cada bit (pun desejado) conta quando se está lidando com conjuntos de dados que podem ter milhões de recursos. Além disso, o custo de encaixotamento entre primitivas e suas contrapartes Object é proibitivo em grande escala.
O Mahout também apresentou um novo módulo de integração contendo código projetado para complementar ou estender as capacidades principais do Mahout, mas não é necessário para todos em todas as situações. Por exemplo, o código do recomendador (filtragem colaborativa) agora tem suporte para armazenar seu modelo em um banco de dados (via JDBC), MongoDB ou Apache Cassandra (consulte os Recursos). Os mecanismos de integração também contêm vários mecanismos para colocar os dados nos formatos do Mahout, bem como avaliar os resultados que são produzidos. Por exemplo, inclui ferramentas que podem converter diretórios repletos de arquivos de texto para o formato de vetor do Mahout (consulte o pacote org.apache.mahout.text no módulo de Integração).
Por fim, o Mahout tem vários novos exemplos, desde calcular recomendações com o conjunto de dados Netflix até armazenamento em cluster de música Last.fm e muitos outros recursos. Além disso, o exemplo que desenvolvi para este artigo também foi adicionado à base de código do Mahout. Incentivo-o a reservar algum tempo para explorar o módulo de exemplos (localizado em $MAHOUT_HOME/examples) em mais detalhes.
Agora que você se atualizou sobre o estado do Mahout, é hora de aprofundar-se no evento principal: como escalar o Mahout.
Fazer o Mahout escalar de maneira eficaz não é tão direto quando simplesmente adicionar mais nós ao cluster Hadoop. Fatores como a escolha do algoritmo, o número de nós, a seleção do recurso e a escassez de dados — bem como os suspeitos comuns de memória, largura de banda e velocidade do processador — desempenham um papel para determinar com quanta eficácia o Mahout pode escalar. Para motivar a discussão, trabalharei com um exemplo de executar alguns dos algoritmos do Mahout em um conjunto de dados disponível ao público de archives de email da Apache Software Foundation (ASF) usando a infraestrutura de computação EC2 da Amazon Hadoop, quando adequado (consulte os Recursos).
Cada uma das subseções após a Configuração requer uma revisão dos problemas principais de escalar o Mahout e explora a sintaxe da execução do exemplo em EC2.
A configuração para os exemplos envolve duas partes: uma configuração local e uma configuração em EC2 (nuvem). Para executar os exemplos, é preciso:
- Apache Maven 3.0.2 ou superior.
- Sistema de controle de versão Git (você também pode desejar ter uma conta Github ).
- Um sistema operacional com base em *NIX, como Linux ou Apple OS X. Cygwin pode funcionar para Windows®, mas não o testei.
Para configurar localmente, execute o seguinte na linha de comando:
mkdir -p scaling_mahout/data/samplegit clone git://github.com/lucidimagination/mahout.git mahout-trunkcd mahout-trunkmvn install(adicione-DskipTestsse desejar ignorar testes do Mahout, que podem levar um tempo para serem executados)cd bin/mahout(deve ser possível ver uma listagem de itens que podem ser executados, comokmeans)
Isso deve fazer todo o código necessário ser compilado e instalado adequadamente. Separadamente, faça o download dos dados de amostra, salve no diretório scaling_mahout/data/sample e desempacote-o (tar -xf scaling_mahout.tar.gz). Para fins de teste, esse é um subconjunto pequeno dos dados que serão usados em EC2.
Para configurar na Amazon, é preciso ter uma conta Amazon Web Services (AWS) (anotando sua chave secreta, chave de acesso e ID da conta) e um entendimento básico de como a EC2 da Amazon e os serviços Elastic Block Store (EBS) funcionam. Siga a documentação no website da Amazon para obter o acesso necessário.
Com os pré-requisitos cumpridos, é hora de ativar um cluster. Provavelmente é melhor começar com um único nó e então adicionar nós conforme o necessário. E observe, é claro, que executar na EC2 custa dinheiro. Portanto, certifique-se de desligar seus nós quando tiver concluído a execução.
Para realizar a inicialização automática de um cluster para uso com os exemplos neste artigo, siga estas etapas:
- Faça o download do Hadoop 0.20.203.0 a partir de um espelho da ASF e desempacote-o localmente.
cd hadoop-0.20.203.0/src/contrib/ec2/bin- Abra hadoop-ec2-env.sh em um editor e:
- Preencha seu
AWS_ACCOUNT_ID,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,EC2_KEYDIR,KEY_NAMEePRIVATE_KEY_PATH. Consulte a página de Wikis do Mahout "Use an Existing Hadoop AMI" para mais informações (consulte Recursos). - Configure
HADOOP_VERSIONpara0.20.203.0. - Configure
S3_BUCKETpara490429964467. - Configure
ENABLE_WEB_PORTS=true. - Configure
INSTANCE_TYPEparam1.xlargeno mínimo.
- Preencha seu
- Aba hadoop-ec2-init-remote.sh em um editor e:
- Na seção que cria hadoop-site.xml, adicione a seguinte propriedade:
<property> <name>mapred.child.java.opts></name> <value>-Xmx8096m></value> </property>
Observação: se você desejar executar classificação, é preciso usar uma instância maior e mais memória. Usei instâncias X-Large duplas e 12GB de heap. - Altere
mapred.output.compressparafalse.
- Na seção que cria hadoop-site.xml, adicione a seguinte propriedade:
- Ative seu cluster:
./hadoop-ec2 launch-cluster mahout-clustering X
Xé o número de nós que você deseja ativar (por exemplo,2ou10). Sugiro começar com um valor pequeno e então adicionar nós conforme seu nível de conforto aumenta. Isso ajudará a controlar os custos. - Crie um volume EBS para o Conjunto de Dados Públicos da ASF (Captura instantânea: snap―17f7f476) e anexe-o à instância de nó principal (essa é a instância no grupo de segurança mahout-clustering-master) em /dev/sdh. (Consulte Recursos para links para instruções detalhadas na documentação on-line de EC2.)
- Se estiver usando as APIs de linha de comando EC2 (consulte os Recursos), é possível:
ec2-create-volume ―snapshot snap-17f7f476 ―z ZONEec2-attach-volume $VOLUME_NUMBER -i $INSTANCE_ID -d /dev/sdh, em que$VOLUME_NUMBERé produzido pela etapa criar-volume e$INSTANCE_IDé o ID do nó principal ativado pelo comando launch-cluster
- Caso contrário, é possível fazer isso usando o console da web AWS.
- Se estiver usando as APIs de linha de comando EC2 (consulte os Recursos), é possível:
- Faça upload do script setup-asf-ec2.sh (consulte Download) para a instância principal:
./hadoop-ec2 push mahout-clustering $PATH/setup-asf-ec2.sh
- Efetue login no seu cluster:
./hadoop-ec2 login mahout-clustering
- Execute o shell script para atualizar seu sistema, instale Git e Mahout e limpe alguns dos archives para tornar mais fácil executar:
./setup-asf-ec2.sh
Com os detalhes de configuração resolvidos, a próxima etapa é ver o que significa colocar alguns dos algoritmos mais populares do Mahout em produção e escalá-los. Focarei principalmente nas tarefas reais de escalar, mas abordarei ao longo do caminho algumas questões sobre seleção de recurso e por que fiz certas escolhas.
Filtragem colaborativa é um dos recursos mais populares e fáceis de usar do Mahout, de modo que é um ponto inicial lógico para uma discussão de como escalar o Mahout. Lembre que estamos trabalhando com archives de email da ASF. No caso de uma tarefa de recomendação, uma possibilidade interessante é desenvolver um sistema que recomende encadeamentos de mensagens potencialmente interessantes para um usuário com base nos encadeamentos que outro usuário leu. Para configurar isso como um problema de filtragem colaborativa, definirei o item que o sistema está recomendando como o encadeamento de mensagens, conforme determinado pelo ID de Mensagem e Referências no cabeçalho do correio. O usuário será definido pelo endereço De na mensagem de email. Em outras palavras, estou preocupado com quem iniciou ou respondeu uma mensagem de correio. Como para o valor da preferência em si, simplesmente irei tratar a interação com o encadeamento de correio como uma preferência booleana: ligado se o usuário X interagiu com o encadeamento Y e desligado se não interagiu. O único efeito a jusante dessa escolha é que devemos usar uma métrica de similaridade que funcione com preferências booleanas, como as similaridades Tanimoto ou de probabilidade de log. Isso normalmente proporciona cálculos mais rápidos e provavelmente reduz a quantidade de ruído no sistema, mas sua milhagem pode variar e você pode desejar experimentar pesos diferentes.
Porque a seleção de recurso é direta no que se refere à filtragem colaborativa (usuário, item, preferência opcional), podemos avançar para ver as etapas para pegar nosso conteúdo dos archives de email brutos para executar localmente e então executar na nuvem. Observe que, em muitas circunstâncias, a última etapa frequentemente não é necessária, já que é possível obter resultados rápido o bastante em uma única máquina sem adicionar a complexidade de Hadoop a equação. Como uma estimativa bruta, a referência da comunidade Mahout sugere que se pode razoavelmente fornecer recomendações de até 100 milhões de usuários em um único nó. No caso de dados de email, não há tantos itens (aproximadamente sete milhões de mensagens), mas irei avançar e executá-los no Hadoop mesmo assim.
Para ver o código em ação, empacotei as etapas necessárias em um shell script localizado no arquivo $MAHOUT_HOME/examples/bin/build-asf-email.sh. Execute o shell script, passando para dentro o local dos dados de entrada e onde gostaria de obter a saída resultante, como em:
./build-asf-email.sh ./scaling_mahout/data/sample/content ./scaling_mahout/output/ |
Quando solicitado, escolha recommender (opção 1), recoste-se e desfrute da prolixidade da saída de criação de log do Mahout e do Hadoop. Quando tiver concluído, você verá algo semelhante à Listagem 1:
Listagem 1. Saída de amostra da execução do código do recomendador
11/09/08 09:57:37 INFO mapred.JobClient: Reduce output records=2072 11/09/08 09:57:37 INFO mapred.JobClient: Spilled Records=48604 11/09/08 09:57:37 INFO mapred.JobClient: Map output bytes=10210854 11/09/08 09:57:37 INFO mapred.JobClient: Combine input records=0 11/09/08 09:57:37 INFO mapred.JobClient: Map output records=24302 11/09/08 09:57:37 INFO mapred.JobClient: SPLIT_RAW_BYTES=165 11/09/08 09:57:37 INFO mapred.JobClient: Reduce input records=24302 11/09/08 09:57:37 INFO driver.MahoutDriver: Program took 74847 ms |
Os resultados dessa tarefa serão todas as recomendações para todos os usuários nos dados de entrada. Os resultados são armazenados em um subdiretório do diretório de saída chamado prefs/recommendations e contêm um ou mais arquivos de texto cujos nomes começam com part-r-. (É assim que o Hadoop produz arquivos.) Examinar um desses arquivos revela, com uma advertência, as recomendações formatadas como:
user_id [item_id:score, item_id:score, ...] |
Por exemplo, o ID do usuário 25 tem recomendações para os IDs de email 26295 e 35548. A advertência é simplesmente que user_id e item_id não são IDs originais, mas mapeamentos dos originais em números inteiros. Para ajudá-lo a entender por que isso é feito, é hora de explicar o que de fato acontece quando o shell script é executado.
Três etapas estão envolvidas na produção dos resultados da recomendação:
- Converter os arquivos mbox brutos para o formato
SequenceFiledo Hadoop usandoSequenceFilesFromMailArchives do Mahout. - Extrair o ID de mensagem e a assinatura de ID das mensagens e produzir os resultados em um formato que o Mahout possa entender.
- Executar a classe
RecommenderJobdo Mahout.
Não abordarei a Etapa 1 além de simplesmente sugerir que leitores interessados consultem o código.
Para a Etapa 2, um pouco mais de trabalho está envolvido para extrair as informações pertinentes dos arquivos (IDs de mensagem, referências de resposta e os endereços De) e então armazená-las como triplos (From ID, Message-ID, preferência) para RecommenderJob consumir. O processo para isso é conduzido por MailToPrefsDriver, que consiste em três tarefas Mapear-Reduzir:
- Criar um dicionário mapeando o ID de mensagem com base em cadeia de caracteres em um único
long. - Criar um dicionário mapeando o endereço de email De com base em cadeia de caracteres em um único
long. - Extrair a Mensagem-ID, Referências e D; mapeá-los para
longs usando os dicionários das Etapas 1 e 2; e produzir os triplos em um arquivo de texto.
Depois disso tudo, é hora de gerar algumas recomendações. Para criar recomendações, RecommenderJob realiza as etapas ilustradas na Figura 1:
Figura 1. Fluxo de tarefas do recomendador
A principal tarefa realizando o serviço pesado no fluxo de trabalho é a etapa "calcular coocorrências". Essa etapa é responsável por realizar comparações entre pares em toda a matriz procurando por pontos em comum. Como um adicional, essa etapa (ativada por RowSimilarityJob do Mahout) geralmente é útil para realizar cálculos entre pares entre quaisquer linhas em uma matriz (não apenas classificações/revisões).
RecommenderJob é chamado no shell script com o comando:
bin/mahout recommenditembased ―input $PREFS_REC_INPUT ―output $RECS_OUT ―tempDir
$PREFS_TMP ―similarityClassname SIMILARITY_LOGLIKELIHOOD
|
O primeiro argumento diz ao Mahout que comando executar (RecommenderJob); muitos dos outros (input/output/tempDir) são autoexplicativos. O similarityClassname indica ao Mahout como calcular a similaridade entre itens ao calcular coocorrências. E escolhi usar probabilidade de log por sua simplicidade, velocidade e qualidade.
Quando os resultados são obtidos, é hora de avaliá-los. O Mahout obtém um pacote de avaliação (org.apache.mahout.cf.taste.eval) com ferramentas úteis que permitem examinar a qualidade dos resultados. Infelizmente, elas não funcionam com os algoritmos com base em Hadoop, mas podem ser úteis em outros casos. Essas ferramentas retêm uma porcentagem dos dados como dados de teste e então os compara com o que o sistema produziu para julgar a qualidade.
Isso é, na verdade, tudo o que há sobre gerar recomendações — e a melhor parte é que elas podem então ser executadas diretamente no cluster. Para isso, efetue login no cluster EC2 configurado anteriormente e execute o mesmo shell script (está em /mnt/asf-email/mahout-trunk/examples/bin) que antes. Conforme são adicionados nós ao cluster, deve ser possível ver uma redução no tempo geral que leva para executar as etapas. Como um exemplo, a execução de um conjunto de dados completo em uma máquina local leva mais de três dias para ser concluída. Executar em um cluster de 10 nós na EC2 levou cerca de 60 minutos para a tarefa de recomendação principal mais o trabalho preparatório de converter o email para um formato utilizável.
A última parte, que deixei como um exercício para o leitor, é consumir as recomendações como parte do aplicativo. Normalmente, uma vez que um número significativo de itens e usuários está no sistema, recomendações são geradas periodicamente — em geral em algum ponto entre a cada hora ou a cada dia, dependendo das necessidades de negócio. Afinal, quando um sistema alcança certa quantidade de usuários e recomendações, alterações às recomendações produzidas serão muito mais sutis.
A seguir, vamos ver a classificação de mensagens de email, o que, em alguns casos, pode ser pensado como um sistema de recomendação contextual.
O Mahout tem vários algoritmos de classificação, sendo que a maioria deles (com uma exceção de destaque, o descendente de gradiente estocástico) é escrita para executar no Hadoop. Para os fins deste artigo, usarei o classificador naïve bayes, com os quais muitas pessoas iniciam e que frequentemente produzem resultados razoáveis enquanto escalam com eficácia. Para mais detalhes sobre outros classificadores, consulte os capítulos adequados em Mahout in Action ou a seção Algorithms no wiki do Mahout (consulte Recursos).
Os documentos de email são divididos pelos projetos Apache (Lucene, Mahout, Tomcat, entre outros), cada projeto normalmente tem duas ou mais listas de email (usuário, desenvolvimento, entre outras). Dado que o conjunto de dados de email da ASF é particionado por projeto, um problema de classificação lógica é tentar prever o projeto ao qual uma nova mensagem recebida deve ser entregue. Por exemplo, uma nova mensagem pertence à lista de emails Lucene ou a lista de emails Tomcat?
Para os algoritmos de classificação do Mahout funcionarem, um modelo deve ser treinado para representar os padrões a serem identificados e então testados com relação a um subconjunto de dados. Na maioria dos problemas de classificação, uma ou mais pessoas passa e anota manualmente um subconjunto de dados a serem usados no treinamento. Felizmente, porém, nestes casos, o conjunto de dados já está separado por projeto, então não há necessidade de anotação manual — embora esteja contando com o fato de que as pessoas normalmente escolhem a lista correta ao enviar o email, o que eu e você sabemos que nem sempre acontece.
Assim como no caso recomendado, as etapas necessárias são pré-empacotadas no script build-asf-email.sh e executadas ao selecionar a opção 3 (e então a opção 1 ao segundo prompt para naïve bayes padrão) no menu. De maneira semelhante a recomendações, parte do trabalho de escalar o código está na preparação dos dados a serem consumidos. Para a classificação do texto, isso significa principalmente codificar os recursos e, em seguida, criar vetores a partir dos recursos, mas também inclui configurar conjuntos de teste e treinamento. O conjunto completo de etapas tomadas é:
- Converter os arquivos mbox brutos para o formato
SequenceFiledo Hadoop usandoSequenceFilesFromMailArchives do Mahout. (Observe que as opções de tempo de execução são ligeiramente diferentes aqui.)bin/mahout org.apache.mahout.text.SequenceFilesFromMailArchives ―charset "UTF-8" ―body ―subject ―input $ASF_ARCHIVES ―output $MAIL_OUT
- Converter as entradas
SequenceFilepara vetores esparsos e modifique os rótulos:bin/mahout seq2sparse ―input $MAIL_OUT ―output $SEQ2SP ―norm 2 ―weight TFIDF ―namedVector ―maxDFPercent 90 ―minSupport 2 ―analyzerName org.apache.mahout.text.MailArchivesClusteringAnalyzerbin/mahout org.apache.mahout.classifier.email.PrepEmailDriver ―input $SEQ2SP ―output $SEQ2SPLABEL ―maxItemsPerLabel 1000
- Dividir a entrada em conjuntos de treinamento e teste:
bin/mahout split ―input $SEQ2SPLABEL ―trainingOutput $TRAIN ―testOutput $TEST ―randomSelectionPct 20 ―overwrite ―sequenceFiles
- Executar o classificador naïve bayes para treinar e testar:
-
bin/mahout trainnb -i $TRAIN -o $MODEL -extractLabels ―labelIndex $LABEL -
bin/mahout testnb -i $TEST -m $MODEL ―labelIndex $LABEL
-
As duas etapas principais dignas de nota são a Etapa 2 e a Etapa 4. A Etapa 2a é a etapa de codificação e seleção de recursos primária, e vários parâmetros de entrada controlam como o texto de entrada será representado como pesos nos vetores. A Tabela 2 divide as opções relacionadas à seleção de recurso da Etapa 2:
Tabela 2. Opções de seleção de recurso para criação de vetor
| Opção | Descrição | Exemplos e observações |
|---|---|---|
―norm
| A norma modifica todos os vetores por uma função que calcula seu comprimento (norma) | 1 norma = distância de Manhattan, 2 normas = distância Euclideana |
―weight
| Calcula o peso de qualquer recurso determinado como TF-IDF (frequência do termo, frequência do documento inverso) ou apenas Frequência do Termo | TF-IDF é um esquema de peso comum em procura e aprendizado de máquina para representar texto como vetores. |
―maxDFPercent, ―minSupport
| Ambas as opções eliminam termos que são frequentes demais (máx.) ou não frequentes o bastante na coleção de documentos | Útil em automaticamente eliminar termos comuns ou muito raros que agregam pouco valor ao cálculo |
―analyzerName
| Uma classe de analisador Apache Lucene que pode ser usada para converter em token, derivar, remover ou de outra forma alterar as palavras no documento | Consulte Recursos para saber mais sobre Lucene |
Vale a pena se aprofundar um pouco mais no processo de análise na Etapa 2a, dado que ele está fazendo muito do serviço pesado necessário para seleção de recurso. Um Analyzer Lucene é composto de uma classe Tokenizer e zero ou mais classes de TokenFilter . O Tokenizer é responsável por dividir a entrada original em zero ou mais tokens (como palavras). Instâncias de TokenFilter são encadeadas juntas para então modificar os tokens produzidos pelo Tokenizer. Por exemplo, o Analyzer usado no exemplo:
- Converte em token espaço em branco, mais alguns casos marginais para pontuação.
- Coloca todos os tokens em minúsculas.
- Converte caracteres não ASCII em ASCII, onde possível convertendo diacríticos, entre outros.
- Descarta tokens com mais de 40 caracteres.
- Remove palavras comuns (consulte o código para a lista, que é longo demais para ser exibido aqui).
- Deriva os tokens usando o lematizador Porter (consulte Recursos.)
O resultado final dessa análise é um vetor significativamente menor para cada documento, bem como um que removeu palavras de "ruído" comuns (a/o , um/uma, uns/umas, e semelhantes) que confundirão o classificador. Esse Analyzer foi desenvolvido iterativamente olhando para os exemplos no email e então os processando através do Analyzer e examinando a saída, tomando decisões sobre a melhor forma de continuar. O processo é tanto de intuição (experiência) quando de ciência, infelizmente. O processo e o resultado estão longe da perfeição, mas provavelmente são bons o suficiente.
A Etapa 2b faz algumas conversões menores dos dados para processamento, bem como descarta algum conteúdo de modo que os vários rótulos sejam representados de maneira uniforme nos dados de treinamento. Esse é um ponto importante, pois meus primeiros experimentos com os dados levaram ao problema extremamente comum, em aprendizado de máquina, de ajustar em excesso para os rótulos com significativamente mais exemplos de treinamento. Na verdade, ao executar no cluster no conjunto completo de dados, configurar ―maxItemsPerLabel até 1.000 ainda não é bom o suficiente para criar ótimos resultados, já que parte das listas de emails tem menos de 1.000 postagens. Isso possivelmente se deve a um erro no Mahout que a comunidade ainda está investigando.
A Etapa 4 é onde o trabalho real é feito tanto para desenvolver um modelo quanto para testar se ele é válido ou não. Na Etapa 4a, a opção ―extractLabels simplesmente indica ao Mahout para descobrir os rótulos de treinamento a partir da entrada. (A alternativa é passá-los para dentro.) A saída dessa etapa é um arquivo que pode ser lido usando a classe org.apache.mahout.classifier.naivebayes.NaiveBayesModel . A etapa 4b toma o modelo, bem como os dados de teste, e verifica a qualidade do trabalho realizado pelo treinamento. A saída é uma matriz confusa como descrito em Introducing Apache Mahout." Para os dados de amostra, a saída está na Listagem 2:
Listagem 2. Saída de amostra da execução do código do classificador
Correctly Classified Instances : 41523 61.9219% Incorrectly Classified Instances : 25534 38.0781% Total Classified Instances : 67057 ======================================================= Confusion Matrix ------------------------------------------------------- a b c d e f ><--Classified as 190440 12 1069 0 0 | 20125 a= cocoon_apache_org_dev 2066 0 1 477 0 0 | 2544 b= cocoon_apache_org_docs 165480 2370 704 0 0 | 19622 c= cocoon_apache_org_users 58 0 0 201090 0 | 20167 d= commons_apache_org_dev 147 0 1 4451 0 0 | 4599 e= commons_apache_org_user |
Deve-se observar que essa é uma apresentação bastante fraca para um classificador (embora melhor que adivinhar). O motivo provável para essa apresentação fraca é que as listas de emails de desenvolvimento e usuário para um dado projeto do Apache estão tão relacionadas no seu vocabulário que é simplesmente difícil demais distingui-las. Isso é apoiado pelo fato de que 16.548 mensagens cocoon_user foram incorretamente classificadas como cocoon_dev. Na verdade, executar a tarefa novamente usando apenas o nome do projeto sem distinguir entre as listas de desenvolvimento e usuário nos dados de amostra rende os resultados na Listagem 3:
Listagem 3. Saída de amostra da nova execução do código do classificador apenas com o nome do projeto
Correctly Classified Instances : 38944 96.8949% Incorrectly Classified Instances : 1248 3.1051% Total Classified Instances : 40192 ======================================================= Confusion Matrix ------------------------------------------------------- a b c ><--Classified as 18733 1241 0 | 19974 a = cocoon_apache_org 7 20211 0 | 20218 b = commons_apache_org |
Acredito que você concordará que ter 96 por cento de precisão é melhor que ter 61 por cento! Na verdade, provavelmente é bom demais para ser verdade. A pontuação provavelmente se deve à natureza desse pequeno conjunto de dados em particular ou talvez um problema mais profundo que precise de investigação. Uma pontuação como essa deveria justificar uma investigação mais aprofundada adicionando dados e revisando o código para gerá-los. Por enquanto, estou satisfeito com isso como um exemplo de como os resultados seriam. Porém, poderíamos tentar outras técnicas ou uma melhor seleção de recursos, ou, quem sabe, mais exemplos de treinamento, para elevar a precisão. Também é comum fazer uma validação múltipla dos resultados. A validação múltipla envolve repetidamente pegar partes dos dados da amostra de treinamento e colocá-los na amostra de teste ou separá-los. O sistema é, então, julgado quanto à qualidade de todas as execuções, não apenas uma.
Levar isso para a nuvem é tão direito quando para os recomendadores. Todo o script deve executar no seu cluster simplesmente passando para dentro os caminhos adequados. Executar isso em EC2 em um cluster de 10 nós levou meros minutos para o treinamento e teste, junto com o trabalho preparatório normal. Infelizmente, porém, quando isso é executado, a qualidade da execução com relação ao conjunto de dados completo na nuvem sofreu porque algumas listas de emails tinham muito poucos pontos de dados. Elas devem provavelmente ser removidas da consideração.
As próximas etapas para produção envolvem disponibilizar o modelo como parte do sistema de tempo de execução, bem como configurar um fluxo de trabalho para garantir que o modelo esteja atualizado conforme é obtido feedback do sistema. A partir daqui, veremos armazenamento em cluster.
Como com classificação, o Mahout tem vários algoritmos de armazenamento em cluster, cada um com diferentes características. Por exemplo, K-Means escala bem, mas exige a especificação antecipada do número de clusters desejados, enquanto o armazenamento em cluster Dirchlet exige a escolha de uma distribuição de modelo, bem como o número de clusters desejados. O armazenamento em cluster também tem uma boa parte em comum com classificação, e é possível, às vezes, que trabalhem juntos usando clusters como parte da classificação. Principalmente, muito do trabalho de preparação de dados para classificação é o mesmo para armazenamento em cluster — como converter conteúdo bruto em arquivos de sequência e então em vetores esparsos — , assim, é possível consultar a seção Classificação para essas informações.
Para armazenamento em cluster, a principal pergunta a ser respondida é: podemos agrupar de maneira lógica todas as mensagens com base em similaridade de conteúdo, independentemente do projeto? Por exemplo, talvez mensagens na lista de emails do Apache Solr sobre o uso do Apache Tomcat como contêiner da web estejam mais próximas de mensagens do projeto Tomcat do que do projeto de origem.
Para este exemplo, as primeiras etapas são muito semelhantes a classificação, divergindo após a conclusão da conversão para vetores esparsos. As etapas específicas são:
- As mesmas etapas que as Etapas 1 e 2 da classificação.
$ bin/mahout kmeans --input "$SEQ2SP/tfidf-vectors" --output $CLUST_OUT -k 50 --maxIter 20 --distanceMeasure org.apache.mahout.common.distance.CosineDistanceMeasure --clustering --method mapreduce --clusters "$CLUST_OUT/clusters"
Neste caso, K-Means é executado para realizar o armazenamento em cluster, mas o shell script tem suporte para execução de armazenamento em cluster Dirichlet também. (Ao executar o script, você é solicitado a escolher o algoritmo que deseja executar.) No exemplo anterior, os parâmetros que valem um aprofundamento são:
-k: o número de clusters a criar. Peguei 50 de um chapéu, mas certamente poderia haver outros valores.―maxIter: K-Means é o algoritmo iterativo pelo qual o centro do cluster é atualizado como parte de cada iteração. Em alguns casos, não há garantia de que conclua por si mesmo, então esse parâmetro pode garantir a conclusão do algoritmo.―distanceMeasure: a medida de distância determina a similaridade entre o centroide atual e o ponto sendo examinado. Neste caso, escolhi a Medida de Distância de Cosseno, que muitas vezes é uma boa escolha para dados de texto. O Mahout tem muitas outras implementações, e você pode considerar útil testá-las para seus dados.―clustering: indica ao Mahout para produzir que pontos pertencem a qual centroide. Por padrão, o Mahout apenas calcula os centroides, porque isso frequentemente é tudo o que é necessário.
Quando a execução está concluída, é possível fazer o dump dos centroides do cluster (e pontos associados) usando o programa ClusterDump do Mahout. Os resultados finais estarão no subdiretório sob o diretório kmeans iniciando com o nome clusters- e terminando com -final. O valor exato dependerá de quantas iterações foram necessárias para executar a tarefa; por exemplo, clusters-2-final é a saída da terceira iteração. Como um exemplo, esse comando realiza o dump dos clusters da execução da pequena amostra de dados:
bin/mahout clusterdump ―seqFileDir ../output/ibm/clustering/kmeans/clusters-2-final
―pointsDir ../output/ibm/clustering/kmeans/clusteredPoints/
|
Os pontos ―seqFileDir nos centroides criados, e -pointsDir é o diretório de pontos armazenados em cluster. Uma pequena amostragem dos resultados está na Listagem 4:
Listagem 4. Saída de amostra da execução de
ClusterDumper
:VL-337881{n=4420 c=[
Top Terms:
user =>0.060885823267350335
mailscann => 0.05059369006868677
cocoon =>0.048781178576134204
virus => 0.04285897589148712
derek => 0.04084340722527813
legal =>0.040052624979813184
scan => 0.03861016730680097
danger => 0.03848600584647758
csir => 0.03712359352614157
transtec => 0.03388019099942435
Weight : [props - optional]: Point:
1.0 : [distance=0.888270593967813]:
/cocoon.apache.org/dev/200004.gz/NBBBIDJGFOCOKIOHGDPBKEPPEEAA.XXXXX =
[ag:0.165, briefli:0.250, chang:0.075, close:0.137, cocoon:0.060,
cocoon1:0.226, cocoon2:0.218, concept:0.277, develop:0.101, differ:0.144,
explain:0.154, greet:0.197, klingenderstrass:0.223, langham:0.223, look:0.105,
mailserv:0.293, matthew:0.277, mlangham:0.240, paderborn:0.215, processor:0.231,
produc:0.202, put:0.170, scan:0.180, tel:0.163, understand:0.127, virus:0.194]
|
Na Listagem 4, observe que a saída inclui uma lista de termos que o algoritmo determinou serem os mais representativos do cluster. Isso pode ser útil para gerar rótulos para uso em produção, bem como para ajustar a seleção de recursos nas etapas preparatórias — porque frequentemente acontece de palavras comuns aparecerem (neste caso, por exemplo, user provavelmente é uma) na lista dos primeiros experimentos com a execução dos dados.
Como você passou a esperar, executar isso no seu cluster é tão simples quanto executá-lo localmente — e tão simples quanto os outros dois exemplos. Além to tempo gasto convertendo o conteúdo (cerca de 150 minutos), a tarefa de armazenamento em cluster real levou cerca de 40 minutos em 10 nós nos meus testes.
Infelizmente, com armazenamento em cluster, avaliar os resultados frequentemente se resume ao "teste do odor", embora o Mahout não tenha algumas ferramentas para avaliar (consulte as opções CDbwEvaluator e ClusterDumper para a saída dos principais termos). Para o teste do odor, visualizar os clusters costuma ser positivo, mas infelizmente muitos kits de ferramentas de visualização gráfica não funcionam em conjuntos de dados grandes, então você pode ser deixado aos seus próprios dispositivos para visualizar.
Como com recomendações e classificações, as etapas para a produção envolvem decidir sobre o fluxo de trabalho para obter os dados, bem como com que frequência realizar o processamento e, é claro, fazer uso dele no seu ambiente de negócios. Provavelmente também será preciso trabalhar através dos vários algoritmos para ver quais funcionam melhor para os seus dados.
O Apache Mahout continua a avançar de várias maneiras. O principal foco da comunidade no momento é pressionar para um release 1.0 realizando teste de desempenho, documentação, melhoria de API e a adição de alguns novos algoritmos. O próximo release, o 0.6, provavelmente acontecerá no final de 2011 ou logo após. Em um nível mais profundo, a comunidade também está começando a olhar para abordagens distribuídas em memória para solucionar os problemas de aprendizado de máquina. Em muitos casos, os problemas de aprendizado de máquina são grandes demais para uma única máquina, mas o Hadoop induz gasto adicional excessivo devido à E/S de disco. Independentemente da abordagem, o Mahout está bem posicionado para ajuda a solucionar os problemas de dados grandes mais urgentes de hoje focando em escalabilidade e facilitando o consumo de algoritmos de aprendizado de máquina complicados.
Agradecimento especial a Timothy Potter pela assistência no empacotamento AMI e aos companheiros committers do Mahout, Sebastian Schelter, Jake Mannix e Sean Owen pela revisão técnica. Parte deste trabalho foi apoiada pelo Amazon Apache Testing Program.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Shell script | j-mahout-scaling.zip | 2KB | HTTP |
Informações sobre métodos de download
Aprender
-
"Introducing Apache Mahout" (Grant Ingersoll, developerWorks, setembro de 2009): o cofundador do Mahout Ingersoll apresenta os conceitos básicos de aprendizado de máquina e demonstra como usar o Mahout para armazenar em cluster documentos, fazer recomendações e organizar conteúdo.
-
Apache Mahout: fique de olho na página inicial do Apache Mahout para todas as últimas notícias, bem como documentação e novos downloads.
-
Ativado por Mahout: ativado por Mahout por página lista empresas dispostas a declarar seu uso dos algoritmos do Mahout.
-
Taming Text (Grant S. Ingersoll, Thomas S. Morton, e Andrew L. Farris, Manning Publications, 2011): esse livro aborda Mahout e tecnologias de software livre relacionadas para desenvolver aplicativos com base em texto.
-
Mahout in Action (Sean Owen, Robin Anil, Ted Dunning e Ellen Friedman, Manning Publications, 2011): esse livro é o guia definitivo para entender Mahout.
-
Apache Hadoop: aprenda sobre Hadoop.
-
Algoritmos: leia mais sobre os algoritmos que o Mahout implementa, bem como as áreas de interesse para a comunidade no Wiki do Mahout.
-
Surpresa e coincidência: leia mais sobre a utilidade da medida de probabilidade de log no blog do committer do Mahout, Ted Dunning.
-
MongoDB: descubra mais sobre MongoDB no seu website.
-
Apache Cassandra: obtenha mais informações sobre o Apache Cassandra navegando no seu website. Leia mais sobre o seu uso com o Mahout na postagem do blog de Sean Owen, "Recommending (from) Cassandra."
-
Amazon Web Services incluindo EC2: saiba mais sobre a infraestrutura EC2 da Amazon.
-
Use uma AMI Hadoop existente: essa página no wiki do Mahout detalha o processo para ativar clusters Hadoop em EC2.
-
Guia do Usuário do Amazon EC2: consulte o Guia do Usuário do EC2 para as etapas de configuração deste artigo:
- Usando conjuntos de dados públicos: como usar os conjuntos de dados públicos do Amazon EC2.
- Archives de email públicos da Apache Software Foundation: use uma captura instantânea dos archives de email públicos da Apache Software Foundation para testar o Mahout.
- Disponibilizando um volume Amazon EBS para uso: como disponibilizar um volume Amazon EBS para seu sistema operacional.
- Introdução a ferramentas de linha de comando: como configurar o ambiente Amazon EC2 para uso com as ferramentas de linha de comando do Amazon EC2 (também chamadas de ferramentas API ou Ferramentas CLI).
-
Message-ID: saiba mais sobre cabeçalhos de correio e ID de mensagem.
-
Apache Lucene: saiba mais sobre o Apache Lucene através do seu website.
-
Lematizadores Snowball do Dr. Martin Porter: frequentemente são úteis para trabalhar com texto em projetos de aprendizado de máquina e procura.
-
Navegue na
livraria de tecnologia para ver livros sobre este e outros tópicos técnicos.
-
Zona tecnologia Java do developerWorks: Encontre centenas de artigos sobre quase todos os aspectos da programação Java.
Obter produtos e tecnologias
-
Apache Mahout: efetue o download da bifurcação de Grant Ingersoll do código de origem do Mahout, incluindo os exemplos.
- Faça o download das
Versões de avaliação de produto IBM ou
explore as versões de teste on-line no IBM SOA Sandbox e tenha contato com as ferramentas de desenvolvimento de aplicativos e produtos de middleware do DB2®, Lotus®, Rational®, Tivoli®e WebSphere®.
Discutir
-
Lista de emails do usuário do Mahout: assine para fazer perguntas, compartilhar conhecimento e discutir problemas.
- Participe da comunidade do developerWorks. Entre em contato com outros usuários do developerWorks, enquanto explora os blogs, fóruns, grupos e wikis orientados ao desenvolvedor.

Grant Ingersoll é um fundador e membro da equipe técnica da Lucid Imagination. A participação de programação de Grant inclui recuperação de informações, aprendizagem por máquina, categorização textual, e extração. Grant é o co-fundador do projeto de aprendizagem por máquina do Apache Mahout, bem como um comprometido e contribuidor nos projetos Apache Lucene e Apache Solr. Ele também é o co-autor do Taming Text (Manning, disponível) que aborda ferramentas de fonte aberta para processamento de linguagem natural.