| 1269 | } |
| 1270 | |
| 1271 | class FeedForwardModel { |
| 1272 | constructor(definition) { |
| 1273 | if (!definition.layers?.length) { |
| 1274 | throw new Error("Die Netzwerkdefinition muss Schichten enthalten."); |
| 1275 | } |
| 1276 | this.normalization = definition.normalization ?? { mean: 0, std: 1 }; |
| 1277 | this.architecture = Array.isArray(definition.architecture) |
| 1278 | ? definition.architecture.slice() |
| 1279 | : this.computeArchitecture(definition.layers); |
| 1280 | this.layers = definition.layers.map((layer, index) => this.normaliseLayer(layer, index)); |
| 1281 | } |
| 1282 | |
| 1283 | computeArchitecture(layers) { |
| 1284 | if (!layers.length) return []; |
| 1285 | const architecture = []; |
| 1286 | const firstLayer = layers[0]; |
| 1287 | architecture.push(firstLayer.weights[0]?.length ?? 0); |
| 1288 | for (const layer of layers) { |
| 1289 | architecture.push(layer.biases.length); |
| 1290 | } |
| 1291 | return architecture; |
| 1292 | } |
| 1293 | |
| 1294 | normaliseLayer(layer, index) { |
| 1295 | if (!layer || !Array.isArray(layer.weights) || layer.weights.length === 0) { |
| 1296 | throw new Error(`Layer ${index} is missing valid weight matrices.`); |
| 1297 | } |
| 1298 | const weights = layer.weights.map((row) => { |
| 1299 | if (row instanceof Float32Array) { |
| 1300 | return new Float32Array(row); |
| 1301 | } |
| 1302 | if (Array.isArray(row)) { |
| 1303 | return Float32Array.from(row); |
| 1304 | } |
| 1305 | throw new Error(`Layer ${index} contains an invalid weight row.`); |
| 1306 | }); |
| 1307 | let biases; |
| 1308 | if (layer.biases instanceof Float32Array) { |
| 1309 | biases = new Float32Array(layer.biases); |
| 1310 | } else if (Array.isArray(layer.biases)) { |
| 1311 | biases = Float32Array.from(layer.biases); |
| 1312 | } else { |
| 1313 | biases = new Float32Array(weights.length > 0 ? weights[0].length : 0); |
| 1314 | } |
| 1315 | return { |
| 1316 | name: typeof layer.name === "string" ? layer.name : `dense_${index}`, |
| 1317 | activation: typeof layer.activation === "string" ? layer.activation : "relu", |
| 1318 | weights, |
| 1319 | biases, |
| 1320 | }; |
| 1321 | } |
| 1322 | |
| 1323 | updateLayers(layerDefinitions) { |
| 1324 | if (!Array.isArray(layerDefinitions) || layerDefinitions.length === 0) { |
| 1325 | throw new Error("Neue Layerdefinitionen müssen mindestens eine Schicht enthalten."); |
| 1326 | } |
| 1327 | this.layers = layerDefinitions.map((layer, index) => this.normaliseLayer(layer, index)); |
| 1328 | this.architecture = this.computeArchitecture(this.layers); |
nothing calls this directly
no outgoing calls
no test coverage detected