SemanticCommunication/code/API.md

600 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# API 接口文档 / API Reference
本文档详细描述了 Co-MADDPG 项目中所有公开类和函数的接口。
---
## 目录 / Table of Contents
1. [环境模块 envs/](#1-环境模块-envs)
- [ChannelModel](#channelmodel)
- [SemanticModule](#semanticmodule)
- [WirelessEnv](#wirelessenv)
2. [算法模块 agents/](#2-算法模块-agents)
- [Actor](#actor)
- [Critic](#critic)
- [OUNoise](#ounoise)
- [ReplayBuffer](#replaybuffer)
- [CoMADDPG](#comaddpg)
3. [基线模块 baselines/](#3-基线模块-baselines)
- [通用接口](#通用接口--common-interface)
- [各基线差异](#各基线差异--baseline-differences)
4. [工具模块 utils/](#4-工具模块-utils)
- [metrics.py](#metricspy)
- [visualization.py](#visualizationpy)
5. [入口脚本](#5-入口脚本--entry-scripts)
- [train.py](#trainpy)
- [evaluate.py](#evaluatepy)
---
## 1. 环境模块 envs/
### ChannelModel
**文件**: `envs/channel_model.py`
3GPP Urban Micro NLOS 信道模型,负责路径损耗计算、复信道增益生成和 SNR 计算。
```python
class ChannelModel:
def __init__(self, config: dict) -> None
```
| 参数 | 类型 | 说明 |
|---|---|---|
| `config` | dict | 完整配置字典,需包含 `config["env"]["carrier_freq"]`, `config["env"]["noise_psd"]`, `config["env"]["subcarrier_spacing"]` |
#### 方法
**`path_loss(distance) -> float`**
计算 3GPP UMi NLOS 路径损耗。
| 参数 | 类型 | 说明 |
|---|---|---|
| `distance` | float / np.ndarray | 收发机距离 (米) |
| **返回** | float / np.ndarray | 路径损耗 (dB) |
公式: `PL(d) = 36.7·log₁₀(d) + 22.7 + 26·log₁₀(fc)`
---
**`generate_channel(distances, num_subcarriers) -> np.ndarray`**
生成复信道增益矩阵。
| 参数 | 类型 | 说明 |
|---|---|---|
| `distances` | np.ndarray (K,) | 每个用户的距离 |
| `num_subcarriers` | int | 子载波数 N |
| **返回** | np.ndarray (K, N) | 复信道增益 `h_{k,n} ~ CN(0, 10^{-PL/10})` |
---
**`compute_snr(channel_gains, power_alloc, noise_power) -> np.ndarray`**
计算每用户每子载波的 SNR。
| 参数 | 类型 | 说明 |
|---|---|---|
| `channel_gains` | np.ndarray (K, N) | 复信道增益 |
| `power_alloc` | np.ndarray (K, N) | 功率分配矩阵 (W) |
| `noise_power` | float | 每子载波噪声功率 σ² (W) |
| **返回** | np.ndarray (K, N) | SNR (线性尺度) |
公式: `γ_{k,n} = p_{k,n} · |h_{k,n}|² / σ²`
---
**`noise_power` (property) -> float**
每子载波热噪声功率 (W)。
公式: `σ² = 10^{(N₀_dBm - 30)/10} · Δf`
---
### SemanticModule
**文件**: `envs/semantic_module.py`
语义通信质量模块,计算 SSim 和语义 QoE。
```python
class SemanticModule:
def __init__(self, config: dict) -> None
```
| 参数 | 类型 | 说明 |
|---|---|---|
| `config` | dict | 需包含 `config["env"]["rho_max"]`, `rho_min`, `w1`, `w2` |
#### 方法
**`compute_ssim(avg_snr, rho) -> float`**
计算语义相似度指数。
| 参数 | 类型 | 说明 |
|---|---|---|
| `avg_snr` | float / np.ndarray | 平均 SNR (线性尺度) |
| `rho` | float | 压缩率 ρ ∈ [ρ_min, ρ_max] |
| **返回** | float / np.ndarray | SSim ∈ [0, 1] |
公式: `φ(γ̄, ρ) = 1 - exp(-a(ρ)·γ̄^{b(ρ)})`,其中 `a(ρ) = 0.8/(ρ+0.1)`, `b(ρ) = 0.6+0.2·ρ`
---
**`compute_avg_snr(snr_per_subcarrier, allocation_mask) -> float`**
计算已分配子载波的平均 SNR。
| 参数 | 类型 | 说明 |
|---|---|---|
| `snr_per_subcarrier` | np.ndarray | 所有子载波的 SNR |
| `allocation_mask` | np.ndarray | 二进制掩码 (1=已分配) |
| **返回** | float | 平均 SNR (无分配时返回 0.0) |
---
**`compute_semantic_qoe(ssim, rho, w1=None, w2=None, rho_max=None) -> float`**
计算语义用户 QoE。
| 参数 | 类型 | 说明 |
|---|---|---|
| `ssim` | float | 语义相似度 ∈ [0, 1] |
| `rho` | float | 压缩率 |
| `w1`, `w2` | float, optional | 权重 (默认使用配置值) |
| `rho_max` | float, optional | 最大压缩率 (默认使用配置值) |
| **返回** | float | QoE ∈ [0, 1] |
公式: `QoE_s = w1·SSim + w2·(1 - ρ/ρ_max)`
---
### WirelessEnv
**文件**: `envs/wireless_env.py`
Gym 风格的无线资源分配环境,管理信道状态、执行动作、计算 QoE。
```python
class WirelessEnv:
def __init__(self, config: dict)
```
| 属性 | 类型 | 说明 |
|---|---|---|
| `obs_dim` | int (property) | 观察维度 = N + 4 |
| `act_dim` | int (property) | 动作维度 = 3 |
| `N` | int | 子载波数量 |
| `K_s`, `K_b`, `K` | int | 语义/传统/总用户数 |
#### 方法
**`reset() -> (obs_s, obs_b)`**
重置环境。随机化用户距离、信道、辅助参数。
| 返回 | 类型 | 说明 |
|---|---|---|
| `obs_s` | np.ndarray (obs_dim,) | 语义 agent 观察 (float32) |
| `obs_b` | np.ndarray (obs_dim,) | 传统 agent 观察 (float32) |
---
**`step(action_s, action_b) -> (obs_s, obs_b, reward_s, reward_b, done, info)`**
执行一步。
| 参数 | 类型 | 说明 |
|---|---|---|
| `action_s` | np.ndarray (3,) | 语义 agent 动作 [sub_frac, power_frac, rho] |
| `action_b` | np.ndarray (3,) | 传统 agent 动作 [sub_frac, power_frac, _] |
| 返回 | 类型 | 说明 |
|---|---|---|
| `obs_s`, `obs_b` | np.ndarray | 新观察 |
| `reward_s`, `reward_b` | float | 各自平均 QoE作为基础奖励 |
| `done` | bool | 是否达到 max_steps |
| `info` | dict | 详细信息(见下表) |
**info 字典内容:**
| Key | 类型 | 说明 |
|---|---|---|
| `qoe_semantic` | float | 语义组平均 QoE |
| `qoe_traditional` | float | 传统组平均 QoE |
| `qoe_sys` | float | 系统平均 QoE |
| `qoe_list` | list[float] | 每个用户的 QoE |
| `rates` | list[float] | 传统用户速率 (bps) |
| `ssim_values` | list[float] | 语义用户 SSim 值 |
| `rate_satisfaction` | float | 速率满足比例 ∈ [0, 1] |
| `rho` | float | 实际使用的压缩率 |
| `n_sub_s`, `n_sub_b` | int | 分配的子载波数量 |
---
## 2. 算法模块 agents/
### Actor
**文件**: `agents/actor.py`
确定性策略网络,输出 [0, 1] 范围的连续动作。
```python
class Actor(nn.Module):
def __init__(self, obs_dim: int, act_dim: int, hidden_sizes: list = [256, 256, 128])
```
**`forward(obs) -> torch.Tensor`**
| 参数 | 类型 | 说明 |
|---|---|---|
| `obs` | Tensor (batch, obs_dim) | 观察 |
| **返回** | Tensor (batch, act_dim) | 动作 ∈ [0, 1],通过 `(tanh(x) + 1) / 2` |
---
### Critic
**文件**: `agents/critic.py`
联合 Q 值网络 (CTDE),输入所有 agent 的观察和动作。
```python
class Critic(nn.Module):
def __init__(self, obs_dim_total: int, act_dim_total: int, hidden_sizes: list = [512, 512, 256])
```
- `obs_dim_total` = obs_dim × 2 = 136
- `act_dim_total` = act_dim × 2 = 6
- 总输入维度 = 142
**`forward(obs, act) -> torch.Tensor`**
| 参数 | 类型 | 说明 |
|---|---|---|
| `obs` | Tensor (batch, obs_dim_total) | 联合观察 concat(obs_s, obs_b) |
| `act` | Tensor (batch, act_dim_total) | 联合动作 concat(act_s, act_b) |
| **返回** | Tensor (batch, 1) | Q 值 |
---
### OUNoise
**文件**: `agents/noise.py`
Ornstein-Uhlenbeck 探索噪声,带线性 sigma 衰减。
```python
class OUNoise:
def __init__(self, size: int, mu: float = 0.0, theta: float = 0.15,
sigma_init: float = 0.2, sigma_min: float = 0.01, decay_period: int = 5000)
```
| 参数 | 说明 |
|---|---|
| `size` | 噪声维度 (= act_dim = 3) |
| `theta` | 回归速率 (默认 0.15) |
| `sigma_init` | 初始标准差 (默认 0.2) |
| `sigma_min` | 最小标准差 (默认 0.01) |
| `decay_period` | 线性衰减周期 (默认 5000 episodes) |
#### 方法
| 方法 | 说明 |
|---|---|
| `reset()` | 重置噪声状态到 μ |
| `sample() -> np.ndarray` | 采样一步 OU 噪声 |
| `decay_sigma(episode)` | 线性衰减 sigma: `σ = max(σ_min, σ_init - (σ_init - σ_min) · episode / decay_period)` |
---
### ReplayBuffer
**文件**: `agents/replay_buffer.py`
9-field 经验回放缓冲区。
```python
class ReplayBuffer:
def __init__(self, capacity: int = 100000)
```
#### 方法
**`push(obs_s, obs_b, act_s, act_b, rew_s, rew_b, next_obs_s, next_obs_b, done)`**
存储一个 transition。所有参数为 numpy array 或 float。
**`sample(batch_size) -> dict`**
随机采样一批 transitions。
| 返回 key | 类型 | Shape |
|---|---|---|
| `obs_s` | np.ndarray | (batch, obs_dim) |
| `obs_b` | np.ndarray | (batch, obs_dim) |
| `act_s` | np.ndarray | (batch, act_dim) |
| `act_b` | np.ndarray | (batch, act_dim) |
| `rew_s` | np.ndarray | (batch, 1) |
| `rew_b` | np.ndarray | (batch, 1) |
| `next_obs_s` | np.ndarray | (batch, obs_dim) |
| `next_obs_b` | np.ndarray | (batch, obs_dim) |
| `done` | np.ndarray | (batch, 1) |
**`__len__() -> int`**: 当前存储的 transition 数量。
---
### CoMADDPG
**文件**: `agents/co_maddpg.py`
Co-MADDPG 主算法,实现 Stackelberg Leader-Follower 更新。
```python
class CoMADDPG:
def __init__(self, config: dict)
```
| 关键属性 | 类型 | 说明 |
|---|---|---|
| `actor_s`, `actor_b` | Actor | 语义/传统 Actor 网络 |
| `critic_s`, `critic_b` | Critic | 语义/传统 Critic 网络 |
| `actor_s_target`, ... | Actor/Critic | Target 网络 (4个) |
| `noise_s`, `noise_b` | OUNoise | 探索噪声 |
| `buffer` | ReplayBuffer | 经验回放 |
| `current_lambda` | float | 当前 λ(t) 值 |
| `device` | torch.device | 计算设备 |
#### 方法
**`select_action(obs_s, obs_b, explore=True) -> (act_s, act_b)`**
| 参数 | 说明 |
|---|---|
| `obs_s`, `obs_b` | np.ndarray (obs_dim,) — 各 agent 观察 |
| `explore` | bool — 是否添加 OU 噪声 |
| **返回** | tuple(np.ndarray, np.ndarray) — 动作 ∈ [0, 1]³ |
---
**`compute_rewards(info) -> (rew_s, rew_b)`**
根据 info 字典计算混合奖励。内部更新 `self.current_lambda`
| 参数 | 说明 |
|---|---|
| `info` | dict — 来自 env.step() |
| **返回** | tuple(float, float) — 混合奖励 |
奖励公式:
```
r_coop_i = coop_self·qoe_i + coop_other·qoe_j + coop_sys·qoe_sys
r_comp_i = comp_self·qoe_i + comp_sys·qoe_sys
r_i = λ·r_coop_i + (1-λ)·r_comp_i
```
---
**`update() -> dict`**
执行 Stackelberg 更新。返回 loss 字典。
| 返回 key | 说明 |
|---|---|
| `critic_loss_b` | Follower Critic 损失 |
| `actor_loss_b` | Follower Actor 损失 |
| `critic_loss_s` | Leader Critic 损失 |
| `actor_loss_s` | Leader Actor 损失 |
| `lambda` | 当前 λ(t) |
---
**`save(path)` / `load(path)`**
保存/加载所有网络参数到指定目录。
| 文件 | 内容 |
|---|---|
| `model_s.pth` | Actor S + Critic S + 对应 Target 网络 |
| `model_b.pth` | Actor B + Critic B + 对应 Target 网络 |
---
## 3. 基线模块 baselines/
### 通用接口 / Common Interface
所有 7 个基线实现与 CoMADDPG 相同的接口:
```python
def __init__(self, config: dict)
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)
# 属性
self.buffer: ReplayBuffer # 或等效
self.noise_s: OUNoise # 部分基线有 (用于 train.py 的 hasattr 检查)
self.noise_b: OUNoise
```
### 各基线差异 / Baseline Differences
| 基线类 | 文件 | λ | 更新方式 | Critic | 特殊类 |
|---|---|---|---|---|---|
| `PureCooperative` | `pure_coop.py` | 1.0 固定 | Simultaneous | Joint | — |
| `PureCompetitive` | `pure_comp.py` | 0.0 固定 | Simultaneous | Joint | — |
| `FixedLambda` | `fixed_lambda.py` | 0.5 固定 | Stackelberg | Joint | — |
| `IndependentDDPG` | `iddpg.py` | 0.0 | Simultaneous | Independent | `IndependentCritic` |
| `SingleAgentDQN` | `single_dqn.py` | 0.5 | N/A (集中) | Centralized | `DQNNet`, `DQNReplayBuffer`, `EpsilonAdapter` |
| `EqualAllocation` | `equal_alloc.py` | 0.5 | N/A (无学习) | None | `DummyBuffer` |
| `SemanticOnly` | `semantic_only.py` | 1.0 | N/A (单策略) | Single | `SemanticCritic`, `SemanticBuffer` |
#### 特殊说明
**SingleAgentDQN**: 48 个离散动作 = 4 (sub_levels) × 4 (power_levels) × 3 (rho_levels)。使用 `EpsilonAdapter` 适配 `noise_s.decay_sigma()` 接口。
**EqualAllocation**: 无学习,永远输出 `[0.5, 0.5, 0.5]`。`DummyBuffer` 有 `push()``__len__()` 但不存储数据。
**IndependentDDPG**: `IndependentCritic` 输入为单个 agent 的 `(obs, act)` 而非联合输入,消融 CTDE 的效果。
---
## 4. 工具模块 utils/
### metrics.py
**文件**: `utils/metrics.py`
#### 函数
**`jain_fairness(values) -> float`**
Jain 公平性指数。`J = (Σx_i)² / (n·Σx_i²)`, 范围 [1/n, 1]。
---
**`rate_satisfaction(rates, min_rate) -> float`**
速率满足比例。满足 `R_k ≥ R_req` 的用户占比。
---
**`compute_system_qoe(qoe_list) -> float`**
系统级 QoE = 所有用户 QoE 的均值。
---
**`compute_lambda(qoe_sys, beta=5.0, q_threshold=0.6) -> float`**
动态协作权重。`λ = 1 / (1 + exp(-β·(QoE_sys - Q_th)))`
---
**`compute_mixed_reward(qoe_s, qoe_b, qoe_sys, lam, reward_config) -> (float, float)`**
计算混合奖励。`r_i = λ·r_coop_i + (1-λ)·r_comp_i`
---
**`moving_average(data, window) -> np.ndarray`**
滑动平均平滑。
---
### visualization.py
**文件**: `utils/visualization.py`
IEEE 风格绘图工具,对应论文 Section VII 的 12 张图。
```python
class Plotter:
def __init__(self, save_dir: str = "results/figures")
```
#### ALGO_STYLES
内置样式字典,为 8 个算法分配颜色、标记、线型:
```python
ALGO_STYLES = {
"Co-MADDPG": {"color": "#E74C3C", "marker": "o", "linestyle": "-"},
"PureCooperative": {"color": "#3498DB", "marker": "s", "linestyle": "--"},
"PureCompetitive": {"color": "#2ECC71", "marker": "^", "linestyle": "--"},
...
}
```
#### 绘图方法
| 方法 | 对应图表 | 参数 |
|---|---|---|
| `plot_convergence(data)` | Fig.2 | `{algo: [episode_rewards]}` |
| `plot_qoe_vs_snr(data)` | Fig.3 | `{algo: {snr: qoe}}` |
| `plot_fairness_vs_snr(data)` | Fig.4 | `{algo: {snr: fairness}}` |
| `plot_qoe_vs_users(data)` | Fig.5 | `{algo: {n_users: qoe}}` |
| `plot_rate_satisfaction(data)` | Fig.6 | `{algo: {n_users: rate_sat}}` |
| `plot_lambda_trajectory(lambdas)` | Fig.7 | `[λ_1, λ_2, ...]` |
| `plot_lambda_qoe_scatter(lambdas, qoes)` | Fig.8 | 两个等长列表 |
| `plot_qoe_vs_semantic_ratio(data)` | Fig.9 | `{algo: {ratio: qoe}}` |
| `plot_ablation(data)` | Fig.10 | `{algo: qoe_mean}` |
| `plot_beta_sensitivity(data)` | Fig.11 | `{beta: qoe}` |
| `plot_qth_sensitivity(data)` | Fig.12 | `{qth: qoe}` |
所有方法自动保存 PNG (300 DPI) 到 `save_dir`
---
## 5. 入口脚本 / Entry Scripts
### train.py
训练入口,支持 CLI 参数。
```bash
python train.py [--algo ALGO] [--config PATH] [--episodes N] [--steps N] [--seed N]
```
| 参数 | 默认值 | 说明 |
|---|---|---|
| `--algo` | `co_maddpg` | 算法名 (`co_maddpg`, `pure_coop`, `all`, 等) |
| `--config` | `configs/default.yaml` | 配置文件路径 |
| `--episodes` | 从配置读取 (5000) | 训练轮数 |
| `--steps` | 从配置读取 (200) | 每轮步数 |
| `--seed` | 从配置读取 (42) | 随机种子 |
**关键函数:**
- `load_config(path)` — 加载 YAML
- `get_algorithm(name, config)` — 工厂函数,返回算法实例
- `train_single(algo_name, config)` — 训练单个算法
- `train_all(config)` — 训练全部 8 个算法
---
### evaluate.py
评估入口,运行 8 个场景生成 12+ 张图。
```bash
python evaluate.py [--results_dir PATH] [--config PATH]
```
**8 个评估场景:**
| # | 函数 | 说明 |
|---|---|---|
| 1 | `scenario_convergence()` | 绘制训练收敛曲线 |
| 2 | `scenario_qoe_vs_snr()` | 扫描 SNR (通过调节 noise_psd) |
| 3 | `scenario_fairness_vs_snr()` | 不同 SNR 下的公平性 |
| 4 | `scenario_qoe_vs_users()` | 扫描用户数量 |
| 5 | `scenario_rate_satisfaction()` | 不同用户数下的速率满足度 |
| 6 | `scenario_lambda_dynamics()` | λ(t) 时间演化 |
| 7 | `scenario_ablation()` | 消融实验对比 |
| 8 | `scenario_sensitivity()` | β 和 Q_th 敏感性 |
---
## 类型约定 / Type Conventions
| 约定 | 说明 |
|---|---|
| 所有观察/动作 | numpy float32 |
| 神经网络输入 | torch.FloatTensor (自动转换) |
| 配置参数 | 从 YAML 加载,保持原始类型 |
| 奖励/QoE | Python float |
| 信道增益 | numpy complex128 |
| 布尔 done | Python bool |