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.python.keras.layers import Dense  # 修改导入方式
from example_utils import get_parser  # 请确保该模块存在
from importance_sampling.training import ConstantTimeImportanceTraining  # 请确保该模块存在
from pennylane.qnn.keras import KerasLayer

# 重定向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

# 设置 Keras 的默认浮点类型为 float64
tf.keras.backend.set_floatx('float64')

# 修改设备定义，使用 lightning.qubit 设备，并确保量子比特数量足够，同时移除 dtype 参数
dev = qml.device("lightning.qubit", wires=11)  # 量子比特编号 0 到 10

def multi_controlled_RY(angle, control_qubits, target, ancilla):
    """
    实现双控制RY门的分解。

    参数：
    - angle (float): 旋转角度。
    - control_qubits (list[int]): 控制比特的索引，例如 [0, 1]。
    - target (int): 目标比特的索引。
    - ancilla (int): 辅助比特的索引。
    """
    qml.CNOT(wires=[control_qubits[0], ancilla])
    qml.CNOT(wires=[control_qubits[1], ancilla])
    qml.RY(angle / 2, wires=target)
    qml.CNOT(wires=[ancilla, target])
    qml.RY(-angle / 2, wires=target)
    qml.CNOT(wires=[control_qubits[1], ancilla])
    qml.CNOT(wires=[control_qubits[0], ancilla])

def encode_group(control_qubits, data_qubits, angle_q2, angle_q3, ancilla=10):
    """
    模块化方法，用于对一组量子比特进行角度编码。

    参数：
    - control_qubits (list[int]): 控制比特的索引，例如 [0, 1]。
    - data_qubits (dict): 包含 'q2' 和 'q3' 的量子比特索引，例如 {'q2': 2, 'q3': 3}。
    - angle_q2 (tensor): q2 的 Ry 旋转角度。
    - angle_q3 (tensor): q3 的 Ry 旋转角度列表，对应4种控制比特组合。
    - ancilla (int): 辅助比特的索引，默认为10。
    """
    control_values = [[0, 0], [0, 1], [1, 0], [1, 1]]

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

        # 对 q2 应用多控制 RY 旋转
        multi_controlled_RY(angle_q2, control_qubits, data_qubits['q2'], ancilla)

        # 对 q3 应用多控制 RY 旋转
        multi_controlled_RY(angle_q3_val, control_qubits, data_qubits['q3'], ancilla)

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

def apply_controlled_swap(swap_qubit, q_swap1, q_swap2):
    """
    模块化方法，用于应用受控 SWAP 门。

    参数：
    - swap_qubit (int): 作为交换门控制比特的量子比特索引。
    - q_swap1 (int): 受交换操作影响的第一个量子比特索引。
    - q_swap2 (int): 受交换操作影响的第二个量子比特索引。
    """
    # 对 swap_qubit 应用 Hadamard 门
    qml.Hadamard(wires=swap_qubit)

    # 应用受控 SWAP 门
    qml.CSWAP(wires=[swap_qubit, q_swap1, q_swap2])

    # 再次对 swap_qubit 应用 Hadamard 门以恢复控制比特
    qml.Hadamard(wires=swap_qubit)

# 定义一个量子节点 (QNode) 用于 KerasLayer
@qml.qnode(dev, interface='tf', diff_method='parameter-shift')
def quantum_neural_network_for_keras(inputs, encoding_weights, rot_weights):
    control_qubits = [0, 1]
    ancilla = 10  # 辅助量子比特

    encoding_data = [
        {'data_qubits': {'q2': 2, 'q3': 3}, 'swap_qubit': 4},
        {'data_qubits': {'q2': 5, 'q3': 6}, 'swap_qubit': 7},
        {'data_qubits': {'q2': 8, 'q3': 9}, 'swap_qubit': 10}
    ]

    # 将输入数据映射到 angles_q2
    angles_q2_list = inputs[:3]  # 假设前3个输入对应3个编码组

    # 将 encoding_weights 映射到 angles_q3
    angles_q3_list = encoding_weights[:3, :, :4]  # Tensor of shape (3, n_layers, 4)

    # 进行编码
    for idx, data_set in enumerate(encoding_data):
        data_qubits = data_set['data_qubits']
        swap_qubit = data_set['swap_qubit']

        angle_q2 = angles_q2_list[idx]  # Tensor scalar

        for layer in range(rot_weights.shape[0]):
            angle_q3_values = angles_q3_list[idx, layer, :]  # Tensor of shape (4,)
            encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values, ancilla)

    # 应用交换操作
    for data_set in encoding_data:
        swap_qubit = data_set['swap_qubit']
        data_qubits = data_set['data_qubits']
        apply_controlled_swap(swap_qubit, data_qubits['q3'], data_qubits['q2'])

    # 应用 Rot 层
    for layer in range(rot_weights.shape[0]):
        for qubit in range(rot_weights.shape[1]):
            rot_angles = rot_weights[layer, qubit, :]  # Tensor of shape (3,)
            qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit)

    # 测量 PauliZ 期望值
    results = [qml.expval(qml.PauliZ(data_set['swap_qubit'])) for data_set in encoding_data]

    return results

