@Test public void testAbstractW2VModel() throws Exception { ClassPathResource resource = new ClassPathResource("big/raw_sentences.txt"); File file = resource.getFile(); logger.info("dtype: {}", Nd4j.dataType()); AbstractCache<VocabWord> vocabCache = new AbstractCache.Builder<VocabWord>().build(); BasicLineIterator underlyingIterator = new BasicLineIterator(file); TokenizerFactory t = new DefaultTokenizerFactory(); t.setTokenPreProcessor(new CommonPreprocessor()); SentenceTransformer transformer = new SentenceTransformer.Builder().iterator(underlyingIterator).tokenizerFactory(t).build(); AbstractSequenceIterator<VocabWord> sequenceIterator = new AbstractSequenceIterator.Builder<>(transformer).build(); VocabConstructor<VocabWord> constructor = new VocabConstructor.Builder<VocabWord>() .addSource(sequenceIterator, 5).setTargetVocabCache(vocabCache).build(); constructor.buildJointVocabulary(false, true); assertEquals(242, vocabCache.numWords()); assertEquals(634303, vocabCache.totalWordOccurrences()); VocabWord wordz = vocabCache.wordFor("day"); logger.info("Wordz: " + wordz); WeightLookupTable<VocabWord> lookupTable = new InMemoryLookupTable.Builder<VocabWord>().lr(0.025) .vectorLength(150).useAdaGrad(false).cache(vocabCache).build(); lookupTable.resetWeights(true); SequenceVectors<VocabWord> vectors = new SequenceVectors.Builder<VocabWord>(new VectorsConfiguration()) .minWordFrequency(5) .lookupTable(lookupTable) .iterate(sequenceIterator) .vocabCache(vocabCache) .batchSize(250) .iterations(1) .epochs(1) .resetModel(false) .trainElementsRepresentation(true).trainSequencesRepresentation(false) .build(); logger.info("Starting training..."); vectors.fit(); logger.info("Model saved..."); double sim = vectors.similarity("day", "night"); logger.info("Day/night similarity: " + sim); assertTrue(sim > 0.6d); Collection<String> labels = vectors.wordsNearest("day", 10); logger.info("Nearest labels to 'day': " + labels); SequenceElementFactory<VocabWord> factory = new AbstractElementFactory<VocabWord>(VocabWord.class); WordVectorSerializer.writeSequenceVectors(vectors, factory, "seqvec.mod"); SequenceVectors<VocabWord> model = WordVectorSerializer.readSequenceVectors(factory, new File("seqvec.mod")); sim = model.similarity("day", "night"); logger.info("day/night similarity: " + sim); }
public void fit() { val props = Nd4j.getExecutioner().getEnvironmentInformation(); if (props.getProperty("backend").equals("CUDA")) { if (Nd4j.getAffinityManager().getNumberOfDevices() > 1) throw new IllegalStateException("Multi-GPU word2vec/doc2vec isn't available atm"); } Nd4j.getRandom().setSeed(configuration.getSeed()); AtomicLong timeSpent = new AtomicLong(0); if (!trainElementsVectors && !trainSequenceVectors) throw new IllegalStateException( "You should define at least one training goal 'trainElementsRepresentation' or 'trainSequenceRepresentation'"); if (iterator == null) throw new IllegalStateException("You can't fit() data without SequenceIterator defined"); if (resetModel || (lookupTable != null && vocab != null && vocab.numWords() == 0)) { buildVocab(); } WordVectorSerializer.printOutProjectedMemoryUse(vocab.numWords(), configuration.getLayersSize(), configuration.isUseHierarchicSoftmax() && configuration.getNegative() > 0 ? 3 : 2); if (vocab == null || lookupTable == null || vocab.numWords() == 0) throw new IllegalStateException("You can't fit() model with empty Vocabulary or WeightLookupTable"); if (!resetModel || existingModel != null) { lookupTable.resetWeights(false); } else { lookupTable.resetWeights(true); if (configuration.isPreciseWeightInit()) { log.info("Using precise weights init..."); iterator.reset(); while (iterator.hasMoreSequences()) { val sequence = iterator.nextSequence(); for (T element : sequence.getElements()) { T realElement = vocab.tokenFor(element.getLabel()); if (realElement != null && !realElement.isInit()) { val rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); val randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } for (T label : sequence.getSequenceLabels()) { T realElement = vocab.tokenFor(label.getLabel()); if (realElement != null && !realElement.isInit()) { Random rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); INDArray randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } } this.iterator.reset(); } } initLearners(); initIntersectVectors(); log.info("Starting learning process..."); timeSpent.set(System.currentTimeMillis()); if (this.stopWords == null) this.stopWords = new ArrayList<>(); val wordsCounter = new AtomicLong(0); for (int currentEpoch = 1; currentEpoch <= numEpochs; currentEpoch++) { val linesCounter = new AtomicLong(0); val sequencer = new AsyncSequencer(this.iterator, this.stopWords); sequencer.start(); val timer = new AtomicLong(System.currentTimeMillis()); val thread = new VectorCalculationsThread(0, currentEpoch, wordsCounter, vocab.totalWordOccurrences(), linesCounter, sequencer, timer, numEpochs); thread.start(); try { sequencer.join(); } catch (Exception e) { throw new RuntimeException(e); } try { thread.join(); } catch (Exception e) { throw new RuntimeException(e); } if (trainElementsVectors && elementsLearningAlgorithm != null && (!trainSequenceVectors || sequenceLearningAlgorithm == null) && elementsLearningAlgorithm.isEarlyTerminationHit()) { break; } if (trainSequenceVectors && sequenceLearningAlgorithm != null && (!trainElementsVectors || elementsLearningAlgorithm == null) && sequenceLearningAlgorithm.isEarlyTerminationHit()) { break; } log.info("Epoch [" + currentEpoch + "] finished; Elements processed so far: [" + wordsCounter.get() + "]; Sequences processed: [" + linesCounter.get() + "]"); if (eventListeners != null && !eventListeners.isEmpty()) { for (VectorsListener listener : eventListeners) { if (listener.validateEvent(ListenerEvent.EPOCH, currentEpoch)) listener.processEvent(ListenerEvent.EPOCH, this, currentEpoch); } } } log.info("Time spent on training: {} ms", System.currentTimeMillis() - timeSpent.get()); }
SequenceVectors extends WordVectorsImpl<T> implements WordVectors { public void fit() { val props = Nd4j.getExecutioner().getEnvironmentInformation(); if (props.getProperty("backend").equals("CUDA")) { if (Nd4j.getAffinityManager().getNumberOfDevices() > 1) throw new IllegalStateException("Multi-GPU word2vec/doc2vec isn't available atm"); } Nd4j.getRandom().setSeed(configuration.getSeed()); AtomicLong timeSpent = new AtomicLong(0); if (!trainElementsVectors && !trainSequenceVectors) throw new IllegalStateException( "You should define at least one training goal 'trainElementsRepresentation' or 'trainSequenceRepresentation'"); if (iterator == null) throw new IllegalStateException("You can't fit() data without SequenceIterator defined"); if (resetModel || (lookupTable != null && vocab != null && vocab.numWords() == 0)) { buildVocab(); } WordVectorSerializer.printOutProjectedMemoryUse(vocab.numWords(), configuration.getLayersSize(), configuration.isUseHierarchicSoftmax() && configuration.getNegative() > 0 ? 3 : 2); if (vocab == null || lookupTable == null || vocab.numWords() == 0) throw new IllegalStateException("You can't fit() model with empty Vocabulary or WeightLookupTable"); if (!resetModel || existingModel != null) { lookupTable.resetWeights(false); } else { lookupTable.resetWeights(true); if (configuration.isPreciseWeightInit()) { log.info("Using precise weights init..."); iterator.reset(); while (iterator.hasMoreSequences()) { val sequence = iterator.nextSequence(); for (T element : sequence.getElements()) { T realElement = vocab.tokenFor(element.getLabel()); if (realElement != null && !realElement.isInit()) { val rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); val randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } for (T label : sequence.getSequenceLabels()) { T realElement = vocab.tokenFor(label.getLabel()); if (realElement != null && !realElement.isInit()) { Random rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); INDArray randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } } this.iterator.reset(); } } initLearners(); initIntersectVectors(); log.info("Starting learning process..."); timeSpent.set(System.currentTimeMillis()); if (this.stopWords == null) this.stopWords = new ArrayList<>(); val wordsCounter = new AtomicLong(0); for (int currentEpoch = 1; currentEpoch <= numEpochs; currentEpoch++) { val linesCounter = new AtomicLong(0); val sequencer = new AsyncSequencer(this.iterator, this.stopWords); sequencer.start(); val timer = new AtomicLong(System.currentTimeMillis()); val thread = new VectorCalculationsThread(0, currentEpoch, wordsCounter, vocab.totalWordOccurrences(), linesCounter, sequencer, timer, numEpochs); thread.start(); try { sequencer.join(); } catch (Exception e) { throw new RuntimeException(e); } try { thread.join(); } catch (Exception e) { throw new RuntimeException(e); } if (trainElementsVectors && elementsLearningAlgorithm != null && (!trainSequenceVectors || sequenceLearningAlgorithm == null) && elementsLearningAlgorithm.isEarlyTerminationHit()) { break; } if (trainSequenceVectors && sequenceLearningAlgorithm != null && (!trainElementsVectors || elementsLearningAlgorithm == null) && sequenceLearningAlgorithm.isEarlyTerminationHit()) { break; } log.info("Epoch [" + currentEpoch + "] finished; Elements processed so far: [" + wordsCounter.get() + "]; Sequences processed: [" + linesCounter.get() + "]"); if (eventListeners != null && !eventListeners.isEmpty()) { for (VectorsListener listener : eventListeners) { if (listener.validateEvent(ListenerEvent.EPOCH, currentEpoch)) listener.processEvent(ListenerEvent.EPOCH, this, currentEpoch); } } } log.info("Time spent on training: {} ms", System.currentTimeMillis() - timeSpent.get()); } }
SequenceVectors extends WordVectorsImpl<T> implements WordVectors { public void fit() { val props = Nd4j.getExecutioner().getEnvironmentInformation(); if (props.getProperty("backend").equals("CUDA")) { if (Nd4j.getAffinityManager().getNumberOfDevices() > 1) throw new IllegalStateException("Multi-GPU word2vec/doc2vec isn't available atm"); } Nd4j.getRandom().setSeed(configuration.getSeed()); AtomicLong timeSpent = new AtomicLong(0); if (!trainElementsVectors && !trainSequenceVectors) throw new IllegalStateException( "You should define at least one training goal 'trainElementsRepresentation' or 'trainSequenceRepresentation'"); if (iterator == null) throw new IllegalStateException("You can't fit() data without SequenceIterator defined"); if (resetModel || (lookupTable != null && vocab != null && vocab.numWords() == 0)) { buildVocab(); } WordVectorSerializer.printOutProjectedMemoryUse(vocab.numWords(), configuration.getLayersSize(), configuration.isUseHierarchicSoftmax() && configuration.getNegative() > 0 ? 3 : 2); if (vocab == null || lookupTable == null || vocab.numWords() == 0) throw new IllegalStateException("You can't fit() model with empty Vocabulary or WeightLookupTable"); if (!resetModel || existingModel != null) { lookupTable.resetWeights(false); } else { lookupTable.resetWeights(true); if (configuration.isPreciseWeightInit()) { log.info("Using precise weights init..."); iterator.reset(); while (iterator.hasMoreSequences()) { val sequence = iterator.nextSequence(); for (T element : sequence.getElements()) { T realElement = vocab.tokenFor(element.getLabel()); if (realElement != null && !realElement.isInit()) { val rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); val randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } for (T label : sequence.getSequenceLabels()) { T realElement = vocab.tokenFor(label.getLabel()); if (realElement != null && !realElement.isInit()) { Random rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); INDArray randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } } this.iterator.reset(); } } initLearners(); initIntersectVectors(); log.info("Starting learning process..."); timeSpent.set(System.currentTimeMillis()); if (this.stopWords == null) this.stopWords = new ArrayList<>(); val wordsCounter = new AtomicLong(0); for (int currentEpoch = 1; currentEpoch <= numEpochs; currentEpoch++) { val linesCounter = new AtomicLong(0); val sequencer = new AsyncSequencer(this.iterator, this.stopWords); sequencer.start(); val timer = new AtomicLong(System.currentTimeMillis()); val thread = new VectorCalculationsThread(0, currentEpoch, wordsCounter, vocab.totalWordOccurrences(), linesCounter, sequencer, timer, numEpochs); thread.start(); try { sequencer.join(); } catch (Exception e) { throw new RuntimeException(e); } try { thread.join(); } catch (Exception e) { throw new RuntimeException(e); } if (trainElementsVectors && elementsLearningAlgorithm != null && (!trainSequenceVectors || sequenceLearningAlgorithm == null) && elementsLearningAlgorithm.isEarlyTerminationHit()) { break; } if (trainSequenceVectors && sequenceLearningAlgorithm != null && (!trainElementsVectors || elementsLearningAlgorithm == null) && sequenceLearningAlgorithm.isEarlyTerminationHit()) { break; } log.info("Epoch [" + currentEpoch + "] finished; Elements processed so far: [" + wordsCounter.get() + "]; Sequences processed: [" + linesCounter.get() + "]"); if (eventListeners != null && !eventListeners.isEmpty()) { for (VectorsListener listener : eventListeners) { if (listener.validateEvent(ListenerEvent.EPOCH, currentEpoch)) listener.processEvent(ListenerEvent.EPOCH, this, currentEpoch); } } } log.info("Time spent on training: {} ms", System.currentTimeMillis() - timeSpent.get()); }  }
SequenceVectors extends WordVectorsImpl<T> implements WordVectors { public void fit() { val props = Nd4j.getExecutioner().getEnvironmentInformation(); if (props.getProperty("backend").equals("CUDA")) { if (Nd4j.getAffinityManager().getNumberOfDevices() > 1) throw new IllegalStateException("Multi-GPU word2vec/doc2vec isn't available atm"); } Nd4j.getRandom().setSeed(configuration.getSeed()); AtomicLong timeSpent = new AtomicLong(0); if (!trainElementsVectors && !trainSequenceVectors) throw new IllegalStateException( "You should define at least one training goal 'trainElementsRepresentation' or 'trainSequenceRepresentation'"); if (iterator == null) throw new IllegalStateException("You can't fit() data without SequenceIterator defined"); if (resetModel || (lookupTable != null && vocab != null && vocab.numWords() == 0)) { buildVocab(); } WordVectorSerializer.printOutProjectedMemoryUse(vocab.numWords(), configuration.getLayersSize(), configuration.isUseHierarchicSoftmax() && configuration.getNegative() > 0 ? 3 : 2); if (vocab == null || lookupTable == null || vocab.numWords() == 0) throw new IllegalStateException("You can't fit() model with empty Vocabulary or WeightLookupTable"); if (!resetModel || existingModel != null) { lookupTable.resetWeights(false); } else { lookupTable.resetWeights(true); if (configuration.isPreciseWeightInit()) { log.info("Using precise weights init..."); iterator.reset(); while (iterator.hasMoreSequences()) { val sequence = iterator.nextSequence(); for (T element : sequence.getElements()) { T realElement = vocab.tokenFor(element.getLabel()); if (realElement != null && !realElement.isInit()) { val rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); val randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } for (T label : sequence.getSequenceLabels()) { T realElement = vocab.tokenFor(label.getLabel()); if (realElement != null && !realElement.isInit()) { Random rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); INDArray randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } } this.iterator.reset(); } } initLearners(); initIntersectVectors(); log.info("Starting learning process..."); timeSpent.set(System.currentTimeMillis()); if (this.stopWords == null) this.stopWords = new ArrayList<>(); val wordsCounter = new AtomicLong(0); for (int currentEpoch = 1; currentEpoch <= numEpochs; currentEpoch++) { val linesCounter = new AtomicLong(0); val sequencer = new AsyncSequencer(this.iterator, this.stopWords); sequencer.start(); val timer = new AtomicLong(System.currentTimeMillis()); val thread = new VectorCalculationsThread(0, currentEpoch, wordsCounter, vocab.totalWordOccurrences(), linesCounter, sequencer, timer, numEpochs); thread.start(); try { sequencer.join(); } catch (Exception e) { throw new RuntimeException(e); } try { thread.join(); } catch (Exception e) { throw new RuntimeException(e); } if (trainElementsVectors && elementsLearningAlgorithm != null && (!trainSequenceVectors || sequenceLearningAlgorithm == null) && elementsLearningAlgorithm.isEarlyTerminationHit()) { break; } if (trainSequenceVectors && sequenceLearningAlgorithm != null && (!trainElementsVectors || elementsLearningAlgorithm == null) && sequenceLearningAlgorithm.isEarlyTerminationHit()) { break; } log.info("Epoch [" + currentEpoch + "] finished; Elements processed so far: [" + wordsCounter.get() + "]; Sequences processed: [" + linesCounter.get() + "]"); if (eventListeners != null && !eventListeners.isEmpty()) { for (VectorsListener listener : eventListeners) { if (listener.validateEvent(ListenerEvent.EPOCH, currentEpoch)) listener.processEvent(ListenerEvent.EPOCH, this, currentEpoch); } } } log.info("Time spent on training: {} ms", System.currentTimeMillis() - timeSpent.get()); }  @Override String getUNK(); @Override void setUNK(String UNK); double getElementsScore(); double getSequencesScore(); @Override INDArray getWordVectorMatrix(String word); void buildVocab(); void fit(); }
SequenceVectors extends WordVectorsImpl<T> implements WordVectors { public void fit() { val props = Nd4j.getExecutioner().getEnvironmentInformation(); if (props.getProperty("backend").equals("CUDA")) { if (Nd4j.getAffinityManager().getNumberOfDevices() > 1) throw new IllegalStateException("Multi-GPU word2vec/doc2vec isn't available atm"); } Nd4j.getRandom().setSeed(configuration.getSeed()); AtomicLong timeSpent = new AtomicLong(0); if (!trainElementsVectors && !trainSequenceVectors) throw new IllegalStateException( "You should define at least one training goal 'trainElementsRepresentation' or 'trainSequenceRepresentation'"); if (iterator == null) throw new IllegalStateException("You can't fit() data without SequenceIterator defined"); if (resetModel || (lookupTable != null && vocab != null && vocab.numWords() == 0)) { buildVocab(); } WordVectorSerializer.printOutProjectedMemoryUse(vocab.numWords(), configuration.getLayersSize(), configuration.isUseHierarchicSoftmax() && configuration.getNegative() > 0 ? 3 : 2); if (vocab == null || lookupTable == null || vocab.numWords() == 0) throw new IllegalStateException("You can't fit() model with empty Vocabulary or WeightLookupTable"); if (!resetModel || existingModel != null) { lookupTable.resetWeights(false); } else { lookupTable.resetWeights(true); if (configuration.isPreciseWeightInit()) { log.info("Using precise weights init..."); iterator.reset(); while (iterator.hasMoreSequences()) { val sequence = iterator.nextSequence(); for (T element : sequence.getElements()) { T realElement = vocab.tokenFor(element.getLabel()); if (realElement != null && !realElement.isInit()) { val rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); val randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } for (T label : sequence.getSequenceLabels()) { T realElement = vocab.tokenFor(label.getLabel()); if (realElement != null && !realElement.isInit()) { Random rng = Nd4j.getRandomFactory().getNewRandomInstance( configuration.getSeed() * realElement.hashCode(), configuration.getLayersSize() + 1); INDArray randArray = Nd4j.rand(new int[] {1, configuration.getLayersSize()}, rng).subi(0.5) .divi(configuration.getLayersSize()); lookupTable.getWeights().getRow(realElement.getIndex(), true).assign(randArray); realElement.setInit(true); } } } this.iterator.reset(); } } initLearners(); initIntersectVectors(); log.info("Starting learning process..."); timeSpent.set(System.currentTimeMillis()); if (this.stopWords == null) this.stopWords = new ArrayList<>(); val wordsCounter = new AtomicLong(0); for (int currentEpoch = 1; currentEpoch <= numEpochs; currentEpoch++) { val linesCounter = new AtomicLong(0); val sequencer = new AsyncSequencer(this.iterator, this.stopWords); sequencer.start(); val timer = new AtomicLong(System.currentTimeMillis()); val thread = new VectorCalculationsThread(0, currentEpoch, wordsCounter, vocab.totalWordOccurrences(), linesCounter, sequencer, timer, numEpochs); thread.start(); try { sequencer.join(); } catch (Exception e) { throw new RuntimeException(e); } try { thread.join(); } catch (Exception e) { throw new RuntimeException(e); } if (trainElementsVectors && elementsLearningAlgorithm != null && (!trainSequenceVectors || sequenceLearningAlgorithm == null) && elementsLearningAlgorithm.isEarlyTerminationHit()) { break; } if (trainSequenceVectors && sequenceLearningAlgorithm != null && (!trainElementsVectors || elementsLearningAlgorithm == null) && sequenceLearningAlgorithm.isEarlyTerminationHit()) { break; } log.info("Epoch [" + currentEpoch + "] finished; Elements processed so far: [" + wordsCounter.get() + "]; Sequences processed: [" + linesCounter.get() + "]"); if (eventListeners != null && !eventListeners.isEmpty()) { for (VectorsListener listener : eventListeners) { if (listener.validateEvent(ListenerEvent.EPOCH, currentEpoch)) listener.processEvent(ListenerEvent.EPOCH, this, currentEpoch); } } } log.info("Time spent on training: {} ms", System.currentTimeMillis() - timeSpent.get()); }  @Override String getUNK(); @Override void setUNK(String UNK); double getElementsScore(); double getSequencesScore(); @Override INDArray getWordVectorMatrix(String word); void buildVocab(); void fit();  }