rikunarita-2 commited on
Commit
fa22337
·
verified ·
1 Parent(s): a8f15bc

Update backend/merge_engines/evolutionary.py

Browse files
Files changed (1) hide show
  1. backend/merge_engines/evolutionary.py +46 -31
backend/merge_engines/evolutionary.py CHANGED
@@ -1,70 +1,85 @@
1
  import os
2
- import torch
3
  import random
4
- import numpy as np
5
- from .linear import linear_merge # reuse for individual creation
6
- from backend.fitness import evaluate_model
7
  import tempfile
8
  import shutil
 
 
 
9
 
10
  def evolutionary_merge(model_a, model_b, dataset_path, output_dir, params):
11
  pop_size = params.get("population_size", 10)
12
  mutation_rate = params.get("mutation_rate", 0.1)
13
- crossover_method = params.get("crossover", "uniform") # or "single_point"
14
  selection = params.get("selection", "tournament")
15
  generations = params.get("generations", 5)
16
- fitness_script = params.get("fitness_script", None) # custom function string?
17
-
 
18
  # Initialize population: list of alpha values
19
  population = [random.random() for _ in range(pop_size)]
20
  best_alpha = None
21
- best_score = float("inf") if params.get("fitness_higher_better", False) else -float("inf")
22
-
23
  for gen in range(generations):
24
  scores = []
25
  for idx, alpha in enumerate(population):
26
  temp_dir = tempfile.mkdtemp()
27
- linear_merge(model_a, model_b, alpha, temp_dir)
28
- score = evaluate_model(temp_dir, dataset_path, fitness_script)
29
- scores.append(score)
30
- shutil.rmtree(temp_dir)
 
 
 
 
31
  # update best
32
- if (params.get("fitness_higher_better", False) and score > best_score) or \
33
- (not params.get("fitness_higher_better", False) and score < best_score):
34
- best_score = score
35
- best_alpha = alpha
 
 
 
 
 
36
  # Selection
37
- new_pop = []
38
- # elitism: keep best
39
- new_pop.append(best_alpha)
40
  for _ in range(pop_size - 1):
41
  if selection == "tournament":
42
  i, j = random.sample(range(pop_size), 2)
43
- winner = population[i] if scores[i] > scores[j] else population[j] if params.get("fitness_higher_better") else (population[i] if scores[i] < scores[j] else population[j])
 
 
 
44
  new_pop.append(winner)
45
  else:
46
- # random parent
47
  new_pop.append(random.choice(population))
 
48
  # Crossover & Mutation
49
  offspring = []
50
- for i in range(0, pop_size, 2):
51
  p1 = new_pop[i]
52
- p2 = new_pop[(i+1) % pop_size]
53
  if crossover_method == "uniform":
54
  c1 = p1 if random.random() < 0.5 else p2
55
  c2 = p2 if random.random() < 0.5 else p1
56
  else: # arithmetic
57
  c1 = (p1 + p2) / 2
58
  c2 = (p1 + p2) / 2
59
- # mutation
60
- c1 = min(max(c1 + random.uniform(-mutation_rate, mutation_rate), 0), 1)
61
- c2 = min(max(c2 + random.uniform(-mutation_rate, mutation_rate), 0), 1)
 
62
  offspring.extend([c1, c2])
 
63
  population = offspring[:pop_size]
64
-
65
  # Final merge with best alpha
66
- linear_merge(model_a, model_b, best_alpha, output_dir)
67
- # Save fitness info
 
 
 
68
  with open(os.path.join(output_dir, "merge_info.json"), "w") as f:
69
- import json
70
  json.dump({"best_alpha": best_alpha, "fitness": best_score}, f)
 
1
  import os
 
2
  import random
 
 
 
3
  import tempfile
4
  import shutil
5
+ import json
6
+ from .linear import merge_models
7
+ from backend.fitness import evaluate_model
8
 
9
  def evolutionary_merge(model_a, model_b, dataset_path, output_dir, params):
10
  pop_size = params.get("population_size", 10)
11
  mutation_rate = params.get("mutation_rate", 0.1)
12
+ crossover_method = params.get("crossover", "uniform") # uniform or arithmetic
13
  selection = params.get("selection", "tournament")
14
  generations = params.get("generations", 5)
15
+ fitness_higher_better = params.get("fitness_higher_better", False)
16
+ fitness_script = params.get("fitness_script", None)
17
+
18
  # Initialize population: list of alpha values
19
  population = [random.random() for _ in range(pop_size)]
20
  best_alpha = None
21
+ best_score = float('-inf') if fitness_higher_better else float('inf')
22
+
23
  for gen in range(generations):
24
  scores = []
25
  for idx, alpha in enumerate(population):
26
  temp_dir = tempfile.mkdtemp()
27
+ try:
28
+ # Use merge_models with method='linear' and alpha
29
+ merge_models(model_a, model_b, temp_dir, method='linear', alpha=alpha)
30
+ score = evaluate_model(temp_dir, dataset_path, fitness_script)
31
+ scores.append(score)
32
+ finally:
33
+ shutil.rmtree(temp_dir)
34
+
35
  # update best
36
+ if fitness_higher_better:
37
+ if score > best_score:
38
+ best_score = score
39
+ best_alpha = alpha
40
+ else:
41
+ if score < best_score:
42
+ best_score = score
43
+ best_alpha = alpha
44
+
45
  # Selection
46
+ new_pop = [best_alpha] # elitism: keep best
47
+
 
48
  for _ in range(pop_size - 1):
49
  if selection == "tournament":
50
  i, j = random.sample(range(pop_size), 2)
51
+ if fitness_higher_better:
52
+ winner = population[i] if scores[i] > scores[j] else population[j]
53
+ else:
54
+ winner = population[i] if scores[i] < scores[j] else population[j]
55
  new_pop.append(winner)
56
  else:
 
57
  new_pop.append(random.choice(population))
58
+
59
  # Crossover & Mutation
60
  offspring = []
61
+ for i in range(0, pop_size-1, 2):
62
  p1 = new_pop[i]
63
+ p2 = new_pop[i+1]
64
  if crossover_method == "uniform":
65
  c1 = p1 if random.random() < 0.5 else p2
66
  c2 = p2 if random.random() < 0.5 else p1
67
  else: # arithmetic
68
  c1 = (p1 + p2) / 2
69
  c2 = (p1 + p2) / 2
70
+
71
+ # Mutation
72
+ c1 = min(max(c1 + random.uniform(-mutation_rate, mutation_rate), 0.0), 1.0)
73
+ c2 = min(max(c2 + random.uniform(-mutation_rate, mutation_rate), 0.0), 1.0)
74
  offspring.extend([c1, c2])
75
+
76
  population = offspring[:pop_size]
77
+
78
  # Final merge with best alpha
79
+ if best_alpha is None:
80
+ best_alpha = 0.5 # fallback
81
+ merge_models(model_a, model_b, output_dir, method='linear', alpha=best_alpha)
82
+
83
+ # Save info
84
  with open(os.path.join(output_dir, "merge_info.json"), "w") as f:
 
85
  json.dump({"best_alpha": best_alpha, "fitness": best_score}, f)