# 定义一个量子节点 (QNode) 用于绘制电路
@qml.qnode(dev)
def quantum_neural_network_draw(inputs, encoding_weights, rot_weights):
    control_qubits = [0, 1]
    ancilla = 10  # 辅助量子比特

    encoding_data = [
        {'data_qubits': {'q2': 2, 'q3': 3}, 'swap_qubit': 4},
        {'data_qubits': {'q2': 5, 'q3': 6}, 'swap_qubit': 7},
        {'data_qubits': {'q2': 8, 'q3': 9}, 'swap_qubit': 10}
    ]

    # 将输入数据映射到 angles_q2
    angles_q2_list = inputs[:3]  # 假设前3个输入对应3个编码组

    # 将 encoding_weights 映射到 angles_q3
    angles_q3_list = encoding_weights[:3, :, :4]  # Tensor of shape (3, n_layers, 4)

    # 进行编码
    for idx, data_set in enumerate(encoding_data):
        data_qubits = data_set['data_qubits']
        swap_qubit = data_set['swap_qubit']

        angle_q2 = angles_q2_list[idx]  # Tensor scalar

        for layer in range(rot_weights.shape[0]):
            angle_q3_values = angles_q3_list[idx, layer, :]  # Tensor of shape (4,)
            encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values, ancilla)

    # 应用交换操作
    for data_set in encoding_data:
        swap_qubit = data_set['swap_qubit']
        data_qubits = data_set['data_qubits']
        apply_controlled_swap(swap_qubit, data_set['data_qubits']['q3'], data_set['data_qubits']['q2'])

    # 应用 Rot 层
    for layer in range(rot_weights.shape[0]):
        for qubit in range(rot_weights.shape[1]):
            rot_angles = rot_weights[layer, qubit, :]  # Tensor of shape (3,)
            qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit)

    # 测量 PauliZ 期望值
    results = [qml.expval(qml.PauliZ(data_set['swap_qubit'])) for data_set in encoding_data]

    return results

# 定义一个量子神经网络层，使用 KerasLayer
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
    def __init__(self, n_qubits, n_layers, num_classes, **kwargs):
        super(QuantumNeuralNetworkLayer, self).__init__(**kwargs)
        self.n_qubits = n_qubits
        self.n_layers = n_layers
        self.num_classes = num_classes

        # 定义 Quantum Layer 使用 KerasLayer，移除 'inputs' 从 weight_shapes
        self.quantum_layer = KerasLayer(
            quantum_neural_network_for_keras,
            weight_shapes={
                "encoding_weights": (3, n_layers, 4),
                "rot_weights": (n_layers, n_qubits, 3)
            },
            output_dim=3  # 根据测量结果数量设置输出维度
        )

    def call(self, inputs):
        return self.quantum_layer(inputs)

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

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

        # Classical layers，确保 Dense 层使用 float64
        self.dense = Dense(num_classes, activation='softmax', dtype='float64')

    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.float64)  # 修改为 float64
    y = iris['target'].reshape(-1, 1)

    # 根据 scikit-learn 版本选择参数名称
    import sklearn
    from packaging import version

    sklearn_version = sklearn.__version__
    print(f"scikit-learn version: {sklearn_version}")
    if version.parse(sklearn_version) >= version.parse("1.2"):
        encoder = OneHotEncoder(sparse_output=False)
    else:
        encoder = OneHotEncoder(sparse=False)

    y = encoder.fit_transform(y).astype(np.float64)  # 修改为 float64

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

    learning_rate = 0.05
    epochs = 100
    batch_size = 8
    num_classes = 3
    n_qubits = 11  # 调整为11个量子比特（0到10）
    n_layers = 3  # 调整为三层

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

    optimizer = tf.keras.optimizers.SGD(learning_rate=learning_rate)

    model.compile(
        optimizer=optimizer,
        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:")
    # 使用 TensorFlow 常量传递参数，并确保类型为 float64
    sample_inputs = tf.constant(np.ones(3, dtype=np.float64) * (np.pi / 2))  # 修改为 float64，并假设3个输入特征
    sample_encoding_weights = tf.constant(np.zeros((3, n_layers, 4), dtype=np.float64))  # encoding_weights 修改为 float64
    sample_rot_weights = tf.constant(np.zeros((n_layers, n_qubits, 3), dtype=np.float64))  # rot_weights 修改为 float64

    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]
        )

    # 在 training.py 文件中
    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)

            # 使用正确的 score_method
            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])
            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 "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane - NewFacility\examples\yuanweihua_renew_usesoftmax_NQNN_newFacility.py", line 334, in <module>
    history = wrapped_model.fit(
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane - NewFacility\importance_sampling\training.py", line 132, in fit
    return self.fit_dataset(
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane - NewFacility\importance_sampling\training.py", line 273, in fit_dataset
    loss_value, metrics_results, scores = self.train_batch(x_batch, y_batch, w)
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane - NewFacility\importance_sampling\training.py", line 365, in train_batch
    weighted_losses = per_sample_losses * weights
  File "C:\Users\liuwenjing\.conda\envs\pennylane3\lib\site-packages\tensorflow\python\util\traceback_utils.py", line 153, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "C:\Users\liuwenjing\.conda\envs\pennylane3\lib\site-packages\tensorflow\python\framework\ops.py", line 7209, in raise_from_not_ok_status
    raise core._status_to_exception(e) from None  # pylint: disable=protected-access
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute Mul as input #1(zero-based) was expected to be a double tensor but is a float tensor [Op:Mul]
出现上述报错，修改代码，不允许改动原文逻辑