Premiers pas pour l'apprentissage profond en Java

Cet article a été écrit dans le but de repousser les personnes qui souhaitent faire du deep learning en Java mais ne peuvent pas faire le premier pas. Vous pouvez facilement découvrir la puissance de l'apprentissage en profondeur, alors veuillez le lire.

Public cible

Nous supposons que l'une des personnes suivantes est un lecteur.

--Un programmeur Java qui veut essayer le deep learning, mais qui n'a jamais écrit de programme en Python ...

En lisant cet article, vous serez en mesure de créer un environnement de développement d'apprentissage en profondeur en utilisant Deeplearning4j avec IntelliJ et d'identifier les nombres manuscrits. Il vous permet également d'exécuter de nombreux exemples d'apprentissage en profondeur en plus de l'identification des numéros. Cependant, vous ne pouvez pas apprendre la théorie de l'apprentissage profond à partir de cet article. Pour apprendre la théorie du deep learning "[Deep Learning from scratch-The Theory and Implementation of Deep Learning Learn with Python](https://www.amazon.co.jp/%E3%82%BC%E3%83%] AD% E3% 81% 8B% E3% 82% 89% E4% BD% 9C% E3% 82% 8B Apprentissage en profondeur-% E2% 80% 95Python% E3% 81% A7% E5% AD% A6% E3% 81 % B6% E3% 83% 87% E3% 82% A3% E3% 83% BC% E3% 83% 97% E3% 83% A9% E3% 83% BC% E3% 83% 8B% E3% 83% B3 % E3% 82% B0% E3% 81% AE% E7% 90% 86% E8% AB% 96% E3% 81% A8% E5% AE% 9F% E8% A3% 85-% E6% 96% 8E% Nous vous recommandons de lire E8% 97% A4-% E5% BA% B7% E6% AF% 85 / dp / 4873117585).

Faites d'abord l'expérience

Je pense que la première étape pour commencer à apprendre le deep learning est d'exécuter le programme et de le «vivre» afin de vous motiver à apprendre. Voir ci-dessous.

hadwrt.gif

Lorsque vous entrez un numéro manuscrit, ce programme affichera le numéro identifié (prédit) dans «Prédiction:» au bas de l'écran.

Si vous voulez écrire un programme qui identifie l'image du nombre manuscrit "7" sans utiliser une bibliothèque spéciale, quel type d'algorithme utiliseriez-vous? Est-ce correct si l'algorithme distingue "7" s'il y a une ligne horizontale en haut de l'image et une ligne descendante à partir du point final? L'algorithme peut-il identifier correctement l'un des éléments suivants comme un «7»? Et comment l'intégrer à votre programme? 0.png36.png255.png2671.png1096.png2622.png8387.png

Identifier des nombres faciles pour les humains n'est pas si facile pour les ordinateurs (lorsqu'ils essaient de les atteindre avec des algorithmes). Mais l'apprentissage en profondeur peut le faire. Et dans cet article, nous allons exécuter le programme ci-dessus.

Configuration requise

La configuration système requise pour Deeplearning4j est la suivante:

--Java 1.7 ou version 64 bits supérieure (définissez également JAVA_HOME) --Maven ou Gradle --IntelliJ ou Eclipse

Environnement utilisé pour la vérification

L'environnement utilisé pour écrire cet article est le suivant.

$ mvn -version
Apache Maven 3.5.0
Maven home: /usr/share/maven
Java version: 1.8.0_171, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.13.0-21-generic", arch: "amd64", family: "unix"

$ git --version
git version 2.14.1

Remarques

Cela prend beaucoup d'espace disque, donc vous voudrez peut-être construire uniquement le sous-projet dl4j-examples des dl4j-examples. Si vous souhaitez créer l'ensemble du projet, vous avez besoin d'au moins 15 Go d'espace libre.

: avertissement: Un grand nombre de fichiers JAR seront téléchargés dans les répertoires suivants, donc lorsque vous supprimez le répertoire de Deeplearning4j qui était git clone, supprimez également ce répertoire.

.m2/repository/org/deeplearning4j/

Procédure de construction de l'environnement de développement

Pour créer l'environnement de développement, procédez comme suit:

$ git clone https://github.com/deeplearning4j/dl4j-examples.git
$ cd dl4j-examples/dl4j-examples
$ mvn clean install

