import sys
import os
import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Dense
from example_utils import get_parser
from importance_sampling.training import ConstantTimeImportanceTraining

# 重定向stdout以捕获打印输出
class Tee(object):
    def __init__(self, *files):
        self.files = files
    def write(self, obj):
        for f in self.files:
            f.write(obj)
            f.flush()
    def flush(self):
        for f in self.files:
            f.flush()

output_file = open('output.log', 'w', encoding='utf-8')
original_stdout = sys.stdout
sys.stdout = Tee(sys.stdout, output_file)

def save_plot(fig, filename):
    fig.savefig(filename)
    plt.close(fig)

def plot_history(history):
    # 绘制训练和验证准确率
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(history.history['accuracy'])
    ax.plot(history.history['val_accuracy'])
    ax.set_title('Model Accuracy')
    ax.set_ylabel('Accuracy')
    ax.set_xlabel('Epoch')
    ax.legend(['Train', 'Validation'], loc='upper left')
    save_plot(fig, 'accuracy_plot.png')

    # 绘制训练和验证损失
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(history.history['loss'])
    ax.plot(history.history['val_loss'])
    ax.set_title('Model Loss')
    ax.set_ylabel('Loss')
    ax.set_xlabel('Epoch')
    ax.legend(['Train', 'Validation'], loc='upper left')
    save_plot(fig, 'loss_plot.png')

def calculate_accuracy_fluctuation(history):
    val_accuracies = history.history['val_accuracy']
    mean_accuracy = np.mean(val_accuracies)
    fluctuation = np.sum(np.abs(val_accuracies - mean_accuracy))
    return mean_accuracy, fluctuation

# 定义设备，使用11个量子比特
dev = qml.device("default.qubit", wires=11)

def encode_group(control_qubits, data_qubits, angle_values, angle_weights):
    control_values = [[0, 0], [0, 1], [1, 0], [1, 1]]

    for cv in control_values:
        # 翻转控制比特为0的量子比特，以便使用受控RY门
        for qubit, val in zip(control_qubits, cv):
            if val == 0:
                qml.PauliX(wires=qubit)

        # 对数据量子比特应用受控 RY 旋转，编码特征值和权重
        for data_qubit, angle_value, angle_weight in zip(data_qubits, angle_values, angle_weights):
            qml.ctrl(qml.RY, control=control_qubits)(angle_value, wires=data_qubit)
            qml.ctrl(qml.RY, control=control_qubits)(angle_weight, wires=data_qubit)

        # 恢复控制比特的原始状态
        for qubit, val in zip(control_qubits, cv):
            if val == 0:
                qml.PauliX(wires=qubit)

def apply_controlled_swap(swap_control_qubit, data_qubits):
    # 应用 Hadamard 门到 swap_control_qubit
    qml.Hadamard(wires=swap_control_qubit)
    # 应用受控 SWAP 门
    qml.CSWAP(wires=[swap_control_qubit, data_qubits[0], data_qubits[1]])
    # 再次应用 Hadamard 门到 swap_control_qubit
    qml.Hadamard(wires=swap_control_qubit)

@qml.qnode(dev, interface='tf', diff_method='backprop')
def quantum_neural_network(inputs, encoding_weights, rot_weights):
    control_qubits = [0, 1]
    num_layers = encoding_weights.shape[0]
    num_features = inputs.shape[0]

    # 定义量子比特索引，每层使用固定的量子比特组
    data_qubits_groups = [
        [2, 3],
        [4, 5],
        [6, 7],
        [8, 9],
        [10, 10]  # 最后一层只有一个数据比特，不进行swap
    ]

    # 为每层分配不同的swap控制比特，确保不重复且在量子比特范围内
    # 这里选择 swap 控制比特为4,6,8,10，最后一层不进行swap操作
    swap_control_qubits = [4, 6, 8, 10, None]  # 最后一层不进行swap

    for layer_idx in range(num_layers):
        data_qubits = data_qubits_groups[layer_idx]
        swap_control_qubit = swap_control_qubits[layer_idx]

        # 编码层
        encode_group(
            control_qubits,
            data_qubits,
            inputs,  # 特征值
            encoding_weights[layer_idx]  # 权重
        )

        # 应用 swap 门，除了最后一层
        if swap_control_qubit is not None:
            apply_controlled_swap(swap_control_qubit, data_qubits)

        # 应用旋转层
        for qubit in range(dev.num_wires):
            rot_angles = rot_weights[layer_idx, qubit, :]
            qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit)

    # 测量 swap 控制比特（不包括最后一层）
    results = []
    for swap_control_qubit in swap_control_qubits:
        if swap_control_qubit is not None:
            results.append(qml.expval(qml.PauliZ(wires=swap_control_qubit)))

    return results

