Chrizz67 commited on
Commit
fcbd781
·
verified ·
1 Parent(s): af2ed30

Main file for hds-deep

Browse files
Files changed (1) hide show
  1. hds-deep.py +223 -0
hds-deep.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from sklearn.base import BaseEstimator, OutlierMixin
3
+ from sklearn.preprocessing import RobustScaler
4
+ from sklearn.neighbors import NearestNeighbors, KDTree
5
+ from sklearn.decomposition import PCA
6
+
7
+
8
+ class HDS(BaseEstimator, OutlierMixin):
9
+ def __init__(
10
+ self,
11
+ scales=(5, 10, 20),
12
+ contamination=0.12,
13
+ memory_capacity=500,
14
+ random_state=42,
15
+ ):
16
+ self.scales = scales
17
+ self.contamination = contamination
18
+ self.memory_capacity = memory_capacity
19
+ self.random_state = random_state
20
+
21
+ self.rag_memory_keys = None
22
+ self.rag_memory_vals = None
23
+
24
+ @staticmethod
25
+ def _rank_score(values):
26
+ values = np.asarray(values, dtype=float)
27
+ order = np.argsort(values, kind="mergesort")
28
+ ranks = np.empty(len(values), dtype=float)
29
+ ranks[order] = np.arange(len(values), dtype=float)
30
+ if len(values) > 1:
31
+ ranks /= len(values) - 1
32
+ return ranks
33
+
34
+ def _update_rag_memory(self, Z, scores):
35
+ if self.rag_memory_keys is None:
36
+ self.rag_memory_keys = Z.copy()
37
+ self.rag_memory_vals = scores.copy()
38
+ else:
39
+ if len(self.rag_memory_keys) > self.memory_capacity:
40
+ self.rag_memory_keys = self.rag_memory_keys[-self.memory_capacity:]
41
+ self.rag_memory_vals = self.rag_memory_vals[-self.memory_capacity:]
42
+ self.rag_memory_keys = np.vstack([self.rag_memory_keys, Z])
43
+ self.rag_memory_vals = np.concatenate([self.rag_memory_vals, scores])
44
+
45
+ def _rag_retrieval_co_thought(self, Z):
46
+ if self.rag_memory_keys is None:
47
+ return np.zeros(len(Z))
48
+ sim_matrix = np.dot(Z, self.rag_memory_keys.T)
49
+ top_k_indices = np.argsort(sim_matrix, axis=1)[:, -5:]
50
+ retrieved_signals = np.zeros(len(Z))
51
+ for i in range(len(Z)):
52
+ retrieved_signals[i] = np.mean(self.rag_memory_vals[top_k_indices[i]])
53
+ return self._rank_score(retrieved_signals)
54
+
55
+ def _deterministic_attention_engine(self, tokens_matrix):
56
+ cov = np.cov(tokens_matrix, rowvar=False) + 1e-5 * np.eye(tokens_matrix.shape[1])
57
+ inv_cov = np.linalg.pinv(cov)
58
+
59
+ attention_energy = np.array([np.dot(row, np.dot(inv_cov, row.T)) for row in tokens_matrix])
60
+ attention_weights = 1.0 / (1.0 + attention_energy)
61
+
62
+ fused_scores = np.dot(tokens_matrix, np.array([0.30, 0.55, 0.15])) * (1.0 + attention_weights)
63
+ return self._rank_score(fused_scores)
64
+
65
+ def fit(self, X, y=None):
66
+ X = np.asarray(X, dtype=float)
67
+ if X.ndim != 2:
68
+ raise ValueError("X must be a 2D array.")
69
+ if len(X) < 8:
70
+ raise ValueError("At least 8 samples are required.")
71
+ if not np.isfinite(X).all():
72
+ raise ValueError("X contains NaN or infinite values.")
73
+ if not 0 <= self.contamination < 0.5:
74
+ raise ValueError("contamination must be in [0, 0.5).")
75
+
76
+ self._fit_X = X.copy()
77
+ self.scaler_ = RobustScaler()
78
+ Z = self.scaler_.fit_transform(X)
79
+
80
+ self.n_samples_in_ = len(Z)
81
+ self.n_features_in_ = Z.shape[1]
82
+
83
+ self.scales_ = sorted({max(2, min(int(k), len(Z) - 1)) for k in self.scales})
84
+ sg_list = []
85
+ cov_matrix = np.cov(Z, rowvar=False) + 1e-5 * np.eye(self.n_features_in_)
86
+ inv_cov = np.linalg.pinv(cov_matrix)
87
+
88
+ for k in self.scales_:
89
+ nbrs = NearestNeighbors(n_neighbors=k + 1, metric="euclidean").fit(Z)
90
+ distances, _ = nbrs.kneighbors(Z)
91
+ euc_radius = np.maximum(distances[:, -1], 1e-12)
92
+ mah_radius = np.array([np.sqrt(np.dot(row.T, np.dot(inv_cov, row))) for row in Z])
93
+ hybrid_global = 0.5 * euc_radius + 0.5 * mah_radius
94
+ sg_list.append(self._rank_score(hybrid_global))
95
+
96
+ self.S_G_ = np.mean(sg_list, axis=0)
97
+
98
+ n_samples = len(Z)
99
+ k_ln = min(max(15, self.n_features_in_ * 3), n_samples - 1)
100
+ nbrs_ln = NearestNeighbors(n_neighbors=k_ln + 1, metric="euclidean").fit(Z)
101
+ _, indices_ln = nbrs_ln.kneighbors(Z)
102
+
103
+ local_recon_errors = np.zeros(n_samples)
104
+ global_pca = PCA(n_components=max(1, self.n_features_in_ - 1), random_state=self.random_state)
105
+ global_pca.fit(Z)
106
+ global_errors = np.linalg.norm(Z - global_pca.inverse_transform(global_pca.transform(Z)), axis=1)
107
+
108
+ for i in range(n_samples):
109
+ neighbors_idx = indices_ln[i]
110
+ local_data = Z[neighbors_idx]
111
+ if len(local_data) <= self.n_features_in_:
112
+ local_recon_errors[i] = global_errors[i]
113
+ continue
114
+ n_comp_local = max(1, min(self.n_features_in_ - 1, len(local_data) - 2))
115
+ local_pca = PCA(n_components=n_comp_local, random_state=self.random_state)
116
+ try:
117
+ local_pca.fit(local_data)
118
+ z_i = Z[i].reshape(1, -1)
119
+ z_proj = local_pca.transform(z_i)
120
+ z_recon = local_pca.inverse_transform(z_proj)
121
+ local_recon_errors[i] = np.linalg.norm(z_i - z_recon)
122
+ except Exception:
123
+ local_recon_errors[i] = global_errors[i]
124
+
125
+ hybrid_residuals = 0.6 * local_recon_errors + 0.4 * global_errors
126
+ self.train_residuals_ = hybrid_residuals
127
+ self.S_LN_ = self._rank_score(hybrid_residuals)
128
+
129
+ self.kdtree_ = KDTree(Z, leaf_size=max(10, n_samples // 10))
130
+ node_depths = []
131
+ for z_i in Z:
132
+ dist, _ = self.kdtree_.query(z_i.reshape(1, -1), k=min(10, n_samples))
133
+ node_depths.append(dist[0][-1])
134
+
135
+ self.train_tn_raw_ = np.array(node_depths)
136
+ self.S_TN_ = self._rank_score(self.train_tn_raw_)
137
+
138
+ tokens = np.column_stack([self.S_G_, self.S_LN_, self.S_TN_])
139
+ attention_scores = self._deterministic_attention_engine(tokens)
140
+
141
+ self._update_rag_memory(Z, attention_scores)
142
+ rag_context = self._rag_retrieval_co_thought(Z)
143
+
144
+ self.decision_scores_ = self._rank_score(0.75 * attention_scores + 0.25 * rag_context)
145
+
146
+ threshold_index = int(np.floor((1 - self.contamination) * len(self.decision_scores_)))
147
+ threshold_index = min(max(threshold_index, 0), len(self.decision_scores_) - 1)
148
+ self.threshold_ = np.sort(self.decision_scores_)[threshold_index]
149
+ self.labels_ = np.where(self.decision_scores_ >= self.threshold_, -1, 1)
150
+
151
+ return self
152
+
153
+ def score_samples(self, X):
154
+ X = np.asarray(X, dtype=float)
155
+ Z = self.scaler_.transform(X)
156
+ ref = self.scaler_.transform(self._fit_X)
157
+ n_query = len(Z)
158
+
159
+ cov_matrix = np.cov(ref, rowvar=False) + 1e-5 * np.eye(self.n_features_in_)
160
+ inv_cov = np.linalg.pinv(cov_matrix)
161
+
162
+ sg_list = []
163
+ for k in self.scales_:
164
+ k_eff = min(k, len(ref))
165
+ nbrs = NearestNeighbors(n_neighbors=k_eff, metric="euclidean").fit(ref)
166
+ distances, _ = nbrs.kneighbors(Z)
167
+ euc_radius = np.maximum(distances[:, -1], 1e-12)
168
+ mah_radius = np.array([np.sqrt(np.dot(row.T, np.dot(inv_cov, row))) for row in Z])
169
+ hybrid_global = 0.5 * euc_radius + 0.5 * mah_radius
170
+
171
+ train_nbrs = NearestNeighbors(n_neighbors=min(k + 1, len(ref)), metric="euclidean").fit(ref)
172
+ train_dist, _ = train_nbrs.kneighbors(ref)
173
+ train_euc = np.maximum(train_dist[:, -1], 1e-12)
174
+ train_mah = np.array([np.sqrt(np.dot(row.T, np.dot(inv_cov, row))) for row in ref])
175
+ train_hybrid = 0.5 * train_euc + 0.5 * train_mah
176
+
177
+ global_rank = np.searchsorted(np.sort(train_hybrid), hybrid_global) / len(train_hybrid)
178
+ sg_list.append(global_rank)
179
+ S_G_q = np.mean(sg_list, axis=0)
180
+
181
+ k_ln = min(max(15, self.n_features_in_ * 3), len(ref))
182
+ nbrs_ln = NearestNeighbors(n_neighbors=k_ln + 1, metric="euclidean").fit(ref)
183
+ _, indices_ln = nbrs_ln.kneighbors(Z)
184
+
185
+ global_pca = PCA(n_components=max(1, self.n_features_in_ - 1), random_state=self.random_state).fit(ref)
186
+ global_errors_q = np.linalg.norm(Z - global_pca.inverse_transform(global_pca.transform(Z)), axis=1)
187
+
188
+ local_recon_errors_q = np.zeros(n_query)
189
+ for i in range(n_query):
190
+ neighbors_idx = indices_ln[i]
191
+ local_data = ref[neighbors_idx]
192
+ if len(local_data) <= self.n_features_in_:
193
+ local_recon_errors_q[i] = global_errors_q[i]
194
+ continue
195
+ n_comp_local = max(1, min(self.n_features_in_ - 1, len(local_data) - 2))
196
+ local_pca = PCA(n_components=n_comp_local, random_state=self.random_state)
197
+ try:
198
+ local_pca.fit(local_data)
199
+ z_i = Z[i].reshape(1, -1)
200
+ z_proj = local_pca.transform(z_i)
201
+ z_recon = local_pca.inverse_transform(z_proj)
202
+ local_recon_errors_q[i] = np.linalg.norm(z_i - z_recon)
203
+ except Exception:
204
+ local_recon_errors_q[i] = global_errors_q[i]
205
+
206
+ hybrid_residuals_q = 0.6 * local_recon_errors_q + 0.4 * global_errors_q
207
+ S_LN_q = np.searchsorted(np.sort(self.train_residuals_), hybrid_residuals_q) / len(self.train_residuals_)
208
+
209
+ q_dist, _ = self.kdtree_.query(Z, k=min(10, len(ref)))
210
+ S_TN_q = np.searchsorted(np.sort(self.train_tn_raw_), q_dist[:, -1]) / len(self.train_tn_raw_)
211
+
212
+ tokens_q = np.column_stack([S_G_q, S_LN_q, S_TN_q])
213
+ attention_scores_q = self._deterministic_attention_engine(tokens_q)
214
+
215
+ rag_context_q = self._rag_retrieval_co_thought(Z)
216
+ return self._rank_score(0.75 * attention_scores_q + 0.25 * rag_context_q)
217
+
218
+ def predict(self, X):
219
+ return np.where(self.score_samples(X) >= self.threshold_, -1, 1)
220
+
221
+ def fit_predict(self, X, y=None):
222
+ self.fit(X, y)
223
+ return self.labels_