#
from __future__ import print_function
# import os
# os.environ['TF_USE_LEGACY_KERAS'] = '1'
# from tensorflow.python.keras.layers import Dense, Activation
# from tensorflow.python.keras import backend as K, Input
# from tensorflow.python.keras.optimizer_v2.adam import Adam
# from sklearn import datasets
# from sklearn.model_selection import train_test_split
# from sklearn.preprocessing import OneHotEncoder
# from sklearn.metrics import roc_curve, auc
# import numpy as np
# import matplotlib.pyplot as plt
# from tensorflow.python.keras.models import Model
# from importance_sampling.training import ConstantTimeImportanceTraining
# from example_utils import get_parser
# import pennylane as qml
# import tensorflow as tf
# # tf.compat.v1.disable_eager_execution()
#
# def plot_history(history):
#     plt.figure(figsize=(12, 5))
#
#     # 绘制训练集和验证集的准确率
#     plt.subplot(121)
#     plt.plot(history.history['accuracy'])
#     plt.plot(history.history['val_accuracy'])
#     plt.title('Model accuracy')
#     plt.ylabel('Accuracy')
#     plt.xlabel('Epoch')
#     plt.legend(['Train', 'Validation'], loc='upper left')
#
#     # 绘制训练集和验证集的损失
#     plt.subplot(122)
#     plt.plot(history.history['loss'])
#     plt.plot(history.history['val_loss'])
#     plt.title('Model loss')
#     plt.ylabel('Loss')
#     plt.xlabel('Epoch')
#     plt.legend(['Train', 'Validation'], loc='upper left')
#
#     plt.tight_layout()
#     plt.show()
#
#
# def plot_roc_curve(y_test, y_pred):
#     n_classes = y_test.shape[1]
#     fpr = dict()
#     tpr = dict()
#     roc_auc = dict()
#
#     for i in range(n_classes):
#         fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_pred[:, i])
#         roc_auc[i] = auc(fpr[i], tpr[i])
#
#     # Compute micro-average ROC curve and ROC area
#     fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_pred.ravel())
#     roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])
#
#     plt.figure()
#     plt.plot(fpr["micro"], tpr["micro"],
#              label='micro-average ROC curve (area = {0:0.2f})'
#                    ''.format(roc_auc["micro"]))
#     for i in range(n_classes):
#         plt.plot(fpr[i], tpr[i],
#                  label='ROC curve of class {0} (area = {1:0.2f})'
#                        ''.format(i, roc_auc[i]))
#
#     plt.plot([0, 1], [0, 1], 'k--')
#     plt.xlim([0.0, 1.0])
#     plt.ylim([0.0, 1.05])
#     plt.xlabel('False Positive Rate')
#     plt.ylabel('True Positive Rate')
#     plt.title('Receiver Operating Characteristic (ROC) Curve')
#     plt.legend(loc="lower right")
#     plt.show()
#
#
# def calculate_accuracy_fluctuation(history):
#     # 获取每个 epoch 的验证集准确率
#     val_accuracies = history.history['val_accuracy']
#
#     # 计算平均准确率
#     mean_accuracy = np.mean(val_accuracies)
#
#     # 计算每个 epoch 的准确率波动（与均值的绝对差值）
#     fluctuation = np.sum(np.abs(val_accuracies - mean_accuracy))
#
#     return mean_accuracy, fluctuation
#
#
# if __name__ == "__main__":
#     parser = get_parser("训练模型于鸢尾花数据集")
#     args = parser.parse_args()
#
#     # 加载并预处理鸢尾花数据集
#     iris = datasets.load_iris()
#     x_data = iris.data
#     y_data = iris.target.reshape(-1, 1)
#
#     # One-hot 编码标签
#     encoder = OneHotEncoder(sparse_output=False)
#     y_data = encoder.fit_transform(y_data)
#
#     # 划分数据集
#     x_train, x_test, y_train, y_test = train_test_split(
#         x_data, y_data, test_size=0.3, random_state=116)
#
#     # 定义超参数
#     learning_rate = 0.1
#     epochs = 100
#     batch_size = 8
#     num_classes = 3  # 鸢尾花数据集有 3 个类别
#
#     # 定义量子设备和电路
#     n_qubits = 4  # 量子比特数量（应与特征数量匹配）
#     dev = qml.device('default.qubit', wires=n_qubits, shots=None)
#
#     @qml.qnode(dev, interface='tf', diff_method='backprop')
#     def quantum_circuit(weights, inputs):
#         inputs = tf.cast(inputs, tf.float32)  # 确保输入为 float32
#         weights = tf.cast(weights, tf.float32)  # 确保权重为 float32
#
#         def circuit_single_sample(x):
#             # 数据编码
#             qml.templates.AngleEmbedding(x, wires=range(n_qubits))
#             # 变分层
#             qml.templates.StronglyEntanglingLayers(weights, wires=range(n_qubits))
#             # 测量
#             return [qml.expval(qml.PauliZ(i)) for i in range(num_classes)]
#
#         # 使用 tf.vectorized_map 或 tf.map_fn 处理批量输入
#         results = tf.map_fn(circuit_single_sample, inputs, dtype=tf.float32)
#         return results
#
#     # 定义权重形状
#     n_layers = 2
#     weight_shapes = {"weights": (n_layers, n_qubits, 3)}
#
#     # 将量子电路包装为 Keras 层
#     qlayer = qml.qnn.KerasLayer(quantum_circuit, weight_shapes, output_dim=num_classes, dtype=tf.float32)
#
#     # 使用 Functional API 构建模型
#     inputs = Input(shape=(4,), dtype=tf.float32)
#     x = qlayer(inputs)
#     outputs = Activation('softmax')(x)
#     model = Model(inputs=inputs, outputs=outputs)
#
#     # 编译模型
#     model.compile(
#         optimizer=Adam(learning_rate=learning_rate),
#         loss='categorical_crossentropy',
#         metrics=['accuracy']
#     )
#
    # # 根据是否启用重要性采样选择训练方法
    # if args.importance_training:
    #     # 使用重要性采样进行自定义训练
    #     wrapped_model = ConstantTimeImportanceTraining(model)
    #     history = wrapped_model.fit(
    #         x_train, y_train,
    #         batch_size=batch_size,
    #         epochs=epochs,
    #         verbose=1,
    #         validation_data=(x_test, y_test)
    #     )
    # else:
    #     # 使用标准的 Keras 训练
    #     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('测试损失:', score[0])
    # print('测试准确率:', score[1])
    #
    # # 计算并显示准确率波动
    # mean_accuracy, fluctuation = calculate_accuracy_fluctuation(history)
    # print('平均验证准确率:', mean_accuracy)
    # print('准确率波动:', fluctuation)
    #
    # # 绘制训练历史
    # plot_history(history)
    #
    # # 预测概率
    # y_pred = model.predict(x_test)
    #
    # # 绘制 ROC 曲线
    # plot_roc_curve(y_test, y_pred)

