ljsysfurry commited on
Commit
a75a35b
·
verified ·
1 Parent(s): f4eeec7

Upload agentframe_quad.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. agentframe_quad.py +65 -21
agentframe_quad.py CHANGED
@@ -13,6 +13,7 @@ AgentFrame 四层融合实现
13
  L4 KVPager — 物理层: 热/温/冷三级换页 + 预测性驱逐
14
  """
15
  import numpy as np
 
16
  from dataclasses import dataclass, field
17
  from typing import Optional, Literal
18
 
@@ -29,6 +30,8 @@ class CompressedKV:
29
  heat: float = 0.5 # 热度 (物理层)
30
  last_access: float = 0.0 # 最后访问时间
31
  size_bytes: int = 0 # 实际字节数
 
 
32
 
33
 
34
  class AbsorbedMLA:
@@ -179,10 +182,51 @@ class LandmarkRouter:
179
  # ============================================================
180
  # L4 物理层: KV 换页 + 预测性驱逐
181
  # ============================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  class KVPager:
183
  """
184
  三级存储: 显存(热) / 内存(温) / 磁盘(冷, mmap)
185
- 预测性驱逐: 注意力衰减 + 访问频率 + 语义相关
186
  """
187
  def __init__(self, vram_limit_mb=10240, ram_limit_mb=32768):
188
  self.vram_limit = vram_limit_mb * 1024 * 1024
@@ -193,16 +237,18 @@ class KVPager:
193
  self.vram_used = 0
194
  self.ram_used = 0
195
  self.access_log = [] # (chunk_id, time, attention_score)
 
196
 
197
  def place(self, kv: CompressedKV, now: float = 0.0):
198
- """放置: 按热度分层"""
199
- if kv.heat >= 0.8:
 
 
200
  if self.vram_used + kv.size_bytes <= self.vram_limit:
201
  self.vram[kv.chunk_id] = kv
202
  self.vram_used += kv.size_bytes
203
  return
204
- kv.heat = 0.6
205
- if kv.heat >= 0.4:
206
  if self.ram_used + kv.size_bytes <= self.ram_limit:
207
  self.ram[kv.chunk_id] = kv
208
  self.ram_used += kv.size_bytes
@@ -210,31 +256,31 @@ class KVPager:
210
  self.disk[kv.chunk_id] = kv
211
 
212
  def access(self, chunk_id: int, attention_score: float, now: float):
213
- """访问: 更新热度 + 日志"""
214
  self.access_log.append((chunk_id, now, attention_score))
215
  kv = self.vram.get(chunk_id) or self.ram.get(chunk_id) or self.disk.get(chunk_id)
216
  if kv:
217
- kv.heat = min(1.0, kv.heat + 0.15)
 
218
  kv.last_access = now
 
 
 
219
  # 磁盘 → 提升
220
- if chunk_id in self.disk and kv.heat >= 0.5:
221
  self.disk.pop(chunk_id)
222
- kv.heat = 0.6
223
  self.place(kv, now)
224
 
225
  def eviction_score(self, kv: CompressedKV, now: float) -> float:
226
- """预测性驱逐分数 (越高越该驱逐)"""
 
 
227
  # 注意力衰减: 最近分数越低越该走
228
  logs = [a for cid, t, a in self.access_log if cid == kv.chunk_id]
229
- if not logs:
230
- return 0.5
231
- attn_decay = 1.0 - np.mean(logs[-5:]) # 最近注意力均值
232
- # 访问频率: 越频繁越留
233
- freq = len(logs) / max(now, 1.0)
234
- access_factor = min(freq * 5, 1.0)
235
  # 时间衰减: 越久没访问越该走
236
- time_decay = min((now - kv.last_access) / 100.0, 1.0)
237
- return 0.5 * attn_decay + 0.3 * (1 - access_factor) + 0.2 * time_decay
238
 
239
  def evict(self, now: float, target_layer: str = "vram"):
240
  """驱逐: 选分数最高的换出"""
@@ -245,11 +291,9 @@ class KVPager:
245
  victim = pool.pop(victim_id)
246
  if target_layer == "vram":
247
  self.vram_used -= victim.size_bytes
248
- victim.heat = 0.5
249
- self.place(victim, now) # 降级到 RAM/DISK
250
  else:
251
  self.ram_used -= victim.size_bytes
252
- victim.heat = 0.2
253
  self.disk[victim_id] = victim
254
  return victim_id
255
 
 
13
  L4 KVPager — 物理层: 热/温/冷三级换页 + 预测性驱逐
14
  """
15
  import numpy as np
16
+ import math
17
  from dataclasses import dataclass, field
18
  from typing import Optional, Literal
19
 
 
30
  heat: float = 0.5 # 热度 (物理层)
31
  last_access: float = 0.0 # 最后访问时间
32
  size_bytes: int = 0 # 实际字节数
33
+ importance: float = 0.5 # 重要性 (遗忘曲线用, 0-1)
34
+ access_count: int = 0 # 访问次数 (遗忘曲线用)
35
 
36
 
37
  class AbsorbedMLA:
 
182
  # ============================================================
183
  # L4 物理层: KV 换页 + 预测性驱逐
184
  # ============================================================
