ruv-swarm
Version:
High-performance neural network swarm orchestration in WebAssembly
1,359 lines (1,148 loc) • 40.7 kB
JavaScript
/**
* Meta-Learning Framework
* Enables learning how to learn and domain adaptation
*/
class MetaLearningFramework {
constructor() {
this.agentExperiences = new Map();
this.domainAdaptations = new Map();
this.transferLearning = new Map();
this.metaStrategies = new Map();
this.learningMetrics = new Map();
// Initialize meta-learning strategies
this.initializeMetaStrategies();
}
/**
* Initialize meta-learning strategies
*/
initializeMetaStrategies() {
// Model-Agnostic Meta-Learning (MAML)
this.metaStrategies.set('maml', {
name: 'Model-Agnostic Meta-Learning',
description: 'Learn good parameter initializations for quick adaptation',
type: 'gradient_based',
parameters: {
innerLearningRate: 0.01,
outerLearningRate: 0.001,
innerSteps: 5,
metaBatchSize: 4,
},
applicability: {
fewShotLearning: 0.9,
domainTransfer: 0.8,
taskAdaptation: 0.9,
continualLearning: 0.6,
},
});
// Prototypical Networks
this.metaStrategies.set('prototypical', {
name: 'Prototypical Networks',
description: 'Learn metric space for few-shot classification',
type: 'metric_based',
parameters: {
embeddingDim: 64,
distanceMetric: 'euclidean',
temperatureScale: 1.0,
},
applicability: {
fewShotLearning: 0.95,
domainTransfer: 0.7,
taskAdaptation: 0.8,
continualLearning: 0.5,
},
});
// Memory-Augmented Networks
this.metaStrategies.set('memory_augmented', {
name: 'Memory-Augmented Networks',
description: 'Use external memory for rapid learning',
type: 'memory_based',
parameters: {
memorySize: 128,
keySize: 64,
valueSize: 64,
readHeads: 1,
writeHeads: 1,
},
applicability: {
fewShotLearning: 0.8,
domainTransfer: 0.6,
taskAdaptation: 0.7,
continualLearning: 0.9,
},
});
// Reptile Meta-Learning
this.metaStrategies.set('reptile', {
name: 'Reptile',
description: 'Simple meta-learning algorithm for good initialization',
type: 'gradient_based',
parameters: {
innerLearningRate: 0.02,
outerLearningRate: 1.0,
innerSteps: 10,
metaBatchSize: 5,
},
applicability: {
fewShotLearning: 0.85,
domainTransfer: 0.75,
taskAdaptation: 0.8,
continualLearning: 0.7,
},
});
// Learning to Optimize
this.metaStrategies.set('learning_to_optimize', {
name: 'Learning to Optimize',
description: 'Learn optimization strategies for different tasks',
type: 'optimization_based',
parameters: {
optimizerType: 'lstm',
optimizerHiddenSize: 20,
learningRate: 0.001,
coordinatewise: true,
},
applicability: {
fewShotLearning: 0.7,
domainTransfer: 0.8,
taskAdaptation: 0.9,
continualLearning: 0.8,
},
});
// Meta-Learning for Domain Adaptation
this.metaStrategies.set('domain_adaptation', {
name: 'Meta-Domain Adaptation',
description: 'Learn domain-invariant representations',
type: 'domain_based',
parameters: {
domainDiscriminatorStrength: 0.1,
gradientReversalLambda: 1.0,
alignmentLoss: 'coral',
adaptationSteps: 20,
},
applicability: {
fewShotLearning: 0.6,
domainTransfer: 0.95,
taskAdaptation: 0.7,
continualLearning: 0.6,
},
});
// Continual Meta-Learning
this.metaStrategies.set('continual_meta', {
name: 'Continual Meta-Learning',
description: 'Meta-learning while avoiding catastrophic forgetting',
type: 'continual_based',
parameters: {
regularizationStrength: 0.01,
memoryReplayRatio: 0.2,
plasticity: 0.8,
stability: 0.7,
},
applicability: {
fewShotLearning: 0.7,
domainTransfer: 0.7,
taskAdaptation: 0.8,
continualLearning: 0.95,
},
});
// Multi-Task Meta-Learning
this.metaStrategies.set('multi_task_meta', {
name: 'Multi-Task Meta-Learning',
description: 'Learn shared representations across multiple tasks',
type: 'multi_task_based',
parameters: {
sharedLayers: 3,
taskSpecificLayers: 2,
taskWeighting: 'equal',
gradientNormalization: true,
},
applicability: {
fewShotLearning: 0.8,
domainTransfer: 0.8,
taskAdaptation: 0.9,
continualLearning: 0.8,
},
});
}
/**
* Adapt configuration for agent based on meta-learning
* @param {string} agentId - Agent identifier
* @param {Object} config - Initial configuration
*/
async adaptConfiguration(agentId, config) {
// Get agent's learning history
const experiences = this.agentExperiences.get(agentId) || [];
if (experiences.length === 0) {
// No prior experience, return base config
return this.applyDefaultMetaLearning(config);
}
// Analyze learning patterns
const learningPatterns = this.analyzeLearningPatterns(experiences);
// Select appropriate meta-learning strategy
const strategy = this.selectMetaLearningStrategy(learningPatterns, config);
// Adapt configuration based on strategy
const adaptedConfig = await this.applyMetaLearningStrategy(config, strategy, learningPatterns);
console.log(`Applied meta-learning strategy '${strategy.name}' for agent ${agentId}`);
return adaptedConfig;
}
/**
* Apply default meta-learning configuration for new agents
* @param {Object} config - Base configuration
*/
applyDefaultMetaLearning(config) {
// Apply conservative meta-learning defaults
return {
...config,
metaLearning: {
enabled: true,
strategy: 'maml',
adaptiveRate: 0.01,
experienceBuffer: 100,
transferThreshold: 0.7,
},
};
}
/**
* Analyze learning patterns from agent experiences
* @param {Array} experiences - Agent's learning experiences
*/
analyzeLearningPatterns(experiences) {
const patterns = {
learningSpeed: this.calculateLearningSpeed(experiences),
convergenceStability: this.calculateConvergenceStability(experiences),
domainVariability: this.calculateDomainVariability(experiences),
taskComplexity: this.calculateAverageTaskComplexity(experiences),
adaptationSuccess: this.calculateAdaptationSuccess(experiences),
forgettingRate: this.calculateForgettingRate(experiences),
transferEfficiency: this.calculateTransferEfficiency(experiences),
};
return patterns;
}
/**
* Calculate learning speed from experiences
* @param {Array} experiences - Learning experiences
*/
calculateLearningSpeed(experiences) {
if (experiences.length === 0) {
return 0.5;
}
let totalSpeed = 0;
let validExperiences = 0;
for (const exp of experiences) {
if (exp.metrics && exp.metrics.convergenceEpochs) {
// Faster convergence = higher speed
const speed = 1 / (1 + exp.metrics.convergenceEpochs / 10);
totalSpeed += speed;
validExperiences++;
}
}
return validExperiences > 0 ? totalSpeed / validExperiences : 0.5;
}
/**
* Calculate convergence stability
* @param {Array} experiences - Learning experiences
*/
calculateConvergenceStability(experiences) {
if (experiences.length === 0) {
return 0.5;
}
let totalStability = 0;
let validExperiences = 0;
for (const exp of experiences) {
if (exp.metrics && exp.metrics.lossVariance !== undefined) {
// Lower variance = higher stability
const stability = 1 / (1 + exp.metrics.lossVariance);
totalStability += stability;
validExperiences++;
}
}
return validExperiences > 0 ? totalStability / validExperiences : 0.5;
}
/**
* Calculate domain variability across experiences
* @param {Array} experiences - Learning experiences
*/
calculateDomainVariability(experiences) {
if (experiences.length === 0) {
return 0.5;
}
const domains = new Set();
for (const exp of experiences) {
if (exp.domain) {
domains.add(exp.domain);
}
}
// Normalize by maximum expected domains
return Math.min(1, domains.size / 10);
}
/**
* Calculate average task complexity
* @param {Array} experiences - Learning experiences
*/
calculateAverageTaskComplexity(experiences) {
if (experiences.length === 0) {
return 0.5;
}
let totalComplexity = 0;
let validExperiences = 0;
for (const exp of experiences) {
if (exp.taskComplexity !== undefined) {
totalComplexity += exp.taskComplexity;
validExperiences++;
}
}
return validExperiences > 0 ? totalComplexity / validExperiences : 0.5;
}
/**
* Calculate adaptation success rate
* @param {Array} experiences - Learning experiences
*/
calculateAdaptationSuccess(experiences) {
if (experiences.length === 0) {
return 0.5;
}
const successfulAdaptations = experiences.filter(exp =>
exp.adaptationResult && exp.adaptationResult.success,
).length;
return successfulAdaptations / experiences.length;
}
/**
* Calculate forgetting rate
* @param {Array} experiences - Learning experiences
*/
calculateForgettingRate(experiences) {
if (experiences.length < 2) {
return 0.5;
}
let totalForgetting = 0;
let validComparisons = 0;
for (let i = 1; i < experiences.length; i++) {
const prev = experiences[i - 1];
const curr = experiences[i];
if (prev.metrics && curr.metrics && prev.metrics.accuracy && curr.metrics.accuracy) {
// If accuracy drops significantly when learning new task, high forgetting
const forgetting = Math.max(0, prev.metrics.accuracy - curr.metrics.accuracy);
totalForgetting += forgetting;
validComparisons++;
}
}
return validComparisons > 0 ? totalForgetting / validComparisons : 0.5;
}
/**
* Calculate transfer learning efficiency
* @param {Array} experiences - Learning experiences
*/
calculateTransferEfficiency(experiences) {
if (experiences.length === 0) {
return 0.5;
}
const transferExperiences = experiences.filter(exp => exp.transferLearning);
if (transferExperiences.length === 0) {
return 0.5;
}
let totalEfficiency = 0;
for (const exp of transferExperiences) {
if (exp.transferLearning.efficiencyGain !== undefined) {
totalEfficiency += exp.transferLearning.efficiencyGain;
}
}
return transferExperiences.length > 0 ? totalEfficiency / transferExperiences.length : 0.5;
}
/**
* Select appropriate meta-learning strategy
* @param {Object} patterns - Learning patterns
* @param {Object} config - Configuration
*/
selectMetaLearningStrategy(patterns, config) {
let bestStrategy = null;
let bestScore = 0;
// Define task characteristics
const taskCharacteristics = this.inferTaskCharacteristics(patterns, config);
for (const [strategyName, strategy] of this.metaStrategies.entries()) {
let score = 0;
// Score based on applicability to current task characteristics
if (taskCharacteristics.fewShot) {
score += strategy.applicability.fewShotLearning * 0.3;
}
if (taskCharacteristics.domainTransfer) {
score += strategy.applicability.domainTransfer * 0.3;
}
if (taskCharacteristics.taskAdaptation) {
score += strategy.applicability.taskAdaptation * 0.2;
}
if (taskCharacteristics.continualLearning) {
score += strategy.applicability.continualLearning * 0.2;
}
// Adjust score based on learning patterns
if (patterns.learningSpeed < 0.3 && strategy.type === 'gradient_based') {
score += 0.1; // Boost gradient-based methods for slow learners
}
if (patterns.forgettingRate > 0.7 && strategy.type === 'memory_based') {
score += 0.2; // Boost memory-based methods for high forgetting
}
if (patterns.domainVariability > 0.6 && strategy.type === 'domain_based') {
score += 0.15; // Boost domain adaptation for high variability
}
if (score > bestScore) {
bestScore = score;
bestStrategy = strategy;
}
}
return bestStrategy || this.metaStrategies.get('maml');
}
/**
* Infer task characteristics from patterns and config
* @param {Object} patterns - Learning patterns
* @param {Object} config - Configuration
*/
inferTaskCharacteristics(patterns, config) {
return {
fewShot: patterns.learningSpeed < 0.4 || config.dataSize < 1000,
domainTransfer: patterns.domainVariability > 0.5,
taskAdaptation: patterns.adaptationSuccess < 0.6,
continualLearning: patterns.forgettingRate > 0.5,
};
}
/**
* Apply meta-learning strategy to configuration
* @param {Object} config - Base configuration
* @param {Object} strategy - Selected strategy
* @param {Object} patterns - Learning patterns
*/
async applyMetaLearningStrategy(config, strategy, patterns) {
const adaptedConfig = { ...config };
// Apply strategy-specific adaptations
switch (strategy.type) {
case 'gradient_based':
adaptedConfig.metaLearning = this.applyGradientBasedMeta(strategy, patterns);
break;
case 'metric_based':
adaptedConfig.metaLearning = this.applyMetricBasedMeta(strategy, patterns);
break;
case 'memory_based':
adaptedConfig.metaLearning = this.applyMemoryBasedMeta(strategy, patterns);
break;
case 'optimization_based':
adaptedConfig.metaLearning = this.applyOptimizationBasedMeta(strategy, patterns);
break;
case 'domain_based':
adaptedConfig.metaLearning = this.applyDomainBasedMeta(strategy, patterns);
break;
case 'continual_based':
adaptedConfig.metaLearning = this.applyContinualBasedMeta(strategy, patterns);
break;
case 'multi_task_based':
adaptedConfig.metaLearning = this.applyMultiTaskBasedMeta(strategy, patterns);
break;
}
// Add common meta-learning properties
adaptedConfig.metaLearning.strategyName = strategy.name;
adaptedConfig.metaLearning.enabled = true;
adaptedConfig.metaLearning.adaptiveThreshold = this.calculateAdaptiveThreshold(patterns);
return adaptedConfig;
}
/**
* Apply gradient-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyGradientBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Adapt inner learning rate based on learning speed
if (patterns.learningSpeed < 0.3) {
config.innerLearningRate *= 1.5; // Increase for slow learners
} else if (patterns.learningSpeed > 0.7) {
config.innerLearningRate *= 0.7; // Decrease for fast learners
}
// Adapt inner steps based on convergence stability
if (patterns.convergenceStability < 0.4) {
config.innerSteps = Math.max(3, config.innerSteps - 2);
} else if (patterns.convergenceStability > 0.8) {
config.innerSteps = Math.min(10, config.innerSteps + 3);
}
return { type: 'gradient_based', ...config };
}
/**
* Apply metric-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyMetricBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Adapt embedding dimension based on task complexity
if (patterns.taskComplexity > 0.7) {
config.embeddingDim = Math.min(128, config.embeddingDim * 1.5);
} else if (patterns.taskComplexity < 0.3) {
config.embeddingDim = Math.max(32, config.embeddingDim * 0.7);
}
// Adapt temperature based on convergence stability
if (patterns.convergenceStability < 0.5) {
config.temperatureScale = Math.max(0.5, config.temperatureScale - 0.2);
}
return { type: 'metric_based', ...config };
}
/**
* Apply memory-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyMemoryBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Increase memory size for high forgetting rate
if (patterns.forgettingRate > 0.6) {
config.memorySize = Math.min(256, config.memorySize * 1.5);
}
// Adjust read/write heads based on domain variability
if (patterns.domainVariability > 0.5) {
config.readHeads = Math.min(4, config.readHeads + 1);
config.writeHeads = Math.min(2, config.writeHeads + 1);
}
return { type: 'memory_based', ...config };
}
/**
* Apply optimization-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyOptimizationBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Adapt optimizer based on learning speed
if (patterns.learningSpeed < 0.4) {
config.optimizerHiddenSize = Math.min(40, config.optimizerHiddenSize * 1.3);
}
// Enable coordinate-wise optimization for complex tasks
if (patterns.taskComplexity > 0.6) {
config.coordinatewise = true;
}
return { type: 'optimization_based', ...config };
}
/**
* Apply domain-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyDomainBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Strengthen domain discriminator for high domain variability
if (patterns.domainVariability > 0.7) {
config.domainDiscriminatorStrength *= 1.3;
config.gradientReversalLambda *= 1.2;
}
// Increase adaptation steps for low transfer efficiency
if (patterns.transferEfficiency < 0.4) {
config.adaptationSteps = Math.min(50, config.adaptationSteps * 1.5);
}
return { type: 'domain_based', ...config };
}
/**
* Apply continual-based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyContinualBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Increase regularization for high forgetting
if (patterns.forgettingRate > 0.6) {
config.regularizationStrength *= 1.4;
config.stability = Math.min(0.9, config.stability + 0.1);
}
// Increase memory replay for domain variability
if (patterns.domainVariability > 0.5) {
config.memoryReplayRatio = Math.min(0.4, config.memoryReplayRatio + 0.1);
}
return { type: 'continual_based', ...config };
}
/**
* Apply multi-task based meta-learning configuration
* @param {Object} strategy - Strategy configuration
* @param {Object} patterns - Learning patterns
*/
applyMultiTaskBasedMeta(strategy, patterns) {
const config = { ...strategy.parameters };
// Adjust shared layers based on transfer efficiency
if (patterns.transferEfficiency > 0.7) {
config.sharedLayers = Math.min(5, config.sharedLayers + 1);
} else if (patterns.transferEfficiency < 0.3) {
config.taskSpecificLayers = Math.min(4, config.taskSpecificLayers + 1);
}
// Enable gradient normalization for stability
if (patterns.convergenceStability < 0.5) {
config.gradientNormalization = true;
}
return { type: 'multi_task_based', ...config };
}
/**
* Calculate adaptive threshold based on patterns
* @param {Object} patterns - Learning patterns
*/
calculateAdaptiveThreshold(patterns) {
// Base threshold adjusted by learning characteristics
let threshold = 0.7;
if (patterns.learningSpeed < 0.3) {
threshold -= 0.1;
} // Lower threshold for slow learners
if (patterns.adaptationSuccess < 0.5) {
threshold -= 0.05;
} // Lower threshold for poor adapters
if (patterns.forgettingRate > 0.6) {
threshold += 0.1;
} // Higher threshold if prone to forgetting
return Math.max(0.3, Math.min(0.9, threshold));
}
/**
* Optimize training parameters using meta-learning
* @param {string} agentId - Agent identifier
* @param {Object} options - Training options
*/
async optimizeTraining(agentId, options) {
const experiences = this.agentExperiences.get(agentId) || [];
if (experiences.length === 0) {
return options; // No optimization without experience
}
const patterns = this.analyzeLearningPatterns(experiences);
const optimizedOptions = { ...options };
// Optimize learning rate
optimizedOptions.learningRate = this.optimizeLearningRate(patterns, options.learningRate);
// Optimize batch size
optimizedOptions.batchSize = this.optimizeBatchSize(patterns, options.batchSize);
// Optimize epochs
optimizedOptions.epochs = this.optimizeEpochs(patterns, options.epochs);
// Add meta-learning specific optimizations
optimizedOptions.metaOptimizations = {
warmupEpochs: this.calculateWarmupEpochs(patterns),
schedulerType: this.selectSchedulerType(patterns),
regularizationStrength: this.optimizeRegularization(patterns),
earlyStoppingPatience: this.optimizeEarlyStopping(patterns),
};
console.log(`Optimized training parameters for agent ${agentId} based on meta-learning`);
return optimizedOptions;
}
/**
* Optimize learning rate based on patterns
* @param {Object} patterns - Learning patterns
* @param {number} baseLR - Base learning rate
*/
optimizeLearningRate(patterns, baseLR) {
let multiplier = 1.0;
// Adjust based on learning speed
if (patterns.learningSpeed < 0.3) {
multiplier *= 1.3; // Increase LR for slow learners
} else if (patterns.learningSpeed > 0.7) {
multiplier *= 0.8; // Decrease LR for fast learners
}
// Adjust based on convergence stability
if (patterns.convergenceStability < 0.4) {
multiplier *= 0.7; // Lower LR for unstable convergence
}
return baseLR * multiplier;
}
/**
* Optimize batch size based on patterns
* @param {Object} patterns - Learning patterns
* @param {number} baseBatchSize - Base batch size
*/
optimizeBatchSize(patterns, baseBatchSize) {
let multiplier = 1.0;
// Adjust based on convergence stability
if (patterns.convergenceStability < 0.4) {
multiplier *= 1.5; // Larger batches for stability
} else if (patterns.convergenceStability > 0.8) {
multiplier *= 0.8; // Smaller batches for exploration
}
// Adjust based on task complexity
if (patterns.taskComplexity > 0.7) {
multiplier *= 0.7; // Smaller batches for complex tasks
}
const optimizedSize = Math.round(baseBatchSize * multiplier);
return Math.max(1, Math.min(256, optimizedSize)); // Clamp to reasonable range
}
/**
* Optimize number of epochs based on patterns
* @param {Object} patterns - Learning patterns
* @param {number} baseEpochs - Base number of epochs
*/
optimizeEpochs(patterns, baseEpochs) {
let multiplier = 1.0;
// Adjust based on learning speed
if (patterns.learningSpeed < 0.3) {
multiplier *= 1.5; // More epochs for slow learners
} else if (patterns.learningSpeed > 0.7) {
multiplier *= 0.7; // Fewer epochs for fast learners
}
// Adjust based on forgetting rate
if (patterns.forgettingRate > 0.6) {
multiplier *= 0.8; // Fewer epochs to avoid overfitting
}
const optimizedEpochs = Math.round(baseEpochs * multiplier);
return Math.max(1, Math.min(200, optimizedEpochs)); // Clamp to reasonable range
}
/**
* Calculate optimal warmup epochs
* @param {Object} patterns - Learning patterns
*/
calculateWarmupEpochs(patterns) {
let warmupEpochs = 0;
// Use warmup for unstable convergence
if (patterns.convergenceStability < 0.5) {
warmupEpochs = Math.ceil(5 * (1 - patterns.convergenceStability));
}
return Math.max(0, Math.min(10, warmupEpochs));
}
/**
* Select learning rate scheduler type
* @param {Object} patterns - Learning patterns
*/
selectSchedulerType(patterns) {
if (patterns.convergenceStability < 0.4) {
return 'cosine_annealing'; // Smooth schedule for unstable training
} else if (patterns.learningSpeed < 0.3) {
return 'exponential_decay'; // Gradual reduction for slow learners
} else if (patterns.taskComplexity > 0.7) {
return 'step_decay'; // Stepwise reduction for complex tasks
}
return 'constant'; // Keep constant for stable cases
}
/**
* Optimize regularization strength
* @param {Object} patterns - Learning patterns
*/
optimizeRegularization(patterns) {
let baseStrength = 0.01;
// Increase regularization for high task complexity
if (patterns.taskComplexity > 0.6) {
baseStrength *= 1.5;
}
// Increase regularization for low convergence stability
if (patterns.convergenceStability < 0.5) {
baseStrength *= 1.3;
}
// Decrease regularization for high forgetting rate (may be overregularized)
if (patterns.forgettingRate > 0.7) {
baseStrength *= 0.7;
}
return Math.max(0.001, Math.min(0.1, baseStrength));
}
/**
* Optimize early stopping patience
* @param {Object} patterns - Learning patterns
*/
optimizeEarlyStopping(patterns) {
let basePatienceEpochs = 10;
// Increase patience for slow learners
if (patterns.learningSpeed < 0.3) {
basePatienceEpochs *= 1.5;
}
// Decrease patience for fast learners
if (patterns.learningSpeed > 0.7) {
basePatienceEpochs *= 0.7;
}
// Increase patience for unstable convergence
if (patterns.convergenceStability < 0.4) {
basePatienceEpochs *= 1.3;
}
return Math.max(3, Math.min(25, Math.round(basePatienceEpochs)));
}
/**
* Extract experiences from agent for meta-learning
* @param {string} agentId - Agent identifier
*/
async extractExperiences(agentId) {
return this.agentExperiences.get(agentId) || [];
}
/**
* Record learning experience for meta-learning
* @param {string} agentId - Agent identifier
* @param {Object} experience - Learning experience
*/
recordExperience(agentId, experience) {
if (!this.agentExperiences.has(agentId)) {
this.agentExperiences.set(agentId, []);
}
const experiences = this.agentExperiences.get(agentId);
// Add timestamp and unique ID
const enrichedExperience = {
...experience,
timestamp: Date.now(),
id: `exp_${agentId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
};
experiences.push(enrichedExperience);
// Keep only recent experiences (last 100)
if (experiences.length > 100) {
experiences.splice(0, experiences.length - 100);
}
// Update learning metrics
this.updateLearningMetrics(agentId, enrichedExperience);
}
/**
* Update learning metrics for agent
* @param {string} agentId - Agent identifier
* @param {Object} experience - Learning experience
*/
updateLearningMetrics(agentId, experience) {
if (!this.learningMetrics.has(agentId)) {
this.learningMetrics.set(agentId, {
totalExperiences: 0,
averageLearningTime: 0,
averageAccuracy: 0,
adaptationSuccessRate: 0,
domainTransferCount: 0,
lastUpdate: Date.now(),
});
}
const metrics = this.learningMetrics.get(agentId);
metrics.totalExperiences++;
metrics.lastUpdate = Date.now();
// Update running averages
if (experience.metrics) {
if (experience.metrics.trainingTime) {
metrics.averageLearningTime = this.updateRunningAverage(
metrics.averageLearningTime,
experience.metrics.trainingTime,
metrics.totalExperiences,
);
}
if (experience.metrics.accuracy) {
metrics.averageAccuracy = this.updateRunningAverage(
metrics.averageAccuracy,
experience.metrics.accuracy,
metrics.totalExperiences,
);
}
}
// Update success rate
if (experience.adaptationResult) {
const successCount = metrics.adaptationSuccessRate * (metrics.totalExperiences - 1);
const newSuccess = experience.adaptationResult.success ? 1 : 0;
metrics.adaptationSuccessRate = (successCount + newSuccess) / metrics.totalExperiences;
}
// Count domain transfers
if (experience.transferLearning) {
metrics.domainTransferCount++;
}
}
/**
* Update running average
* @param {number} currentAvg - Current average
* @param {number} newValue - New value
* @param {number} count - Total count
*/
updateRunningAverage(currentAvg, newValue, count) {
return currentAvg + (newValue - currentAvg) / count;
}
/**
* Perform domain adaptation using meta-learning
* @param {string} agentId - Agent identifier
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
async performDomainAdaptation(agentId, sourceData, targetData) {
// Analyze domain shift
const domainShift = this.analyzeDomainShift(sourceData, targetData);
// Select adaptation strategy
const adaptationStrategy = this.selectAdaptationStrategy(domainShift);
// Apply domain adaptation
const adaptationResult = await this.applyDomainAdaptation(
agentId,
adaptationStrategy,
sourceData,
targetData,
);
// Record domain adaptation experience
this.recordExperience(agentId, {
type: 'domain_adaptation',
sourceData: this.summarizeData(sourceData),
targetData: this.summarizeData(targetData),
domainShift,
adaptationStrategy,
adaptationResult,
transferLearning: {
enabled: true,
efficiencyGain: adaptationResult.efficiencyGain || 0,
},
});
return adaptationResult;
}
/**
* Analyze domain shift between source and target
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
analyzeDomainShift(sourceData, targetData) {
return {
distributionShift: this.calculateDistributionShift(sourceData, targetData),
featureShift: this.calculateFeatureShift(sourceData, targetData),
labelShift: this.calculateLabelShift(sourceData, targetData),
marginalShift: this.calculateMarginalShift(sourceData, targetData),
conditionalShift: this.calculateConditionalShift(sourceData, targetData),
};
}
/**
* Calculate distribution shift between domains
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateDistributionShift(sourceData, targetData) {
// Simplified distribution shift calculation
if (!sourceData.samples || !targetData.samples) {
return 0.5;
}
// Calculate basic statistics for both domains
const sourceStats = this.calculateDataStatistics(sourceData.samples);
const targetStats = this.calculateDataStatistics(targetData.samples);
// Calculate shift as difference in statistics
const meanShift = Math.abs(sourceStats.mean - targetStats.mean);
const varianceShift = Math.abs(sourceStats.variance - targetStats.variance);
return Math.min(1, (meanShift + varianceShift) / 2);
}
/**
* Calculate basic data statistics
* @param {Array} samples - Data samples
*/
calculateDataStatistics(samples) {
if (samples.length === 0) {
return { mean: 0, variance: 0 };
}
// Flatten samples to get all numeric values
const values = samples.flat().filter(v => typeof v === 'number');
if (values.length === 0) {
return { mean: 0, variance: 0 };
}
const mean = values.reduce((sum, v) => sum + v, 0) / values.length;
const variance = values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / values.length;
return { mean, variance };
}
/**
* Calculate feature shift (simplified)
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateFeatureShift(sourceData, targetData) {
// Simplified feature shift - compare feature dimensions
const sourceDim = this.getFeatureDimensions(sourceData);
const targetDim = this.getFeatureDimensions(targetData);
if (sourceDim === 0 || targetDim === 0) {
return 0.5;
}
return Math.abs(sourceDim - targetDim) / Math.max(sourceDim, targetDim);
}
/**
* Get feature dimensions from data
* @param {Object} data - Data object
*/
getFeatureDimensions(data) {
if (!data.samples || data.samples.length === 0) {
return 0;
}
const sample = data.samples[0];
if (Array.isArray(sample)) {
return sample.length;
}
if (typeof sample === 'object' && sample.input) {
return Array.isArray(sample.input) ? sample.input.length : 1;
}
return 1;
}
/**
* Calculate label shift (simplified)
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateLabelShift(sourceData, targetData) {
// Compare label distributions
const sourceLabels = this.extractLabels(sourceData);
const targetLabels = this.extractLabels(targetData);
if (sourceLabels.size === 0 || targetLabels.size === 0) {
return 0.5;
}
const intersection = new Set([...sourceLabels].filter(x => targetLabels.has(x)));
const union = new Set([...sourceLabels, ...targetLabels]);
return 1 - (intersection.size / union.size); // Jaccard distance
}
/**
* Extract unique labels from data
* @param {Object} data - Data object
*/
extractLabels(data) {
const labels = new Set();
if (data.samples) {
data.samples.forEach(sample => {
if (sample.label !== undefined) {
labels.add(sample.label);
}
if (sample.target !== undefined) {
labels.add(sample.target);
}
});
}
return labels;
}
/**
* Calculate marginal shift (simplified)
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateMarginalShift(sourceData, targetData) {
// Simplified marginal shift calculation
return this.calculateDistributionShift(sourceData, targetData);
}
/**
* Calculate conditional shift (simplified)
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateConditionalShift(sourceData, targetData) {
// Simplified conditional shift calculation
const featureShift = this.calculateFeatureShift(sourceData, targetData);
const labelShift = this.calculateLabelShift(sourceData, targetData);
return (featureShift + labelShift) / 2;
}
/**
* Select appropriate domain adaptation strategy
* @param {Object} domainShift - Domain shift analysis
*/
selectAdaptationStrategy(domainShift) {
const { distributionShift, featureShift, labelShift } = domainShift;
if (distributionShift > 0.7) {
return 'adversarial_adaptation';
} else if (featureShift > 0.6) {
return 'feature_alignment';
} else if (labelShift > 0.5) {
return 'label_adaptation';
}
return 'fine_tuning';
}
/**
* Apply domain adaptation strategy
* @param {string} agentId - Agent identifier
* @param {string} strategy - Adaptation strategy
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
async applyDomainAdaptation(agentId, strategy, sourceData, targetData) {
console.log(`Applying domain adaptation strategy '${strategy}' for agent ${agentId}`);
// Simulate domain adaptation (in practice, would involve actual training)
const adaptationResult = {
strategy,
success: Math.random() > 0.3, // 70% success rate simulation
efficiencyGain: Math.random() * 0.4 + 0.1, // 10-50% efficiency gain
accuracyImprovement: Math.random() * 0.2 + 0.05, // 5-25% accuracy improvement
adaptationTime: Math.random() * 100 + 50, // 50-150 time units
transferredKnowledge: this.calculateTransferredKnowledge(sourceData, targetData),
};
// Store adaptation in transfer learning map
if (!this.transferLearning.has(agentId)) {
this.transferLearning.set(agentId, []);
}
this.transferLearning.get(agentId).push({
timestamp: Date.now(),
strategy,
result: adaptationResult,
sourceDataSummary: this.summarizeData(sourceData),
targetDataSummary: this.summarizeData(targetData),
});
return adaptationResult;
}
/**
* Calculate amount of knowledge transferred
* @param {Object} sourceData - Source domain data
* @param {Object} targetData - Target domain data
*/
calculateTransferredKnowledge(sourceData, targetData) {
// Simplified calculation based on data similarity
const similarity = 1 - this.calculateDistributionShift(sourceData, targetData);
return Math.max(0.1, similarity * 0.8); // 10-80% knowledge transfer
}
/**
* Summarize data for storage
* @param {Object} data - Data to summarize
*/
summarizeData(data) {
return {
sampleCount: data.samples ? data.samples.length : 0,
featureDimensions: this.getFeatureDimensions(data),
uniqueLabels: this.extractLabels(data).size,
dataType: this.inferDataType(data),
};
}
/**
* Infer data type from samples
* @param {Object} data - Data object
*/
inferDataType(data) {
if (!data.samples || data.samples.length === 0) {
return 'unknown';
}
const sample = data.samples[0];
if (Array.isArray(sample)) {
return sample.length > 100 ? 'image' : 'vector';
}
if (typeof sample === 'object') {
if (sample.sequence) {
return 'sequence';
}
if (sample.text) {
return 'text';
}
if (sample.image) {
return 'image';
}
}
return 'scalar';
}
/**
* Get meta-learning statistics
*/
getStatistics() {
const totalAgents = this.agentExperiences.size;
let totalExperiences = 0;
let totalAdaptations = 0;
let avgSuccessRate = 0;
for (const [agentId, experiences] of this.agentExperiences.entries()) {
totalExperiences += experiences.length;
const adaptations = experiences.filter(exp => exp.type === 'domain_adaptation');
totalAdaptations += adaptations.length;
const metrics = this.learningMetrics.get(agentId);
if (metrics) {
avgSuccessRate += metrics.adaptationSuccessRate;
}
}
return {
totalAgents,
totalExperiences,
totalAdaptations,
avgExperiencesPerAgent: totalAgents > 0 ? totalExperiences / totalAgents : 0,
avgSuccessRate: totalAgents > 0 ? avgSuccessRate / totalAgents : 0,
availableStrategies: this.metaStrategies.size,
transferLearningInstances: this.transferLearning.size,
};
}
/**
* Preserve meta-learning state for agent
* @param {string} agentId - Agent identifier
*/
async preserveState(agentId) {
return {
experiences: this.agentExperiences.get(agentId) || [],
domainAdaptations: this.domainAdaptations.get(agentId) || [],
transferLearning: this.transferLearning.get(agentId) || [],
learningMetrics: this.learningMetrics.get(agentId) || null,
};
}
/**
* Restore meta-learning state for agent
* @param {string} agentId - Agent identifier
* @param {Object} state - Preserved state
*/
async restoreState(agentId, state) {
if (state.experiences) {
this.agentExperiences.set(agentId, state.experiences);
}
if (state.domainAdaptations) {
this.domainAdaptations.set(agentId, state.domainAdaptations);
}
if (state.transferLearning) {
this.transferLearning.set(agentId, state.transferLearning);
}
if (state.learningMetrics) {
this.learningMetrics.set(agentId, state.learningMetrics);
}
}
}
export { MetaLearningFramework };