Cependant, comme il est utilisé pour dessiner l'écran, veuillez également installer OpenJFX (Java FX) si nécessaire. Sans Java FX, vous obtiendrez l'erreur suivante au moment de la construction:

[ERROR] /home/tamura/git/dl4j-examples/dl4j-examples/src/main/java/org/deeplearning4j/examples/recurrent/character/harmonies/Piano.java:[4,24]Paquet javafx.l'animation n'existe pas

Si vous avez Ubuntu 17.10, vous pouvez l'installer avec:

$ sudo apt-get install openjfx

Contrôle de fonctionnement

Après avoir construit l'environnement de développement, essayons l'identification des nombres manuscrits (l'exemple que nous avons vu plus tôt) qui se positionnent comme "Hello world!" Dans le deep learning. Dans l'apprentissage profond, une grande quantité de données est d'abord «apprise» pour en déduire les paramètres optimaux. Ensuite, sur cette base, nous faisons une «prédiction». La procédure est la suivante.

  1. Lorsque la génération est terminée, ouvrez le projet dans IntelliJ.

  2. Ouvrez le code source de ʻorg.deeplearning4j.examples.convolution.mnist.MnistClassifier` et exécutez-le (cliquez sur le bouton exécuter du triangle vert sur le côté gauche de l'éditeur) (cette étape fait "apprendre") .. 68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f34333836392f33616432346264362d383263662d373361372d313831642d3166363139303835643639662e706e67.png
    以下のようなメッセージが出力されます。

    /usr/lib/jvm/java-8-openjdk-amd64/bin/java -javaagent:/home/tamura/idea-IC-181.5087.20 ... (omis) ... org.deeplearning4j.examples.convolution.mnist.MnistClassifier
    o.d.e.c.m.MnistClassifier - Data load and vectorization...
    o.d.i.r.BaseImageRecordReader - ImageRecordReader: 10 label classes inferred using label generator ParentPathLabelGenerator
    o.d.i.r.BaseImageRecordReader - ImageRecordReader: 10 label classes inferred using label generator ParentPathLabelGenerator
    o.d.e.c.m.MnistClassifier - Network configuration and training...
    o.n.l.f.Nd4jBackend - Loaded [CpuBackend] backend
    o.n.n.NativeOpsHolder - Number of threads used for NativeOps: 1
    o.n.n.Nd4jBlas - Number of threads used for BLAS: 1
    o.n.l.a.o.e.DefaultOpExecutioner - Backend used: [CPU]; OS: [Linux]
    o.n.l.a.o.e.DefaultOpExecutioner - Cores: [4]; Memory: [0.9GB];
    o.n.l.a.o.e.DefaultOpExecutioner - Blas vendor: [MKL]
    o.d.n.m.MultiLayerNetwork - Starting MultiLayerNetwork with WorkspaceModes set to [training: ENABLED; inference: ENABLED], cacheMode set to [NONE]
    o.d.o.l.ScoreIterationListener - Score at iteration 0 is 2.4694731759178388
    o.d.o.l.ScoreIterationListener - Score at iteration 10 is 1.078069156582683
    o.d.o.l.ScoreIterationListener - Score at iteration 20 is 0.7327581484283221
    

... (Omis) ... o.d.o.l.ScoreIterationListener - Score at iteration 1100 is 0.20279510458591593 o.d.o.l.ScoreIterationListener - Score at iteration 1110 is 0.10997898485405874 o.d.e.c.m.MnistClassifier - Completed epoch 0 o.d.e.c.m.MnistClassifier -

========================Evaluation Metrics========================
 # of classes:    10
 Accuracy:        0.9891
 Precision:       0.9891
 Recall:          0.9890
 F1 Score:        0.9891
Precision, recall & F1: macro-averaged (equally weighted avg. of 10 classes)


=========================Confusion Matrix=========================
	0    1    2    3    4    5    6    7    8    9
---------------------------------------------------
  973    0    0    0    0    0    2    2    3    0 | 0 = 0
	0 1132    0    1    0    1    1    0    0    0 | 1 = 1
	2    3 1018    1    0    0    1    6    1    0 | 2 = 2
	0    0    1 1000    0    3    0    4    1    1 | 3 = 3
	0    0    1    0  973    0    3    0    0    5 | 4 = 4
	1    0    0    5    0  882    2    1    1    0 | 5 = 5
	5    2    0    0    2    3  944    0    2    0 | 6 = 6
	0    2    4    0    0    0    0 1017    2    3 | 7 = 7
	3    0    2    1    0    0    1    2  961    4 | 8 = 8
	4    2    1    1    3    0    0    6    1  991 | 9 = 9

Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================

Process finished with exit code 0
```
  1. Ouvrez et exécutez le code source de ʻorg.deeplearning4j.examples.convolution.mnist.MnistClassifierUI`
  2. Lorsque l'écran Java FX qui accepte les nombres manuscrits s'affiche, saisissez les nombres (cette étape effectue une «prédiction»).

Lecture du code source

Alors, quel est le mécanisme pour y parvenir? Images numériques manuscrites "d'apprentissage" [code source Mnist Classifier](https://github.com/deeplearning4j/dl4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/ Jetons un coup d'œil à convolution / mnist / MnistClassifier.java) d'en haut.

: information_source: Une connaissance de base du deep learning est nécessaire pour comprendre les sections suivantes.

Le premier est la destination de téléchargement de l'image numérique manuscrite, les constantes du répertoire temporaire pour le décompresser et les variables de champ de l'enregistreur.

MnistClassifier


public class MnistClassifier {

  private static final Logger log = LoggerFactory.getLogger(MnistClassifier.class);
  private static final String basePath = System.getProperty("java.io.tmpdir") + "/mnist";
  private static final String dataUrl = "http://github.com/myleott/mnist_png/raw/master/mnist_png.tar.gz";

Et cela devient la méthode main () de cette classe. L'appel de cette méthode commencera à apprendre. L'image d'entrée est transmise à la couche d'entrée sous forme de données 3D avec 1 canal et 28 pixels chacun dans les directions verticale et horizontale. Puisqu'il identifie les nombres de 1 à 10, il a 10 couches de sortie, 54 tailles de lots et 1 époque.

  public static void main(String[] args) throws Exception {
    int height = 28;
    int width = 28;
    int channels = 1; // single channel for grayscale images
    int outputNum = 10; // 10 digits classification
    int batchSize = 54;
    int nEpochs = 1;
    int iterations = 1;

    int seed = 1234;
    Random randNumGen = new Random(seed);

Ensuite, téléchargez le mnist_png.tar.gz compressé de 70 000 images numérotées manuscrites depuis GitHub. Et décompressez-le.

    log.info("Data load and vectorization...");
    String localFilePath = basePath + "/mnist_png.tar.gz";
    if (DataUtilities.downloadFile(dataUrl, localFilePath))
      log.debug("Data downloaded from {}", dataUrl);
    if (!new File(basePath + "/mnist_png").exists())
      DataUtilities.extractTarGz(localFilePath, basePath);

Divisez les données d'apprentissage (formation) (60 000) et les données de test (10 000) et stockez-les dans les variables d'itérateur de «trainIter» et «testIter», respectivement.

    // vectorization of train data
    File trainData = new File(basePath + "/mnist_png/training");
    FileSplit trainSplit = new FileSplit(trainData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
    ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator(); // parent path as the image label
    ImageRecordReader trainRR = new ImageRecordReader(height, width, channels, labelMaker);
    trainRR.initialize(trainSplit);
    DataSetIterator trainIter = new RecordReaderDataSetIterator(trainRR, batchSize, 1, outputNum);

    // pixel values from 0-255 to 0-1 (min-max scaling)
    DataNormalization scaler = new ImagePreProcessingScaler(0, 1);
    scaler.fit(trainIter);
    trainIter.setPreProcessor(scaler);

    // vectorization of test data
    File testData = new File(basePath + "/mnist_png/testing");
    FileSplit testSplit = new FileSplit(testData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
    ImageRecordReader testRR = new ImageRecordReader(height, width, channels, labelMaker);
    testRR.initialize(testSplit);
    DataSetIterator testIter = new RecordReaderDataSetIterator(testRR, batchSize, 1, outputNum);
    testIter.setPreProcessor(scaler); // same normalization for better results

Ensuite, ajoutez le paramètre de taux d'apprentissage au HashMap avec le nom de variable lrSchedule. Si le taux d'apprentissage est élevé, l'apprentissage se déroulera rapidement dans la première moitié, mais il ne convergera pas facilement dans la seconde moitié, de sorte que le taux d'apprentissage est abaissé en fonction du nombre de cas traités. Dans ce programme, l'entraînement est répété 1 111 fois (= données d'entraînement: 60 000 / taille du lot: 54). Le taux d'apprentissage est progressivement abaissé en fonction du nombre de répétitions.

    log.info("Network configuration and training...");
    Map<Integer, Double> lrSchedule = new HashMap<>();
    lrSchedule.put(0, 0.06); // iteration #, learning rate
    lrSchedule.put(200, 0.05);
    lrSchedule.put(600, 0.028);
    lrSchedule.put(800, 0.0060);
    lrSchedule.put(1000, 0.001);

À partir de là, le traitement principal de la construction du réseau neuronal est effectué. Ajoutez une couche au réseau neuronal en l'appelant avec la méthode layer () de NeuralNetConfiguration.Builder (). Aucune couche d'entrée supplémentaire n'est requise, donc la première couche à ajouter est la «couche de convolution». Ensuite, nous ajoutons une "couche de sous-échantillonnage". Puis répétez-le, suivi de DenseLayer (couche entièrement connectée), et enfin ajoutez ʻOutputLayer` (couche de sortie). Il s'agit d'une configuration CNN (réseau de neurones convolutifs) souvent utilisée dans la reconnaissance d'images.

    MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
        .seed(seed)
        .l2(0.0005)
        .updater(new Nesterovs(new MapSchedule(ScheduleType.ITERATION, lrSchedule)))
        .weightInit(WeightInit.XAVIER)
        .list()
        .layer(0, new ConvolutionLayer.Builder(5, 5)
            .nIn(channels)
            .stride(1, 1)
            .nOut(20)
            .activation(Activation.IDENTITY)
            .build())
        .layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
            .kernelSize(2, 2)
            .stride(2, 2)
            .build())
        .layer(2, new ConvolutionLayer.Builder(5, 5)
            .stride(1, 1) // nIn need not specified in later layers
            .nOut(50)
            .activation(Activation.IDENTITY)
            .build())
        .layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
            .kernelSize(2, 2)
            .stride(2, 2)
            .build())
        .layer(4, new DenseLayer.Builder().activation(Activation.RELU)
            .nOut(500).build())
        .layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
            .nOut(outputNum)
            .activation(Activation.SOFTMAX)
            .build())
        .setInputType(InputType.convolutionalFlat(28, 28, 1)) // InputType.convolutional for normal image
        .backprop(true).pretrain(false).build();

