-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtrajectory.py
91 lines (77 loc) · 3.59 KB
/
trajectory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import numpy as np
import torch
import itertools
N = 10 # num_clients at current round
# smooth with EMA
def smooth_client_gradients(historical_grads, client_grads, beta):
smoothed_grads = {}
for client_id, grads in client_grads.items():
smoothed_grads[client_id] = {}
for name, grad in grads.items():
historical_grad = historical_grads[client_id][name]
updated_grad = beta * historical_grad + (1 - beta) * grad
historical_grads[client_id][name] = updated_grad
smoothed_grads[client_id][name] = updated_grad
return smoothed_grads
# stat of each neuron's historical gradients
def gradient_statistics_neuron(historical_grads):
stats = {}
for client_id, client_historical_grads in historical_grads.items():
stats[client_id] = {}
for param_name, gradients in client_historical_grads.items():
# Assuming gradients are 2D (for fully connected layers) or 4D (for convolutional layers)
# Adjust the following line if your layers have a different structure
for neuron_idx, neuron_grad in enumerate(gradients.view(-1, gradients.size(-1))):
grad_array = neuron_grad.detach().cpu().numpy()
neuron_stats = {
'mean': np.mean(grad_array),
'max': np.max(grad_array),
'min': np.min(grad_array),
'std': np.std(grad_array),
'95th': np.percentile(grad_array, 95),
'85th': np.percentile(grad_array, 85),
'75th': np.percentile(grad_array, 75),
'50th': np.percentile(grad_array, 50), # Median
'25th': np.percentile(grad_array, 25),
'15th': np.percentile(grad_array, 15),
'5th': np.percentile(grad_array, 5),
}
stats[client_id][(param_name, neuron_idx)] = neuron_stats
return stats
# stat of each layer's historical gradients
def gradient_statistics_layer(historical_grads):
stats = {}
for client_id, client_historical_grads in historical_grads.items():
stats[client_id] = {}
for layer_name, layer_grads in client_historical_grads.items():
grad_array = layer_grads.detach().cpu().numpy().flatten()
layer_stats = {
'mean': np.mean(grad_array),
'max': np.max(grad_array),
'min': np.min(grad_array),
'std': np.std(grad_array),
'95th': np.percentile(grad_array, 95),
'85th': np.percentile(grad_array, 85),
'75th': np.percentile(grad_array, 75),
'50th': np.percentile(grad_array, 50), # Median
'25th': np.percentile(grad_array, 25),
'15th': np.percentile(grad_array, 15),
'5th': np.percentile(grad_array, 5),
}
stats[client_id][layer_name] = layer_stats
return stats
# cos similarity between clients
def cos_similarity_matrix(gradients):
cosine_similarities = torch.zeros((N, N))
for i in range(N):
for j in range(i, N): # Start from i to avoid redundant calculations
if i == j:
cosine_similarities[i, j] = 1
else:
similarity = torch.nn.functional.cosine_similarity(
gradients[i].flatten(),
gradients[j].flatten(),
dim=0, eps=1e-10)
cosine_similarities[i, j] = similarity
cosine_similarities[j, i] = similarity
return cosine_similarities