185
+ # ============================================================
186
+ # L4 物理层: KV 换页 + 预测性驱逐 (含遗忘曲线)
187
+ # ============================================================
188
+ class ForgettingCurve:
189
+ """
190
+ 遗忘曲线 (源自 Project-Aura): 决定 KV 块的热度衰减
191
+
192
+ 公式: S(t) = I · 2^(-t / τ)
193
+ 其中:
194
+ S(t) = t 时刻的记忆强度 (热度)
195
+ I = 初始重要性
196
+ τ = 半衰期 (高频访问的块半衰期延长)
197
+ 访问增强: boost = log2(access_count+1) × 0.1
198
+ """
199
+ def __init__(self, default_half_life: float = 100.0):
200
+ # KV 场景时间尺度小 (轮次而非天), 默认 100 轮
201
+ self.default_half_life = default_half_life
202
+
203
+ def compute_half_life(self, kv: CompressedKV) -> float:
204
+ """根据访问频率动态调整半衰期"""
205
+ base = self.default_half_life
206
+ if kv.access_count > 10:
207
+ base *= 7 # 高频访问延至 7×
208
+ elif kv.access_count > 5:
209
+ base *= 3 # 中频延至 3×
210
+ base *= (0.5 + kv.importance) # 高重要性更持久
211
+ return base
212
+
213
+ def strength(self, kv: CompressedKV, now: float) -> float:
214
+ """记忆强度: 指数衰减 + 访问增强 (替代简单线性热度)"""
215
+ elapsed = max(now - kv.last_access, 0.0)
216
+ half_life = self.compute_half_life(kv)
217
+ decay = math.pow(2, -elapsed / half_life)
218
+ boost = math.log2(kv.access_count + 1) * 0.1
219
+ return min(1.0, kv.importance * decay + boost)
220
+
221
+ def should_forget(self, kv: CompressedKV, now: float, threshold: float = 0.15) -> bool:
222
+ """强度低于阈值 → 该换出"""
223
+ return self.strength(kv, now) < threshold
224
+
225
+
226
  class KVPager:
227
  """
228
  三级存储: 显存(热) / 内存(温) / 磁盘(冷, mmap)
229
+ 预测性驱逐: 遗忘曲线强度 + 注意力衰减
230
  """
231
  def __init__(self, vram_limit_mb=10240, ram_limit_mb=32768):
232
  self.vram_limit = vram_limit_mb * 1024 * 1024
 
237
  self.vram_used = 0
238
  self.ram_used = 0
239
  self.access_log = [] # (chunk_id, time, attention_score)
240
+ self.curve = ForgettingCurve() # 遗忘曲线 (Aura 移植)
241
 
242
  def place(self, kv: CompressedKV, now: float = 0.0):
243
+ """放置: 按遗忘曲线强度分层"""
244
+ strength = self.curve.strength(kv, now)
245
+ kv.heat = strength
246
+ if strength >= 0.6:
247
  if self.vram_used + kv.size_bytes <= self.vram_limit:
248
  self.vram[kv.chunk_id] = kv
249
  self.vram_used += kv.size_bytes
250
  return
251
+ if strength >= 0.3:
 
252
  if self.ram_used + kv.size_bytes <= self.ram_limit:
253
  self.ram[kv.chunk_id] = kv
254
  self.ram_used += kv.size_bytes
 
256
  self.disk[kv.chunk_id] = kv
257
 
258
  def access(self, chunk_id: int, attention_score: float, now: float):
259
+ """访问: 更新访问计数 + 重要性 + 日志"""
260
  self.access_log.append((chunk_id, now, attention_score))
261
  kv = self.vram.get(chunk_id) or self.ram.get(chunk_id) or self.disk.get(chunk_id)
262
  if kv:
263
+ kv.access_count += 1
264
+ kv.importance = min(1.0, kv.importance + abs(attention_score) * 0.05)
265
  kv.last_access = now
266
+ # 重新计算强度并分层
267
+ strength = self.curve.strength(kv, now)
268
+ kv.heat = strength
269
  # 磁盘 → 提升
270
+ if chunk_id in self.disk and strength >= 0.5:
271
  self.disk.pop(chunk_id)
 
272
  self.place(kv, now)
273
 
274
  def eviction_score(self, kv: CompressedKV, now: float) -> float:
275
+ """预测性驱逐分数 (越高越该驱逐): 遗忘曲线 + 注意��衰减"""
276
+ # 遗忘曲线: 强度越低越该走 (主因子)
277
+ forget_factor = 1.0 - self.curve.strength(kv, now)
278
  # 注意力衰减: 最近分数越低越该走
279
  logs = [a for cid, t, a in self.access_log if cid == kv.chunk_id]
280
+ attn_decay = 1.0 - np.mean(logs[-5:]) if logs else 0.5
 
 
 
 
 
281
  # 时间衰减: 越久没访问越该走
282
+ time_decay = min((now - kv.last_access) / self.curve.compute_half_life(kv), 1.0)
283
+ return 0.5 * forget_factor + 0.3 * attn_decay + 0.2 * time_decay
284
 
285
  def evict(self, now: float, target_layer: str = "vram"):
286
  """驱逐: 选分数最高的换出"""
 
291
  victim = pool.pop(victim_id)
292
  if target_layer == "vram":
293
  self.vram_used -= victim.size_bytes
294
+ self.place(victim, now) # 降级到 RAM/DISK (按遗忘曲线自动分)
 
295
  else:
296
  self.ram_used -= victim.size_bytes
 
297
  self.disk[victim_id] = victim
298
  return victim_id
299