apertus-swiss-transparency / examples /advanced_transparency_toolkit.py
Markus Clauss DIRU Vetsuisse
Initial commit - Apertus Swiss AI Transparency Dashboard
b65eda7
"""
πŸ‡¨πŸ‡­ Advanced Apertus Transparency Toolkit
Native weights inspection, attention visualization, layer tracking, and tokenizer comparisons
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
import torch
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Dict, List, Optional
import time
from apertus_core import ApertusCore
from transparency_analyzer import ApertusTransparencyAnalyzer
import warnings
warnings.filterwarnings('ignore')
import sys
from io import StringIO
from datetime import datetime
class AdvancedTransparencyToolkit:
"""Advanced transparency analysis with complete logging of all outputs"""
def __init__(self):
self.apertus = ApertusCore(enable_transparency=True)
self.analyzer = ApertusTransparencyAnalyzer(self.apertus)
# Setup logging capture
self.log_buffer = StringIO()
self.original_stdout = sys.stdout
# Log the initialization
self.log_and_print("πŸ‡¨πŸ‡­ ADVANCED APERTUS TRANSPARENCY TOOLKIT")
self.log_and_print("=" * 70)
self.log_and_print("βœ… Advanced toolkit ready!\n")
def log_and_print(self, message):
"""Print to console AND capture to log"""
print(message)
self.log_buffer.write(message + "\n")
def start_logging(self):
"""Start capturing all print output"""
sys.stdout = self
def stop_logging(self):
"""Stop capturing and restore normal output"""
sys.stdout = self.original_stdout
def write(self, text):
"""Capture output for logging"""
self.original_stdout.write(text)
self.log_buffer.write(text)
def flush(self):
"""Flush both outputs"""
self.original_stdout.flush()
def native_weights_inspection(self, layer_pattern: str = "layers.15.self_attn"):
"""Native inspection of model weights with detailed analysis"""
print(f"βš–οΈ NATIVE WEIGHTS INSPECTION: {layer_pattern}")
print("=" * 70)
matching_layers = []
for name, module in self.apertus.model.named_modules():
if layer_pattern in name and hasattr(module, 'weight'):
matching_layers.append((name, module))
if not matching_layers:
print(f"❌ No layers found matching pattern: {layer_pattern}")
return
for name, module in matching_layers[:3]: # Show first 3 matching layers
print(f"\nπŸ” Layer: {name}")
print("-" * 50)
# Convert bfloat16 to float32 for numpy compatibility
weights = module.weight.data.cpu()
if weights.dtype == torch.bfloat16:
weights = weights.float()
weights = weights.numpy()
# Basic statistics
print(f"πŸ“Š Weight Statistics:")
print(f" Shape: {weights.shape}")
print(f" Parameters: {weights.size:,}")
print(f" Memory: {weights.nbytes / 1024**2:.1f} MB")
print(f" Data type: {weights.dtype}")
# Distribution analysis
print(f"\nπŸ“ˆ Distribution Analysis:")
print(f" Mean: {np.mean(weights):+.6f}")
print(f" Std: {np.std(weights):.6f}")
print(f" Min: {np.min(weights):+.6f}")
print(f" Max: {np.max(weights):+.6f}")
print(f" Range: {np.max(weights) - np.min(weights):.6f}")
# Sparsity analysis
thresholds = [1e-4, 1e-3, 1e-2, 1e-1]
print(f"\nπŸ•ΈοΈ Sparsity Analysis:")
for threshold in thresholds:
sparse_ratio = np.mean(np.abs(weights) < threshold)
print(f" |w| < {threshold:.0e}: {sparse_ratio:.1%}")
# Weight magnitude distribution
weight_magnitudes = np.abs(weights.flatten())
percentiles = [50, 90, 95, 99, 99.9]
print(f"\nπŸ“Š Magnitude Percentiles:")
for p in percentiles:
value = np.percentile(weight_magnitudes, p)
print(f" {p:4.1f}%: {value:.6f}")
# Gradient statistics (if available)
if hasattr(module.weight, 'grad') and module.weight.grad is not None:
grad = module.weight.grad.data.cpu()
if grad.dtype == torch.bfloat16:
grad = grad.float()
grad = grad.numpy()
print(f"\n🎯 Gradient Statistics:")
print(f" Mean: {np.mean(grad):+.6e}")
print(f" Std: {np.std(grad):.6e}")
print(f" Max: {np.max(np.abs(grad)):.6e}")
# Layer-specific analysis
if 'q_proj' in name or 'k_proj' in name or 'v_proj' in name:
print(f"\nπŸ” Attention Projection Analysis:")
# Analyze attention projection patterns
if len(weights.shape) == 2:
# Calculate column norms (output dimension norms)
col_norms = np.linalg.norm(weights, axis=0)
row_norms = np.linalg.norm(weights, axis=1)
print(f" Output dim norms - Mean: {np.mean(col_norms):.4f}, Std: {np.std(col_norms):.4f}")
print(f" Input dim norms - Mean: {np.mean(row_norms):.4f}, Std: {np.std(row_norms):.4f}")
# Check for any unusual patterns
zero_cols = np.sum(col_norms < 1e-6)
zero_rows = np.sum(row_norms < 1e-6)
if zero_cols > 0 or zero_rows > 0:
print(f" ⚠️ Zero columns: {zero_cols}, Zero rows: {zero_rows}")
print(f"\n✨ Native weights inspection completed!")
def real_time_attention_visualization(self, text: str, num_steps: int = 3):
"""Real-time attention pattern visualization during generation"""
print(f"πŸ‘οΈ REAL-TIME ATTENTION VISUALIZATION")
print("=" * 70)
print(f"Text: '{text}'")
# Initial encoding
inputs = self.apertus.tokenizer(text, return_tensors="pt")
input_ids = inputs['input_ids']
# Move to model device
device = next(self.apertus.model.parameters()).device
input_ids = input_ids.to(device)
attention_history = []
for step in range(num_steps):
print(f"\n--- GENERATION STEP {step + 1} ---")
# Get current text
current_text = self.apertus.tokenizer.decode(input_ids[0])
print(f"Current: '{current_text}'")
# Forward pass with attention
with torch.no_grad():
outputs = self.apertus.model(input_ids, output_attentions=True)
logits = outputs.logits[0, -1, :]
attentions = outputs.attentions
# Analyze attention in last layer
last_layer_attention = attentions[-1][0] # [num_heads, seq_len, seq_len]
# Convert bfloat16 to float32 for numpy compatibility
attention_cpu = last_layer_attention.mean(dim=0).cpu()
if attention_cpu.dtype == torch.bfloat16:
attention_cpu = attention_cpu.float()
avg_attention = attention_cpu.numpy()
# Get tokens
tokens = self.apertus.tokenizer.convert_ids_to_tokens(input_ids[0])
print(f"Tokens: {tokens}")
print(f"Attention matrix shape: {avg_attention.shape}")
# Show attention patterns for last token
if len(tokens) > 1:
last_token_attention = avg_attention[-1, :-1] # What last token attends to
top_attended = np.argsort(last_token_attention)[-3:][::-1]
print(f"Last token '{tokens[-1]}' attends most to:")
for i, token_idx in enumerate(top_attended):
if token_idx < len(tokens) - 1:
attention_score = last_token_attention[token_idx]
print(f" {i+1}. '{tokens[token_idx]}' ({attention_score:.3f})")
# Store attention history
attention_history.append({
'step': step + 1,
'tokens': tokens.copy(),
'attention': avg_attention.copy(),
'text': current_text
})
# Generate next token
probabilities = torch.nn.functional.softmax(logits, dim=-1)
next_token_id = torch.multinomial(probabilities, 1)
input_ids = torch.cat([input_ids, next_token_id.unsqueeze(0)], dim=-1)
next_token = self.apertus.tokenizer.decode([next_token_id.item()])
print(f"Next token: '{next_token}'")
print(f"\nβœ… Real-time attention visualization completed!")
return attention_history
def layer_evolution_real_time_tracking(self, text: str):
"""Real-time tracking of layer evolution during forward pass"""
print(f"🧠 REAL-TIME LAYER EVOLUTION TRACKING")
print("=" * 70)
print(f"Text: '{text}'")
inputs = self.apertus.tokenizer(text, return_tensors="pt")
tokens = self.apertus.tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
# Move to model device
device = next(self.apertus.model.parameters()).device
inputs = {k: v.to(device) for k, v in inputs.items()}
print(f"Tokens: {tokens}")
print(f"Tracking through {self.apertus.model.config.num_hidden_layers} layers...\n")
# Forward pass with hidden states
with torch.no_grad():
start_time = time.time()
outputs = self.apertus.model(**inputs, output_hidden_states=True)
forward_time = time.time() - start_time
hidden_states = outputs.hidden_states
# Track evolution through layers
layer_evolution = []
print(f"⏱️ Forward pass took {forward_time:.3f}s")
print(f"\nπŸ”„ Layer-by-Layer Evolution:")
# Sample layers for detailed analysis
sample_layers = list(range(0, len(hidden_states), max(1, len(hidden_states)//10)))
for i, layer_idx in enumerate(sample_layers):
layer_state = hidden_states[layer_idx][0] # Remove batch dimension
# Per-token analysis
token_stats = []
for token_pos in range(layer_state.shape[0]):
token_vector = layer_state[token_pos]
stats = {
'token': tokens[token_pos] if token_pos < len(tokens) else '<pad>',
'l2_norm': torch.norm(token_vector).item(),
'mean': token_vector.mean().item(),
'std': token_vector.std().item(),
'max': token_vector.max().item(),
'min': token_vector.min().item(),
'sparsity': (torch.abs(token_vector) < 0.01).float().mean().item()
}
token_stats.append(stats)
# Layer-level statistics
layer_stats = {
'layer': layer_idx,
'avg_l2_norm': np.mean([s['l2_norm'] for s in token_stats]),
'max_l2_norm': np.max([s['l2_norm'] for s in token_stats]),
'avg_activation': np.mean([s['mean'] for s in token_stats]),
'activation_spread': np.std([s['mean'] for s in token_stats]),
'avg_sparsity': np.mean([s['sparsity'] for s in token_stats])
}
layer_evolution.append(layer_stats)
print(f"Layer {layer_idx:2d}: L2={layer_stats['avg_l2_norm']:.3f}, "
f"Mean={layer_stats['avg_activation']:+.4f}, "
f"Spread={layer_stats['activation_spread']:.4f}, "
f"Sparsity={layer_stats['avg_sparsity']:.1%}")
# Show most active tokens in this layer
top_tokens = sorted(token_stats, key=lambda x: x['l2_norm'], reverse=True)[:3]
active_tokens = [f"'{t['token']}'({t['l2_norm']:.2f})" for t in top_tokens]
print(f" Most active: {', '.join(active_tokens)}")
# Evolution analysis
print(f"\nπŸ“Š Evolution Analysis:")
# Check for increasing/decreasing patterns
l2_norms = [stats['avg_l2_norm'] for stats in layer_evolution]
if len(l2_norms) > 1:
trend = "increasing" if l2_norms[-1] > l2_norms[0] else "decreasing"
change = ((l2_norms[-1] - l2_norms[0]) / l2_norms[0]) * 100
print(f"L2 norm trend: {trend} ({change:+.1f}%)")
# Check layer specialization
sparsity_levels = [stats['avg_sparsity'] for stats in layer_evolution]
if len(sparsity_levels) > 1:
sparsity_trend = "increasing" if sparsity_levels[-1] > sparsity_levels[0] else "decreasing"
print(f"Sparsity trend: {sparsity_trend} (early: {sparsity_levels[0]:.1%}, late: {sparsity_levels[-1]:.1%})")
print(f"\nβœ… Real-time layer tracking completed!")
return layer_evolution
def decision_process_analysis(self, prompt: str, max_steps: int = 5, temperature: float = 0.7, top_p: float = 0.9, top_k: int = 50):
"""Deep analysis of the decision-making process"""
print(f"🎲 DECISION PROCESS ANALYSIS")
print("=" * 70)
print(f"Prompt: '{prompt}'")
print(f"πŸŽ›οΈ Sampling Parameters:")
print(f" Temperature: {temperature} (creativity control)")
print(f" Top-P: {top_p} (nucleus sampling)")
print(f" Top-K: {top_k} (candidate pool size)")
input_ids = self.apertus.tokenizer.encode(prompt, return_tensors="pt")
# Move to model device
device = next(self.apertus.model.parameters()).device
input_ids = input_ids.to(device)
decision_history = []
for step in range(max_steps):
print(f"\n--- DECISION STEP {step + 1} ---")
current_text = self.apertus.tokenizer.decode(input_ids[0])
print(f"Current text: '{current_text}'")
# Forward pass
with torch.no_grad():
outputs = self.apertus.model(input_ids, output_attentions=True, output_hidden_states=True)
logits = outputs.logits[0, -1, :]
attentions = outputs.attentions
hidden_states = outputs.hidden_states
# Apply temperature scaling for decision analysis
scaled_logits = logits / temperature
probabilities = torch.nn.functional.softmax(scaled_logits, dim=-1)
# Show the effect of temperature
original_probs = torch.nn.functional.softmax(logits, dim=-1)
print(f"🌑️ Temperature Effect Analysis:")
orig_top5 = torch.topk(original_probs, 5)[0]
temp_top5 = torch.topk(probabilities, 5)[0]
print(f" Without temp: Top-5 = {[f'{p.item():.1%}' for p in orig_top5]}")
print(f" With temp={temperature}: Top-5 = {[f'{p.item():.1%}' for p in temp_top5]}")
# Entropy analysis (uncertainty measure)
entropy = -torch.sum(probabilities * torch.log(probabilities + 1e-12)).item()
# Confidence analysis
max_prob = probabilities.max().item()
top_probs, top_indices = torch.topk(probabilities, 10)
print(f"🎯 Decision Metrics:")
print(f" Entropy: {entropy:.3f} (uncertainty)")
print(f" Max confidence: {max_prob:.1%}")
print(f" Top-3 probability mass: {top_probs[:3].sum().item():.1%}")
# Analyze what influenced this decision
last_hidden = hidden_states[-1][0, -1, :] # Last token's final hidden state
hidden_magnitude = torch.norm(last_hidden).item()
print(f" Hidden state magnitude: {hidden_magnitude:.2f}")
# Check attention focus
last_attention = attentions[-1][0, :, -1, :-1].mean(dim=0) # Average over heads
top_attention_indices = torch.topk(last_attention, 3)[1]
tokens = self.apertus.tokenizer.convert_ids_to_tokens(input_ids[0])
print(f" Attention focused on:")
for i, idx in enumerate(top_attention_indices):
if idx < len(tokens):
attention_score = last_attention[idx].item()
print(f" {i+1}. '{tokens[idx]}' ({attention_score:.3f})")
# Show top candidates with reasoning
print(f"\nπŸ† Top candidates:")
for i in range(5):
token_id = top_indices[i].item()
token = self.apertus.tokenizer.decode([token_id])
prob = top_probs[i].item()
logit = logits[token_id].item()
# Confidence assessment
if prob > 0.3:
confidence_level = "πŸ”₯ Very High"
elif prob > 0.1:
confidence_level = "βœ… High"
elif prob > 0.05:
confidence_level = "⚠️ Medium"
else:
confidence_level = "❓ Low"
print(f" {i+1}. '{token}' β†’ {prob:.1%} (logit: {logit:+.2f}) {confidence_level}")
# Decision quality assessment
if entropy < 2.0:
decision_quality = "🎯 Confident"
elif entropy < 4.0:
decision_quality = "βš–οΈ Balanced"
else:
decision_quality = "πŸ€” Uncertain"
print(f"\nπŸ“Š Decision quality: {decision_quality}")
# Apply top-k filtering if specified
sampling_probs = probabilities.clone()
if top_k > 0 and top_k < len(probabilities):
top_k_values, top_k_indices = torch.topk(probabilities, top_k)
# Zero out probabilities not in top-k
sampling_probs = torch.zeros_like(probabilities)
sampling_probs[top_k_indices] = top_k_values
sampling_probs = sampling_probs / sampling_probs.sum()
print(f"πŸ”„ Top-K filtering: Reduced {len(probabilities)} β†’ {top_k} candidates")
# Apply top-p (nucleus) filtering if specified
if top_p < 1.0:
sorted_probs, sorted_indices = torch.sort(sampling_probs, descending=True)
cumulative_probs = torch.cumsum(sorted_probs, dim=-1)
nucleus_mask = cumulative_probs <= top_p
nucleus_mask[0] = True # Keep at least one token
nucleus_probs = torch.zeros_like(sampling_probs)
nucleus_probs[sorted_indices[nucleus_mask]] = sorted_probs[nucleus_mask]
sampling_probs = nucleus_probs / nucleus_probs.sum()
nucleus_size = nucleus_mask.sum().item()
nucleus_mass = sorted_probs[nucleus_mask].sum().item()
print(f"πŸŒ€ Top-P filtering: Nucleus size = {nucleus_size} tokens ({nucleus_mass:.1%} probability mass)")
# Show final sampling distribution vs display distribution
final_top5 = torch.topk(sampling_probs, 5)
print(f"🎯 Final sampling distribution:")
for i in range(5):
if final_top5[0][i] > 0:
token = self.apertus.tokenizer.decode([final_top5[1][i].item()])
prob = final_top5[0][i].item()
print(f" {i+1}. '{token}' β†’ {prob:.1%}")
# Make decision (sample next token)
next_token_id = torch.multinomial(sampling_probs, 1)
selected_token = self.apertus.tokenizer.decode([next_token_id.item()])
# Find rank of selected token
selected_rank = "N/A"
if next_token_id in top_indices:
selected_rank = (top_indices == next_token_id).nonzero().item() + 1
print(f"🎲 SELECTED: '{selected_token}' (rank: {selected_rank})")
# Store decision data
decision_history.append({
'step': step + 1,
'text': current_text,
'selected_token': selected_token,
'selected_rank': selected_rank,
'entropy': entropy,
'max_confidence': max_prob,
'hidden_magnitude': hidden_magnitude,
'decision_quality': decision_quality
})
# Update for next step
input_ids = torch.cat([input_ids, next_token_id.unsqueeze(0)], dim=-1)
# Final analysis
final_text = self.apertus.tokenizer.decode(input_ids[0])
print(f"\n✨ FINAL GENERATED TEXT: '{final_text}'")
avg_entropy = np.mean([d['entropy'] for d in decision_history])
avg_confidence = np.mean([d['max_confidence'] for d in decision_history])
print(f"\nπŸ“Š Generation Analysis:")
print(f" Average entropy: {avg_entropy:.2f}")
print(f" Average confidence: {avg_confidence:.1%}")
print(f" Generation quality: {'High' if avg_confidence > 0.3 else 'Medium' if avg_confidence > 0.15 else 'Low'}")
return decision_history
def comprehensive_tokenizer_comparison(self, test_word: str = "Bundesgesundheitsamt"):
"""Compare tokenization across different model tokenizers"""
print(f"πŸ”€ COMPREHENSIVE TOKENIZER COMPARISON")
print("=" * 70)
print(f"Test word: '{test_word}'")
# Test with Apertus tokenizer
print(f"\nπŸ‡¨πŸ‡­ Apertus Tokenizer:")
apertus_tokens = self.apertus.tokenizer.tokenize(test_word)
apertus_ids = self.apertus.tokenizer.encode(test_word, add_special_tokens=False)
print(f" Tokens: {apertus_tokens}")
print(f" Token IDs: {apertus_ids}")
print(f" Token count: {len(apertus_tokens)}")
print(f" Efficiency: {len(test_word) / len(apertus_tokens):.1f} chars/token")
# Detailed analysis of each token
print(f" Token breakdown:")
for i, (token, token_id) in enumerate(zip(apertus_tokens, apertus_ids)):
print(f" {i+1}. '{token}' β†’ ID: {token_id}")
# Try to compare with other common tokenizers (if available)
comparison_results = [
{
'model': 'Apertus Swiss AI',
'tokens': apertus_tokens,
'count': len(apertus_tokens),
'efficiency': len(test_word) / len(apertus_tokens),
'vocab_size': self.apertus.tokenizer.vocab_size
}
]
# Try GPT-2 style tokenizer
try:
from transformers import GPT2Tokenizer
gpt2_tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
gpt2_tokens = gpt2_tokenizer.tokenize(test_word)
print(f"\nπŸ€– GPT-2 Tokenizer (for comparison):")
print(f" Tokens: {gpt2_tokens}")
print(f" Token count: {len(gpt2_tokens)}")
print(f" Efficiency: {len(test_word) / len(gpt2_tokens):.1f} chars/token")
comparison_results.append({
'model': 'GPT-2',
'tokens': gpt2_tokens,
'count': len(gpt2_tokens),
'efficiency': len(test_word) / len(gpt2_tokens),
'vocab_size': gpt2_tokenizer.vocab_size
})
except Exception as e:
print(f"\n⚠️ GPT-2 tokenizer not available: {e}")
# Try BERT tokenizer
try:
from transformers import BertTokenizer
bert_tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# Convert to lowercase for BERT
bert_tokens = bert_tokenizer.tokenize(test_word.lower())
print(f"\nπŸ“š BERT Tokenizer (for comparison):")
print(f" Tokens: {bert_tokens}")
print(f" Token count: {len(bert_tokens)}")
print(f" Efficiency: {len(test_word) / len(bert_tokens):.1f} chars/token")
comparison_results.append({
'model': 'BERT',
'tokens': bert_tokens,
'count': len(bert_tokens),
'efficiency': len(test_word) / len(bert_tokens),
'vocab_size': bert_tokenizer.vocab_size
})
except Exception as e:
print(f"\n⚠️ BERT tokenizer not available: {e}")
# Analysis summary
print(f"\nπŸ“Š TOKENIZATION COMPARISON SUMMARY:")
print(f"{'Model':<20} {'Tokens':<8} {'Efficiency':<12} {'Vocab Size'}")
print("-" * 60)
for result in comparison_results:
print(f"{result['model']:<20} {result['count']:<8} {result['efficiency']:<12.1f} {result['vocab_size']:,}")
# Specific German compound word analysis
if test_word == "Bundesgesundheitsamt":
print(f"\nπŸ‡©πŸ‡ͺ GERMAN COMPOUND WORD ANALYSIS:")
print(f" Word parts: Bundes + gesundheits + amt")
print(f" Meaning: Federal Health Office")
print(f" Character count: {len(test_word)}")
# Check if Apertus handles German compounds better
apertus_efficiency = len(test_word) / len(apertus_tokens)
print(f" Apertus efficiency: {apertus_efficiency:.1f} chars/token")
if apertus_efficiency > 8:
print(f" βœ… Excellent German compound handling!")
elif apertus_efficiency > 6:
print(f" βœ… Good German compound handling")
else:
print(f" ⚠️ Could be more efficient for German compounds")
# Test additional German compound words
additional_tests = [
"Krankenversicherung",
"Donaudampfschifffahrt",
"Rechtsschutzversicherung",
"Arbeitsplatzcomputer"
]
print(f"\nπŸ§ͺ Additional German Compound Tests:")
for word in additional_tests:
tokens = self.apertus.tokenizer.tokenize(word)
efficiency = len(word) / len(tokens)
print(f" '{word}' β†’ {len(tokens)} tokens ({efficiency:.1f} chars/token)")
print(f"\nβœ… Tokenizer comparison completed!")
return comparison_results
def save_complete_log(self, filename: str = None):
"""Save complete command-line output log"""
if filename is None:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"apertus_transparency_log_{timestamp}.txt"
# Get all captured output
log_content = self.log_buffer.getvalue()
# Add header with system info
header = f"""# πŸ‡¨πŸ‡­ Apertus Advanced Transparency Analysis Log
Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
Model: {self.apertus.model_name}
GPU: {self.apertus.device_info['gpu_name'] if self.apertus.device_info['has_gpu'] else 'CPU'}
Memory: {self.apertus.device_info['gpu_memory_gb']:.1f} GB
====================================================================================
COMPLETE COMMAND-LINE OUTPUT CAPTURE:
====================================================================================
"""
# Combine header with all captured output
full_log = header + log_content
# Save log
with open(filename, 'w', encoding='utf-8') as f:
f.write(full_log)
print(f"\nπŸ“ Complete analysis log saved to: {filename}")
print(f"πŸ“Š Log contains {len(log_content)} characters of output")
return filename
def main():
"""Run the advanced transparency toolkit"""
toolkit = AdvancedTransparencyToolkit()
while True:
print("\n🎯 ADVANCED TRANSPARENCY TOOLKIT MENU")
print("=" * 50)
print("1. Native Weights Inspection")
print("2. Real-time Attention Visualization")
print("3. Layer Evolution Real-time Tracking")
print("4. Decision Process Analysis")
print("5. Tokenizer Comparison (Bundesgesundheitsamt)")
print("6. Run All Analyses")
print("7. Save Complete Log")
print("8. Custom Analysis")
print("0. Exit")
try:
choice = input("\nSelect option (0-8): ").strip()
if choice == "0":
print("\nπŸ‘‹ Advanced Transparency Toolkit beendet. Auf Wiedersehen!")
break
elif choice == "1":
layer = input("Enter layer pattern (e.g., 'layers.15.self_attn'): ").strip()
if not layer:
layer = "layers.15.self_attn"
toolkit.native_weights_inspection(layer)
elif choice == "2":
text = input("Enter text for attention analysis: ").strip()
if not text:
text = "Apertus analysiert die Schweizer KI-Transparenz."
toolkit.real_time_attention_visualization(text)
elif choice == "3":
text = input("Enter text for layer tracking: ").strip()
if not text:
text = "Transparenz ist wichtig fΓΌr Vertrauen."
toolkit.layer_evolution_real_time_tracking(text)
elif choice == "4":
prompt = input("Enter prompt for decision analysis: ").strip()
if not prompt:
prompt = "Die Schweizer KI-Forschung ist"
toolkit.decision_process_analysis(prompt)
elif choice == "5":
word = input("Enter word for tokenizer comparison (default: Bundesgesundheitsamt): ").strip()
if not word:
word = "Bundesgesundheitsamt"
toolkit.comprehensive_tokenizer_comparison(word)
elif choice == "6":
print("\nπŸš€ Running all analyses...")
# Start capturing ALL output
toolkit.start_logging()
toolkit.native_weights_inspection()
toolkit.real_time_attention_visualization("Apertus ist transparent.")
toolkit.layer_evolution_real_time_tracking("Schweizer KI-Innovation.")
toolkit.decision_process_analysis("Die Schweizer KI-Forschung ist")
toolkit.comprehensive_tokenizer_comparison("Bundesgesundheitsamt")
# Stop capturing
toolkit.stop_logging()
print("βœ… All analyses completed!")
elif choice == "7":
filename = input("Enter log filename (or press Enter for auto): ").strip()
if not filename:
filename = None
toolkit.save_complete_log(filename)
elif choice == "8":
print("Custom analysis - combine any methods as needed!")
else:
print("Invalid choice, please select 0-8.")
except (KeyboardInterrupt, EOFError):
print("\n\nπŸ‘‹ Advanced toolkit session ended.")
break
except Exception as e:
print(f"\n❌ Error: {e}")
print("Returning to menu...")
if __name__ == "__main__":
main()