@qml.qnode(dev)
def quantum_neural_network_draw(inputs, encoding_weights, rot_weights):
    control_qubits = [0, 1]
    num_layers = encoding_weights.shape[0]
    num_features = inputs.shape[0]

    # 定义量子比特索引，每层使用固定的量子比特组
    data_qubits_groups = [
        [2, 3],
        [4, 5],
        [6, 7],
        [8, 9],
        [10, 10]  # 最后一层只有一个数据比特，不进行swap
    ]

    # 为每层分配不同的swap控制比特，确保不重复且在量子比特范围内
    # 这里选择 swap 控制比特为4,6,8,10，最后一层不进行swap操作
    swap_control_qubits = [4, 6, 8, 10, None]  # 最后一层不进行swap

    for layer_idx in range(num_layers):
        data_qubits = data_qubits_groups[layer_idx]
        swap_control_qubit = swap_control_qubits[layer_idx]

        # 编码层
        encode_group(
            control_qubits,
            data_qubits,
            inputs,  # 特征值
            encoding_weights[layer_idx]  # 权重
        )

        # 应用 swap 门，除了最后一层
        if swap_control_qubit is not None:
            apply_controlled_swap(swap_control_qubit, data_qubits)

        # 应用旋转层
        for qubit in range(dev.num_wires):
            rot_angles = rot_weights[layer_idx, qubit, :]
            qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit)

    # 测量 swap 控制比特（不包括最后一层）
    results = []
    for swap_control_qubit in swap_control_qubits:
        if swap_control_qubit is not None:
            results.append(qml.expval(qml.PauliZ(wires=swap_control_qubit)))

    return results

# 定义一个量子神经网络层
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
    def __init__(self, n_layers, n_features=4, **kwargs):
        super(QuantumNeuralNetworkLayer, self).__init__(**kwargs)
        self.n_layers = n_layers
        self.n_features = n_features

        # 定义编码权重
        self.encoding_weights = self.add_weight(
            shape=(n_layers, n_features),
            initializer=tf.keras.initializers.GlorotUniform(),
            trainable=True,
            name='encoding_weights',
            dtype=tf.float32  # Changed from tf.float64 to tf.float32
        )

        # 总量子比特数 = 11
        self.rot_weights = self.add_weight(
            shape=(n_layers, 11, 3),
            initializer=tf.keras.initializers.GlorotUniform(),
            trainable=True,
            name='rot_weights',
            dtype=tf.float32  # Changed from tf.float64 to tf.float32
        )

    def call(self, inputs):
        def apply_qnode(x):
            x = tf.cast(x, dtype=tf.float32)  # Changed from tf.float64 to tf.float32
            result = quantum_neural_network(x, self.encoding_weights, self.rot_weights)
            return tf.cast(result, dtype=tf.float32)

        outputs = tf.map_fn(
            apply_qnode,
            inputs,
            dtype=tf.float32
        )

        # 打印权重（调试用）
        tf.print("Encoding Weights:", self.encoding_weights)
        tf.print("Rot Weights:", self.rot_weights)

        return outputs

# 定义一个量子神经网络模型
class QuantumNeuralNetwork(tf.keras.Model):
    def __init__(self, n_layers, num_classes, n_features=4, **kwargs):
        super(QuantumNeuralNetwork, self).__init__(**kwargs)
        self.n_layers = n_layers
        self.num_classes = num_classes

        # Quantum layer
        self.quantum_layer = QuantumNeuralNetworkLayer(n_layers, n_features)

        # Classical layers
        self.dense = Dense(num_classes, activation='softmax')

    def call(self, inputs):
        q_output = self.quantum_layer(inputs)
        return self.dense(q_output)

