En essayant de faire du machine learning avec Java ou Scala, je pense que beaucoup de gens ont constaté qu'il n'y avait pas d'outil graphique sympa et que Python avait Matplotlib.
Par conséquent, j'ai créé Matplotlib4j, une bibliothèque qui vous permet d'appeler Matplotlib à partir de Java, je voudrais donc l'introduire.
Voici un exemple de Java. Bien sûr, il peut également être utilisé à partir d'autres langages JVM tels que Scala et Kotlin. Un exemple sera décrit plus loin.
Tout d'abord, ajoutez Matplotlib4j au projet Java dans lequel vous souhaitez utiliser Matplotlib.
Pour Maven, ajoutez la dépendance suivante.
Maven
<dependency>
<groupId>com.github.sh0nk</groupId>
<artifactId>matplotlib4j</artifactId>
<version>0.4.0</version>
</dependency>
De même, pour Gradle, cela ressemble à ceci:
Gradle
compile 'com.github.sh0nk:matplotlib4j:0.4.0'
L'utilisation est similaire à l'API Matplotlib, vous pouvez donc l'écrire de manière intuitive. Créez d'abord un objet Plot, ajoutez un graphe arbitraire en lui appelant la méthode pyploy, et enfin appelez la méthode show (). Puisqu'il s'agit d'un modèle Builder, nous ajouterons des options derrière lui en utilisant la complétion IDE.
Comme point de départ, dessinons un diagramme de dispersion.
ScatterPlot
List<Double> x = NumpyUtils.linspace(-3, 3, 100);
List<Double> y = x.stream().map(xi -> Math.sin(xi) + Math.random()).collect(Collectors.toList());
Plot plt = Plot.create();
plt.plot().add(x, y, "o").label("sin");
plt.legend().loc("upper right");
plt.title("scatter");
plt.show();
Certaines méthodes Numpy, telles que linspace
et meshgrid
, sont fournies sous forme de classes NumpyUtils
pour vous aider à dessiner des graphiques. Nous générons des données x et y pour le traçage dans le premier bloc. Ici, une valeur aléatoire est donnée à la courbe de sin. Après cela, créez un objet Plot, ajoutez les x et y générés à la méthode plot ()
, et enfin appelez show ()
pour dessiner le graphique.
Ceci est à peu près équivalent à l'implémentation Python ci-dessous (presque parce que la partie génération de données de numpy est strictement différente). Les méthodes sont dites similaires et sont plus faciles à utiliser pour Pythonista.
PythonScatterPlot
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
y = np.sin(x) + np.random.rand(100)
plt.plot(x, y, "o", label="sin")
plt.legend(loc="upper right")
plt.title("scatter")
plt.show()
Avec le code Java ci-dessus, vous pouvez dessiner le graphique suivant.
Ensuite, dessinons un diagramme de contour (ligne de contour).
ContourPlot
List<Double> x = NumpyUtils.linspace(-1, 1, 100);
List<Double> y = NumpyUtils.linspace(-1, 1, 100);
NumpyUtils.Grid<Double> grid = NumpyUtils.meshgrid(x, y);
List<List<Double>> zCalced = grid.calcZ((xi, yj) -> Math.sqrt(xi * xi + yj * yj));
Plot plt = Plot.create();
ContourBuilder contour = plt.contour().add(x, y, zCalced);
plt.clabel(contour)
.inline(true)
.fontsize(10);
plt.title("contour");
plt.show();
Vous pouvez dessiner un histogramme de la même manière.
HistogramPlot
Random rand = new Random();
List<Double> x1 = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
.collect(Collectors.toList());
List<Double> x2 = IntStream.range(0, 1000).mapToObj(i -> 4.0 + rand.nextGaussian())
.collect(Collectors.toList());
Plot plt = Plot.create();
plt.hist()
.add(x1).add(x2)
.bins(20)
.stacked(true)
.color("#66DD66", "#6688FF");
plt.xlim(-6, 10);
plt.title("histogram");
plt.show();
Matplotlib4j prend également en charge l'enregistrement dans des fichiers. L'enregistrement du fichier image est pratique pour les cas d'utilisation qui ne disposent pas d'une interface graphique, tels que le traitement périodique de l'apprentissage automatique sur le serveur.
Semblable à l'original Matplotlib, en utilisant la méthode .savefig ()
au lieu de .show ()
, l'image est enregistrée dans un fichier au lieu de faire apparaître la fenêtre de tracé. La seule différence est que «.savefig ()» est suivi de «plt.executeSilently ()». (Ceci est nécessaire pour terminer le traitement car la commande savefig est également connectée par une chaîne de méthodes.)
Random rand = new Random();
List<Double> x = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
.collect(Collectors.toList());
Plot plt = Plot.create();
plt.hist().add(x).orientation(HistBuilder.Orientation.horizontal);
plt.ylim(-5, 5);
plt.title("histogram");
plt.savefig("/tmp/histogram.png ").dpi(200);
//Requis pour sortir le fichier
plt.executeSilently();
En conséquence, l'image suivante sera sortie.
Pour utiliser Matplotlib4j, vous devez utiliser Python avec Matplotlib installé. Par défaut, Matplotlib4j utilise Python qui se trouve dans le chemin, mais je pense qu'il existe de nombreux cas où Matplotlib n'est pas installé dans le système Python par défaut.
Dans ce cas, vous pouvez basculer vers un environnement Python avec Matplotlib installé, tel qu'Anaconda, en utilisant pyenv ou pyenv-virtualenv.
Pour utiliser Python selon l'environnement de Pyenv, spécifiez PythonConfig comme suit lors de la création d'un objet Plot.
pyenv
Plot plot = Plot.create(PythonConfig.pyenvConfig("Tout nom d'environnement pyenv"));
De même, vous pouvez spécifier le nom d'environnement de pyenv-virtualenv.
pyenv-virtualenv
Plot plot = Plot.create(PythonConfig.pyenvVirtualenvConfig("Tout nom d'environnement pyenv", "Tout nom d'environnement virtualenv"));
Scala
Lors de l'utilisation de Scala, l'exemple ci-dessus du diagramme de dispersion peut être écrit comme suit. À ce moment-là, faites attention à la différence entre les classes Box / Unbox et List.
ScalaScatter
import scala.collection.JavaConverters._
val x = NumpyUtils.linspace(-3, 3, 100).asScala.toList
val y = x.map(xi => Math.sin(xi) + Math.random()).map(Double.box)
val plt = Plot.create()
plt.plot().add(x.asJava, y.asJava, "o")
plt.title("scatter")
plt.show()
J'ai récemment commencé à lire "Deep Learning from scratch-The Theory and Implementation of Deep Learning Learn with Python", mais avec Python tel quel Ce n'est pas intéressant de le copier, j'ai donc décidé de l'implémenter avec Scala, que j'ai beaucoup touché récemment. J'ai pu l'écrire comme un type de fonction dans Scala, et j'en ai été très satisfait, mais seulement lorsque j'ai abordé la propagation arrière par la méthode de descente la plus raide, la perte n'a pas du tout diminué, n'y a-t-il pas un bug quelque part? Je suis tombé sur la situation.
Bien sûr, je pense que c'est une pratique courante dans de tels cas que vous pouvez comprendre en épaississant le test, mais avant tout, j'aimerais afficher rapidement le graphique comme dans le livre et voir ce qui se passe. Mais avec Scala, il n'y a pas d'outil graphique sympa ... Cependant, implémenter l'outil graphique à partir de zéro est trop terrible ... J'ai donc décidé d'utiliser Matplotlib, qui est familier avec Python, et c'est la raison pour laquelle j'ai créé la bibliothèque.
Matplotlib4j appelle Matplotlib sous la forme de génération de code Python sans utiliser JNI ou Jython. Au début, je pensais l'implémenter en utilisant Jython, mais en premier lieu la version Python ne prend en charge que jusqu'à 2.7, et numpy ne peut pas être utilisé, donc cela en dépend. J'ai décidé d'abandonner cette voie car Matplotlib ne fonctionne pas non plus.
Il existe également une Bibliothèque qui permet d'utiliser CPython à partir du code Java, et c'est un candidat car Python3 et numpy peuvent être utilisés. Cependant, pour utiliser JNI, une bibliothèque séparée dépendante de l'environnement est installée, et du côté Python, il est nécessaire d'installer la bibliothèque à partir de pip, donc cela prend trop de temps pour l'utiliser juste pour dessiner un graphique. Après tout, j'ai décidé de l'implémenter indépendamment de ces bibliothèques.
Bien sûr, comme il est exécuté via un fichier, il est nécessaire de concevoir comment passer les variables et utiliser la valeur de retour, et les performances sont-elles bonnes? Je suis inquiet à ce sujet. Heureusement, puisque le seul but est de dessiner un graphique, les fonctions de base peuvent être satisfaites en sortant unilatéralement dans un fichier, et je pense qu'un certain temps d'attente pour les performances est dans la plage autorisée.
Recommended Posts