userkuku commited on
Commit
68f61ae
·
verified ·
1 Parent(s): 7bb2a87

Upload utils.py

Browse files
Files changed (1) hide show
  1. utils.py +414 -0
utils.py ADDED
@@ -0,0 +1,414 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Utility functions for LMCODE (Language Model with Memory CODE).
3
+
4
+ Includes memory visualization, analysis, and helper functions.
5
+ """
6
+
7
+ import torch
8
+ import numpy as np
9
+ import matplotlib.pyplot as plt
10
+ from typing import Dict, List, Optional, Tuple
11
+ from collections import defaultdict
12
+ import json
13
+
14
+
15
+ def analyze_memory_capacity(model, test_sequences: List[torch.Tensor],
16
+ retrieval_threshold: float = 0.8) -> Dict:
17
+ """
18
+ Analyze the memory capacity and retrieval accuracy of the model.
19
+
20
+ Args:
21
+ model: LMCODE model
22
+ test_sequences: List of test sequences
23
+ retrieval_threshold: Similarity threshold for successful retrieval
24
+
25
+ Returns:
26
+ Dictionary with analysis results
27
+ """
28
+ results = {
29
+ 'total_memories': 0,
30
+ 'successful_retrievals': 0,
31
+ 'average_similarity': 0,
32
+ 'capacity_utilization': 0
33
+ }
34
+
35
+ similarities = []
36
+
37
+ for seq in test_sequences:
38
+ # Store sequence
39
+ model.store_experience(seq)
40
+
41
+ # Try to retrieve
42
+ retrieved, indices = model.query_memory(seq, top_k=5)
43
+
44
+ # Compute similarity
45
+ with torch.no_grad():
46
+ # Simplified similarity computation
47
+ seq_repr = seq.mean(dim=1) if seq.dim() > 2 else seq
48
+ retrieved_repr = retrieved.mean(dim=1) if retrieved.dim() > 2 else retrieved
49
+
50
+ if seq_repr.shape[-1] == retrieved_repr.shape[-1]:
51
+ # Cosine similarity
52
+ seq_norm = torch.nn.functional.normalize(seq_repr, dim=-1)
53
+ retrieved_norm = torch.nn.functional.normalize(retrieved_repr, dim=-1)
54
+ similarity = (seq_norm * retrieved_norm).sum(dim=-1).mean()
55
+ similarities.append(similarity.item())
56
+
57
+ if similarity > retrieval_threshold:
58
+ results['successful_retrievals'] += 1
59
+
60
+ results['total_memories'] += 1
61
+
62
+ if similarities:
63
+ results['average_similarity'] = np.mean(similarities)
64
+ results['similarity_std'] = np.std(similarities)
65
+
66
+ # Compute capacity utilization
67
+ total_slots = sum(
68
+ layer.long_term_memory.num_slots
69
+ for layer in model.layers
70
+ )
71
+ results['capacity_utilization'] = results['total_memories'] / total_slots
72
+
73
+ return results
74
+
75
+
76
+ def visualize_memory_attention(attention_weights: torch.Tensor,
77
+ save_path: Optional[str] = None) -> plt.Figure:
78
+ """
79
+ Visualize memory attention patterns.
80
+
81
+ Args:
82
+ attention_weights: Attention weights tensor
83
+ save_path: Optional path to save figure
84
+
85
+ Returns:
86
+ Matplotlib figure
87
+ """
88
+ fig, axes = plt.subplots(1, 2, figsize=(12, 5))
89
+
90
+ # Short-term memory attention
91
+ if len(attention_weights.shape) == 4:
92
+ # Multi-head attention
93
+ attention_avg = attention_weights.mean(dim=1)
94
+ else:
95
+ attention_avg = attention_weights
96
+
97
+ im1 = axes[0].imshow(attention_avg[0].cpu().numpy(), cmap='hot', aspect='auto')
98
+ axes[0].set_title('Short-Term Memory Attention')
99
+ axes[0].set_xlabel('Memory Slots')
100
+ axes[0].set_ylabel('Sequence Position')
101
+ plt.colorbar(im1, ax=axes[0])
102
+
103
+ # Long-term memory retrieval weights
104
+ # (This would need actual retrieval weights from a forward pass)
105
+ axes[1].text(0.5, 0.5, 'Long-Term Memory\nRetrieval Weights',
106
+ ha='center', va='center', transform=axes[1].transAxes)
107
+ axes[1].set_title('Long-Term Memory Retrieval')
108
+
109
+ plt.tight_layout()
110
+
111
+ if save_path:
112
+ plt.savefig(save_path, dpi=150, bbox_inches='tight')
113
+
114
+ return fig
115
+
116
+
117
+ def plot_training_history(history: Dict, save_path: Optional[str] = None) -> plt.Figure:
118
+ """
119
+ Plot training history.
120
+
121
+ Args:
122
+ history: Training history dictionary
123
+ save_path: Optional path to save figure
124
+
125
+ Returns:
126
+ Matplotlib figure
127
+ """
128
+ fig, axes = plt.subplots(1, 2, figsize=(12, 4))
129
+
130
+ # Loss plot
131
+ axes[0].plot(history.get('train_loss', []), label='Train Loss', alpha=0.8)
132
+ if 'eval_loss' in history and history['eval_loss']:
133
+ axes[0].plot(history['eval_loss'], label='Eval Loss', alpha=0.8)
134
+ axes[0].set_xlabel('Epoch')
135
+ axes[0].set_ylabel('Loss')
136
+ axes[0].set_title('Training Loss')
137
+ axes[0].legend()
138
+ axes[0].grid(True, alpha=0.3)
139
+
140
+ # Memory statistics
141
+ if 'memory_stats' in history and history['memory_stats']:
142
+ memory_stats = history['memory_stats']
143
+ if isinstance(memory_stats, list) and len(memory_stats) > 0:
144
+ # Extract memory statistics
145
+ if isinstance(memory_stats[0], dict):
146
+ # Get first layer's memory stats
147
+ layer_0_stats = [s.get('layer_0_lt_active_count', 0)
148
+ for s in memory_stats if isinstance(s, dict)]
149
+ if layer_0_stats:
150
+ axes[1].plot(layer_0_stats, label='Active Memories (Layer 0)', alpha=0.8)
151
+ axes[1].set_xlabel('Step')
152
+ axes[1].set_ylabel('Active Memory Count')
153
+ axes[1].set_title('Memory Utilization')
154
+ axes[1].legend()
155
+ axes[1].grid(True, alpha=0.3)
156
+
157
+ plt.tight_layout()
158
+
159
+ if save_path:
160
+ plt.savefig(save_path, dpi=150, bbox_inches='tight')
161
+
162
+ return fig
163
+
164
+
165
+ def compute_memory_efficiency(model, baseline_model=None) -> Dict:
166
+ """
167
+ Compute memory efficiency metrics.
168
+
169
+ Args:
170
+ model: LMCODE model
171
+ baseline_model: Optional baseline model for comparison
172
+
173
+ Returns:
174
+ Dictionary with efficiency metrics
175
+ """
176
+ metrics = {}
177
+
178
+ # Count parameters
179
+ total_params = sum(p.numel() for p in model.parameters())
180
+ memory_params = sum(
181
+ p.numel() for name, p in model.named_parameters()
182
+ if 'memory' in name
183
+ )
184
+
185
+ metrics['total_parameters'] = total_params
186
+ metrics['memory_parameters'] = memory_params
187
+ metrics['memory_parameter_ratio'] = memory_params / total_params
188
+
189
+ # Memory capacity
190
+ total_memory_slots = sum(
191
+ layer.long_term_memory.num_slots
192
+ for layer in model.layers
193
+ )
194
+ metrics['total_memory_slots'] = total_memory_slots
195
+
196
+ # Compute parameter efficiency
197
+ params_per_slot = memory_params / total_memory_slots if total_memory_slots > 0 else 0
198
+ metrics['parameters_per_memory_slot'] = params_per_slot
199
+
200
+ if baseline_model:
201
+ baseline_params = sum(p.numel() for p in baseline_model.parameters())
202
+ metrics['parameter_savings'] = 1 - (total_params / baseline_params)
203
+
204
+ return metrics
205
+
206
+
207
+ def generate_memory_report(model, dataset, output_path: str = 'memory_report.json'):
208
+ """
209
+ Generate a comprehensive memory report.
210
+
211
+ Args:
212
+ model: LMCODE model
213
+ dataset: Evaluation dataset
214
+ output_path: Path to save report
215
+ """
216
+ report = {
217
+ 'model_config': model.config.to_dict() if hasattr(model.config, 'to_dict')
218
+ else vars(model.config),
219
+ 'memory_analysis': {},
220
+ 'efficiency_metrics': {}
221
+ }
222
+
223
+ # Analyze memory
224
+ test_sequences = [d['input_ids'] for d in dataset[:10]] # Sample
225
+ memory_analysis = analyze_memory_capacity(model, test_sequences)
226
+ report['memory_analysis'] = memory_analysis
227
+
228
+ # Compute efficiency
229
+ efficiency = compute_memory_efficiency(model)
230
+ report['efficiency_metrics'] = efficiency
231
+
232
+ # Save report
233
+ with open(output_path, 'w') as f:
234
+ json.dump(report, f, indent=2, default=str)
235
+
236
+ print(f"Memory report saved to {output_path}")
237
+ return report
238
+
239
+
240
+ def visualize_memory_flow(model, input_sequence: torch.Tensor,
241
+ save_path: Optional[str] = None) -> plt.Figure:
242
+ """
243
+ Visualize memory flow through the network.
244
+
245
+ Args:
246
+ model: LMCODE model
247
+ input_sequence: Input sequence
248
+ save_path: Optional path to save figure
249
+
250
+ Returns:
251
+ Matplotlib figure
252
+ """
253
+ model.eval()
254
+
255
+ with torch.no_grad():
256
+ outputs = model(input_sequence.unsqueeze(0), use_long_term_memory=True)
257
+
258
+ fig, axes = plt.subplots(2, 2, figsize=(12, 10))
259
+
260
+ # Plot 1: Hidden state evolution
261
+ hidden_states = outputs['hidden_states']
262
+ if hidden_states:
263
+ # Average across layers
264
+ avg_hidden = torch.stack([hs.mean(dim=0) for hs in hidden_states])
265
+ im1 = axes[0, 0].imshow(avg_hidden.cpu().numpy(), aspect='auto', cmap='viridis')
266
+ axes[0, 0].set_title('Hidden State Evolution Across Layers')
267
+ axes[0, 0].set_xlabel('Hidden Dimension')
268
+ axes[0, 0].set_ylabel('Layer')
269
+ plt.colorbar(im1, ax=axes[0, 0])
270
+
271
+ # Plot 2: Attention weights (first layer)
272
+ if outputs['attention_weights']:
273
+ attn = outputs['attention_weights'][0]
274
+ if attn.dim() == 4:
275
+ attn = attn.mean(dim=1) # Average heads
276
+ im2 = axes[0, 1].imshow(attn[0].cpu().numpy(), aspect='auto', cmap='plasma')
277
+ axes[0, 1].set_title('Self-Attention Weights (Layer 0)')
278
+ axes[0, 1].set_xlabel('Key Position')
279
+ axes[0, 1].set_ylabel('Query Position')
280
+ plt.colorbar(im2, ax=axes[0, 1])
281
+
282
+ # Plot 3: Memory retrieval weights
283
+ if outputs['long_term_outputs'] and outputs['long_term_outputs'][0]:
284
+ lt_output = outputs['long_term_outputs'][0]
285
+ if 'retrieval_weights' in lt_output:
286
+ weights = lt_output['retrieval_weights']
287
+ im3 = axes[1, 0].imshow(weights[0].cpu().numpy(), aspect='auto', cmap='coolwarm')
288
+ axes[1, 0].set_title('Long-Term Memory Retrieval Weights')
289
+ axes[1, 0].set_xlabel('Memory Slot')
290
+ axes[1, 0].set_ylabel('Sequence Position')
291
+ plt.colorbar(im3, ax=axes[1, 0])
292
+
293
+ # Plot 4: Short-term memory read weights
294
+ if outputs['short_term_outputs']:
295
+ st_output = outputs['short_term_outputs'][0]
296
+ if 'read_weights' in st_output:
297
+ weights = st_output['read_weights']
298
+ im4 = axes[1, 1].imshow(weights[0].cpu().numpy(), aspect='auto', cmap='YlOrRd')
299
+ axes[1, 1].set_title('Short-Term Memory Read Weights')
300
+ axes[1, 1].set_xlabel('Memory Slot')
301
+ axes[1, 1].set_ylabel('Sequence Position')
302
+ plt.colorbar(im4, ax=axes[1, 1])
303
+
304
+ plt.tight_layout()
305
+
306
+ if save_path:
307
+ plt.savefig(save_path, dpi=150, bbox_inches='tight')
308
+
309
+ return fig
310
+
311
+
312
+ class MemoryMonitor:
313
+ """
314
+ Monitor memory usage and performance during training.
315
+ """
316
+
317
+ def __init__(self, model):
318
+ self.model = model
319
+ self.history = defaultdict(list)
320
+
321
+ def record_step(self, step: int, outputs: Dict):
322
+ """
323
+ Record memory statistics for a training step.
324
+
325
+ Args:
326
+ step: Current training step
327
+ outputs: Model outputs
328
+ """
329
+ # Record loss
330
+ if 'loss' in outputs and outputs['loss'] is not None:
331
+ self.history['loss'].append((step, outputs['loss'].item()))
332
+
333
+ # Record memory statistics
334
+ for i, lt_output in enumerate(outputs.get('long_term_outputs', [])):
335
+ if lt_output and 'retrieval_weights' in lt_output:
336
+ weights = lt_output['retrieval_weights']
337
+ avg_weight = weights.mean().item()
338
+ self.history[f'layer_{i}_retrieval_weight'].append((step, avg_weight))
339
+
340
+ for i, st_output in enumerate(outputs.get('short_term_outputs', [])):
341
+ if st_output and 'read_weights' in st_output:
342
+ weights = st_output['read_weights']
343
+ avg_weight = weights.mean().item()
344
+ self.history[f'layer_{i}_read_weight'].append((step, avg_weight))
345
+
346
+ def get_statistics(self) -> Dict:
347
+ """
348
+ Get aggregated memory statistics.
349
+
350
+ Returns:
351
+ Dictionary with statistics
352
+ """
353
+ stats = {}
354
+
355
+ for key, values in self.history.items():
356
+ if values:
357
+ vals = [v for _, v in values]
358
+ stats[key] = {
359
+ 'mean': np.mean(vals),
360
+ 'std': np.std(vals),
361
+ 'min': np.min(vals),
362
+ 'max': np.max(vals),
363
+ 'latest': vals[-1]
364
+ }
365
+
366
+ return stats
367
+
368
+ def plot_history(self, save_path: Optional[str] = None) -> plt.Figure:
369
+ """
370
+ Plot monitoring history.
371
+
372
+ Args:
373
+ save_path: Optional path to save figure
374
+
375
+ Returns:
376
+ Matplotlib figure
377
+ """
378
+ n_metrics = len(self.history)
379
+ if n_metrics == 0:
380
+ fig, ax = plt.subplots(1, 1, figsize=(8, 6))
381
+ ax.text(0.5, 0.5, 'No data recorded',
382
+ ha='center', va='center', transform=ax.transAxes)
383
+ return fig
384
+
385
+ n_cols = min(2, n_metrics)
386
+ n_rows = (n_metrics + n_cols - 1) // n_cols
387
+
388
+ fig, axes = plt.subplots(n_rows, n_cols, figsize=(6 * n_cols, 4 * n_rows))
389
+ if n_metrics == 1:
390
+ axes = [axes]
391
+ elif n_rows > 1 and n_cols > 1:
392
+ axes = axes.flatten()
393
+
394
+ for idx, (key, values) in enumerate(self.history.items()):
395
+ if idx >= len(axes):
396
+ break
397
+
398
+ steps, vals = zip(*values)
399
+ axes[idx].plot(steps, vals, alpha=0.7)
400
+ axes[idx].set_title(key.replace('_', ' ').title())
401
+ axes[idx].set_xlabel('Step')
402
+ axes[idx].set_ylabel('Value')
403
+ axes[idx].grid(True, alpha=0.3)
404
+
405
+ # Hide unused subplots
406
+ for idx in range(n_metrics, len(axes)):
407
+ axes[idx].axis('off')
408
+
409
+ plt.tight_layout()
410
+
411
+ if save_path:
412
+ plt.savefig(save_path, dpi=150, bbox_inches='tight')
413
+
414
+ return fig