SemanticCommunication/code/ARCHITECTURE.md

16 KiB
Raw Blame History

架构设计文档 / Architecture Document

系统全局视图 / System Overview

┌─────────────────────────────────────────────────────────────────┐
│                        train.py (入口)                          │
│  CLI 解析 → 加载配置 → 初始化环境+算法 → 训练循环 → 保存模型    │
└──────────┬──────────────────────────────────┬───────────────────┘
           │                                  │
           ▼                                  ▼
┌─────────────────────┐          ┌──────────────────────────┐
│   envs/ (环境层)     │          │  agents/ + baselines/    │
│                     │          │     (算法层)              │
│  WirelessEnv        │◄────────►│  CoMADDPG / 7 baselines  │
│  ├─ ChannelModel    │  obs,    │  ├─ Actor (策略网络)      │
│  ├─ SemanticModule  │  reward, │  ├─ Critic (价值网络)     │
│  └─ step/reset      │  done    │  ├─ ReplayBuffer          │
└─────────────────────┘          │  └─ OUNoise               │
                                 └──────────────────────────┘
                                            │
                                            ▼
                                 ┌──────────────────────────┐
                                 │    utils/ (工具层)        │
                                 │  metrics.py  (评估指标)   │
                                 │  visualization.py (绘图)  │
                                 └──────────────────────────┘
                                            │
                                            ▼
                                 ┌──────────────────────────┐
                                 │   evaluate.py (评估入口)  │
                                 │   8 场景 × 12+ 张图       │
                                 └──────────────────────────┘

模块依赖关系 / Module Dependencies

