4. 数据重上传线路中编码层插入位置的调参
问题定位:重上传结构中的“编码位置”变量
数据重上传(data re-uploading)线路的核心思想是:把同一组经典输入 x 多次编码进线路,并在两次编码之间插入可训练变分层。与“一次性编码 + 深变分层”相比,重上传用更少的可训练参数换取更强的函数拟合能力。但编码层插在哪里、插几次,会同时改变两件事:表达力(能否拟合目标函数)与梯度行为(是否出现梯度衰减)。本例固定参数预算,只调“插入位置与次数”这一个结构变量。
为便于比较,先约定三个结构记号(以 3 个编码块 E、2 个变分层 V 为例):
- 前置式
E-V-E-V-E:编码块与变分层严格交替,编码次数 = 变分层数 + 1,是典型重上传结构。 - 后置式
V-E-V-E-E:首个变分层在编码之前,编码集中在后段。 - 集中式
E-E-E-V-V:所有编码先完成,再堆叠变分层,等价于“单次编码 + 深变分层”的退化情形。
参数预算固定为:可训练参数总数 P = 12,编码层总次数 N_E 在 1~4 之间变化,变分层数 N_V 由预算反推。这样“编码次数”成为唯一自变量,避免参数数量差异干扰结论。
可复现的线路构造与参数预算
采用 4 量子比特、硬件高效风格的旋转层 + 环形 CNOT 纠缠层。每个变分层含 4 个 RY 旋转参数(每比特 1 个),每个编码层对每比特施加 RY(x_i·s),其中 s 为角度缩放因子(本例固定 s = 1.0,避免与前一例的缩放调参混淆)。
import numpy as np
N_QUBIT = 4
PARAM_BUDGET = 12 # 固定可训练参数总数
SCALE = 1.0 # 编码角度缩放,本例固定
def build_schedule(n_encode, n_var, mode="interleave"):
"""返回由 'E' 与 'V' 组成的结构序列。"""
if mode == "interleave": # 前置式:E V E V ... E
seq = []
for i in range(n_var):
seq += ["E", "V"]
seq.append("E")
return seq
if mode == "post": # 后置式:V E V E ... E
seq = []
for i in range(n_var):
seq += ["V", "E"]
seq.append("E")
return seq
if mode == "block": # 集中式:E...E V...V
return ["E"] * n_encode + ["V"] * n_var
raise ValueError(mode)
def count_params(seq):
return seq.count("V") * N_QUBIT # 每变分层 4 个 RY 参数
# 在固定预算下枚举可行的 (N_E, N_V) 组合
candidates = []
for n_e in range(1, 5):
n_v = PARAM_BUDGET // N_QUBIT
if n_v * N_QUBIT != PARAM_BUDGET:
continue
for mode in ("interleave", "post", "block"):
seq = build_schedule(n_e, n_v, mode)
if count_params(seq) == PARAM_BUDGET:
candidates.append((n_e, n_v, mode, "".join(seq)))
for c in candidates:
print(c)
运行后可得到一组结构候选,例如 (3, 3, 'interleave', 'EVEVEVE')、(3, 3, 'post', 'VEVEVEE')、(3, 3, 'block', 'EEEVVV') 等。注意:N_V = 3 时参数恰为 12,因此 N_E 可在 1~4 间自由变化而不改变预算,这正是本例要利用的自由度。
拟合能力与梯度行为的对照实验
目标函数取一个对 4 比特输入具有中等非线性的示例函数(仅作教学示例,非实测结果):
def target(x):
# x: shape (4,), 取值 {-1, +1}
return np.sin(np.pi * x[0] * x[1]) + 0.5 * x[2] * x[3]
def dataset(n=200, seed=0):
rng = np.random.default_rng(seed)
X = rng.choice([-1.0, 1.0], size=(n, N_QUBIT))
y = np.array([target(x) for x in X])
return X, y
对每个候选结构,用同一优化器(Adam,学习率 0.05,迭代 200 步)训练,记录两项指标:
- 最终训练损失:反映拟合能力,越小越好。
- 初始梯度范数:在参数随机初始化后、第一步更新前计算
||∂L/∂θ||₂,反映梯度是否健康。若该值随N_E增大而急剧下降,说明出现梯度衰减。
下表为教学示例中的预期趋势(非实测数据,用于说明判读逻辑):
| 结构 | N_E | N_V | 参数数 | 最终损失(示例趋势) | 初始梯度范数(示例趋势) |
|---|---|---|---|---|---|
| E-V-V-V | 1 | 3 | 12 | 偏高 | 较大 |
| E-V-E-V-V | 2 | 3 | 12 | 中等 | 中等 |
| E-V-E-V-E-V-E | 4 | 3 | 12 | 较低 | 偏小 |
| E-E-E-E-V-V-V | 4 | 3 | 12 | 偏高 | 较小 |
判读要点:编码次数增加通常提升拟合能力,但交替插入比集中插入更能保持梯度;当 N_E 过大时,梯度范数下降可能抵消拟合收益。因此“最优插入位置”不是越多越好,而是在当前数据维度下找到损失与梯度的折中点。
如何确定当前数据维度下的合适结构
上面的趋势图给出的是定性判读。实际调参时,按以下顺序执行即可得到可复现的结论:
- 固定预算:先确定
PARAM_BUDGET,由N_V = PARAM_BUDGET / N_QUBIT得到变分层数,保证所有候选结构参数数相同。 - 枚举结构:对
N_E = 1..4与三种插入模式做笛卡尔积,得到候选序列。 - 统一训练协议:同一初始化种子集合(如 5 个种子)、同一优化器与步数,记录最终损失均值与初始梯度范数均值。
- 判读与选择:若某结构的损失显著更低且梯度范数未低于基线的一半,则选它;若损失相近但梯度更小,选梯度更大的结构,因为它在更大迭代预算下更可能继续下降。
N_E = 2~3 的交替结构通常已足够;继续增加 N_E 带来的拟合收益递减,而梯度衰减风险上升。若输入维度更高或目标函数更复杂,可适当右移折中点,但仍应以梯度范数作为约束条件。