timeFactory = $timeFactory; } /** * @param Config $config * @param TrainingDataConfig $dataConfig * @param AClassificationStrategy $strategy * * @return TrainingResult * * @throws ServiceException * @throws InsufficientDataException */ public function train(Config $config, TrainingDataSet $dataSet, AClassificationStrategy $strategy): TrainingResult { $start = $this->timeFactory->getDateTime(); $layers = array_map(function ($index) use ($strategy) { return new Dense($strategy->getSize()); }, range(0, $config->getLayers() - 2)); $layers[] = new Activation(new Sigmoid()); $classifier = new MultilayerPerceptron( $layers, 128, new Adam($config->getLearningRate()), 1e-4, $config->getEpochs() ); $classifier->train($dataSet->getTrainingData()); $finished = $this->timeFactory->getDateTime(); $elapsed = $finished->getTimestamp() - $start->getTimestamp(); $predicted = $classifier->predict($dataSet->getValidationData()); $reportGenerator = new MulticlassBreakdown(); $report = $reportGenerator->generate($predicted, $dataSet->getValidationData()->labels()); $model = new Model(); $model->setSamplesPositive($dataSet->getNumPositives()); $model->setSamplesShuffled($dataSet->getNumShuffledNegatives()); $model->setSamplesRandom($dataSet->getNumRandomNegatives()); $model->setEpochs($config->getEpochs()); $model->setLayers($config->getLayers()); $model->setVectorDim($strategy->getSize()); $model->setLearningRate($config->getLearningRate()); $model->setPrecisionY($report['classes'][self::LABEL_POSITIVE]['precision']); $model->setPrecisionN($report['classes'][self::LABEL_NEGATIVE]['precision']); $model->setRecallY($report['classes'][self::LABEL_POSITIVE]['recall']); $model->setRecallN($report['classes'][self::LABEL_NEGATIVE]['recall']); $model->setDuration($elapsed); $model->setAddressType($strategy::getTypeName()); $model->setCreatedAt($this->timeFactory->getTime()); return new TrainingResult($classifier, $model, $report); } }