()
| 170 | } |
| 171 | |
| 172 | async function initializeVisualizer() { |
| 173 | initializeInfoDialog(); |
| 174 | |
| 175 | const weightDefinitionUrl = new URL(VISUALIZER_CONFIG.weightUrl, window.location.href); |
| 176 | const definition = await fetchNetworkDefinition(weightDefinitionUrl.toString()); |
| 177 | if (!definition?.network) { |
| 178 | throw new Error("Ungültige Netzwerkdefinition."); |
| 179 | } |
| 180 | |
| 181 | const timelineSnapshots = hydrateTimeline(definition.timeline, { |
| 182 | layerMetadata: definition.network.layers, |
| 183 | baseUrl: weightDefinitionUrl, |
| 184 | }); |
| 185 | if (!timelineSnapshots.length) { |
| 186 | throw new Error("Keine gültigen Timeline-Snapshots gefunden."); |
| 187 | } |
| 188 | const defaultSnapshotIndex = Math.max(timelineSnapshots.length - 1, 0); |
| 189 | const initialSnapshot = timelineSnapshots[defaultSnapshotIndex]; |
| 190 | const initialLayers = await initialSnapshot.loadLayers(); |
| 191 | |
| 192 | const neuralModel = new FeedForwardModel({ |
| 193 | normalization: definition.network.normalization, |
| 194 | architecture: definition.network.architecture, |
| 195 | layers: initialLayers, |
| 196 | }); |
| 197 | const gridContainerElement = document.getElementById("gridContainer"); |
| 198 | const digitCanvas = new DigitSketchPad(gridContainerElement, 28, 28, { |
| 199 | brush: VISUALIZER_CONFIG.brush, |
| 200 | }); |
| 201 | const probabilityPanel = new ProbabilityPanel(document.getElementById("predictionChart")); |
| 202 | const networkInfoPanelElement = document.getElementById("networkInfoPanel"); |
| 203 | const networkInfoPanel = networkInfoPanelElement ? new NetworkInfoPanel(networkInfoPanelElement) : null; |
| 204 | const neuronDetailPanelElement = document.getElementById("neuronDetailPanel"); |
| 205 | const neuronDetailPanel = new NeuronDetailPanel(neuronDetailPanelElement); |
| 206 | const neuralScene = new NeuralVisualizer(neuralModel, { |
| 207 | layerSpacing: VISUALIZER_CONFIG.layerSpacing, |
| 208 | maxConnectionsPerNeuron: VISUALIZER_CONFIG.maxConnectionsPerNeuron, |
| 209 | inputSpacing: VISUALIZER_CONFIG.inputSpacing, |
| 210 | hiddenSpacing: VISUALIZER_CONFIG.hiddenSpacing, |
| 211 | inputNodeSize: VISUALIZER_CONFIG.inputNodeSize, |
| 212 | hiddenNodeRadius: VISUALIZER_CONFIG.hiddenNodeRadius, |
| 213 | connectionRadius: VISUALIZER_CONFIG.connectionRadius, |
| 214 | connectionWeightThreshold: VISUALIZER_CONFIG.connectionWeightThreshold, |
| 215 | showFpsOverlay: VISUALIZER_CONFIG.showFpsOverlay, |
| 216 | onNeuronFocusChange: (payload) => neuronDetailPanel.update(payload), |
| 217 | }); |
| 218 | networkInfoPanel?.update(neuralModel); |
| 219 | neuronDetailPanel.setOnClear(() => neuralScene.clearSelection()); |
| 220 | |
| 221 | if (gridContainerElement && neuronDetailPanelElement) { |
| 222 | const rootStyle = document.documentElement?.style ?? null; |
| 223 | const spacingBelowSketchPad = 16; |
| 224 | const bottomMargin = 24; |
| 225 | |
| 226 | const applyNeuronPanelLayout = () => { |
| 227 | if (!rootStyle) return; |
| 228 | const gridRect = gridContainerElement.getBoundingClientRect(); |
| 229 | const rawTop = Math.round(gridRect.bottom + spacingBelowSketchPad); |
no test coverage detected