dodle commited on
Commit
cc69dae
·
verified ·
1 Parent(s): 387e8e2

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +23 -0
  2. me.py +42 -0
README.md CHANGED
@@ -45,6 +45,28 @@ with open("noe-model.dodl", "wb") as model_file:
45
  model_file.write(engine.export_model())
46
  ```
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  ## Generate a reply with OpenAI or Gemini
49
 
50
  `LLMProvider` sends the input, current state, and up to five recent memories to OpenAI or Gemini. It uses Python's standard library, so no provider SDK is required. Set the provider and its API key in the environment; credentials are never stored in the DODL file:
@@ -84,6 +106,7 @@ The file starts with the `DODL` magic signature and a versioned header. It store
84
  - `create_model_file(path)` creates a fresh model and writes it to `path`.
85
  - `serialize_model(model)` converts a model to DODL bytes.
86
  - `deserialize_model(data)` converts DODL bytes back to a model.
 
87
  - `AIEngine(model=None)` runs and updates a model; without an argument it creates a fresh one.
88
  - `AIEngine.step(input_value)` observes input, chooses and executes an action, evaluates it, learns, updates state, and returns the cycle result.
89
  - `LLMProvider(provider=None)` configures an OpenAI or Gemini text-generation adapter from environment variables.
 
45
  model_file.write(engine.export_model())
46
  ```
47
 
48
+ ## Merge compatible models
49
+
50
+ `merge_models(model_a, model_b, alpha=0.5)` interpolates corresponding network parameters. `alpha=0` keeps model A's parameters, `alpha=1` uses model B's, and values in between blend the two. Both models must have the same version and network shape. The merged model keeps model A's state, rules, memory, behavior, and goals, while receiving a new ID and timestamps.
51
+
52
+ Load both files into model dictionaries, merge them, then serialize the result:
53
+
54
+ ```python
55
+ from model.me import deserialize_model, merge_models, serialize_model
56
+
57
+ with open("model-a.dodl", "rb") as model_file:
58
+ model_a = deserialize_model(model_file.read())
59
+
60
+ with open("model-b.dodl", "rb") as model_file:
61
+ model_b = deserialize_model(model_file.read())
62
+
63
+ merged = merge_models(model_a, model_b, alpha=0.5)
64
+ with open("merged-model.dodl", "wb") as model_file:
65
+ model_file.write(serialize_model(merged))
66
+ ```
67
+
68
+ This merges weights and biases only; it does not combine memories, rules, or other model metadata. Direct parameter averaging may work poorly for independently trained networks, even when their shapes match. Other model formats require a format-specific importer before their parameters can be merged.
69
+
70
  ## Generate a reply with OpenAI or Gemini
71
 
72
  `LLMProvider` sends the input, current state, and up to five recent memories to OpenAI or Gemini. It uses Python's standard library, so no provider SDK is required. Set the provider and its API key in the environment; credentials are never stored in the DODL file:
 
106
  - `create_model_file(path)` creates a fresh model and writes it to `path`.
107
  - `serialize_model(model)` converts a model to DODL bytes.
108
  - `deserialize_model(data)` converts DODL bytes back to a model.
109
+ - `merge_models(model_a, model_b, alpha=0.5)` blends compatible models' network parameters.
110
  - `AIEngine(model=None)` runs and updates a model; without an argument it creates a fresh one.
111
  - `AIEngine.step(input_value)` observes input, chooses and executes an action, evaluates it, learns, updates state, and returns the cycle result.
112
  - `LLMProvider(provider=None)` configures an OpenAI or Gemini text-generation adapter from environment variables.
me.py CHANGED
@@ -4,6 +4,7 @@
4
 
5
  from array import array
6
  import base64
 
7
  import json
8
  import math
9
  import os
@@ -408,6 +409,47 @@ def create_model():
408
  }
409
 
410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  def validate_model(model):
412
  if len(model["memory"]) > CONFIG["MEMORY_LIMIT"]:
413
  raise ValueError("Memory limit exceeded.")
 
4
 
5
  from array import array
6
  import base64
7
+ import copy
8
  import json
9
  import math
10
  import os
 
409
  }
410
 
411
 
412
+ def merge_models(model_a, model_b, alpha=0.5):
413
+ if isinstance(alpha, bool) or not isinstance(alpha, (int, float)) or not math.isfinite(alpha):
414
+ raise ValueError("alpha must be a finite number between 0 and 1.")
415
+ if not 0 <= alpha <= 1:
416
+ raise ValueError("alpha must be between 0 and 1.")
417
+ if model_a["version"] != model_b["version"]:
418
+ raise ValueError("Models must have matching versions.")
419
+
420
+ network_a = model_a["network"]
421
+ network_b = model_b["network"]
422
+ shape_keys = ("inputSize", "hiddenSize", "outputSize")
423
+ if any(network_a[key] != network_b[key] for key in shape_keys):
424
+ raise ValueError("Models must have matching network shapes.")
425
+
426
+ input_size = network_a["inputSize"]
427
+ hidden_size = network_a["hiddenSize"]
428
+ output_size = network_a["outputSize"]
429
+ expected_lengths = {
430
+ "weights1": input_size * hidden_size,
431
+ "bias1": hidden_size,
432
+ "weights2": hidden_size * output_size,
433
+ "bias2": output_size,
434
+ }
435
+ merged = copy.deepcopy(model_a)
436
+ merged["id"] = list(secrets.token_bytes(16))
437
+ merged["createdAt"] = now()
438
+ merged["updatedAt"] = merged["createdAt"]
439
+
440
+ for key, expected_length in expected_lengths.items():
441
+ values_a = network_a[key]
442
+ values_b = network_b[key]
443
+ if len(values_a) != expected_length or len(values_b) != expected_length:
444
+ raise ValueError(f"Models have invalid {key} array lengths.")
445
+ merged["network"][key] = array(
446
+ "f",
447
+ ((1 - alpha) * value_a + alpha * value_b for value_a, value_b in zip(values_a, values_b)),
448
+ )
449
+
450
+ return merged
451
+
452
+
453
  def validate_model(model):
454
  if len(model["memory"]) > CONFIG["MEMORY_LIMIT"]:
455
  raise ValueError("Memory limit exceeded.")