public void Train(Dataset dataset, ILoss loss, IOptimizer optimizer, int batchSize, int nEpoches, double minError, Dataset valDataset, IMetric metric, bool shuffle = true) { if (dataset.InputShape != InputShape) { throw new ShapeMismatchException($"{nameof(dataset)} {nameof(dataset.InputShape)}"); } if (dataset.TargetShape != OutputShape) { throw new ShapeMismatchException($"{nameof(dataset)} {nameof(dataset.TargetShape)}"); } if (valDataset.InputShape != InputShape) { throw new ShapeMismatchException($"{nameof(valDataset)} {nameof(dataset.InputShape)}"); } if (valDataset.TargetShape != OutputShape) { throw new ShapeMismatchException($"{nameof(valDataset)} {nameof(dataset.TargetShape)}"); } ClearCache(); double valError = Validate(valDataset, metric); int epoch; OnStart?.Invoke(valError); for (epoch = 0; epoch < nEpoches; epoch++) { if (valError <= minError) { break; } if (shuffle) { dataset.Shuffle(); } dataset.ForEach((D, index) => { Forward(D.Inputs, true); CalcGrads(loss, D.Targets); optimizer.UpdateEpoch(epoch); Optimize(optimizer); if (index % batchSize == 0) { Update(); OnBatch?.Invoke(index / batchSize); } }); valError = Validate(valDataset, metric); OnEpoch?.Invoke(epoch, valError); } OnFinish?.Invoke(epoch, valError); }