moflo 4.8.32 → 4.8.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/generate-code-map.mjs +1 -1
- package/bin/index-guidance.mjs +1 -1
- package/bin/index-tests.mjs +1 -1
- package/bin/setup-project.mjs +1 -1
- package/package.json +8 -4
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +1298 -1107
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +4 -7
- package/src/@claude-flow/neural/README.md +260 -0
- package/src/@claude-flow/neural/dist/algorithms/a2c.js +361 -0
- package/src/@claude-flow/neural/dist/algorithms/curiosity.js +392 -0
- package/src/@claude-flow/neural/dist/algorithms/decision-transformer.js +415 -0
- package/src/@claude-flow/neural/dist/algorithms/dqn.js +303 -0
- package/src/@claude-flow/neural/dist/algorithms/index.js +74 -0
- package/src/@claude-flow/neural/dist/algorithms/ppo.js +331 -0
- package/src/@claude-flow/neural/dist/algorithms/q-learning.js +259 -0
- package/src/@claude-flow/neural/dist/algorithms/sarsa.js +297 -0
- package/src/@claude-flow/neural/dist/application/index.js +7 -0
- package/src/@claude-flow/neural/dist/application/services/neural-application-service.js +161 -0
- package/src/@claude-flow/neural/dist/domain/entities/pattern.js +134 -0
- package/src/@claude-flow/neural/dist/domain/index.js +8 -0
- package/src/@claude-flow/neural/dist/domain/services/learning-service.js +195 -0
- package/src/@claude-flow/neural/dist/index.js +201 -0
- package/src/@claude-flow/neural/dist/modes/balanced.js +234 -0
- package/src/@claude-flow/neural/dist/modes/base.js +77 -0
- package/src/@claude-flow/neural/dist/modes/batch.js +316 -0
- package/src/@claude-flow/neural/dist/modes/edge.js +310 -0
- package/src/@claude-flow/neural/dist/modes/index.js +13 -0
- package/src/@claude-flow/neural/dist/modes/real-time.js +196 -0
- package/src/@claude-flow/neural/dist/modes/research.js +389 -0
- package/src/@claude-flow/neural/dist/pattern-learner.js +603 -0
- package/src/@claude-flow/neural/dist/reasoning-bank.js +993 -0
- package/src/@claude-flow/neural/dist/reasoningbank-adapter.js +463 -0
- package/src/@claude-flow/neural/dist/sona-integration.js +316 -0
- package/src/@claude-flow/neural/dist/sona-manager.js +695 -0
- package/src/@claude-flow/neural/dist/types.js +11 -0
- package/src/@claude-flow/neural/package.json +26 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Research Mode Implementation
|
|
3
|
+
*
|
|
4
|
+
* Optimized for maximum quality with:
|
|
5
|
+
* - +55% quality improvement target
|
|
6
|
+
* - Learning rate 0.002 (sweet spot)
|
|
7
|
+
* - Rank-16 LoRA
|
|
8
|
+
* - Gradient checkpointing
|
|
9
|
+
* - Full learning pipeline
|
|
10
|
+
*/
|
|
11
|
+
import { BaseModeImplementation } from './base.js';
|
|
12
|
+
/**
|
|
13
|
+
* Research mode for maximum quality learning
|
|
14
|
+
*/
|
|
15
|
+
export class ResearchMode extends BaseModeImplementation {
|
|
16
|
+
mode = 'research';
|
|
17
|
+
// Extended pattern storage
|
|
18
|
+
patternIndex = new Map();
|
|
19
|
+
clusterCentroids = [];
|
|
20
|
+
// Learning state with checkpointing
|
|
21
|
+
gradientHistory = [];
|
|
22
|
+
checkpoints = [];
|
|
23
|
+
// Adam optimizer state
|
|
24
|
+
adamM = new Map();
|
|
25
|
+
adamV = new Map();
|
|
26
|
+
adamStep = 0;
|
|
27
|
+
// Stats
|
|
28
|
+
totalPatternMatches = 0;
|
|
29
|
+
totalPatternTime = 0;
|
|
30
|
+
totalLearnTime = 0;
|
|
31
|
+
learnIterations = 0;
|
|
32
|
+
qualityHistory = [];
|
|
33
|
+
explorationRewards = [];
|
|
34
|
+
async initialize() {
|
|
35
|
+
await super.initialize();
|
|
36
|
+
this.patternIndex.clear();
|
|
37
|
+
this.clusterCentroids = [];
|
|
38
|
+
this.gradientHistory = [];
|
|
39
|
+
this.checkpoints = [];
|
|
40
|
+
this.adamM.clear();
|
|
41
|
+
this.adamV.clear();
|
|
42
|
+
this.adamStep = 0;
|
|
43
|
+
}
|
|
44
|
+
async cleanup() {
|
|
45
|
+
this.patternIndex.clear();
|
|
46
|
+
this.clusterCentroids = [];
|
|
47
|
+
this.gradientHistory = [];
|
|
48
|
+
this.checkpoints = [];
|
|
49
|
+
this.adamM.clear();
|
|
50
|
+
this.adamV.clear();
|
|
51
|
+
await super.cleanup();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Find patterns using cluster-based search
|
|
55
|
+
*/
|
|
56
|
+
async findPatterns(embedding, k, patterns) {
|
|
57
|
+
const startTime = performance.now();
|
|
58
|
+
// Update clusters if needed
|
|
59
|
+
if (this.clusterCentroids.length !== this.config.patternClusters) {
|
|
60
|
+
await this.rebuildClusters(patterns);
|
|
61
|
+
}
|
|
62
|
+
// Find nearest cluster
|
|
63
|
+
let bestCluster = 0;
|
|
64
|
+
let bestSim = -1;
|
|
65
|
+
for (let c = 0; c < this.clusterCentroids.length; c++) {
|
|
66
|
+
const sim = this.cosineSimilarity(embedding, this.clusterCentroids[c]);
|
|
67
|
+
if (sim > bestSim) {
|
|
68
|
+
bestSim = sim;
|
|
69
|
+
bestCluster = c;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Search within cluster + nearby clusters
|
|
73
|
+
const clustersToSearch = this.getNearestClusters(embedding, 3);
|
|
74
|
+
const candidates = [];
|
|
75
|
+
for (const pattern of patterns) {
|
|
76
|
+
const patternCluster = this.patternIndex.get(pattern.patternId);
|
|
77
|
+
if (patternCluster !== undefined && clustersToSearch.includes(patternCluster)) {
|
|
78
|
+
const similarity = this.cosineSimilarity(embedding, pattern.embedding);
|
|
79
|
+
candidates.push({
|
|
80
|
+
pattern,
|
|
81
|
+
similarity,
|
|
82
|
+
confidence: this.computeConfidence(pattern, similarity),
|
|
83
|
+
latencyMs: 0,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// If not enough candidates, search all patterns
|
|
88
|
+
if (candidates.length < k) {
|
|
89
|
+
for (const pattern of patterns) {
|
|
90
|
+
if (!candidates.find(c => c.pattern.patternId === pattern.patternId)) {
|
|
91
|
+
const similarity = this.cosineSimilarity(embedding, pattern.embedding);
|
|
92
|
+
candidates.push({
|
|
93
|
+
pattern,
|
|
94
|
+
similarity,
|
|
95
|
+
confidence: this.computeConfidence(pattern, similarity),
|
|
96
|
+
latencyMs: 0,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Sort and return top-k
|
|
102
|
+
candidates.sort((a, b) => b.similarity - a.similarity);
|
|
103
|
+
this.totalPatternTime += performance.now() - startTime;
|
|
104
|
+
this.totalPatternMatches++;
|
|
105
|
+
return candidates.slice(0, k);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Learn using full Adam optimizer with gradient checkpointing
|
|
109
|
+
*/
|
|
110
|
+
async learn(trajectories, config, ewcState) {
|
|
111
|
+
const startTime = performance.now();
|
|
112
|
+
if (trajectories.length === 0)
|
|
113
|
+
return 0;
|
|
114
|
+
// Research mode uses low threshold to learn from all data
|
|
115
|
+
const learningRate = config.learningRate; // 0.002 sweet spot
|
|
116
|
+
const batchSize = config.batchSize;
|
|
117
|
+
// Sort trajectories by quality
|
|
118
|
+
const sortedTrajectories = [...trajectories].sort((a, b) => b.qualityScore - a.qualityScore);
|
|
119
|
+
// Create checkpoint before learning
|
|
120
|
+
if (this.learnIterations % 10 === 0) {
|
|
121
|
+
this.createCheckpoint();
|
|
122
|
+
}
|
|
123
|
+
let totalLoss = 0;
|
|
124
|
+
let batchCount = 0;
|
|
125
|
+
// Process in mini-batches
|
|
126
|
+
for (let i = 0; i < sortedTrajectories.length; i += batchSize) {
|
|
127
|
+
const batch = sortedTrajectories.slice(i, i + batchSize);
|
|
128
|
+
const batchLoss = await this.processBatch(batch, learningRate, ewcState, config.ewcLambda);
|
|
129
|
+
totalLoss += batchLoss;
|
|
130
|
+
batchCount++;
|
|
131
|
+
}
|
|
132
|
+
// Track quality
|
|
133
|
+
const avgQuality = sortedTrajectories.reduce((s, t) => s + t.qualityScore, 0) / sortedTrajectories.length;
|
|
134
|
+
this.qualityHistory.push(avgQuality);
|
|
135
|
+
if (this.qualityHistory.length > 1000) {
|
|
136
|
+
this.qualityHistory = this.qualityHistory.slice(-1000);
|
|
137
|
+
}
|
|
138
|
+
// Compute improvement
|
|
139
|
+
const recentAvg = this.qualityHistory.slice(-10).reduce((a, b) => a + b, 0) / Math.min(10, this.qualityHistory.length);
|
|
140
|
+
const oldAvg = this.qualityHistory.slice(0, Math.max(1, this.qualityHistory.length - 10)).reduce((a, b) => a + b, 0) / Math.max(1, this.qualityHistory.length - 10);
|
|
141
|
+
const improvementDelta = recentAvg - oldAvg;
|
|
142
|
+
this.totalLearnTime += performance.now() - startTime;
|
|
143
|
+
this.learnIterations++;
|
|
144
|
+
return Math.max(0, improvementDelta * 2); // Scale for research mode
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Apply LoRA with rank-16 for maximum expressivity
|
|
148
|
+
*/
|
|
149
|
+
async applyLoRA(input, weights) {
|
|
150
|
+
if (!weights) {
|
|
151
|
+
return input;
|
|
152
|
+
}
|
|
153
|
+
const output = new Float32Array(input.length);
|
|
154
|
+
output.set(input);
|
|
155
|
+
const rank = this.config.loraRank; // 16 for research mode
|
|
156
|
+
// Apply to all modules with higher blending
|
|
157
|
+
for (const module of ['q_proj', 'v_proj', 'k_proj', 'o_proj']) {
|
|
158
|
+
const A = weights.A.get(module);
|
|
159
|
+
const B = weights.B.get(module);
|
|
160
|
+
if (A && B) {
|
|
161
|
+
const adapted = this.applyLoRATransform(input, A, B, rank);
|
|
162
|
+
const alpha = 0.3; // Higher blending for research
|
|
163
|
+
for (let i = 0; i < output.length; i++) {
|
|
164
|
+
output[i] = output[i] * (1 - alpha) + adapted[i] * alpha;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return output;
|
|
169
|
+
}
|
|
170
|
+
getStats() {
|
|
171
|
+
const avgQuality = this.qualityHistory.length > 0
|
|
172
|
+
? this.qualityHistory.reduce((a, b) => a + b, 0) / this.qualityHistory.length
|
|
173
|
+
: 0;
|
|
174
|
+
const recentQuality = this.qualityHistory.slice(-10).reduce((a, b) => a + b, 0) / Math.min(10, this.qualityHistory.length) || 0;
|
|
175
|
+
return {
|
|
176
|
+
avgPatternMatchMs: this.totalPatternMatches > 0
|
|
177
|
+
? this.totalPatternTime / this.totalPatternMatches
|
|
178
|
+
: 0,
|
|
179
|
+
avgLearnMs: this.learnIterations > 0
|
|
180
|
+
? this.totalLearnTime / this.learnIterations
|
|
181
|
+
: 0,
|
|
182
|
+
avgQuality,
|
|
183
|
+
recentQuality,
|
|
184
|
+
qualityImprovement: recentQuality - avgQuality,
|
|
185
|
+
clusterCount: this.clusterCentroids.length,
|
|
186
|
+
checkpointCount: this.checkpoints.length,
|
|
187
|
+
adamStep: this.adamStep,
|
|
188
|
+
learnIterations: this.learnIterations,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Rebuild cluster centroids using k-means
|
|
193
|
+
*/
|
|
194
|
+
async rebuildClusters(patterns) {
|
|
195
|
+
if (patterns.length === 0)
|
|
196
|
+
return;
|
|
197
|
+
const k = Math.min(this.config.patternClusters, patterns.length);
|
|
198
|
+
const dim = patterns[0].embedding.length;
|
|
199
|
+
// Initialize centroids randomly
|
|
200
|
+
this.clusterCentroids = [];
|
|
201
|
+
const indices = new Set();
|
|
202
|
+
while (indices.size < k) {
|
|
203
|
+
indices.add(Math.floor(Math.random() * patterns.length));
|
|
204
|
+
}
|
|
205
|
+
for (const idx of indices) {
|
|
206
|
+
this.clusterCentroids.push(new Float32Array(patterns[idx].embedding));
|
|
207
|
+
}
|
|
208
|
+
// Run k-means iterations
|
|
209
|
+
for (let iter = 0; iter < 10; iter++) {
|
|
210
|
+
// Assign patterns to clusters
|
|
211
|
+
const clusterAssignments = Array.from({ length: k }, () => []);
|
|
212
|
+
for (let p = 0; p < patterns.length; p++) {
|
|
213
|
+
let bestCluster = 0;
|
|
214
|
+
let bestSim = -1;
|
|
215
|
+
for (let c = 0; c < k; c++) {
|
|
216
|
+
const sim = this.cosineSimilarity(patterns[p].embedding, this.clusterCentroids[c]);
|
|
217
|
+
if (sim > bestSim) {
|
|
218
|
+
bestSim = sim;
|
|
219
|
+
bestCluster = c;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
clusterAssignments[bestCluster].push(p);
|
|
223
|
+
this.patternIndex.set(patterns[p].patternId, bestCluster);
|
|
224
|
+
}
|
|
225
|
+
// Update centroids
|
|
226
|
+
for (let c = 0; c < k; c++) {
|
|
227
|
+
if (clusterAssignments[c].length > 0) {
|
|
228
|
+
const newCentroid = new Float32Array(dim);
|
|
229
|
+
for (const p of clusterAssignments[c]) {
|
|
230
|
+
for (let d = 0; d < dim; d++) {
|
|
231
|
+
newCentroid[d] += patterns[p].embedding[d];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
for (let d = 0; d < dim; d++) {
|
|
235
|
+
newCentroid[d] /= clusterAssignments[c].length;
|
|
236
|
+
}
|
|
237
|
+
this.clusterCentroids[c] = newCentroid;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get nearest clusters to embedding
|
|
244
|
+
*/
|
|
245
|
+
getNearestClusters(embedding, n) {
|
|
246
|
+
const similarities = [];
|
|
247
|
+
for (let c = 0; c < this.clusterCentroids.length; c++) {
|
|
248
|
+
similarities.push({ cluster: c, sim: this.cosineSimilarity(embedding, this.clusterCentroids[c]) });
|
|
249
|
+
}
|
|
250
|
+
similarities.sort((a, b) => b.sim - a.sim);
|
|
251
|
+
return similarities.slice(0, n).map(s => s.cluster);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Compute confidence for pattern match
|
|
255
|
+
*/
|
|
256
|
+
computeConfidence(pattern, similarity) {
|
|
257
|
+
// Combine similarity with pattern history
|
|
258
|
+
const historyWeight = Math.min(pattern.usageCount / 10, 1);
|
|
259
|
+
return similarity * (1 - historyWeight * 0.3) + pattern.successRate * historyWeight * 0.3;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Create learning checkpoint
|
|
263
|
+
*/
|
|
264
|
+
createCheckpoint() {
|
|
265
|
+
const state = new Map();
|
|
266
|
+
for (const [key, value] of this.adamM) {
|
|
267
|
+
state.set(`m_${key}`, new Float32Array(value));
|
|
268
|
+
}
|
|
269
|
+
for (const [key, value] of this.adamV) {
|
|
270
|
+
state.set(`v_${key}`, new Float32Array(value));
|
|
271
|
+
}
|
|
272
|
+
this.checkpoints.push({ iteration: this.learnIterations, state });
|
|
273
|
+
// Keep only last 10 checkpoints
|
|
274
|
+
if (this.checkpoints.length > 10) {
|
|
275
|
+
this.checkpoints = this.checkpoints.slice(-10);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Process a mini-batch with Adam optimizer
|
|
280
|
+
*/
|
|
281
|
+
async processBatch(batch, learningRate, ewcState, ewcLambda) {
|
|
282
|
+
const beta1 = 0.9;
|
|
283
|
+
const beta2 = 0.999;
|
|
284
|
+
const epsilon = 1e-8;
|
|
285
|
+
this.adamStep++;
|
|
286
|
+
let totalLoss = 0;
|
|
287
|
+
for (const trajectory of batch) {
|
|
288
|
+
if (trajectory.steps.length === 0)
|
|
289
|
+
continue;
|
|
290
|
+
// Compute gradient from trajectory
|
|
291
|
+
const gradient = this.computeTrajectoryGradient(trajectory);
|
|
292
|
+
for (const [key, grad] of gradient) {
|
|
293
|
+
// Get or initialize Adam state
|
|
294
|
+
let m = this.adamM.get(key);
|
|
295
|
+
let v = this.adamV.get(key);
|
|
296
|
+
if (!m) {
|
|
297
|
+
m = new Float32Array(grad.length);
|
|
298
|
+
this.adamM.set(key, m);
|
|
299
|
+
}
|
|
300
|
+
if (!v) {
|
|
301
|
+
v = new Float32Array(grad.length);
|
|
302
|
+
this.adamV.set(key, v);
|
|
303
|
+
}
|
|
304
|
+
// Update biased first moment estimate
|
|
305
|
+
for (let i = 0; i < grad.length; i++) {
|
|
306
|
+
m[i] = beta1 * m[i] + (1 - beta1) * grad[i];
|
|
307
|
+
}
|
|
308
|
+
// Update biased second moment estimate
|
|
309
|
+
for (let i = 0; i < grad.length; i++) {
|
|
310
|
+
v[i] = beta2 * v[i] + (1 - beta2) * grad[i] * grad[i];
|
|
311
|
+
}
|
|
312
|
+
// Bias correction
|
|
313
|
+
const mHat = new Float32Array(grad.length);
|
|
314
|
+
const vHat = new Float32Array(grad.length);
|
|
315
|
+
for (let i = 0; i < grad.length; i++) {
|
|
316
|
+
mHat[i] = m[i] / (1 - Math.pow(beta1, this.adamStep));
|
|
317
|
+
vHat[i] = v[i] / (1 - Math.pow(beta2, this.adamStep));
|
|
318
|
+
}
|
|
319
|
+
// Compute loss contribution
|
|
320
|
+
for (let i = 0; i < grad.length; i++) {
|
|
321
|
+
totalLoss += grad[i] * grad[i];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Add EWC penalty
|
|
326
|
+
const ewcPenalty = this.computeEWCLoss(ewcState, ewcLambda);
|
|
327
|
+
totalLoss += ewcPenalty;
|
|
328
|
+
return totalLoss / batch.length;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Compute gradient from trajectory
|
|
332
|
+
*/
|
|
333
|
+
computeTrajectoryGradient(trajectory) {
|
|
334
|
+
const gradient = new Map();
|
|
335
|
+
if (trajectory.steps.length < 2)
|
|
336
|
+
return gradient;
|
|
337
|
+
// Use advantage estimation
|
|
338
|
+
const rewards = trajectory.steps.map(s => s.reward);
|
|
339
|
+
const advantages = this.computeAdvantages(rewards);
|
|
340
|
+
for (let i = 0; i < trajectory.steps.length; i++) {
|
|
341
|
+
const step = trajectory.steps[i];
|
|
342
|
+
const advantage = advantages[i];
|
|
343
|
+
// Policy gradient: grad = advantage * grad_log_pi
|
|
344
|
+
const stateGrad = new Float32Array(step.stateAfter.length);
|
|
345
|
+
for (let j = 0; j < stateGrad.length; j++) {
|
|
346
|
+
stateGrad[j] = step.stateAfter[j] * advantage;
|
|
347
|
+
}
|
|
348
|
+
gradient.set(`step_${i}`, stateGrad);
|
|
349
|
+
}
|
|
350
|
+
return gradient;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Compute advantages using GAE
|
|
354
|
+
*/
|
|
355
|
+
computeAdvantages(rewards) {
|
|
356
|
+
const gamma = 0.99;
|
|
357
|
+
const lambda = 0.95;
|
|
358
|
+
const advantages = new Array(rewards.length).fill(0);
|
|
359
|
+
let lastGae = 0;
|
|
360
|
+
for (let t = rewards.length - 1; t >= 0; t--) {
|
|
361
|
+
const nextValue = t < rewards.length - 1 ? rewards[t + 1] : 0;
|
|
362
|
+
const delta = rewards[t] + gamma * nextValue - rewards[t];
|
|
363
|
+
lastGae = delta + gamma * lambda * lastGae;
|
|
364
|
+
advantages[t] = lastGae;
|
|
365
|
+
}
|
|
366
|
+
// Normalize advantages
|
|
367
|
+
const mean = advantages.reduce((a, b) => a + b, 0) / advantages.length;
|
|
368
|
+
const std = Math.sqrt(advantages.reduce((a, b) => a + (b - mean) ** 2, 0) / advantages.length) + 1e-8;
|
|
369
|
+
return advantages.map(a => (a - mean) / std);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Compute EWC loss for continual learning
|
|
373
|
+
*/
|
|
374
|
+
computeEWCLoss(ewcState, lambda) {
|
|
375
|
+
let loss = 0;
|
|
376
|
+
for (const [key, fisher] of ewcState.fisher) {
|
|
377
|
+
const means = ewcState.means.get(key);
|
|
378
|
+
const current = this.adamM.get(key);
|
|
379
|
+
if (means && current) {
|
|
380
|
+
for (let i = 0; i < Math.min(fisher.length, means.length, current.length); i++) {
|
|
381
|
+
const diff = current[i] - means[i];
|
|
382
|
+
loss += fisher[i] * diff * diff;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return lambda * loss * 0.5;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=research.js.map
|