Files
uwca-semantic-mac/simulation/realdata_plot.py
T

129 lines
6.4 KiB
Python
Executable File

"""Real-data (digits) Fig. 5 generator: downstream classification accuracy vs SNR
for HIGH/LOW/MIX, parallel to the synthetic Fig. 2.
Curves per panel:
- OFDMA [division], SFDMA [feature div.], NOMA-SIC (analytical baselines)
- UWCA (analytical) : oracle-beta cross-attention (relevance SUPPLIED) -- dotted
- UWCA w/o MAML : decoder TRAINED on real digits, no meta-learning (from realdata_train.json)
- UWCA w/ MAML : decoder TRAINED on real digits with MAML (proposed) -- hollow circles
Trained curves are read from results/realdata_train.json (produced by
revision_realdata_train.py); the analytical / baseline curves are recomputed here
so they share one Monte-Carlo setting. Saves results/fig_realdata_c.pdf.
"""
import json, numpy as np
import matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
RNG = np.random.default_rng(7)
U, D = 4, 64
DPU = D // U
MASKS = np.zeros((U, D))
for u in range(U):
MASKS[u, u*DPU:(u+1)*DPU] = 1.0
NOMA_POWER = np.array([0.40, 0.30, 0.20, 0.10])
TAU = 0.45
X, y = load_digits(return_X_y=True)
X = X.astype(np.float64); X = X - X.mean(0, keepdims=True)
X = X / (np.linalg.norm(X, axis=1, keepdims=True) + 1e-8)
by_class = {c: X[y == c] for c in range(10)}
PROTO = np.stack([by_class[c].mean(0) for c in range(10)])
PROTO = PROTO / (np.linalg.norm(PROTO, axis=1, keepdims=True) + 1e-8)
def _norm(E): return E / (np.linalg.norm(E, axis=-1, keepdims=True) + 1e-8)
def se_channel(E, snr):
n = E.shape[0]; Ytx = (E * MASKS[None]).sum(1)
h = np.sqrt(RNG.standard_normal((n, U, 1))**2 + RNG.standard_normal((n, U, 1))**2)*np.sqrt(0.5)
nstd = np.sqrt(float(np.mean(Ytx**2))/(10**(snr/10)))
return h*Ytx[:, None, :] + RNG.standard_normal((n, U, D))*nstd
def ofdma(Y): return np.stack([_norm(Y[:, u, :]*MASKS[u]) for u in range(U)], 1)
def sfdma(E, snr):
"""Full-band, orthogonal semantic-subspace division (block basis)."""
n = E.shape[0]
h = np.sqrt(RNG.standard_normal((n, U, 1))**2 + RNG.standard_normal((n, U, 1))**2)*np.sqrt(0.5)
X_ = E * MASKS[None]
yv = (h * X_).sum(1)
yv = yv + RNG.standard_normal((n, D))*np.sqrt(float(np.mean(yv**2))/(10**(snr/10)))
return np.stack([_norm((yv * MASKS[u])/(h[:, u, :]+1e-8)) for u in range(U)], 1)
def noma_ch(E, snr):
n = E.shape[0]
h = np.sqrt(RNG.standard_normal((n, U, 1))**2 + RNG.standard_normal((n, U, 1))**2)*np.sqrt(0.5)
yv = (E*np.sqrt(NOMA_POWER)[None, :, None]*h).sum(1)
yv = yv + RNG.standard_normal((n, D))*np.sqrt(float(np.mean(yv**2))/(10**(snr/10)))
return yv, h
def noma_sic(yv, h):
n = yv.shape[0]; Eh = np.zeros((n, U, D)); res = yv.copy()
for u in range(U):
Eh[:, u, :] = _norm(res/(h[:, u, :]+1e-8)); res -= h[:, u, :]*np.sqrt(NOMA_POWER[u])*Eh[:, u, :]
return Eh
def uwca_oracle(Y, bmc):
"""Analytical UWCA: oracle-beta cross-attention (relevance supplied)."""
R = Y[:, :, None, :]*MASKS[None, None]
a = bmc.copy(); np.fill_diagonal(a, 1.0); a /= a.sum(1, keepdims=True)+1e-8
ctx = np.einsum('ui,buid->bud', a, R)
return np.stack([_norm(ctx[:, u, :]) for u in range(U)], 1)
SCEN = {'HIGH': [3, 3, 3, 3], 'LOW': [0, 1, 7, 4], 'MIX': [3, 3, 8, 1]}
def sample(n, ca): return np.stack([by_class[ca[u]][RNG.integers(0, len(by_class[ca[u]]), n)] for u in range(U)], 1)
def emp_beta(ca, n=4000):
E = sample(n, ca); return np.einsum('nud,nvd->uv', E, E)/n
def acc(Eh, ca):
pred = np.einsum('nud,cd->nuc', _norm(Eh), PROTO).argmax(-1)
return (pred == np.array(ca)[None, :]).mean()
SNR = np.arange(0, 21, 2)
trained = json.load(open('results/realdata_train.json')) # trained UWCA w/ and w/o MAML
# --- recompute analytical / baseline accuracy (shared MC) ---
ana = {s: {m: [] for m in ['OFDMA', 'SFDMA', 'NOMA-SIC', 'UWCA (analytical)']} for s in SCEN}
for s, ca in SCEN.items():
bm = emp_beta(ca); bmc = bm.copy(); np.fill_diagonal(bmc, 0.0); bmc = np.clip(bmc, 0, None)
for snr in SNR:
ao = asf = an = au = 0.0; nmc = 200
for _ in range(nmc):
E = sample(64, ca)
ao += acc(ofdma(se_channel(E, snr)), ca)
asf += acc(sfdma(E, snr), ca)
yv, h = noma_ch(E, snr); an += acc(noma_sic(yv, h), ca)
au += acc(uwca_oracle(se_channel(E, snr), bmc), ca)
ana[s]['OFDMA'].append(ao/nmc); ana[s]['SFDMA'].append(asf/nmc)
ana[s]['NOMA-SIC'].append(an/nmc); ana[s]['UWCA (analytical)'].append(au/nmc)
# --- plot: downstream accuracy, 1 row x 3 cols ---
COL = {'OFDMA': '#546E7A', 'SFDMA': '#9C27B0', 'NOMA-SIC': '#E65100',
'UWCA (analytical)': '#1565C0', 'UWCA w/o MAML': '#2E7D32', 'UWCA w/ MAML': '#1565C0'}
fig, ax = plt.subplots(1, 3, figsize=(11, 3.4))
betas = {s: emp_beta(SCEN[s])[~np.eye(U, dtype=bool)].mean() for s in SCEN}
for j, s in enumerate(['HIGH', 'LOW', 'MIX']):
a = ax[j]
a.plot(SNR, ana[s]['OFDMA'], 's--', color=COL['OFDMA'], lw=2, ms=5, label='OMA')
a.plot(SNR, ana[s]['SFDMA'], 'v:', color=COL['SFDMA'], lw=2, ms=5, mfc='none', label='SFDMA')
a.plot(SNR, ana[s]['NOMA-SIC'], '^-.', color=COL['NOMA-SIC'], lw=2, ms=5, label='NOMA-SIC')
a.plot(SNR, ana[s]['UWCA (analytical)'], ':', color=COL['UWCA (analytical)'], lw=2.4, label='UWCA (genie)')
a.plot(SNR, trained[s]['UWCA w/ MAML'], 'o-', color=COL['UWCA w/ MAML'], lw=1.6, ms=6, mfc='none', mew=1.6, label='UWCA (trained)')
a.set_ylim(0.1, 1.02); a.set_xlim(0, 20); a.grid(alpha=.3); a.set_box_aspect(0.85)
a.set_xlabel('SNR (dB)', fontsize=10)
a.text(0.5, -0.34, f"({chr(97+j)}) {s} ($\\hat\\beta_{{u,v}}\\approx{betas[s]:.2f}$)",
transform=a.transAxes, ha='center', fontsize=11)
if j == 0:
a.set_ylabel('Downstream accuracy', fontsize=10)
ax[0].legend(fontsize=7.0, loc='upper left', bbox_to_anchor=(0.46, 0.37),
bbox_transform=ax[0].transAxes, framealpha=0.9, borderaxespad=0.0)
fig.tight_layout()
fig.savefig('results/fig_realdata.pdf', bbox_inches='tight')
fig.savefig('results/fig_realdata.png', dpi=140, bbox_inches='tight')
fig.savefig('results/fig_realdata_c.pdf', bbox_inches='tight')
print('saved results/fig_realdata_c.pdf')
for s in SCEN:
print(f"[{s}] @20dB OFDMA={ana[s]['OFDMA'][-1]:.3f} SFDMA={ana[s]['SFDMA'][-1]:.3f} "
f"NOMA={ana[s]['NOMA-SIC'][-1]:.3f} UWCA-ana={ana[s]['UWCA (analytical)'][-1]:.3f} "
f"UWCA-MAML(tr)={trained[s]['UWCA w/ MAML'][-1]:.3f}")