-
-
Notifications
You must be signed in to change notification settings - Fork 31
/
coordinate.dart
107 lines (87 loc) · 3.47 KB
/
coordinate.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import 'dart:math' as math;
import 'package:dart_ml/src/cost_function/cost_function.dart';
import 'package:dart_ml/src/optimizer/initial_weights_generator/initial_weights_generator.dart';
import 'package:dart_ml/src/optimizer/optimizer.dart';
import 'package:linalg/vector.dart';
class CoordinateOptimizer implements Optimizer {
final InitialWeightsGenerator _initialCoefficientsGenerator;
final CostFunction _costFn;
//hyper parameters declaration
final double _coefficientDiffThreshold;
final int _iterationLimit;
final double _lambda;
//hyper parameters declaration end
Float32x4Vector _normalizer;
CoordinateOptimizer(
this._initialCoefficientsGenerator,
this._costFn,
{
double minCoefficientsDiff,
int iterationLimit,
double lambda
}
) :
_iterationLimit = iterationLimit ?? 1000,
_coefficientDiffThreshold = minCoefficientsDiff,
_lambda = lambda ?? 0.0;
@override
Float32x4Vector findExtrema(
covariant List<Float32x4Vector> points,
covariant Float32x4Vector labels,
{
covariant Float32x4Vector initialWeights,
bool isMinimizingObjective = true,
bool arePointsNormalized = false
}
) {
final numOfDimensions = points.first.length;
_normalizer = arePointsNormalized
? new Float32x4Vector.filled(numOfDimensions, 1.0)
: points.reduce((final combine, final vector) => (combine + vector * vector) as Float32x4Vector);
Float32x4Vector coefficients = initialWeights ?? _initialCoefficientsGenerator.generate(points.first.length);
final changes = new List<double>.filled(numOfDimensions, double.INFINITY);
int iteration = 0;
while (!_isConverged(changes, iteration)) {
final updatedCoefficients = new List<double>.filled(coefficients.length, 0.0, growable: false);
for (int j = 0; j < coefficients.length; j++) {
final oldWeight = updatedCoefficients[j];
final newWeight = _coordinateDescentStep(j, points, labels, coefficients);
changes[j] = (oldWeight - newWeight).abs();
updatedCoefficients[j] = newWeight;
coefficients = new Float32x4Vector.from(updatedCoefficients);
}
iteration++;
}
return coefficients;
}
bool _isConverged(List<double> changes, int iterationCount) =>
_coefficientDiffThreshold != null &&
changes.reduce((double maxValue, double value) => math.max<double>(maxValue ?? 0.0, value)) <= _coefficientDiffThreshold ||
iterationCount >= _iterationLimit;
double _coordinateDescentStep(int coefficientNum, List<Float32x4Vector> points, Float32x4Vector labels,
Float32x4Vector coefficients) {
final currentCoefficient = coefficients[coefficientNum];
double updatedCoefficient = currentCoefficient;
for (int rowNum = 0; rowNum < points.length; rowNum++) {
final point = points[rowNum];
final output = labels[rowNum];
updatedCoefficient += _costFn.getSparseSolutionPartial(coefficientNum, point, coefficients, output);
}
return _regularize(updatedCoefficient, _lambda, coefficientNum);
}
double _regularize(double coefficient, double lambda, int coefNum) {
if (lambda == 0.0) {
return coefficient;
}
final delta = lambda / 2;
double regularized;
if (coefficient > delta) {
regularized = (coefficient - delta) / _normalizer[coefNum];
} else if (coefficient < -delta) {
regularized = (coefficient + delta) / _normalizer[coefNum];
} else {
regularized = 0.0;
}
return regularized;
}
}