@astermind/astermind-premium
Version:
Astermind Premium - Premium ML Toolkit
150 lines • 5.6 kB
JavaScript
// recurrent-elm.ts — Recurrent ELM (R-ELM)
// Recurrent connections in ELM for sequence modeling
import { ELM } from '@astermind/astermind-elm';
import { requireLicense } from '../core/license.js';
/**
* Recurrent ELM for sequence modeling
* Features:
* - Recurrent connections
* - Sequence modeling
* - Temporal dependencies
* - Memory of past inputs
*/
export class RecurrentELM {
constructor(options) {
this.hiddenState = [];
this.trained = false;
requireLicense(); // Premium feature - requires valid license
this.categories = options.categories;
this.options = {
categories: options.categories,
hiddenUnits: options.hiddenUnits ?? 256,
recurrentUnits: options.recurrentUnits ?? 128,
sequenceLength: options.sequenceLength ?? 10,
activation: options.activation ?? 'tanh',
maxLen: options.maxLen ?? 100,
useTokenizer: options.useTokenizer ?? true,
};
this.elm = new ELM({
useTokenizer: this.options.useTokenizer ? true : undefined,
hiddenUnits: this.options.hiddenUnits,
categories: this.options.categories,
maxLen: this.options.maxLen,
activation: this.options.activation,
});
// Initialize hidden state
this.hiddenState = new Array(this.options.recurrentUnits).fill(0);
}
/**
* Train on sequences
*/
train(X, y) {
// Prepare labels
const labelIndices = y.map(label => typeof label === 'number'
? label
: this.options.categories.indexOf(label));
// Process sequences with recurrent connections
const features = this._processSequences(X);
// Train ELM
this.elm.setCategories?.(this.options.categories);
this.elm.trainFromData?.(features, labelIndices);
this.trained = true;
}
/**
* Process sequences with recurrent connections
*/
_processSequences(sequences) {
const features = [];
for (const sequence of sequences) {
// Reset hidden state for each sequence
this.hiddenState = new Array(this.options.recurrentUnits).fill(0);
// Process sequence step by step
for (const step of sequence) {
// Combine input with hidden state
const combined = [...step, ...this.hiddenState];
// Update hidden state (simplified recurrent update)
this._updateHiddenState(step);
}
// Use final hidden state + last input as features
const finalFeatures = [...sequence[sequence.length - 1] || [], ...this.hiddenState];
features.push(finalFeatures);
}
return features;
}
/**
* Update hidden state (recurrent connection)
*/
_updateHiddenState(input) {
// Simplified recurrent update: h_t = tanh(W * [x_t; h_{t-1}])
const combined = [...input, ...this.hiddenState];
const newState = new Array(this.options.recurrentUnits).fill(0);
// Simple linear transformation (in practice, use learned weights)
for (let i = 0; i < this.options.recurrentUnits; i++) {
let sum = 0;
for (let j = 0; j < combined.length; j++) {
// Simple hash-based weight (in practice, use learned weights)
const hash = this._hash(`recurrent_${i}_${j}`);
sum += combined[j] * hash;
}
// Apply activation
if (this.options.activation === 'tanh') {
newState[i] = Math.tanh(sum);
}
else if (this.options.activation === 'relu') {
newState[i] = Math.max(0, sum);
}
else if (this.options.activation === 'sigmoid') {
newState[i] = 1 / (1 + Math.exp(-sum));
}
else {
newState[i] = sum;
}
}
this.hiddenState = newState;
}
_hash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return (hash / 2147483647) * 0.1; // Small weights
}
/**
* Predict on sequence
*/
predict(X, topK = 3) {
if (!this.trained) {
throw new Error('Model must be trained before prediction');
}
const sequences = Array.isArray(X[0][0])
? X
: [X];
const results = [];
for (const sequence of sequences) {
// Process sequence
this.hiddenState = new Array(this.options.recurrentUnits).fill(0);
for (const step of sequence) {
this._updateHiddenState(step);
}
const finalFeatures = [...sequence[sequence.length - 1] || [], ...this.hiddenState];
const preds = this.elm.predictFromVector?.([finalFeatures], topK) || [];
for (const pred of preds.slice(0, topK)) {
results.push({
label: pred.label || this.options.categories[pred.index || 0],
prob: pred.prob || 0,
hiddenState: [...this.hiddenState],
});
}
}
return results;
}
/**
* Reset hidden state
*/
resetState() {
this.hiddenState = new Array(this.options.recurrentUnits).fill(0);
}
}
//# sourceMappingURL=recurrent-elm.js.map