UNPKG

ruv-swarm

Version:

High-performance neural network swarm orchestration in WebAssembly

269 lines (219 loc) 6.12 kB
/** * Base Neural Model Class * Abstract base class for all neural network models */ class NeuralModel { constructor(modelType) { this.modelType = modelType; this.isInitialized = false; this.trainingHistory = []; this.metrics = { accuracy: 0, loss: 1.0, epochsTrained: 0, totalSamples: 0, }; } // Abstract methods to be implemented by subclasses async forward(input, _training = false) { throw new Error('forward() must be implemented by subclass'); } async train(trainingData, _options = {}) { throw new Error('train() must be implemented by subclass'); } async backward(loss, _learningRate) { // Default backward pass - can be overridden console.log(`Backward pass for ${this.modelType} with loss: ${loss}`); return true; } async validate(validationData) { let totalLoss = 0; let batchCount = 0; for (const batch of validationData) { const predictions = await this.forward(batch.inputs, false); const loss = this.crossEntropyLoss(predictions, batch.targets); totalLoss += loss; batchCount++; } return totalLoss / batchCount; } // Common utility methods matmul(a, b) { // Matrix multiplication helper // Assumes a is [m, n] and b is [n, p] if (!a.shape || !b.shape || a.shape.length < 2 || b.shape.length < 2) { throw new Error('Invalid matrix dimensions for multiplication'); } const m = a.shape[0]; const n = a.shape[1]; const p = b.shape[b.shape.length - 1]; const result = new Float32Array(m * p); for (let i = 0; i < m; i++) { for (let j = 0; j < p; j++) { let sum = 0; for (let k = 0; k < n; k++) { sum += a[i * n + k] * b[k * p + j]; } result[i * p + j] = sum; } } result.shape = [m, p]; return result; } add(a, b) { // Element-wise addition if (a.length !== b.length) { throw new Error('Tensors must have same length for addition'); } const result = new Float32Array(a.length); for (let i = 0; i < a.length; i++) { result[i] = a[i] + b[i]; } result.shape = a.shape; return result; } addBias(input, bias) { // Add bias to last dimension const result = new Float32Array(input.length); const lastDim = bias.length; for (let i = 0; i < input.length; i++) { result[i] = input[i] + bias[i % lastDim]; } result.shape = input.shape; return result; } relu(input) { // ReLU activation const result = new Float32Array(input.length); for (let i = 0; i < input.length; i++) { result[i] = Math.max(0, input[i]); } result.shape = input.shape; return result; } sigmoid(input) { // Sigmoid activation const result = new Float32Array(input.length); for (let i = 0; i < input.length; i++) { result[i] = 1 / (1 + Math.exp(-input[i])); } result.shape = input.shape; return result; } tanh(input) { // Tanh activation const result = new Float32Array(input.length); for (let i = 0; i < input.length; i++) { result[i] = Math.tanh(input[i]); } result.shape = input.shape; return result; } dropout(input, rate) { // Apply dropout during training if (rate <= 0) { return input; } const result = new Float32Array(input.length); const scale = 1 / (1 - rate); for (let i = 0; i < input.length; i++) { if (Math.random() > rate) { result[i] = input[i] * scale; } else { result[i] = 0; } } result.shape = input.shape; return result; } crossEntropyLoss(predictions, targets) { // Cross-entropy loss for classification let loss = 0; const epsilon = 1e-7; // For numerical stability for (let i = 0; i < predictions.length; i++) { const pred = Math.max(epsilon, Math.min(1 - epsilon, predictions[i])); if (targets[i] === 1) { loss -= Math.log(pred); } else { loss -= Math.log(1 - pred); } } return loss / predictions.length; } meanSquaredError(predictions, targets) { // MSE loss for regression let loss = 0; for (let i = 0; i < predictions.length; i++) { const diff = predictions[i] - targets[i]; loss += diff * diff; } return loss / predictions.length; } shuffle(array) { // Fisher-Yates shuffle const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } // Model persistence methods async save(filePath) { const modelData = { modelType: this.modelType, config: this.getConfig(), weights: this.getWeights(), metrics: this.metrics, trainingHistory: this.trainingHistory, }; // In a real implementation, save to file console.log(`Saving ${this.modelType} model to ${filePath}`); return modelData; } async load(filePath) { // In a real implementation, load from file console.log(`Loading ${this.modelType} model from ${filePath}`); return true; } getWeights() { // To be overridden by subclasses return {}; } setWeights(_weights) { // To be overridden by subclasses console.log(`Setting weights for ${this.modelType}`); } getConfig() { // To be overridden by subclasses return { modelType: this.modelType, }; } getMetrics() { return { ...this.metrics, modelType: this.modelType, trainingHistory: this.trainingHistory, }; } updateMetrics(loss, accuracy = null) { this.metrics.loss = loss; if (accuracy !== null) { this.metrics.accuracy = accuracy; } this.metrics.epochsTrained++; } reset() { // Reset model to initial state this.trainingHistory = []; this.metrics = { accuracy: 0, loss: 1.0, epochsTrained: 0, totalSamples: 0, }; this.initializeWeights(); } } export { NeuralModel };