ʻActivation.IDENTITY est une fonction égale ($ \ scriptsize {f (x) = x} $, c'est-à-dire ne rien faire) pour la fonction d'activation, ʻActivation.RELU est une fonction ReLU et ʻActivation.SOFTMAX` est souple. Signifie utiliser la fonction Max.

Cela peut être difficile à comprendre avec des mots seuls, j'ai donc essayé d'illustrer la configuration du réseau neuronal. cnn1.png En comparant ce chiffre avec le code source, si vous ne comprenez pas, veuillez consulter Deeplearning4j Cheat Sheet etc. N'expliquera pas).

Allons-nous en. Si vous l'appelez avec la méthode setListeners () de MultiLayerNetwork, l'état d'apprentissage sera affiché périodiquement.

    MultiLayerNetwork net = new MultiLayerNetwork(conf);
    net.init();
    net.setListeners(new ScoreIterationListener(10));
    log.debug("Total num of params: {}", net.numParams());

Enfin, appelez la méthode fit () pour commencer l'entraînement avec les données d'entraînement. Lorsque la formation est terminée, donnez les données de test à MultiLayerNetwork.evaluate () et évaluez-les. Enfin, enregistrez les paramètres dérivés ensemble dans minist-model.zip.

    // evaluation while training (the score should go down)
    for (int i = 0; i < nEpochs; i++) {
      net.fit(trainIter);
      log.info("Completed epoch {}", i);
      Evaluation eval = net.evaluate(testIter);
      log.info(eval.stats());
      trainIter.reset();
      testIter.reset();
    }
    ModelSerializer.writeModel(net, new File(basePath + "/minist-model.zip"), true);
  }
}

Une autre classe, «MnistClassifierUI», lit ce «minist-model.zip» pour construire un réseau neuronal et «prédire» des images numériques manuscrites. Une explication détaillée de «MnistClassifierUI» est omise.

application

Modifions un peu le code source de MnistClassifier et faisons diverses expériences.

Tracez la situation d'apprentissage

Modifions la classe d'écouteur donnée à la méthode setListeners () de MultiLayerNetwork par autre chose. Définissons la classe d'écouteur introduite dans cette page.

    // net.setListeners(new ScoreIterationListener(10));
    //Commentez la ligne du haut et ajoutez les 4 lignes du bas
    UIServer uiServer = UIServer.getInstance();
    StatsStorage statsStorage = new InMemoryStatsStorage();
    uiServer.attach(statsStorage);
    net.setListeners(Arrays.asList(new ScoreIterationListener(1), new StatsListener(statsStorage)));

Après avoir modifié le code source, exécutez à nouveau le programme. Ce qui suit est émis vers la sortie standard,

o.d.u.p.PlayUIServer - DL4J UI Server started at http://localhost:9000

Lorsque vous accédez à http: // localhost: 9000, vous verrez un graphique qui visualise la situation d'apprentissage actuelle d'une manière facile à comprendre, comme indiqué ci-dessous.

Screenshot from 2018-12-12 14-35-36.png

: information_source: Cliquez sur l'onglet "Langue" sur le côté droit de l'écran et sélectionnez japonais.

Vous pouvez voir la configuration de ce réseau de neurones dans un schéma simple en cliquant sur l'onglet "Système".

Screenshot from 2018-12-12 15-21-59.png

Changer l'algorithme d'optimisation

Ensuite, changeons l'algorithme d'optimisation en méthode Stocastic Gradient Descent (SGD). Remplacez Nesterovs dans l'argument de la méthode ʻupdater () de NeuralNetConfiguration.Builder () par Sgd.

Et quand j'ai lancé le programme, j'ai obtenu le résultat suivant.

========================Evaluation Metrics========================
 # of classes:    10
 Accuracy:        0.9698
 Precision:       0.9696
 Recall:          0.9697
 F1 Score:        0.9697
Precision, recall & F1: macro-averaged (equally weighted avg. of 10 classes)


=========================Confusion Matrix=========================
    0    1    2    3    4    5    6    7    8    9
---------------------------------------------------
  969    0    1    0    0    2    3    1    4    0 | 0 = 0
    0 1120    3    2    0    1    3    0    6    0 | 1 = 1
    6    2  993    4    6    3    3    9    6    0 | 2 = 2
    1    0    7  976    0    7    0    9    7    3 | 3 = 3
    1    1    2    0  955    0    5    2    2   14 | 4 = 4
    2    1    0   11    1  866    5    1    3    2 | 5 = 5
   10    3    1    0    6    3  933    0    2    0 | 6 = 6
    2    8   16    2    1    0    0  982    3   14 | 7 = 7
    6    0    1    4    4    5    4    6  941    3 | 8 = 8
    5    7    0    9   11    7    1    5    1  963 | 9 = 9

Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================

La précision a un peu baissé. J'en ai essayé quelques-uns, mais dans ce cas, «Nesterovs» (la méthode de descente de gradient accélérée de Nesterov) semble être un bon choix.

Réglez la valeur initiale du poids à zéro

Osons le déplacer avec des paramètres incorrects. Donnez WeightInit.ZERO à la méthode weightInit () deNeuralNetConfiguration.Builder ()pour mettre le poids initial à zéro.

De cette façon, le score se terminera autour de "2,3" avec presque aucun changement. Et enfin, toutes les images devraient être "1".

=========================Confusion Matrix=========================
    0    1    2    3    4    5    6    7    8    9
---------------------------------------------------
    0  980    0    0    0    0    0    0    0    0 | 0 = 0
    0 1135    0    0    0    0    0    0    0    0 | 1 = 1
    0 1032    0    0    0    0    0    0    0    0 | 2 = 2
    0 1010    0    0    0    0    0    0    0    0 | 3 = 3
    0  982    0    0    0    0    0    0    0    0 | 4 = 4
    0  892    0    0    0    0    0    0    0    0 | 5 = 5
    0  958    0    0    0    0    0    0    0    0 | 6 = 6
    0 1028    0    0    0    0    0    0    0    0 | 7 = 7
    0  974    0    0    0    0    0    0    0    0 | 8 = 8
    0 1009    0    0    0    0    0    0    0    0 | 9 = 9

Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================

En effet, toutes les valeurs de poids sont mises à jour uniformément.

Résumé

J'ai donc essayé d'identifier facilement les numéros manuscrits en utilisant Deeplearning4j. Avec cela, je pense que nous avons franchi le premier pas vers l'apprentissage profond en Java. Le code source de git clone contient de nombreux autres exemples. À l'étape suivante, vous souhaiterez peut-être essayer d'exécuter un autre programme. Ceux qui ne comprennent pas la théorie sont invités à lire les livres mentionnés ci-dessus.

référence

Recommended Posts

Premiers pas pour l'apprentissage profond en Java
Pour l'apprentissage JAVA (2018-03-16-01)
Étudiez le Deep Learning à partir de zéro en Java.
Apprendre pour la première fois java [Introduction]
L'histoire de l'apprentissage de Java dans la première programmation
[Deep Learning from scratch] dans Java 3. Réseau neuronal
Livres utilisés pour apprendre Java
Mémo d'apprentissage lors de l'apprentissage de Java pour la première fois (mémo d'apprentissage personnel)
Premier développement Java dans Eclipse
Collecte de copies approfondies en Java
[Deep Learning from scratch] en Java 1. Pour le moment, différenciation et différenciation partielle
Enfant orienté objet!? J'ai essayé le Deep Learning avec Java (édition d'essai)
Deep Learning Java from scratch 6.4 Régularisation
[Pour les débutants] Exécutez Selenium sur Java
Paramètres de débogage SSL dans Java
Apprendre Java (0)
[DL4J] Premier apprentissage en profondeur Java (reconnaissance de caractères manuscrits à l'aide d'un réseau neuronal entièrement connecté)
Points clés pour l'introduction de gRPC en Java
Deep Learning Java à partir de zéro Chapitre 1 Introduction
Deep Learning Java from scratch 6.1 Mise à jour des paramètres
Deep Learning Java à partir de zéro Chapitre 2 Perceptron
Deep Learning Java from scratch 6.3 Normalisation par lots
[Communication Socket (Java)] Impressions de la mise en œuvre de la communication Socket dans la pratique pour la première fois
Première programmation de ma vie Java 1st Hello World
[Apprentissage profond à partir de zéro] 2. Il n'existe pas de NumPy en Java.
9 meilleurs sites pour apprendre Java par auto-apprentissage
ChatWork4j pour l'utilisation de l'API ChatWork en Java
Jour d'apprentissage Java 5
Deep Learning from scratch Java Chapter 4 Apprentissage des réseaux de neurones
Changements dans Java 11
La solution pour NetBeans 8.2 ne fonctionne pas dans l'environnement Java 9
Janken à Java
Configuration PC la plus rapide pour un apprentissage en profondeur à partir de zéro
Impressions et doutes sur l'utilisation de Java pour la première fois dans Android Studio
Créez votre propre application Android pour l'apprentissage Java
IDE 2017 pour Java
Définissez un affichage contextuel pour le langage Java avec vim.
Taux circonférentiel à Java
Deep Learning Java à partir de zéro Chapitre 3 Réseau neuronal
Java pour instruction
FizzBuzz en Java
Comparez la sortie PDF en Java pour les tests d'instantanés
java learning day 2
Activer / désactiver SNI en Java pour chaque communication
Points à connaître avec Java Equals
java learning day 1
Points à surveiller dans le développement futur de Java
[Mémo personnel] Créez une copie complète simple avec Java
Remarque sur l'initialisation des champs dans le didacticiel Java
[Pour les débutants] Exemple minimum pour afficher RecyclerView en Java
Obtention des objets Locale pour tous les paramètres régionaux disponibles en Java
Apprentissage pour la première fois des expressions et opérateurs Java # 3
Ceci et cela pour éditer ini en Java. : inieditor-java
[Java] explique ConcurrentModificationException qui se produit dans java.util.ArrayList pour les nouveaux arrivants
J'ai essayé d'utiliser l'instruction Extended for en Java
Deep Learning Java from scratch 6.2 Valeur initiale du poids
[mémo] Générer une paire de clés RSA pour SSH en Java