configs/default.yaml
    │
    ├──► envs/channel_model.py      (读取 env.carrier_freq, env.noise_psd, env.subcarrier_spacing)
    ├──► envs/semantic_module.py    (读取 env.rho_max, env.rho_min, env.w1, env.w2)
    ├──► envs/wireless_env.py       (读取 env.* 和 training.max_steps)
    │        ├── uses ChannelModel
    │        └── uses SemanticModule
    │
    ├──► agents/co_maddpg.py        (读取 env.num_subcarriers, training.*, network.*, reward.*)
    │        ├── uses Actor          (agents/actor.py)
    │        ├── uses Critic         (agents/critic.py)
    │        ├── uses ReplayBuffer   (agents/replay_buffer.py)
    │        └── uses OUNoise        (agents/noise.py)
    │
    ├──► baselines/*.py             (各基线复用 Actor, Critic, ReplayBuffer, OUNoise)
    │
    └──► utils/metrics.py           (读取 reward.* 权重)
         utils/visualization.py     (独立,无配置依赖)

数据流 / Data Flow

训练循环(单个 Episode

                     ┌─── Episode 开始 ───┐
                     │                     │
                     ▼                     │
              env.reset()                  │
              → (obs_s, obs_b)             │
                     │                     │
         ┌───► Step 循环 (200 步) ◄────┐  │
         │           │                  │  │
         │     agent.select_action      │  │
         │     (obs_s) → act_s          │  │
         │     (obs_b) → act_b          │  │
         │           │                  │  │
         │     env.step(act_s, act_b)   │  │
         │     → (obs_s', obs_b',       │  │
         │        rew_s, rew_b,         │  │
         │        done, info)           │  │
         │           │                  │  │
         │     agent.compute_rewards    │  │
         │     (info) → (r_s, r_b)      │  │
         │           │                  │  │
         │     buffer.push(             │  │
         │       obs_s, obs_b,          │  │
         │       act_s, act_b,          │  │
         │       r_s, r_b,             │  │
         │       obs_s', obs_b',        │  │
         │       done)                  │  │
         │           │                  │  │
         │     agent.update()           │  │
         │           │                  │  │
         │     not done ────────────────┘  │
         │                                 │
         └─── done ─── noise.decay() ──────┘
                          │
                    save model + log

环境 step() 内部流程8 步)

Action Decode        Subcarrier Alloc       Power Alloc
(act_s, act_b)  →   Greedy by channel  →   Equal within group
     │                    │                      │
     ▼                    ▼                      ▼
  n_sub_s, n_sub_b   sem_subs, trad_subs   power_matrix (K×N)
                          │                      │
                          ▼                      ▼
                    ┌─── SNR = p·|h|²/σ² ───┐
                    │                        │
          ┌─────────┴──────┐      ┌──────────┴──────┐
          │ Traditional    │      │ Semantic         │
          │ Rate = Σ Δf·   │      │ avg_SNR →        │
          │   log₂(1+γ)   │      │ SSim(γ̄, ρ) →    │
          │ QoE_b = min    │      │ QoE_s = w1·SSim  │
          │  (R/R_req, 1)  │      │  + w2·(1-ρ/ρ_max)│
          └───────┬────────┘      └────────┬─────────┘
                  │                        │
                  └────────┬───────────────┘
                           ▼
                    QoE_sys = mean(all QoE)
                           │
                    Regenerate channel (block fading)
                           │
                    Build (obs_s', obs_b', rew_s, rew_b, done, info)

Co-MADDPG Stackelberg 更新机制 / Stackelberg Update Mechanism

这是本算法的核心创新。更新顺序体现了 Leader-Follower 博弈结构:

┌─────────────────────────────────────────────────────────────────┐
│                    Stackelberg Update                           │
│                                                                 │
│  PHASE 1: 更新 Follower (Agent B) / Update Follower First      │
│  ┌───────────────────────────────────────────────────────┐     │
│  │  1. Critic B: L_B = (Q_B(s,a) - y_B)²                │     │
│  │     y_B = r_B + γ·Q_B'(s', a_s'_target, a_b'_target) │     │
│  │  2. Actor B:  max Q_B(s, a_s_current, π_B(o_b))      │     │
│  │  3. Soft update: θ_B_target ← τ·θ_B + (1-τ)·θ_B_tgt │     │
│  └───────────────────────────────────────────────────────┘     │
│                          │                                      │
│                          ▼ (B's policy is now updated)          │
│                                                                 │
│  PHASE 2: 更新 Leader (Agent S) / Update Leader with B's BR    │
│  ┌───────────────────────────────────────────────────────┐     │
│  │  1. Get B's best response: a_b_br = π_B_updated(o_b)  │     │
│  │     .detach() — 不反传梯度给 B                         │     │
│  │  2. Critic S: L_S = (Q_S(s, a) - y_S)²               │     │
│  │  3. Actor S:  max Q_S(s, π_S(o_s), a_b_br)           │     │
│  │     Leader 优化时考虑了 Follower 的最优响应              │     │
│  │  4. Soft update: θ_S_target ← τ·θ_S + (1-τ)·θ_S_tgt │     │
│  └───────────────────────────────────────────────────────┘     │
│                                                                 │
│  PHASE 3: 更新动态 λ / Update Dynamic λ                        │
│  ┌───────────────────────────────────────────────────────┐     │
│  │  λ(t) = sigmoid(β · (QoE_sys - Q_th))                │     │
│  │  β=5.0 控制切换陡度Q_th=0.6 为切换阈值               │     │
│  └───────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────────┘

奖励计算流程 / Reward Computation Flow

              env.step() 输出 info dict
                      │
            ┌─────────┴─────────┐
            │ qoe_semantic      │
            │ qoe_traditional   │
            │ qoe_sys           │
            └─────────┬─────────┘
                      │
              agent.compute_rewards(info)
                      │
         ┌────────────┴────────────┐
         ▼                         ▼
   r_coop_s =                r_coop_b =
   0.5·qoe_s +              0.5·qoe_b +
   0.3·qoe_b +              0.3·qoe_s +
   0.2·qoe_sys              0.2·qoe_sys
         │                         │
   r_comp_s =                r_comp_b =
   0.8·qoe_s +              0.8·qoe_b +
   0.2·qoe_sys              0.2·qoe_sys
         │                         │
         └────────────┬────────────┘
                      │
              λ = sigmoid(β·(qoe_sys - Q_th))
                      │
              r_s = λ·r_coop_s + (1-λ)·r_comp_s
              r_b = λ·r_coop_b + (1-λ)·r_comp_b

观察空间与动作空间 / Observation & Action Spaces

观察空间 (obs_dim = N + 4 = 68)

维度 内容 (语义 Agent S) 内容 (传统 Agent B)
[0 : N] 语义用户平均信道功率 (归一化) 传统用户平均信道功率 (归一化)
[N] qoe_avg_s (滚动平均 QoE) qoe_avg_b (滚动平均 QoE)
[N+1] content_sensitivity business_priority
[N+2] alloc_s (当前子载波分配比) alloc_b (当前子载波分配比)
[N+3] load_s (流量负载) load_b (流量负载)

动作空间 (act_dim = 3, 连续 [0,1])

维度 含义 (语义 Agent S) 含义 (传统 Agent B)
[0] 请求子载波比例 n_sub_frac 请求子载波比例 n_sub_frac
[1] 功率分配比例 p_frac 功率分配比例 p_frac
[2] 压缩率 ρ (映射到 [ρ_min, ρ_max]) 冗余参数 (未使用)

网络架构 / Network Architecture

Actor Network

Input: obs (68,)
  │
  ├─ Linear(68 → 256) + ReLU
  ├─ Linear(256 → 256) + ReLU
  ├─ Linear(256 → 128) + ReLU
  ├─ Linear(128 → 3)
  └─ (Tanh + 1) / 2  →  output ∈ [0, 1]³

Critic Network (Joint, CTDE)

Input: concat(obs_s, obs_b, act_s, act_b) = (142,)
  │
  ├─ Linear(142 → 512) + ReLU
  ├─ Linear(512 → 512) + ReLU
  ├─ Linear(512 → 256) + ReLU
  └─ Linear(256 → 1)  →  Q-value (scalar)

经验回放 / Replay Buffer

9-field transitions:

Transition = (obs_s, obs_b, act_s, act_b, rew_s, rew_b, next_obs_s, next_obs_b, done)
              (68,)   (68,)  (3,)   (3,)   (1,)   (1,)    (68,)       (68,)      (1,)
  • 容量: 100,000 transitions
  • 采样: 均匀随机采样 batch_size=256
  • 存储: deque 结构FIFO 淘汰

Agent 接口契约 / Agent Interface Contract

所有 8 个算法必须实现以下接口,以兼容 train.py 的训练循环:

class AgentInterface:
    # 必须有以下属性之一
    self.buffer: ReplayBuffer      # 优先检查
    self.replay_buffer: ReplayBuffer  # 备选

    # 选择动作
    def select_action(obs_s, obs_b, explore=True) -> (act_s, act_b)

    # 计算奖励
    def compute_rewards(info) -> (rew_s, rew_b)

    # 更新网络
    def update() -> dict or None

    # 保存/加载模型
    def save(path)
    def load(path)

    # 噪声衰减 (可选train.py 通过 hasattr 检查)
    self.noise_s: OUNoise  # 需有 decay_sigma(episode) 方法
    self.noise_b: OUNoise

信道模型 / Channel Model

基于 3GPP Urban Micro (UMi) NLOS 模型:

距离: d ~ U(50, 500) 米
路径损耗: PL(d) = 36.7·log₁₀(d) + 22.7 + 26·log₁₀(fc)   [dB]
信道增益: h_{k,n} ~ CN(0, 10^{-PL/10})   (Rayleigh fading)
噪声功率: σ² = 10^{(N₀_dBm - 30)/10} · Δf   [W]
SNR:     γ_{k,n} = p_{k,n} · |h_{k,n}|² / σ²
  • 块衰落模型 (Block fading): 每个 step 重新生成信道
  • K_s=3 语义用户 + K_b=3 传统用户 = 6 users
  • N=64 个 OFDM 子载波
  • 子载波分配: 贪婪算法 (语义用户优先)
  • 功率分配: 组内均分

设计决策 / Design Decisions

1. 为什么用 Stackelberg 而不是 Nash

  • Stackelberg 适合异构场景:语义用户 (Leader) 先决策,传统用户 (Follower) 最优响应
  • 保证了均衡存在性(定理 1-2 在论文中证明)

2. 为什么 λ(t) 用 sigmoid

  • 连续可微,适合梯度训练
  • β 参数控制切换陡度Q_th 控制切换点
  • 系统 QoE 高时偏合作 (λ→1),低时偏竞争 (λ→0)

3. 为什么观察空间包含额外 4 维?

  • 仅信道信息不够agent 需要知道当前 QoE 水平、流量负载、分配状况
  • 这些额外信息帮助 agent 做出更有环境感知的决策

4. 为什么 Critic 是联合的 (CTDE)

  • 集中训练时可访问所有信息,解决非平稳性问题
  • 分散执行时只用各自的 Actor降低通信开销

5. 为什么语义用户优先分配子载波?

  • 体现 Leader 的先动优势 (First-mover advantage)
  • 与 Stackelberg 博弈结构一致