[PYTHON] Comparaison des implémentations LDA

(Je publierai un article que j'ai oublié de publier il y a un an pour un brouillon de digestion)

J'ai abordé certaines des implémentations LDA à des fins de comparaison. Il semble que les options sont les suivantes, mais je vais résumer la procédure jusqu'à l'exécution LDA de chaque langue écrite dans un mémo.

Langue utilisée Modèle d'utilisation Extensibilité de la charge algorithme
Spark MLlib 1.6.0 Scala,Java,
Python,R
Bibliothèque Parallèle/Distribué Variante Bayes, EM
gensim Python Bibliothèque Parallèle Variante Bayes
GibbsLDA++ coquille commander - Gibbs Sampling
R R Bibliothèque - Gibbs Sampling

Coût d'exécution

Chacun est exécuté et le temps est mesuré, mais les conditions d'exécution sont assez différentes comme indiqué ci-dessous. Veuillez le lire sans aucun malentendu.

Exécuté dans les conditions $ k = 100 $ et $ iter = 50 $ pour 13 033 $ document $ 20 780 $ mots obtenus en effectuant une analyse morphologique et en supprimant les éléments morphologiques inutiles.

Spark MLlib

algorithme Nodes Cores Temps d'exécution
EM 5 80 224.092
EM 1 8 81.854
EM 1 1 112.606
Variante Bayes 1 8 220.147
Variante Bayes 1 1 310.367

Le temps d'exécution est plus lent que les autres car il inclut également le processus de lecture du fichier local et de création du BoW par RDD. Le résultat le plus lent de l'exécution distribuée est probablement dû au fait que le coût du brassage et du transfert de données entre les nœuds est plus élevé que le coût de calcul de LDA lui-même.

gensim

algorithme Nodes Cores Temps d'exécution
Variante Bayes 1 4 15.396
Variante Bayes 1 1 20.576

Le gensim de Python semble n'être que la variante Bayes, mais il semble avoir un bon équilibre entre performances avec plus de travailleurs, traitement parallèle, vitesse rapide.

GibbsLDA++

algorithme Nodes Cores Temps d'exécution
Gibbs Sampling 1 1 58.993

C'était plus rapide que gensim près de $ k = 10 $ avec le traitement d'entrée / sortie des fichiers locaux en plus d'un seul thread, mais est-ce plus lent à mesure que $ k $ devient plus grand? L'échelle peut être difficile, mais convient-elle à une petite exécution ad hoc?

Langue R

algorithme Nodes Cores Temps d'exécution
Collapsed Gibbs Sampling 1 1 24.247

Le calcul lui-même était étonnamment plus rapide que celui de GibbsLDA ++ R lda.collapsed.gibbs.sampler {lda} (Cependant, le processus de lecture d'un fichier local et de le convertir en un format qui peut être passé à la bibliothèque était lent, donc il est lent au total). R est plus rapide que la vitesse pratique lda {lda} et lda.cvb0 {lda} C'est une bonne impression d'attendre la partie où vous pouvez essayer de nombreuses implémentations et algorithmes tels que: //www.inside-r.org/packages/cran/lda/docs/lda.cvb0).

Essayez d'utiliser chaque implémentation

gensim

# -*- coding: utf-8 -*-
#Exemple de LDA par Python gensim
from gensim import corpora, models
import time

#Lire les données du document(Analyse morphologique/Un fichier texte dans lequel les mots sont séparés par des espaces dans un document ligne par ligne avec une nomenclature extraite.)
texts = [ ]
for line in open('docs.gibbs', 'r'):
    texts.append(line.split())

#Créer un dictionnaire(id:mot:Nombre d'apparitions)
dictionary = corpora.Dictionary(texts)
dictionary.save_as_text('./docs.dic')
# dictionary = corpora.Dictionary.load_from_text("./docs.dic")

#Création de corpus
corpus = [dictionary.doc2bow(text) for text in texts]
corpora.MmCorpus.serialize('corpus.mm', corpus)
# corpus = corpora.MmCorpus('corpus.mm')

#Calcul LDA
t0 = int(time.time() * 1000)
lda = models.ldamodel.LdaModel(corpus, num_topics=100, iterations=50)
t1 = int(time.time() * 1000)
print t1 - t0

#Calcul LDA(Version compatible multiprocesseur)
t0 = int(time.time() * 1000)
lda = models.ldamulticore.LdaMulticore(corpus, num_topics=10, iterations=50, workers=4)
t1 = int(time.time() * 1000)
print t1 - t0

GibbsLDA++

GibbsLDA ++ et son port Java de JGibbsLDA sont des implémentations LDA en ligne de commande. J'ai implémenté Gibbs Sampling, mais il ne semble pas prendre en charge le traitement parallèle (support multi-core) ou le traitement distribué.

Construire

Téléchargez GibbsLDA ++ - 0.2.tar.gz depuis GibbsLDA ++: A C / C ++ Gibbs Sampling LDA, décompressez et compilez.

$ tar zxvf GibbsLDA++-0.2.tar.gz
$ cd GibbsLDA++-0.2/
$ make all

Si g ++ est disponible, make all terminera la construction et la commande src / lda sera exécutée.

ʻError: 'atof' n'a pas été déclaré dans cette portée, ʻerror: 'printf' n'a pas été déclaré dans cette portée [ici](http://yuutookun.hatenablog.com/entry/20120831/ 2 Ajoutez # include au fichier faisant référence à 1346394002).

$ vim src/util.cpp
...
#include <stdio.h>
#include <stdlib.h>  //ajouter à
#include <string>
...
$ vim src/lda.cpp
...
*/

#include <stdio.h>  //ajouter à
#include "model.h"
...
$ make clean; make all
make -C src/ -f Makefile clean
make[1]: Entering directory `/export/home/t_takami/git/gibbslda++/GibbsLDA++-0.2/src'
...
make[1]: Leaving directory `/export/home/t_takami/git/gibbslda++/GibbsLDA++-0.2/src'

$ src/lda --help
Please specify the task you would like to perform (-est/-estc/-inf)!
Command line usage:
        lda -est -alpha <double> -beta <double> -ntopics <int> -niters <int> -savestep <int> -twords <int> -dfile <string>
        lda -estc -dir <string> -model <string> -niters <int> -savestep <int> -twords <int>
        lda -inf -dir <string> -model <string> -niters <int> -twords <int> -dfile <string>

Préparation des données

Créez un fichier dans lequel les mots contenus dans le document sont listés séparés par des blancs afin que le nombre de documents soit sur la première ligne, puis "1 ligne = 1 document". S'il y a des lignes vides (documents avec 0 mots qui représentent des caractéristiques), l'erreur ʻDocument invalide (vide)! `Se produira.

$ head -n 5 docs.gibbs
13033
Demande de stockage Sélectionnez Carte Carte Cas de la carte Méthode de réponse Méthode Modèle interne possible Enregistrement de capacité Enregistrement Enregistrement Enregistrement Enregistrement Régler l'heure Enregistrer Enregistrer Enregistrer Enregistrer Enregistrer
Le monde, le monde, le monde, les choses importantes, le bon sens, le bon sens, le bon sens, le bon sens, le bon sens, le bon sens, moi-même
Jeu d'opération de vêtements de caractère
Meilleure date de la meilleure illusion
Téléphone Téléphone Téléphone Adieu Réel Présent Présent Comme Présent Comme S'il Vous Plaît S'il Vous Plaît Larmes Larmes Larmes Narita Conversation Yeux Négatifs Relation Salle Amour Uruguay Uruguay Uruguay Uruguai Owl Sentiments finaux Dans les coulisses…
…

Résultat d'exécution

Exécutez en spécifiant le nombre de sujets $ k $ et le nombre de répétitions sur la ligne de commande.

$ src/lda -est -niters 50 -ntopics 10 -twords 5 -dfile docs.gibbs
Sampling 50 iterations!
Iteration 1 ...
...
Iteration 50 ...
Gibbs sampling completed!
Saving the final model!

Lorsque vous avez terminé, vous devriez avoir des fichiers.

model-final.others est le paramètre d'exécution lorsque ce modèle a été créé, et wordmap.txt contient l'ID attribué au mot.

$ cat model-final.others
alpha=5.000000
beta=0.100000
ntopics=10
ndocs=13033
nwords=20779
liter=50

$ cat wordmap.txt
20779
T-shirt 4601
Ai 1829
Aiko 19897
Salut 2125
...

model-final.twords liste les mots les plus caractéristiques pour chaque sujet, comme spécifié par l'option -twords (ce fichier ne sera pas créé si l'option -twords est omise).

$ cat model-final.twords
Topic 0th:
Personne 0.047465
Ressentir 0.019363
Qi 0.018178
Autre (0.016968
Normal 0.016004
Topic 1th:
Travail 0.043820
Heure 0.024824
Maison 0.019440
Maintenant 0.017962
Mère 0.016881
Topic 2th:
Si 0.033522
Mois 0.018820
Société 0.018083
Assurance 0.015252
Demande 0.012468
…

model-final.phi est la probabilité d'apparition des mots pour chaque sujet. 1 ligne = 1 sujet et le nombre de colonnes dans une ligne correspond au nombre de mots du corpus. En d'autres termes, il s'agit d'une matrice de "$ k $ lignes (nombre total de mots) colonnes". Ce sont les données numériques qui sont à la base de model-final.twords.

$ head -c 100 model-final.phi
0.000002 0.000002 0.000002 0.000002 0.000799 0.000002 0.000002 0.002415 0.000002 0.000002 0.000002 0

model-final.theta est la probabilité que chaque document appartienne à quel sujet. Correspond à 1 ligne = 1 document et 1 colonne = 1 sujet. En d'autres termes, ce sont les données matricielles de "(nombre de documents) lignes $ k $ colonnes".

$ head -n 5 model-final.theta
0.081081 0.216216 0.067568 0.067568 0.162162 0.081081 0.067568 0.108108 0.081081 0.067568
0.076923 0.076923 0.123077 0.092308 0.076923 0.076923 0.107692 0.076923 0.076923 0.215385
0.086207 0.103448 0.103448 0.086207 0.137931 0.086207 0.103448 0.086207 0.086207 0.120690
0.090909 0.090909 0.109091 0.127273 0.090909 0.090909 0.090909 0.090909 0.090909 0.127273
0.035971 0.028777 0.111511 0.323741 0.050360 0.086331 0.248201 0.039568 0.028777 0.046763

model-final.tassign est une liste de données source au format [mot ID: sujet] pour chaque ligne = 1 document.

$ head -n 5 model-final.tassign
0:1 1:4 2:1 3:7 3:7 4:8 4:7 5:5 6:1 6:1 7:4 8:1 9:4 10:1 11:4 11:4 11:4 11:4 12:1 13:0 14:1 14:1 14:1 14:1
15:9 15:9 15:9 16:3 17:6 18:6 19:2 19:9 19:2 19:2 19:9 19:9 20:9 20:9 20:9
21:2 22:9 23:1 24:4 25:6 26:9 9:4 27:4
28:9 28:2 29:9 30:3 30:3
31:4 31:6 31:6 32:3 33:2 34:3 34:3 35:3 35:3 1:5 1:2 36:3 36:3 36:3 37:6 38:2 39:6 40:6 41:6 42:3 42:6 43:6 44:3 …

GibbsLDA ++ est presque au point de créer un modèle numérique, vous devez donc mapper vous-même les résultats autres que «twords» aux documents et aux mots.

Langue R

Personnellement, c'est un langage R qui est difficile à entrer dans la fonction de langage et qui est un peu timide, mais [lda.collapsed.gibbs.sampler {lda}](http://www.inside-r.org/packages/cran/lda/docs/lda Si vous regardez .collapsed.gibbs.sampler), vous pouvez voir que certains modèles de Collapsed Gibbs Sampling sont implémentés.

Il ne semble pas prendre en charge le traitement parallèle (support multicœur) ou le traitement distribué.

Installation

Tout d'abord, installez le langage R sur CentOS 7.2 (si la commande rpm ci-dessous donne un 404, supprimez la partie fichier de l'URL pour trouver la version appropriée).

$ sudo rpm -ihv http://ftp.riken.jp/Linux/fedora/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
$ sudo yum install R

Une fois l'installation de R terminée, lancez l'interface interactive et installez le package LDA. En chemin, j'essaye d'installer le paquet LDA dans / usr / lib64 / R / library, mais je ne suis pas un utilisateur root, donc je spécifie une bibliothèque personnelle. Il vous sera également demandé la source du téléchargement, alors sélectionnez le miroir CRAN du Japon (Tokyo).

Ci-dessous, reshape2 et ggplot2 sont également installés pour exécuter la démo.

$ R
R version 3.2.3 (2015-12-10) -- "Wooden Christmas-Tree"
Copyright (C) 2015 The R Foundation for Statistical Computing
Platform: x86_64-redhat-linux-gnu (64-bit)
...
> install.packages("lda")
...
Would you like to use a personal library instead?  (y/n) y
...
Selection: 13
...
> install.packages("reshape2")
> install.packages("ggplot2")
> require("lda")
> demo(lda)

Il semble que ne suivant pas le changement de spécification de ggplot2 stat_count () ne doit pas être utilisé avec ay esthétique. Se produira et le graphique ne sera pas affiché. Si vous démarrez la partie qplot () correctement et manuellement, cela fonctionnera, mais comme le processus de calcul LDA lui-même est terminé, ignorez-le et continuez.

> top.topic.words(result$topics, 5)
     [,1]         [,2]        [,3]        [,4]       [,5]       [,6]
[1,] "algorithm"  "learning"  "model"     "learning" "neural"   "learning"
[2,] "model"      "algorithm" "report"    "neural"   "networks" "network"
[3,] "algorithms" "paper"     "models"    "networks" "network"  "feature"
[4,] "data"       "examples"  "bayesian"  "paper"    "learning" "model"
[5,] "results"    "number"    "technical" "network"  "research" "features"
     [,7]        [,8]          [,9]        [,10]
[1,] "knowledge" "problem"     "paper"     "learning"
[2,] "system"    "genetic"     "decision"  "reinforcement"
[3,] "reasoning" "control"     "algorithm" "paper"
[4,] "design"    "performance" "results"   "problem"
[5,] "case"      "search"      "method"    "method"

Les résultats sortent.

Préparation des données

vocab to use [ lda.collapsed.gibbs.sampler {lda} ](http://www.inside-r.org/packages/cran/lda/docs/lda.collapsed.gibbs.sampler) Préparez les fichiers de données correspondant à , documents.

Puisque «vocab» représente un corpus, faites d'abord une liste de mots $ N $ (sous forme de chaînes) contenus dans tous les documents. Cela fera que chaque mot sera représenté par un index $ i $ sur vocab.

{\tt vocab} = \{w_0, w_1, ..., w_{N-1}\} \\
{\tt vocab[}i{\tt]} = w_i

En tant que fichier de données, créez un corpus de corpus_r.txt avec 1 ligne = 1 mot, qui est une collection de mots dans tous les documents sans duplication.

$ head -n 5 corpus_r.txt
Assen
Capitale
la personne
Goutte
Lantanoïde
$ wc -l corpus_r.txt
20778 corpus_r.txt

documents est une liste de documents $ d_k $. Le document $ d_k $ est représenté par l'index $ i_ {k, j} $ du mot contenu dans le document et la matrice $ m \ times 2 $ du nombre d'occurrences de ce mot dans le document $ c_j $.

{\tt documents} = \{ d_0, d_1, ..., d_k, ..., d_{m-1} \} \\
d_k = \begin{pmatrix}
i_{k,0} & i_{k,1} & ... & i_{k,n-1} \\
c_{k,0} & c_{k,1} & ... & c_{k,n-1}
\end{pmatrix}

En tant que fichier de données, 1 ligne = 1 document, et préparez bow_r.txt avec l'index (à partir de 0) des mots contenus dans le document et le nombre d'occurrences séparées par deux-points.

$ head -n 5 bow_r.txt
74:1    1109:1  1788:1  7000:2  10308:2 10552:1 12332:2 13489:1 14996:1 15448:1 15947:1 16354:4 17577:1 18262:1 19831:4
3256:3  5278:1  9039:1  12247:1 14529:6 17026:3
2181:1  4062:1  6270:1  6508:1  7405:1  8662:1  15448:1 18905:1
8045:2  9323:1  5934:2
288:3   624:1   691:1   820:2   1078:2  1109:2  1148:3  1251:1  2025:1  2050:1  2072:1  2090:1  2543:2  2626:1  2759:1…
$ wc -l bow_r.txt
13017 bow_r.txt

Résultat d'exécution

Exécutez-le avec le code suivant. Il est plus gros d'analyser le fichier de données et de créer la structure de données supposée que le traitement LDA (il est peut-être plus facile d'écrire si vous êtes bon en R?).

require("lda")

vocab <- as.vector(read.table("corpus_r.txt", header=FALSE)$V1)

file <- file("bow_r.txt", "r")
docs <- list()
repeat {
  line <- readLines(con=file, 1)
  if(length(line) == 0) break
  doc <- NULL
  for(tc in strsplit(line, "\t")[[1]]){
    col <- c()
    for(c in strsplit(tc, ":")[[1]]){
      col <- c(col, as.integer(c))
    }
    if(is.null(doc))  doc <- cbind(col)
    else              doc <- cbind(doc, col)
  }
  docs <- append(docs, list(doc))
}
close(file)

result = lda.collapsed.gibbs.sampler(docs, 100, vocab, 50, 0.1, 0.1)

top.topic.words(result$topics, 5)

Lancer top.topic.words () listera les mots qui caractérisent chacun des sujets $ k = 100 $.

     [,1]   [,2]     [,3]     [,4]     [,5]     [,6]   [,7]       [,8]
[1,] "problème" "période"   "Ichiban"   "Œil"     "chambre"   "Problème" "Idole" "boîte"
[2,] "Membre du Congrès" "S'il vous plaît" "Météo"   "Fermer à clé" "Maison"     "à partir de maintenant" "ventilateur"   "partie"
[3,] "société" "procès"   "Chine"   "rotation"   "toilette" "Temple" "Bizarre"       "autocollant"
[4,] "religion" "toutes les personnes" "erreur" "Inutile"   "eau"     "Impossible" "Intérêt"     "vernis"
[5,] "Principe" "Employé à plein temps" "Tout"   "Chine"   "La lessive"   "Contenu" "Obéissant"     "information"
     [,9]   [,10]      [,11]    [,12]      [,13]    [,14]      [,15]  [,16]
[1,] "Femme" "argent"       "image"   "site"   "Chanson"     "S'il vous plaît"   "circuit" "travaux"
[2,] "Homme"   "Myopie"     "Attachement"   "Méthode"     "S'il vous plaît" "ma"     "régiment" "Compagnie"
[3,] "Masculin" "adulte"     "Plusieurs"   "enregistrement"     "piano" "Raison"     "infanterie" "patron"
[4,] "Homme"   "goûter" "Photo"   "domaine" "musiques"   "Ventes"     "Courant" "Homme"
[5,] "femme"   "Livre d'images"     "Terre" "page"   "Sentiment"   "nombre" "Photo" "lieu de travail"
... (Continue jusqu'à 100 sujets)

Recommended Posts

Comparaison des implémentations LDA
Comparaison des classificateurs en ligne
Comparaison des programmes d'adaptation
Comparaison de 4 types de frameworks Web Python
Comparaison d'Apex et de Lamvery
Comparaison de la vitesse de la perspective XML Python
Comparaison des outils de migration de base de données autonomes 2020
Comparaison des modules de conversion japonais en Python3
Comparaison de gem, bundler et pip, venv
comparaison de chaînes python / utiliser 'list' et 'in' au lieu de '==' et 'ou'
[EDA] Introduction de Sweetviz (comparaison avec + pandas-profiling)
Comparaison des solutions aux problèmes d'appariement de poids
Comparaison de l'héritage de classe et de la description du constructeur
Essayez la comparaison de vitesse de l'API BigQuery Storage
Astuces: Comparaison de la taille de trois valeurs
Comparaison des frameworks sans serveur Python-Zappa vs Chalice
Comparaison de la régularisation L1 et Leaky Relu
Comparaison de la vitesse de transposition de la matrice par Python
Comparaison de vitesse de murmurhash3, md5 et sha1