English
AGofficial commited on
Commit
bcc7e5b
·
verified ·
1 Parent(s): 5c5464d

Upload NeuralCode9.py

Browse files
Files changed (1) hide show
  1. NeuralCode9.py +469 -0
NeuralCode9.py ADDED
@@ -0,0 +1,469 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import random
3
+ import time
4
+ import os # Added for path joining
5
+
6
+ # CUSTOMIZATION
7
+
8
+ CONTEXT_WINDOW = 4
9
+ EPOCHS = 100
10
+ LR = 0.01
11
+
12
+ def relu(x):
13
+ return max(0.0, x)
14
+
15
+ def stable_softmax(x_list):
16
+ if not x_list:
17
+ return []
18
+ m = max(x_list)
19
+ exps = [math.exp(i - m) for i in x_list]
20
+ s = sum(exps)
21
+ if s == 0:
22
+ return [1.0 / len(x_list)] * len(x_list)
23
+ return [e / s for e in exps]
24
+
25
+ class NeuralNetwork:
26
+ def __init__(self, layer_sizes=None, activation='relu', output_activation='softmax',
27
+ init_range=0.1, grad_clip=1.0, seed=None, context_window=5):
28
+ if seed is not None:
29
+ random.seed(seed)
30
+ self.layer_sizes = layer_sizes[:] if layer_sizes is not None else None
31
+ self.activation = relu if activation == 'relu' else (lambda x: x)
32
+ self.output_activation = stable_softmax if output_activation == 'softmax' else (lambda x: x)
33
+ self.init_range = float(init_range)
34
+ self.grad_clip = grad_clip
35
+ self.context_window = context_window
36
+ self.weights = []
37
+ self.biases = []
38
+ self.vocab = []
39
+ self.word_to_idx = {}
40
+ self.idx_to_word = {}
41
+
42
+ def prepare_data_with_context(self, text):
43
+ words = [w.strip() for w in text.replace('\n', ' ').split(' ') if w.strip()]
44
+ self.vocab = sorted(list(set(words)))
45
+ self.word_to_idx = {w: i for i, w in enumerate(self.vocab)}
46
+ self.idx_to_word = {i: w for w, i in self.word_to_idx.items()}
47
+
48
+ vocab_size = len(self.vocab)
49
+ X = []
50
+ Y = []
51
+
52
+ for i in range(len(words) - self.context_window):
53
+ context_words = words[i : i + self.context_window]
54
+ target_word = words[i + self.context_window]
55
+
56
+ x = [0.0] * vocab_size
57
+ for word in context_words:
58
+ if word in self.word_to_idx:
59
+ x[self.word_to_idx[word]] = 1.0
60
+
61
+ y = [0.0] * vocab_size
62
+ if target_word in self.word_to_idx:
63
+ y[self.word_to_idx[target_word]] = 1.0
64
+
65
+ X.append(x)
66
+ Y.append(y)
67
+
68
+ return X, Y
69
+
70
+ def initialize_weights(self):
71
+ if self.layer_sizes is None:
72
+ raise ValueError("layer_sizes must be set before initializing weights.")
73
+ if self.weights:
74
+ return
75
+ for i in range(len(self.layer_sizes) - 1):
76
+ in_dim = self.layer_sizes[i]
77
+ out_dim = self.layer_sizes[i + 1]
78
+ W = [[random.uniform(-self.init_range, self.init_range) for _ in range(out_dim)] for _ in range(in_dim)]
79
+ b = [0.0 for _ in range(out_dim)]
80
+ self.weights.append(W)
81
+ self.biases.append(b)
82
+
83
+ def forward(self, x):
84
+ a = x[:]
85
+ for i in range(len(self.weights) - 1):
86
+ next_a = []
87
+ W = self.weights[i]
88
+ b = self.biases[i]
89
+ out_dim = len(W[0])
90
+ for j in range(out_dim):
91
+ s = sum(a[k] * W[k][j] for k in range(len(a))) + b[j]
92
+ next_a.append(self.activation(s))
93
+ a = next_a
94
+
95
+ W = self.weights[-1]
96
+ b = self.biases[-1]
97
+ out = []
98
+ out_dim = len(W[0])
99
+ for j in range(out_dim):
100
+ s = sum(a[k] * W[k][j] for k in range(len(a))) + b[j]
101
+ out.append(s)
102
+ return self.output_activation(out)
103
+
104
+ def train(self, training_data, lr=0.01, epochs=500, verbose_every=50):
105
+ X, Y = self.prepare_data_with_context(training_data)
106
+ if not X:
107
+ raise ValueError("Not enough tokens in training data to create context windows.")
108
+
109
+ vocab_size = len(self.vocab)
110
+ if self.layer_sizes is None:
111
+ self.layer_sizes = [vocab_size, 64, vocab_size]
112
+ else:
113
+ self.layer_sizes[0] = vocab_size
114
+ self.layer_sizes[-1] = vocab_size
115
+
116
+ self.initialize_weights()
117
+
118
+ for epoch in range(epochs):
119
+ total_loss = 0.0
120
+ indices = list(range(len(X)))
121
+ random.shuffle(indices)
122
+
123
+ for idx in indices:
124
+ x = X[idx]
125
+ y = Y[idx]
126
+
127
+ activations = [x[:]]
128
+ pre_acts = []
129
+ a = x[:]
130
+
131
+ for i in range(len(self.weights) - 1):
132
+ W, b = self.weights[i], self.biases[i]
133
+ z = []
134
+ out_dim = len(W[0])
135
+ for j in range(out_dim):
136
+ s = sum(a[k] * W[k][j] for k in range(len(a))) + b[j]
137
+ z.append(s)
138
+ pre_acts.append(z)
139
+ a = [self.activation(val) for val in z]
140
+ activations.append(a)
141
+
142
+ W, b = self.weights[-1], self.biases[-1]
143
+ z_final = []
144
+ out_dim = len(W[0])
145
+ for j in range(out_dim):
146
+ s = sum(a[k] * W[k][j] for k in range(len(a))) + b[j]
147
+ z_final.append(s)
148
+ pre_acts.append(z_final)
149
+ out = self.output_activation(z_final)
150
+
151
+ delta = [out[j] - y[j] for j in range(len(y))]
152
+
153
+ for i in reversed(range(len(self.weights))):
154
+ in_act = activations[i]
155
+ in_dim = len(in_act)
156
+ out_dim = len(delta)
157
+
158
+ db = delta[:]
159
+ if self.grad_clip is not None:
160
+ db = [max(-self.grad_clip, min(self.grad_clip, g)) for g in db]
161
+ for j in range(len(self.biases[i])):
162
+ self.biases[i][j] -= lr * db[j]
163
+
164
+ for k in range(in_dim):
165
+ for j in range(out_dim):
166
+ grad_w = in_act[k] * delta[j]
167
+ if self.grad_clip is not None:
168
+ grad_w = max(-self.grad_clip, min(self.grad_clip, grad_w))
169
+ self.weights[i][k][j] -= lr * grad_w
170
+
171
+ if i != 0:
172
+ prev_delta = [0.0] * in_dim
173
+ for p in range(in_dim):
174
+ s = sum(self.weights[i][p][j] * delta[j] for j in range(out_dim))
175
+ if pre_acts[i-1][p] > 0:
176
+ prev_delta[p] = s
177
+ delta = prev_delta
178
+
179
+ if epoch % verbose_every == 0 or epoch == epochs - 1:
180
+ loss = 0.0
181
+ for x_val, y_val in zip(X, Y):
182
+ p = self.forward(x_val)
183
+ for j in range(len(y_val)):
184
+ if y_val[j] > 0:
185
+ loss -= math.log(p[j] + 1e-12)
186
+ print(f"Epoch {epoch}, Loss: {loss / len(X):.6f}")
187
+
188
+ def export_to_python(self, filename):
189
+ lines = []
190
+ lines.append("import math\n")
191
+ lines.append("import time\n\n")
192
+ lines.append("def relu(x):\n return max(0.0, x)\n\n")
193
+ lines.append("def softmax(x_list):\n")
194
+ lines.append(" if not x_list:\n")
195
+ lines.append(" return []\n")
196
+ lines.append(" m = max(x_list)\n")
197
+ lines.append(" exps = [math.exp(i - m) for i in x_list]\n")
198
+ lines.append(" s = sum(exps)\n")
199
+ lines.append(" if s == 0:\n")
200
+ lines.append(" return [1.0 / len(x_list)] * len(x_list)\n")
201
+ lines.append(" return [e / s for e in exps]\n\n")
202
+
203
+ neuron_id = 0
204
+ for layer_idx, (W, b) in enumerate(zip(self.weights, self.biases)):
205
+ in_dim, out_dim = len(W), len(W[0])
206
+ for j in range(out_dim):
207
+ terms = " + ".join([f"{W[i][j]:.8f}*inputs[{i}]" for i in range(in_dim)]) or "0.0"
208
+ b_term = f"{b[j]:.8f}"
209
+ if layer_idx != len(self.weights) - 1:
210
+ lines.append(f"def neuron_{neuron_id}(inputs):\n return relu({terms} + {b_term})\n\n")
211
+ else:
212
+ lines.append(f"def neuron_{neuron_id}(inputs):\n return {terms} + {b_term}\n\n")
213
+ neuron_id += 1
214
+
215
+ neuron_counter = 0
216
+ for layer_idx, (W, b) in enumerate(zip(self.weights, self.biases)):
217
+ out_dim = len(W[0])
218
+ lines.append(f"def layer_{layer_idx}(inputs):\n")
219
+ inner = ", ".join([f"neuron_{neuron_counter + j}(inputs)" for j in range(out_dim)])
220
+ lines.append(f" return [{inner}]\n\n")
221
+ neuron_counter += out_dim
222
+
223
+ lines.append("def predict(inputs):\n")
224
+ lines.append(" a = inputs\n")
225
+ for i in range(len(self.weights)):
226
+ lines.append(f" a = layer_{i}(a)\n")
227
+ lines.append(" return softmax(a)\n\n")
228
+
229
+ lines.append(f"vocab = {self.vocab}\n")
230
+ lines.append(f"word_to_idx = {{w: i for i, w in enumerate(vocab)}}\n")
231
+ lines.append(f"context_window = {self.context_window}\n\n")
232
+
233
+ lines.append("if __name__ == '__main__':\n")
234
+ lines.append(" print('Interactive multi-word text completion.')\n")
235
+ lines.append(" print(f'Model context window: {context_window} words. Type text or empty to exit.')\n")
236
+ lines.append(" while True:\n")
237
+ lines.append(" inp = input('> ').strip()\n")
238
+ lines.append(" if not inp:\n")
239
+ lines.append(" break\n")
240
+ lines.append(" words = [w.strip() for w in inp.split(' ') if w.strip()]\n")
241
+ lines.append(" generated_words = words[:]\n")
242
+ lines.append(" print('Input:', ' '.join(generated_words), end='', flush=True)\n")
243
+ lines.append(" for _ in range(20):\n")
244
+ lines.append(" context = generated_words[-context_window:]\n")
245
+ lines.append(" x = [0.0] * len(vocab)\n")
246
+ lines.append(" for word in context:\n")
247
+ lines.append(" if word in word_to_idx:\n")
248
+ lines.append(" x[word_to_idx[word]] = 1.0\n")
249
+ lines.append(" out = predict(x)\n")
250
+ lines.append(" idx = out.index(max(out))\n")
251
+ lines.append(" next_word = vocab[idx]\n")
252
+ lines.append(" if next_word == '<|endoftext|>': break\n")
253
+ lines.append(" generated_words.append(next_word)\n")
254
+ lines.append(" print(' ' + next_word, end='', flush=True)\n")
255
+ lines.append(" time.sleep(0.1)\n")
256
+ lines.append(" print('\\n')\n")
257
+
258
+ with open(filename, "w") as f:
259
+ f.writelines(lines)
260
+ print(f"Exported network to {filename}")
261
+
262
+ def export_to_js(self, base_filename):
263
+ js_filename = base_filename + ".js"
264
+ html_filename = base_filename + ".html"
265
+
266
+ # --- Create JavaScript File ---
267
+ js_lines = []
268
+ js_lines.append("'use strict';\n\n")
269
+ js_lines.append("function relu(x) {\n return Math.max(0.0, x);\n}\n\n")
270
+ js_lines.append("function softmax(x_list) {\n")
271
+ js_lines.append(" if (!x_list || x_list.length === 0) return [];\n")
272
+ js_lines.append(" const m = Math.max(...x_list);\n")
273
+ js_lines.append(" const exps = x_list.map(x => Math.exp(x - m));\n")
274
+ js_lines.append(" const s = exps.reduce((a, b) => a + b, 0);\n")
275
+ js_lines.append(" if (s === 0) return Array(x_list.length).fill(1.0 / x_list.length);\n")
276
+ js_lines.append(" return exps.map(e => e / s);\n}\n\n")
277
+
278
+ neuron_id = 0
279
+ for layer_idx, (W, b) in enumerate(zip(self.weights, self.biases)):
280
+ in_dim, out_dim = len(W), len(W[0])
281
+ for j in range(out_dim):
282
+ terms = " + ".join([f"{W[i][j]:.8f} * inputs[{i}]" for i in range(in_dim)]) or "0.0"
283
+ b_term = f"{b[j]:.8f}"
284
+ js_lines.append(f"function neuron_{neuron_id}(inputs) {{\n")
285
+ if layer_idx != len(self.weights) - 1:
286
+ js_lines.append(f" return relu({terms} + {b_term});\n}}\n\n")
287
+ else:
288
+ js_lines.append(f" return {terms} + {b_term};\n}}\n\n")
289
+ neuron_id += 1
290
+
291
+ neuron_counter = 0
292
+ for layer_idx, (W, b) in enumerate(zip(self.weights, self.biases)):
293
+ out_dim = len(W[0])
294
+ js_lines.append(f"function layer_{layer_idx}(inputs) {{\n")
295
+ inner = ", ".join([f"neuron_{neuron_counter + j}(inputs)" for j in range(out_dim)])
296
+ js_lines.append(f" return [{inner}];\n}}\n\n")
297
+ neuron_counter += out_dim
298
+
299
+ js_lines.append("function predict(inputs) {\n")
300
+ js_lines.append(" let a = inputs;\n")
301
+ for i in range(len(self.weights)):
302
+ js_lines.append(f" a = layer_{i}(a);\n")
303
+ js_lines.append(" return softmax(a);\n}\n\n")
304
+
305
+ js_lines.append(f"const vocab = {self.vocab};\n")
306
+ js_lines.append("const word_to_idx = {};\n")
307
+ js_lines.append("vocab.forEach((w, i) => { word_to_idx[w] = i; });\n")
308
+ js_lines.append(f"const context_window = {self.context_window};\n\n")
309
+
310
+ # Add interactive browser logic
311
+ js_lines.append("""
312
+ function completeText(inputText) {
313
+ const words = inputText.trim().split(/\\s+/).filter(w => w.length > 0);
314
+ let generatedWords = [...words];
315
+
316
+ for (let i = 0; i < 20; i++) {
317
+ const context = generatedWords.slice(-context_window);
318
+ const x = Array(vocab.length).fill(0.0);
319
+
320
+ context.forEach(word => {
321
+ if (word in word_to_idx) {
322
+ x[word_to_idx[word]] = 1.0;
323
+ }
324
+ });
325
+
326
+ const out = predict(x);
327
+ const maxProb = Math.max(...out);
328
+ const idx = out.indexOf(maxProb);
329
+ const nextWord = vocab[idx];
330
+
331
+ if (nextWord === '<|endoftext|>') {
332
+ break;
333
+ }
334
+ generatedWords.push(nextWord);
335
+ }
336
+ return generatedWords.join(' ');
337
+ }
338
+
339
+ document.addEventListener('DOMContentLoaded', () => {
340
+ const generateButton = document.getElementById('generateButton');
341
+ const userInput = document.getElementById('userInput');
342
+ const outputText = document.getElementById('outputText');
343
+
344
+ generateButton.addEventListener('click', () => {
345
+ const text = userInput.value;
346
+ if (text) {
347
+ const result = completeText(text);
348
+ outputText.textContent = result;
349
+ }
350
+ });
351
+ });
352
+ """)
353
+ with open(js_filename, "w") as f:
354
+ f.writelines(js_lines)
355
+
356
+ # --- Create HTML File ---
357
+ html_lines = [
358
+ '<!DOCTYPE html>\n',
359
+ '<html lang="en">\n',
360
+ '<head>\n',
361
+ ' <meta charset="UTF-8">\n',
362
+ ' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n',
363
+ ' <title>Neural Network Text Completion</title>\n',
364
+ f' <script src="{os.path.basename(js_filename)}"></script>\n',
365
+ ' <style>\n',
366
+ ' body { font-family: sans-serif; margin: 2em; background: #f0f0f0; }\n',
367
+ ' .container { max-width: 600px; margin: auto; background: white; padding: 2em; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }\n',
368
+ ' h1 { text-align: center; color: #333; }\n',
369
+ ' textarea { width: 95%; height: 80px; padding: 10px; margin-bottom: 1em; border-radius: 4px; border: 1px solid #ccc; font-size: 1em; }\n',
370
+ ' button { display: block; width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; font-size: 1.1em; cursor: pointer; }\n',
371
+ ' button:hover { background: #0056b3; }\n',
372
+ ' #outputText { margin-top: 1.5em; padding: 1em; background: #e9ecef; border-radius: 4px; min-height: 40px; white-space: pre-wrap; word-wrap: break-word; }\n',
373
+ ' </style>\n',
374
+ '</head>\n',
375
+ '<body>\n',
376
+ ' <div class="container">\n',
377
+ ' <h1>Text Completion Model</h1>\n',
378
+ ' <textarea id="userInput" placeholder="Enter starting text... (e.g., user: hi)"></textarea>\n',
379
+ ' <button id="generateButton">Generate</button>\n',
380
+ ' <h3>Output:</h3>\n',
381
+ ' <div id="outputText"></div>\n',
382
+ ' </div>\n',
383
+ '</body>\n',
384
+ '</html>\n'
385
+ ]
386
+ with open(html_filename, "w") as f:
387
+ f.writelines(html_lines)
388
+
389
+ print(f"Exported browser-runnable model to {js_filename} and {html_filename}")
390
+
391
+ @staticmethod
392
+ def load_network(filename):
393
+ ns = {"__name__": "__loaded_model__"}
394
+ with open(filename, "r") as f:
395
+ code = f.read()
396
+ exec(code, ns)
397
+ class ModelWrapper:
398
+ def __init__(self, ns):
399
+ self.ns = ns
400
+ self.vocab = ns.get("vocab", [])
401
+ self.word_to_idx = ns.get("word_to_idx", {})
402
+ self.context_window = ns.get("context_window", 5)
403
+
404
+ def complete(self, input_text, max_new_words=20):
405
+ words = [w.strip() for w in input_text.strip().split(' ') if w.strip()]
406
+ generated = words[:]
407
+ for _ in range(max_new_words):
408
+ context = generated[-self.context_window:]
409
+ x = [0.0] * len(self.vocab)
410
+ for word in context:
411
+ if word in self.word_to_idx:
412
+ x[self.word_to_idx[word]] = 1.0
413
+
414
+ out = self.ns["predict"](x)
415
+ idx = out.index(max(out))
416
+ next_word = self.vocab[idx]
417
+
418
+ if next_word == '<|endoftext|>':
419
+ break
420
+ generated.append(next_word)
421
+ return ' '.join(generated)
422
+
423
+ return ModelWrapper(ns)
424
+
425
+
426
+ if __name__ == "__main__":
427
+ sample_text = """
428
+ user: hi
429
+ ai: Hello! How can I help you today?
430
+ <|endoftext|>
431
+ user: hi
432
+ ai: Hi! What can I do for you today?
433
+ <|endoftext|>
434
+ user: hello
435
+ ai: Hello! How can I help you today?
436
+ <|endoftext|>
437
+ user: hey
438
+ ai: Hi! What can I do for you today?
439
+ <|endoftext|>
440
+ user: How's your day going?
441
+ ai: It's been great! Thanks for asking! How about yours?
442
+ <|endoftext|>
443
+ user: What's new with you?
444
+ ai: Not much, just here and ready to help! What's new with you?
445
+ <|endoftext|>
446
+ user: What can you do?
447
+ ai: I can help you with a variety of tasks. What's on your mind?
448
+ <|endoftext|>
449
+ user: Tell me a joke.
450
+ ai: Why did the scarecrow win an award? Because he was outstanding in his field!
451
+ <|endoftext|>
452
+ """
453
+ nn = NeuralNetwork(context_window=CONTEXT_WINDOW, seed=42)
454
+ nn.train(training_data=sample_text, lr=LR, epochs=EPOCHS, verbose_every=50)
455
+
456
+ # Export both Python and JavaScript versions
457
+ nn.export_to_python("exported_model.py")
458
+ nn.export_to_js("web_model") # This will create web_model.js and web_model.html
459
+
460
+ model = NeuralNetwork.load_network("exported_model.py")
461
+ print("\n--- Testing loaded Python model ---")
462
+ print(f"Vocabulary size: {len(model.vocab)}")
463
+
464
+ test_inputs = ["user: hi", "user: What's new", "ai: It's been"]
465
+ for test_input in test_inputs:
466
+ completion = model.complete(test_input, max_new_words=10)
467
+ print(f"Input: '{test_input}'\nOutput: '{completion}'\n")
468
+
469
+ print("\nTo test the JavaScript model, open 'web_model.html' in your browser.")