UNPKG

@astermind/astermind-premium

Version:

Astermind Premium - Premium ML Toolkit

150 lines 5.72 kB
// adaptive-kernel-elm.ts — Adaptive Kernel ELM // Data-dependent kernel parameters with local kernel adaptation import { KernelELM } from '@astermind/astermind-elm'; import { requireLicense } from '../core/license.js'; /** * Adaptive Kernel ELM with data-dependent kernel parameters * Features: * - Local kernel adaptation * - Sample-specific kernels * - Adaptive gamma/degree parameters * - Improved performance on non-stationary data */ export class AdaptiveKernelELM { constructor(options) { this.trained = false; this.adaptiveKernels = new Map(); requireLicense(); // Premium feature - requires valid license this.categories = options.categories; this.options = { categories: options.categories, kernelType: options.kernelType ?? 'rbf', adaptiveGamma: options.adaptiveGamma ?? true, adaptiveDegree: options.adaptiveDegree ?? false, baseGamma: options.baseGamma ?? 1.0, baseDegree: options.baseDegree ?? 2, baseCoef0: options.baseCoef0 ?? 0, activation: options.activation ?? 'relu', maxLen: options.maxLen ?? 100, useTokenizer: options.useTokenizer ?? true, }; this.kelm = new KernelELM({ useTokenizer: this.options.useTokenizer ? true : undefined, categories: this.options.categories, maxLen: this.options.maxLen, kernel: this.options.kernelType, gamma: this.options.baseGamma, degree: this.options.baseDegree, coef0: this.options.baseCoef0, }); } /** * Train with adaptive kernels */ train(X, y) { // Prepare labels const labelIndices = y.map(label => typeof label === 'number' ? label : this.options.categories.indexOf(label)); // Compute adaptive kernel parameters for each sample if (this.options.adaptiveGamma || this.options.adaptiveDegree) { this._computeAdaptiveKernels(X); } // Train base KernelELM this.kelm.setCategories?.(this.options.categories); this.kelm.trainFromData?.(X, labelIndices); this.trained = true; } /** * Compute adaptive kernel parameters */ _computeAdaptiveKernels(X) { // Compute local statistics for each sample for (let i = 0; i < X.length; i++) { const x = X[i]; const neighbors = this._findNeighbors(x, X, 5); // Find 5 nearest neighbors const params = {}; if (this.options.adaptiveGamma) { // Adapt gamma based on local density const localDensity = this._computeLocalDensity(x, neighbors); params.gamma = this.options.baseGamma / (1 + localDensity); } if (this.options.adaptiveDegree) { // Adapt degree based on local complexity const localComplexity = this._computeLocalComplexity(neighbors); params.degree = Math.max(1, Math.round(this.options.baseDegree * localComplexity)); } this.adaptiveKernels.set(i, params); } } /** * Find nearest neighbors */ _findNeighbors(x, X, k) { const distances = X.map((xi, i) => ({ index: i, dist: this._euclideanDistance(x, xi), })); distances.sort((a, b) => a.dist - b.dist); return distances.slice(1, k + 1).map(d => X[d.index]); } /** * Compute local density */ _computeLocalDensity(x, neighbors) { if (neighbors.length === 0) return 1; const avgDist = neighbors.reduce((sum, n) => sum + this._euclideanDistance(x, n), 0) / neighbors.length; return avgDist; } /** * Compute local complexity */ _computeLocalComplexity(neighbors) { if (neighbors.length < 2) return 1; // Compute variance in neighbors as complexity measure const variances = []; for (let i = 0; i < neighbors[0].length; i++) { const values = neighbors.map(n => n[i]); const mean = values.reduce((a, b) => a + b, 0) / values.length; const variance = values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / values.length; variances.push(variance); } const avgVariance = variances.reduce((a, b) => a + b, 0) / variances.length; return Math.sqrt(avgVariance); } _euclideanDistance(a, b) { let sum = 0; for (let i = 0; i < Math.min(a.length, b.length); i++) { sum += Math.pow(a[i] - b[i], 2); } return Math.sqrt(sum); } /** * Predict with adaptive kernels */ predict(X, topK = 3) { if (!this.trained) { throw new Error('Model must be trained before prediction'); } const XArray = Array.isArray(X[0]) ? X : [X]; const results = []; for (const x of XArray) { // Get base prediction const preds = this.kelm.predictFromVector?.([x], topK) || []; // Get adaptive kernel params for this sample (if available) const sampleIndex = XArray.indexOf(x); const kernelParams = this.adaptiveKernels.get(sampleIndex); for (const pred of preds.slice(0, topK)) { results.push({ label: pred.label || this.options.categories[pred.index || 0], prob: pred.prob || 0, kernelParams, }); } } return results; } } //# sourceMappingURL=adaptive-kernel-elm.js.map