if __name__ == "__main__":
    parser = get_parser("Train model on Iris dataset")
    args = parser.parse_args()

    iris = load_iris()
    X = iris['data'].astype(np.float32)
    y = iris['target'].reshape(-1, 1)

    encoder = OneHotEncoder(sparse_output=False)
    y = encoder.fit_transform(y).astype(np.float32)

    x_train, x_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=116
    )

    learning_rate = 0.2
    epochs = 100
    batch_size = 8
    num_classes = 3
    n_layers = 5  # 修改层数为5，代表整个QNN的层数

    model = QuantumNeuralNetwork(
        n_layers=n_layers,
        num_classes=num_classes
    )

    model.compile(
        optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate),
        loss='categorical_crossentropy',
        metrics=['accuracy']
    )

    def is_quantum_model(model):
        for layer in model.layers:
            if isinstance(layer, QuantumNeuralNetworkLayer):
                return True
        return False

    if is_quantum_model(model):
        print("The model contains a Quantum Neural Network (QNN) layer.")
    else:
        print("The model does not contain a Quantum Neural Network (QNN) layer.")

    print("\nQuantum Circuit Diagram:")
    sample_inputs = np.ones(4, dtype=np.float32) * (np.pi / 2)  # Changed dtype to float32
    sample_encoding_weights = np.zeros((n_layers, 4), dtype=np.float32)  # Changed dtype to float32
    sample_rot_weights = np.zeros((n_layers, 11, 3), dtype=np.float32)  # Changed dtype to float32

    print(qml.draw(quantum_neural_network_draw)(sample_inputs, sample_encoding_weights, sample_rot_weights))  # 使用绘制专用的 QNode

    if args.importance_training:
        wrapped_model = ConstantTimeImportanceTraining(model, score="loss")
        history = wrapped_model.fit(
            x_train, y_train,
            batch_size=batch_size,
            epochs=epochs,
            verbose=1,
            validation_data=(x_test, y_test)
        )
    else:
        history = model.fit(
            x_train, y_train,
            batch_size=batch_size,
            epochs=epochs,
            verbose=1,
            validation_data=(x_test, y_test)
        )

    score = model.evaluate(x_test, y_test, verbose=0)
    print('Test loss:', score[0])
    print('Test accuracy:', score[1])

    mean_accuracy, fluctuation = calculate_accuracy_fluctuation(history)
    print('Mean validation accuracy:', mean_accuracy)
    print('Accuracy fluctuation:', fluctuation)

    plot_history(history)

    # 关闭输出文件并恢复stdout
    sys.stdout = original_stdout
    output_file.close()

print("脚本执行完成。查看 'output.log' 获取打印输出，查看当前目录获取保存的图表。")
上述是yuanweihua.py
import sys
import numpy as np
import logging
from collections.abc import Iterable
import tensorflow as tf
from tensorflow.python.keras.callbacks import BaseLogger, CallbackList, History, ProgbarLogger
from tensorflow.python.keras.layers import Dropout
#from tensorflow.python.keras.utils import Sequence
from blinker import signal
from .datasets import InMemoryDataset, GeneratorDataset
from .model_wrappers import OracleWrapper
from .samplers import ConditionalStartSampler, VarianceReductionCondition, \
    AdaptiveAdditiveSmoothingSampler, AdditiveSmoothingSampler, ModelSampler, \
    ConstantVarianceSampler, ConstantTimeSampler, SCSGSampler
from .reweighting import BiasedReweightingPolicy, NoReweightingPolicy
from .utils.functional import ___, compose, partial