import pennylane as qml
import tensorflow as tf
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
import matplotlib.pyplot as plt
from tensorflow.python.keras.layers import Dense  # 使用公共 API 导入
from tensorflow.python.keras.optimizer_v1 import Adam, SGD
from example_utils import get_parser
from importance_sampling.training import ConstantTimeImportanceTraining
from sklearn.metrics import roc_curve, auc

def plot_history(history):
    plt.figure(figsize=(12, 5))

    # 绘制训练集和验证集的准确率
    plt.subplot(121)
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('Model Accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Validation'], loc='upper left')

    # 绘制训练集和验证集的损失
    plt.subplot(122)
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model Loss')
    plt.ylabel('Loss')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Validation'], loc='upper left')

    plt.tight_layout()
    plt.show()

def plot_roc_curve(y_test, y_pred):
    n_classes = y_test.shape[1]
    fpr = dict()
    tpr = dict()
    roc_auc = dict()

    for i in range(n_classes):
        fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_pred[:, i])
        roc_auc[i] = auc(fpr[i], tpr[i])

    # Compute micro-average ROC curve and ROC area
    fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_pred.ravel())
    roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])

    plt.figure()
    plt.plot(fpr["micro"], tpr["micro"],
             label='micro-average ROC curve (area = {0:0.2f})'.format(roc_auc["micro"]))
    for i in range(n_classes):
        plt.plot(fpr[i], tpr[i],
                 label='ROC curve of class {0} (area = {1:0.2f})'.format(i, roc_auc[i]))

    plt.plot([0, 1], [0, 1], 'k--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver Operating Characteristic (ROC) Curve')
    plt.legend(loc="lower right")
    plt.show()

def calculate_accuracy_fluctuation(history):
    # 获取每个 epoch 的验证集准确率
    val_accuracies = history.history['val_accuracy']

    # 计算平均准确率
    mean_accuracy = np.mean(val_accuracies)

    # 计算每个 epoch 的准确率波动（与均值的绝对差值）
    fluctuation = np.sum(np.abs(val_accuracies - mean_accuracy))

    return mean_accuracy, fluctuation

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

        # 定义量子设备
        self.dev = qml.device('default.qubit', wires=self.n_qubits)

        # 定义量子电路
        @qml.qnode(self.dev, interface='tf', diff_method='backprop')
        def quantum_circuit(inputs, weights):
            qml.templates.AngleEmbedding(inputs, wires=range(n_qubits))
            qml.templates.StronglyEntanglingLayers(weights, wires=range(n_qubits))
            expvals = [qml.expval(qml.PauliZ(i)) for i in range(num_classes)]
            return qml.math.stack(expvals)

        self.quantum_circuit = quantum_circuit

        # 定义权重形状
        weight_shapes = {"weights": (self.n_layers, self.n_qubits, 3)}

        # 将量子电路包装为 Keras 层
        self.qnn_layer = qml.qnn.KerasLayer(
            self.quantum_circuit,
            weight_shapes,
            output_dim=self.num_classes,
            dtype=tf.float32
        )

        # 定义经典神经网络层
        self.dense = Dense(self.num_classes, activation='softmax')

    def call(self, inputs):
        x = self.qnn_layer(inputs)
        return self.dense(x)

