<think>我们遇到了一个异常:`NoiseModel.from_noise_model_like() got an unexpected keyword argument 'deprecated_noise'`。这是因为在较新的Cirq版本中,`from_noise_model_like`方法已经不再接受`deprecated_noise`参数。我们需要更新噪声模型的构建方式。
此外,由于多个任务失败,导致最终收集结果时`results`为空,因此出现了`ValueError: not enough values to unpack (expected 3, got 0)`。
解决方案:
1. 更新噪声模型的构建方式,使用`cirq.ConstantQubitNoiseModel`或者直接添加噪声门到电路中(我们已经在添加噪声门,所以实际上不需要再创建一个噪声模型?)。
2. 实际上,在`_build_circuit`方法中,我们并没有使用`noise_model`变量。我们是在每个门之后直接添加了噪声门。因此,我们可以删除创建`noise_model`的代码。
修改步骤:
- 删除创建`noise_model`的两行代码。
- 因为我们已经在每个需要噪声的门后面添加了噪声操作,所以不需要额外的噪声模型。
另外,由于之前的错误导致所有任务失败,因此我们需要确保噪声添加正确。
此外,我们还需要确保在多个进程中,每个进程都能够正确初始化模拟器,并且不会因为异常而失败。
修改后的`_build_circuit`方法中噪声部分代码:
```python
# 删除以下两行(它们没有使用):
# if self.noise:
# noise_model = cirq.NoiseModel.from_noise_model_like(
# deprecated_noise=cirq.DepolarizingChannel(self.noise_param['single_qubit_channel_depolarizing_p'])
# )
```
完整修改后的代码:
</think># 错误分析及修复方案
## 错误分析
报错信息指出:
```bash
Exception occurred: NoiseModel.from_noise_model_like() got an unexpected keyword argument 'deprecated_noise'
```
这个错误是由于 Cirq 库的 API 变更引起的。在较新的 Cirq 版本中,`NoiseModel.from_noise_model_like` 方法不再接受 `deprecated_noise` 参数。
## 解决方案
### 1. 更新噪声模型构建方式
使用 Cirq 推荐的噪声模型构建方式:
```python
# 替换旧的噪声模型构建方式
noise_model = cirq.NoiseModel.from_noise_model_like(
deprecated_noise=cirq.DepolarizingChannel(...)
)
# 使用新的方式:
noise_model = cirq.ConstantQubitNoiseModel(cirq.DepolarizingChannel(...))
```
### 2. 完全移除不必要的噪声模型
实际上在您的代码中,噪声模型变量 `noise_model` 并没有被使用。您已经在每个门后直接添加了噪声操作,所以可以完全移除这些噪声模型创建的行。
## 完整修复代码
以下是修复后的完整代码:
```python
import os
import numpy as np
import cirq
import qsimcirq
from functools import partial
import matplotlib.pyplot as plt
import time
from scipy.optimize import minimize
from concurrent.futures import ProcessPoolExecutor, as_completed
import utils
import argparse
# 全局模拟器实例(每个进程一个)
global_simulator = None
class VqeTrainerNew:
def __init__(self, n_cir_parallel, n_runs, max_iteration, n_qubit, hamiltonian, noise_param=None):
self.n_qubit = n_qubit
self.max_iteration = max_iteration
self.n_cir_parallel = n_cir_parallel
self.n_runs = n_runs
self.hamiltonian = hamiltonian
self.noise = noise_param is not None
self.noise_param = noise_param
# 构建哈密顿量(Pauli项列表)
self.h_terms = self._build_hamiltonian_terms()
def _build_hamiltonian_terms(self):
"""构建哈密顿量的Pauli项列表"""
terms = []
pbc = self.hamiltonian['pbc']
# 添加ZZ耦合项
for i in range(self.n_qubit - 1 + pbc):
j = (i + 1) % self.n_qubit
if self.hamiltonian['hzz'] != 0:
terms.append((self.hamiltonian['hzz'], cirq.PauliString(cirq.Z(cirq.LineQubit(i)) * cirq.Z(cirq.LineQubit(j)))))
# 添加XX耦合项
for i in range(self.n_qubit - 1 + pbc):
j = (i + 1) % self.n_qubit
if self.hamiltonian['hxx'] != 0:
terms.append((self.hamiltonian['hxx'], cirq.PauliString(cirq.X(cirq.LineQubit(i)) * cirq.X(cirq.LineQubit(j)))))
# 添加YY耦合项
for i in range(self.n_qubit - 1 + pbc):
j = (i + 1) % self.n_qubit
if self.hamiltonian['hyy'] != 0:
terms.append((self.hamiltonian['hyy'], cirq.PauliString(cirq.Y(cirq.LineQubit(i)) * cirq.Y(cirq.LineQubit(j)))))
# 添加单粒子项
for i in range(self.n_qubit):
if self.hamiltonian['hz'] != 0:
terms.append((self.hamiltonian['hz'], cirq.PauliString(cirq.Z(cirq.LineQubit(i)))))
if self.hamiltonian['hx'] != 0:
terms.append((self.hamiltonian['hx'], cirq.PauliString(cirq.X(cirq.LineQubit(i)))))
if self.hamiltonian['hy'] != 0:
terms.append((self.hamiltonian['hy'], cirq.PauliString(cirq.Y(cirq.LineQubit(i)))))
return terms
def compute_energy(self, params, structure):
"""计算给定参数下的能量期望值"""
# 使用全局模拟器,每个进程一个实例
simulator = global_simulator
circuit = self._build_circuit(params, structure)
if self.noise:
# 噪声情况使用密度矩阵模拟
result = simulator.simulate(circuit)
density_matrix = result.density_matrix()
energy = 0.0
for coeff, pauli_string in self.h_terms:
# 计算每个Pauli项的期望值
expectation = pauli_string.expectation_from_density_matrix(
density_matrix, qubits=cirq.LineQubit.range(self.n_qubit)
)
energy += coeff * np.real(expectation)
else:
# 无噪声情况使用纯态模拟
result = simulator.simulate(circuit)
state_vector = result.state_vector()
energy = 0.0
for coeff, pauli_string in self.h_terms:
# 计算每个Pauli项的期望值
expectation = pauli_string.expectation_from_state_vector(
state_vector, qubits=cirq.LineQubit.range(self.n_qubit)
)
energy += coeff * np.real(expectation)
return energy
def _build_circuit(self, params, structure):
"""构建Cirq量子电路"""
qubits = cirq.LineQubit.range(self.n_qubit)
circuit = cirq.Circuit()
param_idx = 0
# 不再使用废弃的NoiseModel API
# 直接在每个门后添加噪声操作
for gate in structure:
if gate[0] == "cx":
circuit.append(cirq.CNOT(qubits[gate[1]], qubits[gate[2]]))
if self.noise:
# 添加双量子比特噪声
noise_op = cirq.DepolarizingChannel(
self.noise_param['two_qubit_channel_depolarizing_p']).on(qubits[gate[1]], qubits[gate[2]])
circuit.append(noise_op)
elif gate[0] == "cz":
circuit.append(cirq.CZ(qubits[gate[1]], qubits[gate[2]]))
if self.noise:
noise_op = cirq.DepolarizingChannel(
self.noise_param['two_qubit_channel_depolarizing_p']).on(qubits[gate[1]], qubits[gate[2]])
circuit.append(noise_op)
elif gate[0] == "ry":
circuit.append(cirq.ry(params[param_idx])(qubits[gate[1]]))
param_idx += 1
if self.noise:
# 添加单量子比特噪声
noise_op = cirq.DepolarizingChannel(
self.noise_param['single_qubit_channel_depolarizing_p']).on(qubits[gate[1]])
circuit.append(noise_op)
elif gate[0] == "rz":
circuit.append(cirq.rz(params[param_idx])(qubits[gate[1]]))
param_idx += 1
if self.noise:
noise_op = cirq.DepolarizingChannel(
self.noise_param['single_qubit_channel_depolarizing_p']).on(qubits[gate[1]])
circuit.append(noise_op)
elif gate[0] == "rx":
circuit.append(cirq.rx(params[param_idx])(qubits[gate[1]]))
param_idx += 1
if self.noise:
noise_op = cirq.DepolarizingChannel(
self.noise_param['single_qubit_channel_depolarizing_p']).on(qubits[gate[1]])
circuit.append(noise_op)
# 添加比特翻转噪声
if self.noise:
for q in qubits:
circuit.append(cirq.BitFlipChannel(self.noise_param['bit_flip_p'])(q))
return circuit
@staticmethod
def get_param_num(cir):
"""计算电路中的参数数量"""
param_num = 0
for gate in cir:
if gate[0] in ['rx', 'ry', 'rz']:
param_num += 1
return param_num
def train_circuit(self, circuit_and_seed):
"""训练单个电路结构"""
single_circuit, seed = circuit_and_seed
np.random.seed(seed)
param_num = VqeTrainerNew.get_param_num(single_circuit[0])
L = single_circuit[1]
init_params = np.random.normal(loc=0, scale=1/(8*(L+2)), size=param_num)
energy_epoch = []
# 优化回调函数记录能量
def callback(xk):
energy = self.compute_energy(xk, single_circuit[0])
energy_epoch.append(energy)
print(f"Seed {seed}: Iteration {len(energy_epoch)} Energy = {energy:.6f}")
return False
if param_num > 0:
# 使用BFGS优化器
result = minimize(
fun=lambda p: self.compute_energy(p, single_circuit[0]),
x0=init_params,
method='BFGS',
callback=callback,
options={'maxiter': self.max_iteration}
)
final_energy = result.fun
final_params = result.x
else:
# 无参电路直接计算能量
final_energy = self.compute_energy([], single_circuit[0])
final_params = np.array([])
energy_epoch = [final_energy] * self.max_iteration
return final_energy, final_params, energy_epoch
def draw(self, loss_list, exp_dir, circuit_id, best_index):
"""绘制训练曲线"""
epochs = range(1, len(loss_list) + 1)
plt.figure(figsize=(10, 6))
plt.plot(epochs, loss_list, label='Training Loss', marker='o', markersize=1, color='blue')
plt.title('Training Loss Over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid()
plt.tight_layout()
save_path_img = f'{exp_dir}/circuit_train_curve/'
os.makedirs(save_path_img, exist_ok=True)
plt.savefig(f'{save_path_img}circuit_{circuit_id}_{best_index}.png')
plt.close()
def batch_train_parallel(self, device_name, task_name, run_id):
"""并行训练批次电路"""
start_time = time.time()
exp_dir = f'result/cir_sample/{device_name}_{task_name}/training/run_{run_id}/'
samples = utils.load_pkl(f'{exp_dir}samples.pkl')[:10]
work_queue = [(samples[i], j) for i in range(len(samples)) for j in range(self.n_runs)]
# 使用进程池初始化函数创建模拟器
def init_simulator():
"""每个进程初始化时创建自己的模拟器"""
global global_simulator
options = {'t': 16, 'f': 2, 'g': 0} # GPU配置
global_simulator = qsimcirq.QSimSimulator(options)
# 使用ProcessPoolExecutor替代multiprocessing.Pool
with ProcessPoolExecutor(
max_workers=self.n_cir_parallel,
initializer=init_simulator
) as executor:
# 使用partial绑定train_circuit方法
train_func = partial(train_circuit_wrapper, trainer=self)
future_to_work = {
executor.submit(train_func, work): work
for work in work_queue
}
results = []
for future in as_completed(future_to_work):
try:
results.append(future.result())
except Exception as e:
print(f"Exception occurred during task: {e}")
# 处理空结果的情况
if not results:
print("Warning: No results returned from tasks")
energy_f, param_f, energy_epoch_f = [], [], []
else:
energies, params, energy_epochs = zip(*results)
# 提取最佳结果
energy_f, param_f, energy_epoch_f = [], [], []
for i in range(len(samples)):
start_idx = i * self.n_runs
end_idx = start_idx + self.n_runs
best_idx = np.argmin(energies[start_idx:end_idx]) + start_idx
energy_f.append(energies[best_idx])
param_f.append(params[best_idx])
energy_epoch_f.append(energy_epochs[best_idx])
self.draw(energy_epochs[best_idx], exp_dir, i, best_idx)
# 保存结果
os.makedirs(exp_dir, exist_ok=True)
utils.save_pkl(energy_f, f'{exp_dir}energy.pkl')
utils.save_pkl(param_f, f'{exp_dir}param.pkl')
utils.save_pkl(energy_epoch_f, f'{exp_dir}energy_epoch.pkl')
duration = time.time() - start_time
print(f"Run time: {int(duration//3600)}h {int((duration%3600)//60)}m")
utils.save_pkl(duration, f'{exp_dir}duration.pkl')
# 包装函数用于多进程
def train_circuit_wrapper(work, trainer):
return trainer.train_circuit(work)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--noise", type=bool, default=True, help="是否考虑噪声")
parser.add_argument("--two_qubit_depolarizing_p", type=float, default=0.01, help="双量子比特去极化噪声大小")
parser.add_argument("--single_qubit_depolarizing_p", type=float, default=0.001, help="单量子比特去极化噪声大小")
parser.add_argument("--bit_flip_p", type=float, default=0.01, help="比特翻转噪声大小")
args = parser.parse_args()
device_name = 'grid_16q'
task_name = 'Heisenberg_12'
qubit = 12
noise_param = None
if args.noise:
noise_param = {
'two_qubit_channel_depolarizing_p': args.two_qubit_depolarizing_p,
'single_qubit_channel_depolarizing_p': args.single_qubit_depolarizing_p,
'bit_flip_p': args.bit_flip_p
}
hamiltonian = {
'pbc': True,
'hzz': 1,
'hxx': 1,
'hyy': 1,
'hx': 0,
'hy': 0,
'hz': 1,
'sparse': False
}
trainer = VqeTrainerNew(
n_cir_parallel=4,
n_runs=3,
max_iteration=1000,
n_qubit=qubit,
hamiltonian=hamiltonian,
noise_param=noise_param
)
run_id = 0
trainer.batch_train_parallel(device_name, task_name, run_id)
```
## 关键修复点说明
### 1. 噪声模型API修复
移除了废弃的 `NoiseModel.from_noise_model_like()` API 调用:
```python
# 删除以下废弃代码
# if self.noise:
# noise_model = cirq.NoiseModel.from_noise_model_like(...)
```
### 2. 异常处理增强
添加了对空结果的容错处理:
```python
# 处理空结果的情况
if not results:
print("Warning: No results returned from tasks")
energy_f, param_f, energy_epoch_f = [], [], []
else:
# 正常处理结果
```
### 3. 错误日志改进
提供更详细的错误信息:
```python
except Exception as e:
print(f"Exception occurred during task: {e}")
```
### 4. 代码结构优化
保留了原有的核心功能,包括:
- 多进程处理 (`ProcessPoolExecutor`)
- GPU加速 (`{'t': 16, 'f': 2, 'g': 0}`)
- 噪声模型支持
- 能量计算优化
- 绘图功能
## 测试建议
1. **基本功能测试**:
```bash
python vqe_qsim.py --max_iteration 10 --n_runs 1
```
2. **噪声模式测试**:
```bash
python vqe_qsim.py --noise True \
--single_qubit_depolarizing_p 0.001 \
--two_qubit_depolarizing_p 0.01 \
--bit_flip_p 0.005
```
3. **无噪声模式测试**:
```bash
python vqe_qsim.py --noise False
```
这个修复版本:
1. 解决了 `deprecated_noise` API 问题
2. 增强了对异常情况的处理
3. 保留了原有的GPU加速功能
4. 维持了多进程并行处理结构