class _BaseImportanceTraining(object):
    def __init__(self, model, score="gnorm", layer=None):
        """重要性采样训练的基类。

        参数：
            model: 要训练的 Keras 模型。
        """
        # 检查模型是否兼容，并包装模型以支持重要性采样
        self._check_model(model)
        self.original_model = model
        self.model = OracleWrapper(
            model,
            self.reweighting,
            score=score,
            layer=layer
        )
        self.original_model.optimizer = self.model.optimizer
        signal("is.sample").connect(self._on_sample)
        signal("is.score").connect(self._on_scores)

    def _on_sample(self, event):
        self._latest_sample_event = event

    def _on_scores(self, scores):
        self._latest_scores = scores

    def _check_model(self, model):
        """检查模型是否使用了 Dropout 和 BatchNorm，并警告可能影响重要性计算。"""
        if any(
                isinstance(l, (tf.keras.layers.BatchNormalization, Dropout))
                for l in model.layers
        ):
            sys.stderr.write(("[NOTICE]: 您正在使用 BatchNormalization 和/或 Dropout。\n"
                              "这些层可能会影响重要性计算，建议您用 LayerNormalization 或 "
                              "在测试模式下的 BatchNormalization 以及 L2 正则化替代它们。\n"))

    @property
    def reweighting(self):
        """控制重要性采样时偏置的重加权策略。"""
        raise NotImplementedError()

    def sampler(self, dataset, batch_size, steps_per_epoch, epochs):
        """为给定的数据集创建一个新的采样器，以使用重要性采样进行采样。"""
        raise NotImplementedError()

    def fit(self, x, y, batch_size=32, epochs=1, verbose=1, callbacks=None,
            validation_split=0.0, validation_data=None, steps_per_epoch=None,
            on_sample=None, on_scores=None):
        """使用给定的数据创建一个 InMemoryDataset 实例，并使用重要性采样训练模型。

        参数：
            x: 训练数据的 Numpy 数组或 Numpy 数组列表。
            y: 目标数据的 Numpy 数组。
            batch_size: 每个梯度更新的样本数。
            epochs: 遍历整个训练集的次数。
            verbose: {0, >0}，是否使用 Keras 的进度条回调。
            callbacks: 在训练期间调用的 Keras 回调列表。
            validation_split: [0, 1) 之间的浮点数，用于验证的数据百分比。
            validation_data: tuple，(x_val, y_val)，用于模型验证的数据。
            steps_per_epoch: int 或 None，每个 epoch 的步数。
            on_sample: 接受 sampler, idxs, w, scores 的回调函数。
            on_scores: 接受 sampler 和 scores 的回调函数。
        返回：
            包含训练期间收集的信息的 Keras `History` 对象。
        """
        # 处理验证数据集
        if validation_data is not None:
            x_train, y_train = x, y
            x_test, y_test = validation_data
        elif validation_split > 0:
            assert validation_split < 1, "验证集比例必须小于 1"
            n = int(round(validation_split * len(x)))
            idxs = np.arange(len(x))
            np.random.shuffle(idxs)
            x_train, y_train = x[idxs[n:]], y[idxs[n:]]
            x_test, y_test = x[idxs[:n]], y[idxs[:n]]
        else:
            x_train, y_train = x, y
            x_test, y_test = np.empty(shape=(0, x.shape[1])), np.empty(shape=(0, y.shape[1]))

        # 创建数据集
        dataset = InMemoryDataset(
            x_train,
            y_train,
            x_test,
            y_test,
            categorical=False  # 不需要转换标签
        )

        return self.fit_dataset(
            dataset=dataset,
            batch_size=batch_size,
            epochs=epochs,
            steps_per_epoch=steps_per_epoch,
            verbose=verbose,
            callbacks=callbacks,
            on_sample=on_sample,
            on_scores=on_scores
        )

    def fit_generator(self, train, steps_per_epoch=None, batch_size=32,
                      epochs=1, verbose=1, callbacks=None,
                      validation_data=None, validation_steps=None,
                      on_sample=None, on_scores=None):
        """创建一个 GeneratorDataset 实例，并使用重要性采样训练模型。

        参数：
            train: 返回 (inputs, targets) 的生成器或可迭代对象。
            steps_per_epoch: 每个 epoch 的梯度更新次数。
            batch_size: 每个梯度更新的样本数。
            epochs: 训练轮数。
            verbose: {0, >0}，是否使用 Keras 的进度条回调。
            validation_data: 生成器、可迭代对象或 (inputs, targets) 元组。
            validation_steps: 如果 validation_data 是生成器，则需要指定此参数。
            on_sample: 接受 sampler, idxs, w, scores 的回调函数。
            on_scores: 接受 sampler 和 scores 的回调函数。
        """

        def infinite_iterator(iterable):
            while True:
                yield from iterable

        # 处理验证数据集
        if validation_data is not None:
            if isinstance(validation_data, (tuple, list)):
                test = validation_data
                test_len = None
            elif isinstance(validation_data, Iterable):
                test = infinite_iterator(validation_data)
                try:
                    test_len = len(validation_data) * batch_size
                except TypeError:
                    test_len = validation_steps * batch_size if validation_steps else None
            else:
                test = validation_data
                test_len = validation_steps * batch_size if validation_steps else None
        else:
            test = (np.empty(shape=(0, 1)), np.empty(shape=(0, 1)))
            test_len = None
            logging.info("未提供验证数据")

        # 设置训练数据和每个 epoch 的步数
        if isinstance(train, Iterable):
            if steps_per_epoch is None:
                try:
                    steps_per_epoch = len(train)
                except TypeError:
                    raise ValueError("使用没有 __len__ 方法的生成器时必须设置 steps_per_epoch")
            train = infinite_iterator(train)
        elif steps_per_epoch is None:
            raise ValueError("steps_per_epoch 未设置")

        dataset = GeneratorDataset(train, test, test_len)

        return self.fit_dataset(
            dataset=dataset,
            batch_size=batch_size,
            epochs=epochs,
            steps_per_epoch=steps_per_epoch,
            verbose=verbose,
            callbacks=callbacks,
            on_sample=on_sample,
            on_scores=on_scores
        )

    def fit_dataset(self, dataset, steps_per_epoch=None, batch_size=32,
                    epochs=1, verbose=1, callbacks=None, on_sample=None,
                    on_scores=None):
        """在给定的数据集上训练模型。

        参数：
            dataset: `BaseDataset` 的实例，提供要训练的数据。
            steps_per_epoch: int，每个 epoch 的梯度更新次数。
            batch_size: 每个梯度更新的样本数。
            epochs: 训练轮数。
            verbose: {0, >0}，是否使用 Keras 的进度条回调。
            callbacks: Keras 回调列表。
            on_sample: 接受 sampler, idxs, w, scores 的回调函数。
            on_scores: 接受 sampler 和 scores 的回调函数。
        """
        try:
            if len(dataset.train_data) < batch_size:
                raise ValueError("batch_size 大于训练集大小")
        except RuntimeError as e:
            assert "no size" in str(e)

        # 设置 steps_per_epoch
        if steps_per_epoch is None:
            steps_per_epoch = len(dataset.train_data) // batch_size

        # 创建回调列表
        self.history = History()
        callbacks = [BaseLogger()] + (callbacks or []) + [self.history]
        if verbose > 0:
            callbacks += [ProgbarLogger(count_mode="steps")]
        callbacks = CallbackList(callbacks)
        callbacks.set_model(self.original_model)
        callbacks.set_params({
            "epochs": epochs,
            "steps": steps_per_epoch,
            "verbose": verbose,
            "do_validation": len(dataset.test_data) > 0,
            "metrics": self.metrics_names + [
                "val_" + n for n in self.metrics_names
            ]
        })

        # 创建采样器
        sampler = self.sampler(dataset, batch_size, steps_per_epoch, epochs)

        # 开始训练循环
        epoch = 0
        self.original_model.stop_training = False
        callbacks.on_train_begin()
        while epoch < epochs:
            callbacks.on_epoch_begin(epoch)

            for step in range(steps_per_epoch):
                batch_logs = {"batch": step, "size": batch_size}
                callbacks.on_batch_begin(step, batch_logs)

                # 在这里进行重要性采样
                idxs, (x_batch, y_batch), w = sampler.sample(batch_size)

                # 将 x_batch 和 y_batch 转换为 TensorFlow 张量
                x_batch = tf.convert_to_tensor(x_batch)
                y_batch = tf.convert_to_tensor(y_batch)
                w = tf.convert_to_tensor(w, dtype=tf.float32)

                # 自定义训练步骤
                loss_value, metrics_results, scores = self.train_batch(x_batch, y_batch, w)

                # 更新采样器
                sampler.update(idxs, scores)

                # 记录指标
                batch_logs['loss'] = loss_value
                for metric_name, metric_value in zip(self.metrics_names[1:], metrics_results):
                    batch_logs[metric_name] = metric_value
                callbacks.on_batch_end(step, batch_logs)

                if on_scores is not None and hasattr(self, "_latest_scores"):
                    on_scores(
                        sampler,
                        self._latest_scores
                    )

                if on_sample is not None:
                    on_sample(
                        sampler,
                        self._latest_sample_event["idxs"],
                        self._latest_sample_event["w"],
                        self._latest_sample_event["predicted_scores"]
                    )

                if self.original_model.stop_training:
                    break

            # 在每个 epoch 结束时进行评估
            epoch_logs = {}
            if len(dataset.test_data) > 0:
                val_loss, val_metrics = self.evaluate(dataset.test_data)
                epoch_logs['val_loss'] = val_loss
                for name, value in zip(self.metrics_names[1:], val_metrics):
                    epoch_logs['val_' + name] = value
            callbacks.on_epoch_end(epoch, epoch_logs)
            if self.original_model.stop_training:
                break
            epoch += 1
        callbacks.on_train_end()

        return self.history

    @property
    def metrics_names(self):
        def name(x):
            if isinstance(x, str):
                return x
            if hasattr(x, "name"):
                return x.name
            if hasattr(x, "__name__"):
                return x.__name__
            return str(x)

        metrics = self.model.model.metrics or []
        return (
                ["loss"] +
                [name(m) for m in metrics]
        )

    def train_batch(self, x, y, w):
        with tf.GradientTape() as tape:
            y_pred = self.model.model(x, training=True)

            # 获取损失函数
            loss_fn = self.model.model.loss

            # 处理字符串形式的损失函数
            if isinstance(loss_fn, str):
                loss_fn = tf.keras.losses.get(loss_fn)
            elif isinstance(loss_fn, dict):
                loss_fn = tf.keras.losses.get(loss_fn)
            elif not callable(loss_fn):
                raise ValueError(f"Unsupported loss function type: {type(loss_fn)}")

            # 确保损失函数的 reduction 设置为 NONE
            if isinstance(loss_fn, tf.keras.losses.Loss):
                loss_config = loss_fn.get_config()
                per_example_loss_fn = loss_fn.__class__(reduction=tf.keras.losses.Reduction.NONE, **loss_config)
                per_sample_losses = per_example_loss_fn(y, y_pred)
            else:
                per_sample_losses = loss_fn(y, y_pred)

            # 使用正确的评分方法
            if self.model.score_method == "loss":
                scores = per_sample_losses
            else:
                scores = tf.ones_like(per_sample_losses)

            # 计算样本权重和加权损失
            weights = self.reweighting.weight_layer()([scores, w])

            # **确保两个张量都是 float32**
            per_sample_losses = tf.cast(per_sample_losses, tf.float32)
            weights = tf.cast(weights, tf.float32)

            weighted_losses = per_sample_losses * weights
            loss = tf.reduce_mean(weighted_losses)

        trainable_vars = self.model.model.trainable_variables
        gradients = tape.gradient(loss, trainable_vars)
        self.model.model.optimizer.apply_gradients(zip(gradients, trainable_vars))

        self.model.model.compiled_metrics.update_state(y, y_pred, sample_weight=weights)
        metrics = [metric.result().numpy() for metric in self.model.model.metrics]

        return loss.numpy(), metrics, scores.numpy()

    def evaluate(self, test_data):
        print(f"test_data type: {type(test_data)}, length: {len(test_data)}")
        print(f"test_data contents: {test_data}")

        x_test, y_test = test_data[:2]
        # 只获取前两个元素
        x_test, y_test = test_data[:2]

        # 如果 x_test 或 y_test 是元组，提取其中的数组
        if isinstance(x_test, tuple) or isinstance(x_test, list):
            x_test = x_test[0]
        if isinstance(y_test, tuple) or isinstance(y_test, list):
            y_test = y_test[0]

        # 确保 x_test 和 y_test 是 NumPy 数组或张量
        x_test = np.asarray(x_test)
        y_test = np.asarray(y_test)

        y_pred = self.model.model.predict(x_test, batch_size=128)

        # 确保 y_test 和 y_pred 是张量
        y_test = tf.convert_to_tensor(y_test)
        y_pred = tf.convert_to_tensor(y_pred)

        loss_value = self.model.model.compiled_loss(y_test, y_pred, regularization_losses=self.model.model.losses)

        # 更新指标
        self.model.model.compiled_metrics.update_state(y_test, y_pred)
        metrics_results = [m.result().numpy() for m in self.model.model.metrics]

        return loss_value.numpy(), metrics_results

