commit 888d7ef4d205912a9eeebe500a7fd03bcda2f3cc
Author: root <root@hub.scroll.pub>
Date: 2025-01-07 21:48:46 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..b268bc2
--- /dev/null
+++ b/body.html
@@ -0,0 +1,70 @@
+<header>
+ <h1>KAN Experiment</h1>
+ <p>Configure and visualize Kolmogorov-Arnold Networks with dynamic weights and attention mechanisms</p>
+</header>
+
+<main>
+ <section id="config">
+ <h2>Network Configuration</h2>
+ <div class="grid">
+ <div class="param">
+ <label for="inner-units">Inner Units</label>
+ <input type="number" id="inner-units" min="1" max="20" value="6">
+ </div>
+ <div class="param">
+ <label for="outer-units">Outer Units</label>
+ <input type="number" id="outer-units" min="1" max="20" value="4">
+ </div>
+ <div class="param">
+ <label for="grid-points">Grid Points</label>
+ <input type="number" id="grid-points" min="5" max="50" value="25">
+ </div>
+ <div class="param">
+ <label for="spline-degree">Spline Degree</label>
+ <input type="number" id="spline-degree" min="1" max="5" value="3">
+ </div>
+ <div class="param">
+ <label for="learning-rate">Learning Rate</label>
+ <input type="number" id="learning-rate" min="0.0001" max="0.1" step="0.0001" value="0.001">
+ </div>
+ <div class="param">
+ <label for="epochs">Epochs</label>
+ <input type="number" id="epochs" min="10" max="500" value="60">
+ </div>
+ <div class="param">
+ <label for="attention-type">Attention Type</label>
+ <select id="attention-type">
+ <option value="softmax">Softmax</option>
+ <option value="softplus">Softplus</option>
+ <option value="rectify">Rectify</option>
+ </select>
+ </div>
+ </div>
+ <button id="run-experiment">Run Experiment</button>
+ </section>
+
+ <section id="results">
+ <h2>Experiment Results</h2>
+ <div class="metrics">
+ <div class="metric">
+ <span class="value" id="auc">-</span>
+ <span class="label">AUC</span>
+ </div>
+ <div class="metric">
+ <span class="value" id="ks">-</span>
+ <span class="label">KS Statistic</span>
+ </div>
+ <div class="metric">
+ <span class="value" id="logloss">-</span>
+ <span class="label">Log Loss</span>
+ </div>
+ </div>
+ <div class="charts">
+ <canvas id="loss-chart"></canvas>
+ </div>
+ </section>
+</main>
+
+<footer>
+ <p>Explore the power of Kolmogorov-Arnold Networks</p>
+</footer>
\ No newline at end of file
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..13f4691
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://kan-experiment.scroll.pub
+metaTags
+editButton /edit.html
+title KAN Experiment: Configure & Visualize Kolmogorov-Arnold Networks
+style.css
+body.html
+script.js
\ No newline at end of file
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..360e0fe
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,25 @@
+{
+ "id": "500dfe67-66d8-44a4-9fd9-96b82d6222ce",
+ "object": "chat.completion",
+ "created": 1736286483,
+ "model": "deepseek-chat",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nkan-experiment.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://kan-experiment.scroll.pub\nmetaTags\neditButton /edit.html\ntitle KAN Experiment: Configure & Visualize Kolmogorov-Arnold Networks\nstyle.css\nbody.html\nscript.js\n---body.html---\n<header>\n <h1>KAN Experiment</h1>\n <p>Configure and visualize Kolmogorov-Arnold Networks with dynamic weights and attention mechanisms</p>\n</header>\n\n<main>\n <section id=\"config\">\n <h2>Network Configuration</h2>\n <div class=\"grid\">\n <div class=\"param\">\n <label for=\"inner-units\">Inner Units</label>\n <input type=\"number\" id=\"inner-units\" min=\"1\" max=\"20\" value=\"6\">\n </div>\n <div class=\"param\">\n <label for=\"outer-units\">Outer Units</label>\n <input type=\"number\" id=\"outer-units\" min=\"1\" max=\"20\" value=\"4\">\n </div>\n <div class=\"param\">\n <label for=\"grid-points\">Grid Points</label>\n <input type=\"number\" id=\"grid-points\" min=\"5\" max=\"50\" value=\"25\">\n </div>\n <div class=\"param\">\n <label for=\"spline-degree\">Spline Degree</label>\n <input type=\"number\" id=\"spline-degree\" min=\"1\" max=\"5\" value=\"3\">\n </div>\n <div class=\"param\">\n <label for=\"learning-rate\">Learning Rate</label>\n <input type=\"number\" id=\"learning-rate\" min=\"0.0001\" max=\"0.1\" step=\"0.0001\" value=\"0.001\">\n </div>\n <div class=\"param\">\n <label for=\"epochs\">Epochs</label>\n <input type=\"number\" id=\"epochs\" min=\"10\" max=\"500\" value=\"60\">\n </div>\n <div class=\"param\">\n <label for=\"attention-type\">Attention Type</label>\n <select id=\"attention-type\">\n <option value=\"softmax\">Softmax</option>\n <option value=\"softplus\">Softplus</option>\n <option value=\"rectify\">Rectify</option>\n </select>\n </div>\n </div>\n <button id=\"run-experiment\">Run Experiment</button>\n </section>\n\n <section id=\"results\">\n <h2>Experiment Results</h2>\n <div class=\"metrics\">\n <div class=\"metric\">\n <span class=\"value\" id=\"auc\">-</span>\n <span class=\"label\">AUC</span>\n </div>\n <div class=\"metric\">\n <span class=\"value\" id=\"ks\">-</span>\n <span class=\"label\">KS Statistic</span>\n </div>\n <div class=\"metric\">\n <span class=\"value\" id=\"logloss\">-</span>\n <span class=\"label\">Log Loss</span>\n </div>\n </div>\n <div class=\"charts\">\n <canvas id=\"loss-chart\"></canvas>\n </div>\n </section>\n</main>\n\n<footer>\n <p>Explore the power of Kolmogorov-Arnold Networks</p>\n</footer>\n---style.css---\n:root {\n --primary: #4f46e5;\n --primary-hover: #4338ca;\n --background: #f8fafc;\n --text: #0f172a;\n --border: #e2e8f0;\n --shadow: 0 1px 3px rgba(0,0,0,0.1);\n --radius: 0.5rem;\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, sans-serif;\n line-height: 1.5;\n color: var(--text);\n background: var(--background);\n padding: 2rem 1rem;\n max-width: 1200px;\n margin: 0 auto;\n}\n\nheader {\n text-align: center;\n margin-bottom: 3rem;\n}\n\nheader h1 {\n font-size: 2.5rem;\n color: var(--primary);\n margin-bottom: 0.5rem;\n}\n\nheader p {\n color: #64748b;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n}\n\n.param {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\nlabel {\n font-weight: 500;\n color: #334155;\n}\n\ninput, select {\n padding: 0.75rem;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: white;\n font-size: 1rem;\n transition: all 0.2s;\n}\n\ninput:focus, select:focus {\n outline: none;\n border-color: var(--primary);\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n#run-experiment {\n width: 100%;\n padding: 1rem;\n background: var(--primary);\n color: white;\n border: none;\n border-radius: var(--radius);\n font-size: 1rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n}\n\n#run-experiment:hover {\n background: var(--primary-hover);\n}\n\n#results {\n margin-top: 3rem;\n}\n\n.metrics {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n}\n\n.metric {\n background: white;\n padding: 1.5rem;\n border-radius: var(--radius);\n box-shadow: var(--shadow);\n text-align: center;\n}\n\n.metric .value {\n font-size: 2rem;\n font-weight: 600;\n color: var(--primary);\n display: block;\n margin-bottom: 0.5rem;\n}\n\n.metric .label {\n color: #64748b;\n font-size: 0.9rem;\n}\n\n.charts {\n background: white;\n padding: 1.5rem;\n border-radius: var(--radius);\n box-shadow: var(--shadow);\n}\n\ncanvas {\n width: 100% !important;\n height: 400px !important;\n}\n\nfooter {\n margin-top: 3rem;\n text-align: center;\n color: #64748b;\n padding: 1rem;\n}\n\n@media (max-width: 768px) {\n body {\n padding: 1rem;\n }\n \n header h1 {\n font-size: 2rem;\n }\n \n .grid {\n grid-template-columns: 1fr;\n }\n}\n---script.js---\n// Initialize Chart.js\nconst ctx = document.getElementById('loss-chart').getContext('2d');\nlet chart = new Chart(ctx, {\n type: 'line',\n data: {\n labels: [],\n datasets: [{\n label: 'Training Loss',\n data: [],\n borderColor: '#4f46e5',\n backgroundColor: 'rgba(79, 70, 229, 0.1)',\n borderWidth: 2,\n fill: true\n }]\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n scales: {\n x: {\n title: {\n display: true,\n text: 'Epochs'\n }\n },\n y: {\n title: {\n display: true,\n text: 'Loss'\n }\n }\n }\n }\n});\n\n// Update metrics display\nfunction updateMetrics(auc, ks, logloss) {\n document.getElementById('auc').textContent = auc.toFixed(4);\n document.getElementById('ks').textContent = ks.toFixed(4);\n document.getElementById('logloss').textContent = logloss.toFixed(4);\n}\n\n// Update chart with new data\nfunction updateChart(lossData) {\n chart.data.labels = lossData.map((_, i) => i + 1);\n chart.data.datasets[0].data = lossData;\n chart.update();\n}\n\n// Run experiment\ndocument.getElementById('run-experiment').addEventListener('click', async () => {\n const config = {\n innerUnits: parseInt(document.getElementById('inner-units').value),\n outerUnits: parseInt(document.getElementById('outer-units').value),\n gridPoints: parseInt(document.getElementById('grid-points').value),\n splineDegree: parseInt(document.getElementById('spline-degree').value),\n learningRate: parseFloat(document.getElementById('learning-rate').value),\n epochs: parseInt(document.getElementById('epochs').value),\n attentionType: document.getElementById('attention-type').value\n };\n\n // Simulate API call\n const response = await fetch('/api/experiment', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(config)\n });\n\n const data = await response.json();\n \n // Update UI with results\n updateMetrics(data.auc, data.ks, data.logloss);\n updateChart(data.lossHistory);\n});\n---end---"
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 4812,
+ "completion_tokens": 2119,
+ "total_tokens": 6931,
+ "prompt_cache_hit_tokens": 4800,
+ "prompt_cache_miss_tokens": 12
+ },
+ "system_fingerprint": "fp_3a5770e1b4"
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..41d887b
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# kan-experiment.scroll.pub
+Website generated by DeepSeek from prompt: Develop a website that allows users to configure and experiment with parameters of the Attention-KAN approach detailed in this article: Kolmogorov-Arnold Networks: Exploring Dynamic Weights and Attention Mechanisms. Frontend Requirements: 1. Create an intuitive user interface for configuring the parameters of Kolmogorov-Arnold Networks (KAN) and its dynamic weight integration. • Include all input parameters discussed in the article, such as the number of inner/outer units, grid points, spline degrees, learning rate, and other relevant hyperparameters. • Allow users to adjust these parameters via sliders, dropdowns, or input fields. 2. Provide real-time visualizations: • Display metrics such as AUC, KS Statistic, and Log Loss after the experiments. • Generate a chart of the loss function over training epochs (X-axis = epochs, Y-axis = loss). • Optionally, include visualizations of network behavior or intermediate results if described in the article. Backend Requirements: 1. Implement the following example experiments provided in the article: • Example 1: Training and evaluation of a Dynamic Weight KAN. • Example 2: Training and evaluation of an Improved Standard KAN using spline-based utilities. 2. The backend should: • Use the provided PyTorch code to compute metrics (AUC, KS Statistic, Log Loss) based on user-configured parameters. • Log and output the training loss at each epoch for visualization in the frontend. 3. Ensure the backend is capable of processing user-configured input parameters and reflecting them in the experiment results. (Code provided below should be integrated into the backend implementation.) Below are the code snippet for Backend Implementation of 2 examples ### Code for Example 1: of Dynamic KAN Experiment ==================================================== import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import roc_auc_score, log_loss, roc_curve from sklearn.model_selection import train_test_split # Dynamic Weight Generator class DynamicWeightGenerator(nn.Module): def __init__(self, input_dim, output_dim): super(DynamicWeightGenerator, self).__init__() self.fc1 = nn.Linear(input_dim, 128) self.fc2 = nn.Linear(128, 64) self.fc_weight = nn.Linear(64, output_dim) self.fc_bias = nn.Linear(64, output_dim) self.softplus = nn.Softplus() def forward(self, x): h = torch.relu(self.fc1(x)) h = torch.relu(self.fc2(h)) weight = self.softplus(self.fc_weight(h)) bias = self.fc_bias(h) return weight, bias # Kolmogorov-Arnold Network (KAN) class KAN(nn.Module): def __init__(self, input_dim, num_inner_units, num_outer_units, dynamic=True): super(KAN, self).__init__() self.dynamic = dynamic self.num_inner_units = num_inner_units self.num_outer_units = num_outer_units if dynamic: self.inner_weight_generators = nn.ModuleList([ DynamicWeightGenerator(input_dim, input_dim) for _ in range(num_inner_units) ]) self.outer_weight_generators = nn.ModuleList([ DynamicWeightGenerator(input_dim, 1) for _ in range(num_outer_units) ]) else: self.inner_weights = nn.ParameterList([ nn.Parameter(torch.randn(input_dim, input_dim)) for _ in range(num_inner_units) ]) self.inner_biases = nn.ParameterList([ nn.Parameter(torch.randn(input_dim)) for _ in range(num_inner_units) ]) self.outer_weights = nn.ParameterList([ nn.Parameter(torch.randn(num_inner_units)) for _ in range(num_outer_units) ]) self.outer_biases = nn.ParameterList([ nn.Parameter(torch.randn(1)) for _ in range(num_outer_units) ]) def forward(self, x): inner_outputs = [] if self.dynamic: for generator in self.inner_weight_generators: weight, bias = generator(x) inner_output = torch.sum(weight * x + bias, dim=-1, keepdim=True) inner_outputs.append(inner_output) else: for weight, bias in zip(self.inner_weights, self.inner_biases): inner_output = torch.sum(torch.matmul(x, weight) + bias, dim=-1, keepdim=True) inner_outputs.append(inner_output) aggregated_inner_output = torch.cat(inner_outputs, dim=-1) outer_outputs = [] if self.dynamic: for generator in self.outer_weight_generators: weight, bias = generator(x) outer_output = torch.sum(weight * aggregated_inner_output + bias, dim=-1, keepdim=True) outer_outputs.append(outer_output) else: for weight, bias in zip(self.outer_weights, self.outer_biases): outer_output = torch.sum(aggregated_inner_output * weight + bias, dim=-1, keepdim=True) outer_outputs.append(outer_output) final_output = torch.sum(torch.cat(outer_outputs, dim=-1), dim=-1, keepdim=True) return final_output # Data generation torch.manual_seed(42) num_samples = 1200 input_dim = 5 # Generate complex non-linear data X = torch.rand((num_samples, input_dim)) * 10 - 5 noise = torch.randn(num_samples) * 0.5 Y = ((torch.sin(X[:, 0]) + torch.cos(X[:, 1]) + 0.3 * X[:, 2] - 0.2 * X[:, 3] ** 2 + noise) > 0).float().unsqueeze(1) # Split data X_train, X_val, Y_train, Y_val = train_test_split(X.numpy(), Y.numpy(), test_size=0.2, random_state=42) # Train Dynamic Weight KAN device = 'cuda' if torch.cuda.is_available() else 'cpu' dynamic_model = KAN(input_dim, num_inner_units=6, num_outer_units=4, dynamic=True).to(device) criterion = nn.BCELoss() optimizer = optim.Adam(dynamic_model.parameters(), lr=0.001) print("\nTraining Dynamic KAN") epochs = 60 for epoch in range(epochs): dynamic_model.train() optimizer.zero_grad() outputs = torch.sigmoid(dynamic_model(torch.tensor(X_train, dtype=torch.float32).to(device))) loss = criterion(outputs, torch.tensor(Y_train, dtype=torch.float32).to(device)) loss.backward() optimizer.step() if (epoch + 1) % 10 == 0: print(f"Dynamic KAN - Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}") # Evaluate Dynamic KAN dynamic_model.eval() with torch.no_grad(): dynamic_predictions = torch.sigmoid(dynamic_model(torch.tensor(X_val, dtype=torch.float32).to(device))).cpu().numpy() dynamic_auc = roc_auc_score(Y_val, dynamic_predictions) dynamic_fpr, dynamic_tpr, _ = roc_curve(Y_val, dynamic_predictions) dynamic_ks = max(dynamic_tpr - dynamic_fpr) dynamic_logloss = log_loss(Y_val, dynamic_predictions) print("\nDynamic KAN Metrics:") print(f"AUC: {dynamic_auc:.4f}") print(f"KS Statistic: {dynamic_ks:.4f}") print(f"Log Loss: {dynamic_logloss:.4f}") # Train Improved Standard KAN # Spline Utilities def B_batch(x, grid, k=3): x = x.unsqueeze(2) grid = grid.unsqueeze(0) if k == 0: value = (x >= grid[:, :, :-1]) * (x < grid[:, :, 1:]) else: B_km1 = B_batch(x[:, :, 0], grid[0], k=k - 1) value = ( (x - grid[:, :, :-(k + 1)]) / (grid[:, :, k:-1] - grid[:, :, :-(k + 1)]) * B_km1[:, :, :-1] + (grid[:, :, k + 1:] - x) / (grid[:, :, k + 1:] - grid[:, :, 1:-k]) * B_km1[:, :, 1:] ) return torch.nan_to_num(value) def coef2curve(x_eval, grid, coef, k): b_splines = B_batch(x_eval, grid, k) return torch.einsum("ijk,jlk->ijl", b_splines, coef.to(b_splines.device)) # Improved Standard KAN class StandardKAN(nn.Module): def __init__(self, input_dim, num_inner_units, num_outer_units, grid_points=20, spline_degree=3): super(StandardKAN, self).__init__() self.input_dim = input_dim self.num_inner_units = num_inner_units self.num_outer_units = num_outer_units self.spline_degree = spline_degree # Adaptive grids self.inner_grid = nn.Parameter(torch.linspace(-10, 10, steps=grid_points).repeat(input_dim, 1), requires_grad=False) self.outer_grid = nn.Parameter(torch.linspace(-10, 10, steps=grid_points).repeat(num_inner_units, 1), requires_grad=False) # Initialize spline coefficients self.inner_coef = nn.Parameter(torch.randn(input_dim, num_inner_units, grid_points - spline_degree - 1) * 0.01) self.outer_coef = nn.Parameter(torch.randn(num_inner_units, num_outer_units, grid_points - spline_degree - 1) * 0.01) def forward(self, x): # Inner layer: Map inputs to hidden features inner_outputs = coef2curve(x, self.inner_grid, self.inner_coef, self.spline_degree) inner_outputs = inner_outputs.sum(dim=1) # Outer layer: Map hidden features to outputs outer_outputs = coef2curve(inner_outputs, self.outer_grid, self.outer_coef, self.spline_degree) final_output = outer_outputs.sum(dim=1).mean(dim=1, keepdim=True) return final_output ###################Standard KAN######################## # Data generation torch.manual_seed(42) num_samples = 1200 input_dim = 5 # Generate complex non-linear data X = torch.rand((num_samples, input_dim)) * 10 - 5 noise = torch.randn(num_samples) * 0.5 Y = ((torch.sin(X[:, 0]) + torch.cos(X[:, 1]) + 0.3 * X[:, 2] - 0.2 * X[:, 3] ** 2 + noise) > 0).float().unsqueeze(1) # Split data X_train, X_val, Y_train, Y_val = train_test_split(X.numpy(), Y.numpy(), test_size=0.2, random_state=42) # Train Improved Standard KAN device = 'cuda' if torch.cuda.is_available() else 'cpu' std_model = StandardKAN(input_dim, num_inner_units=8, num_outer_units=4, grid_points=25, spline_degree=3).to(device) criterion = nn.BCELoss() optimizer = optim.Adam(std_model.parameters(), lr=0.001) scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.5) epochs = 60 for epoch in range(epochs): std_model.train() optimizer.zero_grad() outputs = torch.sigmoid(std_model(torch.tensor(X_train, dtype=torch.float32).to(device))) loss = criterion(outputs, torch.tensor(Y_train, dtype=torch.float32).to(device)) loss.backward() optimizer.step() scheduler.step() if (epoch + 1) % 10 == 0: print(f"Improved Standard KAN - Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}") # Evaluate Improved Standard KAN std_model.eval() with torch.no_grad(): std_predictions = torch.sigmoid(std_model(torch.tensor(X_val, dtype=torch.float32).to(device))).cpu().numpy() std_auc = roc_auc_score(Y_val, std_predictions) std_fpr, std_tpr, _ = roc_curve(Y_val, std_predictions) std_ks = max(std_tpr - std_fpr) std_logloss = log_loss(Y_val, std_predictions) print("\nImproved Standard KAN Metrics:") print(f"AUC: {std_auc:.4f}") print(f"KS Statistic: {std_ks:.4f}") print(f"Log Loss: {std_logloss:.4f}") ==================================================== ### Code for Example 2: Attention-Based KAN with three normalization functions: Softmax, Softplus, and Rectify ==================================================== import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import roc_auc_score, log_loss, roc_curve from sklearn.model_selection import train_test_split def custom_softplus(scores): return torch.log(1 + torch.exp(scores)) / torch.sum(torch.log(1 + torch.exp(scores)), dim=-1, keepdim=True) def custom_softmax(scores): exps = torch.exp(scores - torch.max(scores, dim=-1, keepdim=True)[0]) return exps / exps.sum(dim=-1, keepdim=True) def custom_rectify(scores): relu_scores = torch.relu(scores) return relu_scores / torch.sum(relu_scores, dim=-1, keepdim=True) # Attention Mechanism for KAN with multiple functions class AttentionWeightGenerator(nn.Module): def __init__(self, input_dim, norm_function): super(AttentionWeightGenerator, self).__init__() self.query = nn.Linear(input_dim, input_dim, bias=False) self.key = nn.Linear(input_dim, input_dim, bias=False) self.value = nn.Linear(input_dim, input_dim, bias=False) self.norm_function = norm_function def forward(self, x): Q = self.query(x) # Query K = self.key(x) # Key V = self.value(x) # Value scores = torch.matmul(Q, K.transpose(-1, -2)) / (x.size(-1) ** 0.5) # Scaled dot-product attention_weights = self.norm_function(scores) # Custom normalization output = torch.matmul(attention_weights, V) # Weighted sum of values return output # Kolmogorov-Arnold Network (KAN) with Attention Mechanism class AttentionKAN(nn.Module): def __init__(self, input_dim, num_inner_units, num_outer_units, norm_function): super(AttentionKAN, self).__init__() self.num_inner_units = num_inner_units self.num_outer_units = num_outer_units self.inner_attention_layers = nn.ModuleList([ AttentionWeightGenerator(input_dim, norm_function) for _ in range(num_inner_units) ]) self.outer_attention_layers = nn.ModuleList([ AttentionWeightGenerator(num_inner_units, norm_function) for _ in range(num_outer_units) ]) self.output_layer = nn.Linear(num_outer_units, 1) # Final output layer def forward(self, x): inner_outputs = [] for attention_layer in self.inner_attention_layers: inner_output = attention_layer(x).mean(dim=-1, keepdim=True) # Aggregate inner output inner_outputs.append(inner_output) aggregated_inner_output = torch.cat(inner_outputs, dim=-1) # Combine inner outputs outer_outputs = [] for attention_layer in self.outer_attention_layers: outer_output = attention_layer(aggregated_inner_output).mean(dim=-1, keepdim=True) outer_outputs.append(outer_output) aggregated_outer_output = torch.cat(outer_outputs, dim=-1) final_output = self.output_layer(aggregated_outer_output) # Final prediction return final_output # Data generation torch.manual_seed(42) num_samples = 1200 input_dim = 5 # Generate complex non-linear data X = torch.rand((num_samples, input_dim)) * 10 - 5 noise = torch.randn(num_samples) * 0.5 Y = ((torch.sin(X[:, 0]) + torch.cos(X[:, 1]) + 0.3 * X[:, 2] - 0.2 * X[:, 3] ** 2 + noise) > 0).float().unsqueeze(1) # Split data X_train, X_val, Y_train, Y_val = train_test_split(X.numpy(), Y.numpy(), test_size=0.2, random_state=42) # Train Attention KAN with different functions norm_functions = { "Softmax": custom_softmax, "Softplus": custom_softplus, "Rectify": custom_rectify, } results = {} for name, norm_function in norm_functions.items(): print(f"\nTraining Attention KAN with {name}") device = 'cuda' if torch.cuda.is_available() else 'cpu' attention_model = AttentionKAN(input_dim, num_inner_units=6, num_outer_units=4, norm_function=norm_function).to(device) criterion = nn.BCELoss() optimizer = optim.Adam(attention_model.parameters(), lr=0.001) epochs = 100 for epoch in range(epochs): attention_model.train() optimizer.zero_grad() outputs = torch.sigmoid(attention_model(torch.tensor(X_train, dtype=torch.float32).to(device))) loss = criterion(outputs, torch.tensor(Y_train, dtype=torch.float32).to(device)) loss.backward() optimizer.step() if (epoch + 1) % 10 == 0: print(f"{name} - Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}") # Evaluate Attention KAN attention_model.eval() with torch.no_grad(): attention_predictions = torch.sigmoid(attention_model(torch.tensor(X_val, dtype=torch.float32).to(device))).cpu().numpy() attention_auc = roc_auc_score(Y_val, attention_predictions) attention_fpr, attention_tpr, _ = roc_curve(Y_val, attention_predictions) attention_ks = max(attention_tpr - attention_fpr) attention_logloss = log_loss(Y_val, attention_predictions) results[name] = { "AUC": attention_auc, "KS Statistic": attention_ks, "Log Loss": attention_logloss } print(f"\n{name} Metrics:") print(f"AUC: {attention_auc:.4f}") print(f"KS Statistic: {attention_ks:.4f}") print(f"Log Loss: {attention_logloss:.4f}") # Print final results print("\nComparison of Normalization Functions:") for name, metrics in results.items(): print(f"{name}: AUC={metrics['AUC']:.4f}, KS={metrics['KS Statistic']:.4f}, Log Loss={metrics['Log Loss']:.4f}") ====================================================
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..6a1dbb0
--- /dev/null
+++ b/script.js
@@ -0,0 +1,76 @@
+// Initialize Chart.js
+const ctx = document.getElementById('loss-chart').getContext('2d');
+let chart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: [],
+ datasets: [{
+ label: 'Training Loss',
+ data: [],
+ borderColor: '#4f46e5',
+ backgroundColor: 'rgba(79, 70, 229, 0.1)',
+ borderWidth: 2,
+ fill: true
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: 'Epochs'
+ }
+ },
+ y: {
+ title: {
+ display: true,
+ text: 'Loss'
+ }
+ }
+ }
+ }
+});
+
+// Update metrics display
+function updateMetrics(auc, ks, logloss) {
+ document.getElementById('auc').textContent = auc.toFixed(4);
+ document.getElementById('ks').textContent = ks.toFixed(4);
+ document.getElementById('logloss').textContent = logloss.toFixed(4);
+}
+
+// Update chart with new data
+function updateChart(lossData) {
+ chart.data.labels = lossData.map((_, i) => i + 1);
+ chart.data.datasets[0].data = lossData;
+ chart.update();
+}
+
+// Run experiment
+document.getElementById('run-experiment').addEventListener('click', async () => {
+ const config = {
+ innerUnits: parseInt(document.getElementById('inner-units').value),
+ outerUnits: parseInt(document.getElementById('outer-units').value),
+ gridPoints: parseInt(document.getElementById('grid-points').value),
+ splineDegree: parseInt(document.getElementById('spline-degree').value),
+ learningRate: parseFloat(document.getElementById('learning-rate').value),
+ epochs: parseInt(document.getElementById('epochs').value),
+ attentionType: document.getElementById('attention-type').value
+ };
+
+ // Simulate API call
+ const response = await fetch('/api/experiment', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(config)
+ });
+
+ const data = await response.json();
+
+ // Update UI with results
+ updateMetrics(data.auc, data.ks, data.logloss);
+ updateChart(data.lossHistory);
+});
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..42fdf76
--- /dev/null
+++ b/style.css
@@ -0,0 +1,157 @@
+:root {
+ --primary: #4f46e5;
+ --primary-hover: #4338ca;
+ --background: #f8fafc;
+ --text: #0f172a;
+ --border: #e2e8f0;
+ --shadow: 0 1px 3px rgba(0,0,0,0.1);
+ --radius: 0.5rem;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+ line-height: 1.5;
+ color: var(--text);
+ background: var(--background);
+ padding: 2rem 1rem;
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 3rem;
+}
+
+header h1 {
+ font-size: 2.5rem;
+ color: var(--primary);
+ margin-bottom: 0.5rem;
+}
+
+header p {
+ color: #64748b;
+ max-width: 600px;
+ margin: 0 auto;
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 1.5rem;
+ margin-bottom: 2rem;
+}
+
+.param {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+label {
+ font-weight: 500;
+ color: #334155;
+}
+
+input, select {
+ padding: 0.75rem;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: white;
+ font-size: 1rem;
+ transition: all 0.2s;
+}
+
+input:focus, select:focus {
+ outline: none;
+ border-color: var(--primary);
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
+}
+
+#run-experiment {
+ width: 100%;
+ padding: 1rem;
+ background: var(--primary);
+ color: white;
+ border: none;
+ border-radius: var(--radius);
+ font-size: 1rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: background 0.2s;
+}
+
+#run-experiment:hover {
+ background: var(--primary-hover);
+}
+
+#results {
+ margin-top: 3rem;
+}
+
+.metrics {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: 1.5rem;
+ margin-bottom: 2rem;
+}
+
+.metric {
+ background: white;
+ padding: 1.5rem;
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ text-align: center;
+}
+
+.metric .value {
+ font-size: 2rem;
+ font-weight: 600;
+ color: var(--primary);
+ display: block;
+ margin-bottom: 0.5rem;
+}
+
+.metric .label {
+ color: #64748b;
+ font-size: 0.9rem;
+}
+
+.charts {
+ background: white;
+ padding: 1.5rem;
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+}
+
+canvas {
+ width: 100% !important;
+ height: 400px !important;
+}
+
+footer {
+ margin-top: 3rem;
+ text-align: center;
+ color: #64748b;
+ padding: 1rem;
+}
+
+@media (max-width: 768px) {
+ body {
+ padding: 1rem;
+ }
+
+ header h1 {
+ font-size: 2rem;
+ }
+
+ .grid {
+ grid-template-columns: 1fr;
+ }
+}
\ No newline at end of file