if __name__ == "__main__":
    # 确保 `get_parser` 函数的正确实现
    parser = get_parser("训练模型于鸢尾花数据集")
    args = parser.parse_args()

    # 加载并预处理鸢尾花数据集
    iris = load_iris()
    X = iris['data']
    y = iris['target'].reshape(-1, 1)

    # One-hot 编码标签
    encoder = OneHotEncoder(sparse_output=False)
    y = encoder.fit_transform(y)

    # 划分数据集
    x_train, x_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=116
    )

    # 定义超参数
    learning_rate = 0.1
    epochs = 100
    batch_size = 8
    num_classes = 3  # 鸢尾花数据集有 3 个类别
    n_qubits = 4  # 量子比特数量（应与特征数量匹配）
    n_layers = 2

    # 创建模型
    model = QuantumNeuralNetwork(
        n_qubits=n_qubits,
        n_layers=n_layers,
        num_classes=num_classes
    )

    # 编译模型
    model.compile(
        optimizer=tf.keras.optimizers.SGD(lr=learning_rate),  # 使用公共 API 导入的 Adam
        loss='categorical_crossentropy',
        metrics=['accuracy']
    )

    # 根据是否启用重要性采样选择训练方法
    if args.importance_training:
        # 使用重要性采样进行自定义训练
        wrapped_model = ConstantTimeImportanceTraining(model)
        history = wrapped_model.fit(
            x_train, y_train,
            batch_size=batch_size,
            epochs=epochs,
            verbose=1,
            validation_data=(x_test, y_test)
        )
    else:
        # 使用标准的 Keras 训练
        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('测试损失:', score[0])
    print('测试准确率:', score[1])

    # 计算并显示准确率波动
    mean_accuracy, fluctuation = calculate_accuracy_fluctuation(history)
    print('平均验证准确率:', mean_accuracy)
    print('准确率波动:', fluctuation)

    # 绘制训练历史
    plot_history(history)

    # 预测概率
    y_pred = model.predict(x_test)

    # 绘制 ROC 曲线
    plot_roc_curve(y_test, y_pred)
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.original_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(x, training=True)
            # 计算损失时，需要确保 sample_weight 与 y_pred 形状兼容
            loss = self.model.compiled_loss(
                y,
                y_pred,
                sample_weight=w,
                regularization_losses=self.model.losses
            )
        # 确保 QuantumLayer 的参数被追踪
        trainable_vars = self.model.trainable_variables
        # 计算梯度
        gradients = tape.gradient(loss, trainable_vars)
        # 更新模型参数
        self.model.optimizer.apply_gradients(zip(gradients, trainable_vars))

        # 计算指标
        self.model.compiled_metrics.update_state(y, y_pred, sample_weight=w)
        metrics = [metric.result().numpy() for metric in self.model.metrics]

        # 返回损失、指标和得分（这里我们使用损失作为得分）
        scores = loss.numpy()

        return loss.numpy(), metrics, scores

    def evaluate(self, test_data):
        """评估模型在测试集上的性能。"""
        x_test, y_test = test_data[:]
        y_pred = self.model.predict(x_test, batch_size=128)
        loss_value = self.model.compiled_loss(y_test, y_pred, regularization_losses=self.model.losses)

        # 更新指标
        self.model.compiled_metrics.update_state(y_test, y_pred)
        metrics_results = [m.result().numpy() for m in self.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_pass_multiplier=self._backward_pass_multiplier,
            extra_samples=self._extra_samples
        )
上述代码报错To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
C:\Users\liuwenjing\.conda\envs\pennylane2\lib\site-packages\keras\optimizers\optimizer_v2\gradient_descent.py:111: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
  super().__init__(name, **kwargs)
Traceback (most recent call last):
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane\examples\yuanweihua.py", line 359, in <module>
    history = wrapped_model.fit(
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane\importance_sampling\training.py", line 132, in fit
    return self.fit_dataset(
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane\importance_sampling\training.py", line 251, in fit_dataset
    sampler = self.sampler(dataset, batch_size, steps_per_epoch, epochs)
  File "C:\代码备份库\importance-sampling-master-yuanweihua-QNN-pennylane\importance_sampling\training.py", line 404, in sampler
    return ConstantTimeSampler(
TypeError: __init__() got an unexpected keyword argument 'backward_pass_multiplier'
这是什么原因