class _UnbiasedImportanceTraining(_BaseImportanceTraining):
    def __init__(self, model, score="gnorm", layer=None):
        self._reweighting = BiasedReweightingPolicy(1.0)  # 无偏

        super(_UnbiasedImportanceTraining, self).__init__(model, score, layer)

    @property
    def reweighting(self):
        return self._reweighting

class ConstantTimeImportanceTraining(_UnbiasedImportanceTraining):
    """使用常时间重要性采样训练模型。

    参数：
        model: 要训练的 Keras 模型。
        score: {"gnorm", "loss", "full_gnorm"}，用于重要性采样的重要性度量。
        layer: None 或 int 或 Layer，计算 gnorm 时使用的层。
    """

    def __init__(self, model, backward_pass_multiplier=2.0, extra_samples=0.1,
                 score="gnorm", layer=None):
        self._backward_pass_multiplier = backward_pass_multiplier
        self._extra_samples = extra_samples

        super(ConstantTimeImportanceTraining, self).__init__(
            model,
            score,
            layer
        )

    def sampler(self, dataset, batch_size, steps_per_epoch, epochs):
        return ConstantTimeSampler(
            dataset,
            self.reweighting,
            self.model,
            backward_time=self._backward_pass_multiplier,
        )
上述是training.py文件
出现报错
Traceback (most recent call last):
  File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 301, in <module>
    history = wrapped_model.fit(
  File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\importance_sampling\training.py", line 132, in fit
    return self.fit_dataset(
  File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\importance_sampling\training.py", line 304, in fit_dataset
    val_loss, val_metrics = self.evaluate(dataset.test_data)
  File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\importance_sampling\training.py", line 399, in evaluate
    y_pred = self.model.model.predict(x_test, batch_size=128)
  File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "G:\anaconda3\envs\pennylane2\lib\site-packages\tensorflow\python\framework\func_graph.py", line 1233, in autograph_handler
    raise e.ag_error_metadata.to_exception(e)
tensorflow.python.framework.errors_impl.OperatorNotAllowedInGraphError: in user code:

    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 2041, in predict_function  *
        return step_function(self, iterator)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 2027, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 2015, in run_step  **
        outputs = model.predict_step(data)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1983, in predict_step
        return self(x, training=False)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
        raise e.with_traceback(filtered_tb) from None

    OperatorNotAllowedInGraphError: Exception encountered when calling layer "quantum_neural_network" "                 f"(type QuantumNeuralNetwork).
    
    in user code:
    
        File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 246, in call  *
            q_output = self.quantum_layer(inputs)
        File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler  **
            raise e.with_traceback(filtered_tb) from None
    
        OperatorNotAllowedInGraphError: Exception encountered when calling layer "quantum_neural_network_layer" "                 f"(type QuantumNeuralNetworkLayer).
        
        in user code:
        
            File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 217, in apply_qnode  *
                result = quantum_neural_network(x, self.encoding_weights, self.rot_weights)
            File "G:\anaconda3\envs\pennylane2\lib\site-packages\pennylane\qnode.py", line 552, in __call__  *
                self.construct(args, kwargs)
            File "G:\anaconda3\envs\pennylane2\lib\site-packages\pennylane\qnode.py", line 481, in construct  *
                self.qfunc_output = self.func(*args, **kwargs)
            File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 117, in quantum_neural_network  *
                encode_group(
            File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 76, in encode_group  *
                for data_qubit, angle_value, angle_weight in zip(data_qubits, angle_values, angle_weights):
        
            OperatorNotAllowedInGraphError: Iterating over a symbolic `tf.Tensor` is not allowed: AutoGraph did convert this function. This might indicate you are trying to use an unsupported feature.
        
        
        Call arguments received by layer "quantum_neural_network_layer" "                 f"(type QuantumNeuralNetworkLayer):
          • inputs=tf.Tensor(shape=(None, 4), dtype=float32)
    
    
    Call arguments received by layer "quantum_neural_network" "                 f"(type QuantumNeuralNetwork):
      • inputs=tf.Tensor(shape=(None, 4), dtype=float32)
如何解决报错