CRZ to CNOT 问题
Creato il: 24 dicembre 2024
Creato il: 24 dicembre 2024
import sys
import os
import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler, LabelEncoder
from sklearn.decomposition import PCA # 导入 PCA
import matplotlib
matplotlib.use('Agg') # Use non-interactive backend
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Dense
from importance_sampling.training import ConstantTimeImportanceTraining
from importance_sampling.samplers import ConstantTimeSampler
from importance_sampling.datasets import InMemoryDataset
from importance_sampling.reweighting import BiasedReweightingPolicy
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
import logging
import pandas as pd
import seaborn as sns # 导入 seaborn 用于加载 Penguins 数据集
tf.keras.backend.set_floatx('float32')
class Tee(object):
def init(self, *files):
self.files = files
self.encoding = getattr(files[0], 'encoding', 'utf-8') # Add encoding attribute
textdef 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('企鹅_CRZ修改为CNOT.log', 'w', encoding='utf-8')
original_stdout = sys.stdout
tee = Tee(sys.stdout, output_file)
sys.stdout = tee
logger = logging.getLogger('my_sampler')
logger.setLevel(logging.INFO)
stream_handler = logging.StreamHandler(tee)
stream_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
if not logger.handlers:
logger.addHandler(stream_handler)
else:
logger.handlers = []
logger.addHandler(stream_handler)
logging.getLogger('qiskit').setLevel(logging.WARNING)
def save_plot(fig, filename):
fig.savefig(filename)
plt.close(fig)
def plot_history(history):
# Plot training and validation accuracy
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(history.history['accuracy'], label='Training Accuracy')
if 'val_accuracy' in history.history:
ax.plot(history.history['val_accuracy'], label='Validation Accuracy')
else:
print("Validation accuracy not found in history.")
ax.set_title('Model Accuracy')
ax.set_ylabel('Accuracy')
ax.set_xlabel('Epoch')
ax.legend(loc='upper left')
save_plot(fig, 'accuracy_plot.png')
text# Plot training and validation loss fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(history.history['loss'], label='Training Loss') if 'val_loss' in history.history: ax.plot(history.history['val_loss'], label='Validation Loss') else: print("Validation loss not found in history.") ax.set_title('Model Loss') ax.set_ylabel('Loss') ax.set_xlabel('Epoch') ax.legend(loc='upper right') save_plot(fig, 'loss_plot.png')
def calculate_accuracy_fluctuation(history):
if 'val_accuracy' in history.history:
accuracies = history.history['val_accuracy']
elif 'accuracy' in history.history:
accuracies = history.history['accuracy']
else:
print("Accuracy metric not found in history.")
return None, None
mean_accuracy = np.mean(accuracies)
fluctuation = np.sum(np.abs(accuracies - mean_accuracy))
return mean_accuracy, fluctuation
dev = qml.device("default.qubit", wires=14)
def encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values):
qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]],
control_values=[0, 0])
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]],
control_values=[0, 0])
textqml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1]) qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1]) qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1])
def encode_group_second(control_qubits, data_qubits, angle_q3_values):
# 第一组
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']),
control=[control_qubits[0], control_qubits[1]], control_values=[0, 0])
text# 第二组 qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) # 第三组 qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1]) # 第四组 qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1])
def apply_controlled_swap(swap_qubit, q_swap1, q_swap2):
"""
Modular method to apply a controlled SWAP gate.
textParameters: - swap_qubit (int): Control qubit for the SWAP gate. - q_swap1 (int): First qubit to swap. - q_swap2 (int): Second qubit to swap. """ qml.Hadamard(wires=swap_qubit) qml.CSWAP(wires=[swap_qubit, q_swap1, q_swap2]) qml.Hadamard(wires=swap_qubit)
@qml.qnode(dev, interface='tf', diff_method='backprop')
def quantum_neural_network(inputs, encoding_weights, rot_weights, entangle_weights):
control_qubits = [0, 1]
text# Neuron groups 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}, {'data_qubits': {'q2': 11, 'q3': 12}, 'swap_qubit': 13} ] # Angle encoding: inputs are mapped to [0, pi/2] angles_q2_list = inputs # inputs shape is (4,) # Encoding weights mapped to angles_q3 angles_q3_list = encoding_weights # shape: (4, n_layers, 8) # 第一层:同时编码values和weights qml.Hadamard(wires=control_qubits[0]) qml.Hadamard(wires=control_qubits[1]) for idx, data_set in enumerate(encoding_data): swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] angle_q2 = angles_q2_list[idx] # scalar value angle_q3_values = angles_q3_list[idx, 0, :] # shape: (8,) # 编码一个神经元 encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[0, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # 原先的 CRZ 改为 CNOT for qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 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']) # 第二层:仅编码weights for layer in range(rot_weights.shape[0] - 1): # 每层的内容 layer_second = layer + 1 # 每层完整编码特征值和权重值 for idx, data_set in enumerate(encoding_data): data_qubits = data_set['data_qubits'] angle_q3_values = angles_q3_list[idx, layer_second, :] # shape: (8,) # 编码一个神经元 encode_group_second(control_qubits, data_qubits, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[layer_second, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # 原先的 CRZ 改为 CNOT for qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 for data_set in encoding_data: swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] if layer % 2 == 0: apply_controlled_swap(data_qubits['q2'], swap_qubit, data_qubits['q3']) else: apply_controlled_swap(swap_qubit, data_qubits['q2'], data_qubits['q3']) if n_layers % 2 == 1: measured_qubits = [4, 7, 10, 13] else: measured_qubits = [2, 5, 8, 11] results = [qml.expval(qml.PauliZ(qubit)) for qubit in measured_qubits] return results
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
def init(self, n_qubits, n_layers, num_classes):
super(QuantumNeuralNetworkLayer, self).init()
self.n_qubits = n_qubits
self.n_layers = n_layers
self.num_classes = num_classes
text# Define encoding weights with L2 regularization initializer = tf.keras.initializers.GlorotUniform() regularizer = tf.keras.regularizers.l2(0.01) self.encoding_weights = self.add_weight( shape=(4, self.n_layers, 4), initializer=initializer, regularizer=regularizer, trainable=True, name='encoding_weights', dtype=tf.float32 ) # Define rotation layer weights with L2 regularization self.rot_weights = self.add_weight( shape=(n_layers, n_qubits, 3), initializer=initializer, regularizer=regularizer, trainable=True, name='rot_weights', dtype=tf.float32 ) # Define entangling weights with L2 regularization self.entangle_weights = self.add_weight( shape=(n_layers, n_qubits - 1), initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi), regularizer=regularizer, trainable=True, name='entangle_weights', dtype=tf.float32 ) def call(self, inputs): outputs_list = [] for i in range(tf.shape(inputs)[0]): x = inputs[i] x = tf.cast(x, tf.float32) result = quantum_neural_network(x, self.encoding_weights, self.rot_weights, self.entangle_weights) outputs_list.append(tf.cast(result, tf.float32)) outputs = tf.stack(outputs_list, axis=0) return outputs
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
text# Quantum layer self.quantum_layer = QuantumNeuralNetworkLayer(n_qubits, n_layers, num_classes) # Classical layers self.dense1 = tf.keras.layers.Dense( 16, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01), dtype=tf.float32 ) self.dense2 = tf.keras.layers.Dense( 8, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01), dtype=tf.float32 ) # Output layer directly connected to quantum outputs self.output_layer = Dense( num_classes, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2(0.01), dtype=tf.float32 # Ensure the output layer is float32 ) def call(self, inputs): q_output = self.quantum_layer(inputs) x = self.dense1(q_output) x = self.dense2(x) return self.output_layer(x)
def is_quantum_model(model):
for layer in model.layers:
if isinstance(layer, QuantumNeuralNetworkLayer):
return True
elif hasattr(layer, 'layers'):
if is_quantum_model(layer):
return True
return False
if name == "main":
# Load Palmer Penguins dataset
url = 'https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv'
try:
data = pd.read_csv(url)
except Exception as e:
print(f"Error loading the Penguins dataset: {e}")
sys.exit(1)
text# Handle missing values by dropping rows with any NaNs data = data.dropna() # Separate features and labels X = data.drop('species', axis=1) y = data['species'].values.reshape(-1, 1) # Labels: (n_samples,1) # Identify numerical and categorical features numerical_features = X.select_dtypes(include=['float64', 'int64']).columns.tolist() categorical_features = X.select_dtypes(include=['object', 'category']).columns.tolist() # Initialize encoders encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore') scaler = StandardScaler() min_max_scaler = MinMaxScaler(feature_range=(0, np.pi/2)) pca = PCA(n_components=4) # Set desired number of PCA components # Encode categorical features if categorical_features: X_categorical = encoder.fit_transform(X[categorical_features]) categorical_feature_names = encoder.get_feature_names_out(categorical_features) else: X_categorical = np.array([]).reshape(len(X), 0) categorical_feature_names = [] # Extract numerical features X_numerical = X[numerical_features].values.astype(np.float32) # Combine numerical and categorical features X_combined = np.hstack((X_numerical, X_categorical)).astype(np.float32) combined_feature_names = numerical_features + list(categorical_feature_names) # One-Hot encode labels label_encoder = OneHotEncoder(sparse_output=False) y_encoded = label_encoder.fit_transform(y).astype(np.float32) num_classes = y_encoded.shape[1] # Split into training and temp sets first (60% train, 40% temp) x_train, x_temp, y_train, y_temp = train_test_split( X_combined, y_encoded, test_size=0.4, random_state=42, stratify=y_encoded ) # Then split temp into validation and testing sets (20% each of the total data) x_val, x_test, y_val, y_test = train_test_split( x_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp ) # Now, x_train is 60%, x_val is 20%, x_test is 20% # Perform PCA on training data only X_train_reduced = pca.fit_transform(x_train).astype(np.float32) # (n_train_samples, n_components) X_val_reduced = pca.transform(x_val).astype(np.float32) X_test_reduced = pca.transform(x_test).astype(np.float32) # Standardize and normalize data (fit only on training set) X_train_standardized = scaler.fit_transform(X_train_reduced).astype(np.float32) X_val_standardized = scaler.transform(X_val_reduced).astype(np.float32) X_test_standardized = scaler.transform(X_test_reduced).astype(np.float32) # Map features to [0, π/2] range X_train_mapped = min_max_scaler.fit_transform(X_train_standardized).astype(np.float32) X_val_mapped = min_max_scaler.transform(X_val_standardized).astype(np.float32) X_test_mapped = min_max_scaler.transform(X_test_standardized).astype(np.float32) # Hyperparameters learning_rate = 0.01 # Learning rate epochs = 200 # Number of training epochs batch_size = 16 # Batch size n_qubits = 14 # 14 qubits as per the original QNN n_layers = 2 # Number of layers model = QuantumNeuralNetwork( n_qubits=n_qubits, n_layers=n_layers, num_classes=num_classes ) if is_quantum_model(model): print("The model contains quantum neural network (QNN) layers.") else: print("The model does not contain quantum neural network (QNN) layers.") # Draw the quantum circuit sample_inputs = np.ones(4, dtype=np.float32) * (np.pi / 4) # Inputs mapped to [0, π/2] sample_encoding_weights = np.zeros((4, n_layers, 4), dtype=np.float32) sample_rot_weights = np.zeros((n_layers, n_qubits, 3), dtype=np.float32) sample_entangle_weights = np.zeros((n_layers, n_qubits - 1), dtype=np.float32) qml.drawer.use_style('sketch') print("\nQuantum circuit diagram:") print(qml.draw(quantum_neural_network)(sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights)) qml.draw_mpl(quantum_neural_network)(sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights)[0].savefig('企鹅_添加H.png') steps_per_epoch = len(X_train_mapped) // batch_size total_steps = epochs * steps_per_epoch # Create dataset (including validation set) dataset = InMemoryDataset( X_train_mapped, y_train, X_val_mapped, y_val, categorical=True ) # Initialize reweighting policy reweighting_policy = BiasedReweightingPolicy(k=1.0) # Initialize importance sampling training wrapped_model = ConstantTimeImportanceTraining(model, score="loss") # Use loss as score # Modify sampler to use dynamic alpha and beta def custom_sampler(dataset, batch_size, steps_per_epoch, epochs): return ConstantTimeSampler( dataset, reweighting_policy, model=wrapped_model.model, ) # Assign custom sampler to wrapped_model wrapped_model.sampler = custom_sampler # Use per-sample loss function loss_fn = tf.keras.losses.CategoricalCrossentropy(from_logits=False, reduction=tf.keras.losses.Reduction.NONE) # Compile model model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss=loss_fn, metrics=['accuracy'], run_eagerly=True # Set to False for better performance ) # Create a callback class to save training metrics class MetricsHistory(tf.keras.callbacks.Callback): def on_train_begin(self, logs=None): self.history = {'loss': [], 'accuracy': [], 'val_loss': [], 'val_accuracy': []} def on_epoch_end(self, epoch, logs=None): self.history['loss'].append(logs.get('loss')) self.history['accuracy'].append(logs.get('accuracy')) self.history['val_loss'].append(logs.get('val_loss')) self.history['val_accuracy'].append(logs.get('val_accuracy')) # Instantiate callbacks metrics_history = MetricsHistory() # Add early stopping callback callbacks = [ metrics_history, EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True) ] # Train model using fit_dataset history = wrapped_model.fit_dataset( dataset=dataset, batch_size=batch_size, epochs=epochs, steps_per_epoch=steps_per_epoch, verbose=1, callbacks=callbacks ) # 在训练完成后,评估测试集 print("\nEvaluating on test set:") test_loss, test_accuracy = wrapped_model.evaluate((X_test_mapped, y_test), mode='test') print('Test loss:', test_loss) print('Test accuracy:', test_accuracy) # Plot graphs using history from custom callback plot_history(metrics_history) mean_accuracy, fluctuation = calculate_accuracy_fluctuation(metrics_history) if mean_accuracy is not None and fluctuation is not None: print('Validation set mean accuracy:', mean_accuracy) print('Accuracy fluctuation:', fluctuation) print( "Script execution completed. Please check 'output.log' for print output and check the saved plots in the current directory." )
上述代码中使用的纠缠门是否有问题,简要进行说明
In the provided code, entangling gates play a crucial role in establishing quantum correlations between qubits, which are essential for the functionality of a Quantum Neural Network (QNN). However, there are a few issues related to how these entangling gates are implemented:
Replacement of Controlled RZ (CRZ) Gates with CNOT Gates:
# 原先的 CRZ 改为 CNOT indicates that the original entangling operation used Controlled RZ (CRZ) gates.Lack of Parameterization for Entangling Operations:
entangle_weights as trainable parameters:
However, these weights are never utilized within thepythonself.entangle_weights = self.add_weight( shape=(n_layers, n_qubits - 1), initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi), regularizer=regularizer, trainable=True, name='entangle_weights', dtype=tf.float32 )
quantum_neural_network function. Instead, fixed CNOT gates are applied:
pythonfor qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1])
entangle_weights into the entangling operations, the network misses out on the potential to learn optimal entanglement strategies. This makes the entanglement static and non-adaptive, potentially hindering the model's performance and expressiveness.Entanglement Pattern Constraints:
qubit and qubit + 1), creating a linear entanglement pattern.Controlled SWAP (CSWAP) Gate Usage:
apply_controlled_swap function introduces CSWAP gates controlled by specific qubits.entangle_weights, these gates might not contribute effectively to the learning process.Reintroduce Parameterization: Utilize the entangle_weights to parameterize the entangling gates. For example, replace fixed CNOT gates with parameterized controlled rotations (like CRZ) where the rotation angles are learnable weights.
pythonfor qubit in range(rot_weights.shape[1] - 1): qml.CRZ(entangle_weights[layer, qubit], wires=[qubit, qubit + 1])
Explore Flexible Entanglement Patterns: Instead of a fixed linear entanglement, consider more dynamic patterns such as all-to-all entanglement or using entangling gates based on learned connectivity.
Optimize Gate Usage: Evaluate the necessity of CSWAP gates in the architecture. If they do not contribute meaningfully to the learning task, simplifying the circuit by removing or replacing them might be beneficial.
By addressing these issues, the QNN can achieve better adaptability and performance, leveraging the full potential of quantum entanglement in learning complex patterns from data.
import sys
import os
from typing import List, Tuple
import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler
from sklearn.decomposition import PCA
import matplotlib
matplotlib.use('Agg') # Use non-interactive backend
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Dense
from importance_sampling.training import ConstantTimeImportanceTraining
from importance_sampling.samplers import ConstantTimeSampler
from importance_sampling.datasets import InMemoryDataset
from importance_sampling.reweighting import BiasedReweightingPolicy
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
import logging
tf.keras.backend.set_floatx('float32')
class Tee(object):
def init(self, *files):
self.files = files
self.encoding = getattr(files[0], 'encoding', 'utf-8') # Add encoding attribute
textdef 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('seeds_添加Hlr_0.01.log', 'w', encoding='utf-8')
original_stdout = sys.stdout
tee = Tee(sys.stdout, output_file)
sys.stdout = tee
logger = logging.getLogger('my_sampler')
logger.setLevel(logging.INFO)
stream_handler = logging.StreamHandler(tee)
stream_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
if not logger.handlers:
logger.addHandler(stream_handler)
else:
logger.handlers = []
logger.addHandler(stream_handler)
logging.getLogger('qiskit').setLevel(logging.WARNING)
def save_plot(fig, filename):
fig.savefig(filename)
plt.close(fig)
def plot_history(history):
# Plot training and validation accuracy
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(history.history['accuracy'], label='Training Accuracy')
if 'val_accuracy' in history.history:
ax.plot(history.history['val_accuracy'], label='Validation Accuracy')
else:
print("Validation accuracy not found in history.")
ax.set_title('Model Accuracy')
ax.set_ylabel('Accuracy')
ax.set_xlabel('Epoch')
ax.legend(loc='upper left')
save_plot(fig, 'accuracy_plot.png')
text# Plot training and validation loss fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(history.history['loss'], label='Training Loss') if 'val_loss' in history.history: ax.plot(history.history['val_loss'], label='Validation Loss') else: print("Validation loss not found in history.") ax.set_title('Model Loss') ax.set_ylabel('Loss') ax.set_xlabel('Epoch') ax.legend(loc='upper right') save_plot(fig, 'loss_plot.png')
def calculate_accuracy_fluctuation(history):
if 'val_accuracy' in history.history:
accuracies = history.history['val_accuracy']
elif 'accuracy' in history.history:
accuracies = history.history['accuracy']
else:
print("Accuracy metric not found in history.")
return None, None
mean_accuracy = np.mean(accuracies)
fluctuation = np.sum(np.abs(accuracies - mean_accuracy))
return mean_accuracy, fluctuation
dev = qml.device("default.qubit", wires=14)
def encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values):
qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]],
control_values=[0, 0])
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]],
control_values=[0, 0])
textqml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1]) qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1]) qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1])
def encode_group_second(control_qubits, data_qubits, angle_q3_values):
# 第一组
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']),
control=[control_qubits[0], control_qubits[1]], control_values=[0, 0])
text# 第二组 qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 0]) # 第三组 qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[1, 1]) # 第四组 qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=[control_qubits[0], control_qubits[1]], control_values=[0, 1])
def apply_controlled_swap(swap_qubit, q_swap1, q_swap2):
"""
Modular method to apply a controlled SWAP gate.
textParameters: - swap_qubit (int): Control qubit for the SWAP gate. - q_swap1 (int): First qubit to swap. - q_swap2 (int): Second qubit to swap. """ qml.Hadamard(wires=swap_qubit) qml.CSWAP(wires=[swap_qubit, q_swap1, q_swap2]) qml.Hadamard(wires=swap_qubit)
@qml.qnode(dev, interface='tf', diff_method='backprop')
def quantum_neural_network(inputs, encoding_weights, rot_weights, entangle_weights):
control_qubits = [0, 1]
text# Neuron groups 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}, {'data_qubits': {'q2': 11, 'q3': 12}, 'swap_qubit': 13} ] # Angle encoding: inputs are mapped to [0, pi/2] angles_q2_list = inputs # inputs shape is (4,) # Encoding weights mapped to angles_q3 angles_q3_list = encoding_weights # shape: (4, n_layers, 8) # 第一层:同时编码values和weights qml.Hadamard(wires=control_qubits[0]) qml.Hadamard(wires=control_qubits[1]) for idx, data_set in enumerate(encoding_data): swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] angle_q2 = angles_q2_list[idx] # scalar value angle_q3_values = angles_q3_list[idx, 0, :] # shape: (8,) # 编码一个神经元 encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[0, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # Apply parameterized entanglement gates for qubit in range(rot_weights.shape[1] - 1): qml.CRZ(entangle_weights[0, qubit], wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 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']) # 第二层:仅编码weights for layer in range(rot_weights.shape[0] - 1): # 每层的内容 layer_second = layer + 1 # 每层完整编码特征值和权重值 for idx, data_set in enumerate(encoding_data): data_qubits = data_set['data_qubits'] angle_q3_values = angles_q3_list[idx, layer_second, :] # shape: (8,) # 编码一个神经元 encode_group_second(control_qubits, data_qubits, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[layer_second, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # Apply parameterized entanglement gates for qubit in range(rot_weights.shape[1] - 1): qml.CRZ(entangle_weights[layer_second, qubit], wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 for data_set in encoding_data: swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] if layer % 2 == 0: apply_controlled_swap(data_qubits['q2'], swap_qubit, data_qubits['q3']) else: apply_controlled_swap(swap_qubit, data_qubits['q2'], data_qubits['q3']) if n_layers % 2 == 1: measured_qubits = [4, 7, 10, 13] else: measured_qubits = [2, 5, 8, 11] results = [qml.expval(qml.PauliZ(qubit)) for qubit in measured_qubits] return results
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
def init(self, n_qubits, n_layers, num_classes):
super(QuantumNeuralNetworkLayer, self).init()
self.n_qubits = n_qubits
self.n_layers = n_layers
self.num_classes = num_classes
text# Define encoding weights with L2 regularization initializer = tf.keras.initializers.GlorotUniform() regularizer = tf.keras.regularizers.l2(0.01) self.encoding_weights = self.add_weight( shape=(4, self.n_layers, 4), initializer=initializer, regularizer=regularizer, trainable=True, name='encoding_weights', dtype=tf.float32 ) # Define rotation layer weights with L2 regularization self.rot_weights = self.add_weight( shape=(n_layers, n_qubits, 3), initializer=initializer, regularizer=regularizer, trainable=True, name='rot_weights', dtype=tf.float32 ) # Define entangling weights with L2 regularization self.entangle_weights = self.add_weight( shape=(n_layers, n_qubits - 1), initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi), regularizer=regularizer, trainable=True, name='entangle_weights', dtype=tf.float32 ) def call(self, inputs): outputs_list = [] for i in range(tf.shape(inputs)[0]): x = inputs[i] x = tf.cast(x, tf.float32) result = quantum_neural_network(x, self.encoding_weights, self.rot_weights, self.entangle_weights) outputs_list.append(tf.cast(result, tf.float32)) outputs = tf.stack(outputs_list, axis=0) return outputs
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
text# Quantum layer self.quantum_layer = QuantumNeuralNetworkLayer(n_qubits, n_layers, num_classes) # Classical layers self.dense1 = tf.keras.layers.Dense( 16, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.001), dtype=tf.float32 ) self.dense2 = tf.keras.layers.Dense( 8, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.001), dtype=tf.float32 ) # Output layer directly connected to quantum outputs self.output_layer = Dense( num_classes, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2(0.01), dtype=tf.float32 # Ensure the output layer is float32 ) def call(self, inputs): q_output = self.quantum_layer(inputs) x = self.dense1(q_output) x = self.dense2(x) return self.output_layer(x)
def is_quantum_model(model):
for layer in model.layers:
if isinstance(layer, QuantumNeuralNetworkLayer):
return True
elif hasattr(layer, 'layers'):
if is_quantum_model(layer):
return True
return False
def load_seeds_data(url: str, column_names: List[str]) -> pd.DataFrame:
"""Load the Seeds dataset from URL."""
try:
data = pd.read_csv(url, sep='\s+', header=None, names=column_names)
return data
except Exception as e:
print(f"Error loading the Seeds dataset: {e}")
sys.exit(1)
def stratified_split(X: np.ndarray, y: np.ndarray, samples_per_class: dict) -> Tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Perform stratified splitting of data for each class according to specified samples per class.
textArgs: X: Features array y: Labels array (not one-hot encoded) samples_per_class: Dictionary specifying number of samples for train/val/test per class Returns: Tuple of train, validation, and test sets (both features and labels) """ unique_classes = np.unique(y) X_train, y_train = [], [] X_val, y_val = [], [] X_test, y_test = [], [] for class_label in unique_classes: # Get indices for current class class_indices = np.where(y == class_label)[0] np.random.shuffle(class_indices) # Split indices according to specified numbers train_idx = class_indices[:samples_per_class['train']] val_idx = class_indices[samples_per_class['train']:samples_per_class['train'] + samples_per_class['val']] test_idx = class_indices[samples_per_class['train'] + samples_per_class['val']: samples_per_class['train'] + samples_per_class['val'] + samples_per_class['test']] # Add to respective sets X_train.append(X[train_idx]) y_train.append(y[train_idx]) X_val.append(X[val_idx]) y_val.append(y[val_idx]) X_test.append(X[test_idx]) y_test.append(y[test_idx]) return (np.vstack(X_train), np.concatenate(y_train), np.vstack(X_val), np.concatenate(y_val), np.vstack(X_test), np.concatenate(y_test))
if name == "main":
# Set random seed for reproducibility
np.random.seed(42)
tf.random.set_seed(42)
text# Load Seeds dataset url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00236/seeds_dataset.txt' column_names = ['area', 'perimeter', 'compactness', 'length_of_kernel', 'width_of_kernel', 'asymmetry_coefficient', 'length_of_kernel_groove', 'class'] data = load_seeds_data(url, column_names) X = data.iloc[:, :-1].values.astype(np.float32) # Features y = data.iloc[:, -1].values.reshape(-1, 1) # Labels # Define samples per class for each split samples_per_class = { 'train': 42, 'val': 14, 'test': 14 } # Perform stratified split X_train, y_train, X_val, y_val, X_test, y_test = stratified_split(X, y, samples_per_class) # Standardize features (fit only on training data) scaler = StandardScaler() X_train_standardized = scaler.fit_transform(X_train) X_val_standardized = scaler.transform(X_val) X_test_standardized = scaler.transform(X_test) # Perform PCA (fit only on training data) pca = PCA(n_components=4) X_train_reduced = pca.fit_transform(X_train_standardized).astype(np.float32) X_val_reduced = pca.transform(X_val_standardized).astype(np.float32) X_test_reduced = pca.transform(X_test_standardized).astype(np.float32) # One-Hot encode labels encoder = OneHotEncoder(sparse_output=False) y_train_encoded = encoder.fit_transform(y_train).astype(np.float32) y_val_encoded = encoder.transform(y_val).astype(np.float32) y_test_encoded = encoder.transform(y_test).astype(np.float32) num_classes = y_train_encoded.shape[1] # Map features to [0, π/2] range min_max_scaler = MinMaxScaler(feature_range=(0, np.pi / 2)) X_train_mapped = min_max_scaler.fit_transform(X_train_reduced).astype(np.float32) X_val_mapped = min_max_scaler.transform(X_val_reduced).astype(np.float32) X_test_mapped = min_max_scaler.transform(X_test_reduced).astype(np.float32) # Hyperparameters learning_rate = 0.01 epochs = 200 batch_size = 16 n_qubits = 14 n_layers = 2 model = QuantumNeuralNetwork( n_qubits=n_qubits, n_layers=n_layers, num_classes=num_classes ) if is_quantum_model(model): print("The model contains quantum neural network (QNN) layers.") else: print("The model does not contain quantum neural network (QNN) layers.") steps_per_epoch = len(X_train_mapped) // batch_size total_steps = epochs * steps_per_epoch # Create dataset dataset = InMemoryDataset( X_train_mapped, y_train_encoded, X_val_mapped, y_val_encoded, categorical=True ) # Initialize reweighting policy and importance sampling reweighting_policy = BiasedReweightingPolicy(k=1.0) wrapped_model = ConstantTimeImportanceTraining(model, score="loss") def custom_sampler(dataset, batch_size, steps_per_epoch, epochs): return ConstantTimeSampler( dataset, reweighting_policy, model=wrapped_model.model, ) wrapped_model.sampler = custom_sampler # Loss function and compilation loss_fn = tf.keras.losses.CategoricalCrossentropy(from_logits=False, reduction=tf.keras.losses.Reduction.NONE) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss=loss_fn, metrics=['accuracy'], run_eagerly=True ) # Callbacks class MetricsHistory(tf.keras.callbacks.Callback): def on_train_begin(self, logs=None): self.history = {'loss': [], 'accuracy': [], 'val_loss': [], 'val_accuracy': []} def on_epoch_end(self, epoch, logs=None): self.history['loss'].append(logs.get('loss')) self.history['accuracy'].append(logs.get('accuracy')) self.history['val_loss'].append(logs.get('val_loss')) self.history['val_accuracy'].append(logs.get('val_accuracy')) metrics_history = MetricsHistory() callbacks = [ metrics_history, EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True) ] # Train model history = wrapped_model.fit_dataset( dataset=dataset, batch_size=batch_size, epochs=epochs, steps_per_epoch=steps_per_epoch, verbose=1, callbacks=callbacks ) # Evaluate on test set print("\nEvaluating on test set:") test_loss, test_accuracy = wrapped_model.evaluate((X_test_mapped, y_test_encoded), mode='test') print('Test loss:', test_loss) print('Test accuracy:', test_accuracy) # Plot training history and calculate metrics plot_history(metrics_history) mean_accuracy, fluctuation = calculate_accuracy_fluctuation(metrics_history) if mean_accuracy is not None and fluctuation is not None: print('Validation set mean accuracy:', mean_accuracy) print('Accuracy fluctuation:', fluctuation)
上述代码使用的就是CRZ门进行纠缠,但是问题在于是否能够使得不同的量子比特之间进行纠缠?
Yes, the Controlled RZ (CRZ) gates used in your updated code are capable of generating entanglement between different qubits. Here's a detailed explanation to clarify how your implementation facilitates entanglement and ensure it functions as intended:
Controlled RZ (CRZ) Gates:
Entanglement Generation:
qml.Rot), CRZ gates can generate complex, non-separable quantum states, which are essential for capturing intricate patterns in data.Layered Entanglement:
n_layers = 2) of CRZ gates, allowing entanglement to propagate through the qubit register. This layered approach enhances the network's capacity to model complex correlations.qubit and qubit + 1), you establish a chain of entangled qubits. Over multiple layers, this can lead to more intricate entanglement patterns across the entire set of qubits.Parameter Utilization:
entangle_weights are defined as trainable parameters (shape=(n_layers, n_qubits - 1)), allowing the model to learn optimal rotation angles that facilitate meaningful entanglement tailored to the specific dataset and task.entangle_weights adjust, enabling the CRZ gates to create dynamic entanglement patterns that can adapt to the data's underlying structure.Controlled SWAP Gates:
apply_controlled_swap function introduces Controlled SWAP (CSWAP) gates, which can further manipulate entanglement by swapping the states of qubits based on control conditions.While your implementation is fundamentally sound in utilizing CRZ gates for entanglement, consider the following points to ensure optimal performance:
entangle_weights are effectively integrated and utilized within the quantum circuit. This allows the network to learn the most beneficial entanglement angles during training.Your updated code effectively employs CRZ gates to introduce entanglement between different qubits within the quantum neural network. By parameterizing these gates and integrating them into multiple layers, the model can learn and adapt entanglement patterns that enhance its ability to model complex data relationships. Ensure that the overall circuit design, including gate connectivity and parameter utilization, aligns with your specific task requirements to maximize the benefits of quantum entanglement in your neural network.
If you encounter any unexpected behaviors or performance issues, revisiting the entanglement strategy and experimenting with different gate configurations or connectivity patterns might provide further improvements.
import sys
import os
from typing import List, Tuple
import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler
from sklearn.decomposition import PCA
import matplotlib
matplotlib.use('Agg') # Use non-interactive backend
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Dense
from importance_sampling.training import ConstantTimeImportanceTraining
from importance_sampling.samplers import ConstantTimeSampler
from importance_sampling.datasets import InMemoryDataset
from importance_sampling.reweighting import BiasedReweightingPolicy
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
import logging
tf.keras.backend.set_floatx('float32')
class Tee(object):
def init(self, *files):
self.files = files
self.encoding = getattr(files[0], 'encoding', 'utf-8') # Add encoding attribute
textdef 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('seeds_将CRZ修改为CNOT_lr0.02.log', 'w', encoding='utf-8')
original_stdout = sys.stdout
tee = Tee(sys.stdout, output_file)
sys.stdout = tee
logger = logging.getLogger('my_sampler')
logger.setLevel(logging.INFO)
stream_handler = logging.StreamHandler(tee)
stream_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
if not logger.handlers:
logger.addHandler(stream_handler)
else:
logger.handlers = []
logger.addHandler(stream_handler)
logging.getLogger('qiskit').setLevel(logging.WARNING)
def save_plot(fig, filename):
fig.savefig(filename)
plt.close(fig)
def plot_history(history):
# Plot training and validation accuracy
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(history.history['accuracy'], label='Training Accuracy')
if 'val_accuracy' in history.history:
ax.plot(history.history['val_accuracy'], label='Validation Accuracy')
else:
print("Validation accuracy not found in history.")
ax.set_title('Model Accuracy')
ax.set_ylabel('Accuracy')
ax.set_xlabel('Epoch')
ax.legend(loc='upper left')
save_plot(fig, 'accuracy_plot.png')
text# Plot training and validation loss fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(history.history['loss'], label='Training Loss') if 'val_loss' in history.history: ax.plot(history.history['val_loss'], label='Validation Loss') else: print("Validation loss not found in history.") ax.set_title('Model Loss') ax.set_ylabel('Loss') ax.set_xlabel('Epoch') ax.legend(loc='upper right') save_plot(fig, 'loss_plot.png')
def calculate_accuracy_fluctuation(history):
if 'val_accuracy' in history.history:
accuracies = history.history['val_accuracy']
elif 'accuracy' in history.history:
accuracies = history.history['accuracy']
else:
print("Accuracy metric not found in history.")
return None, None
mean_accuracy = np.mean(accuracies)
fluctuation = np.sum(np.abs(accuracies - mean_accuracy))
return mean_accuracy, fluctuation
dev = qml.device("default.qubit", wires=14)
def encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values):
qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=control_qubits,
control_values=[0, 0])
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']), control=control_qubits,
control_values=[0, 0])
textqml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=control_qubits, control_values=[0, 1]) qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=control_qubits, control_values=[0, 1]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=control_qubits, control_values=[1, 0]) qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=control_qubits, control_values=[1, 0]) qml.ctrl(qml.RY(angle_q2, wires=data_qubits['q2']), control=control_qubits, control_values=[1, 1]) qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=control_qubits, control_values=[1, 1])
def encode_group_second(control_qubits, data_qubits, angle_q3_values):
# 第一组
qml.ctrl(qml.RY(angle_q3_values[0], wires=data_qubits['q3']),
control=control_qubits, control_values=[0, 0])
text# 第二组 qml.ctrl(qml.RY(angle_q3_values[1], wires=data_qubits['q3']), control=control_qubits, control_values=[1, 0]) # 第三组 qml.ctrl(qml.RY(angle_q3_values[2], wires=data_qubits['q3']), control=control_qubits, control_values=[1, 1]) # 第四组 qml.ctrl(qml.RY(angle_q3_values[3], wires=data_qubits['q3']), control=control_qubits, control_values=[0, 1])
def apply_controlled_swap(swap_qubit, q_swap1, q_swap2):
"""
Modular method to apply a controlled SWAP gate.
textParameters: - swap_qubit (int): Control qubit for the SWAP gate. - q_swap1 (int): First qubit to swap. - q_swap2 (int): Second qubit to swap. """ qml.Hadamard(wires=swap_qubit) qml.CSWAP(wires=[swap_qubit, q_swap1, q_swap2]) qml.Hadamard(wires=swap_qubit)
@qml.qnode(dev, interface='tf', diff_method='backprop')
def quantum_neural_network(inputs, encoding_weights, rot_weights):
control_qubits = [0, 1]
text# Neuron groups 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}, {'data_qubits': {'q2': 11, 'q3': 12}, 'swap_qubit': 13} ] # Angle encoding: inputs are mapped to [0, pi/2] angles_q2_list = inputs # inputs shape is (4,) # Encoding weights mapped to angles_q3 angles_q3_list = encoding_weights # shape: (4, n_layers, 4) # 第一层:同时编码values和weights for idx, data_set in enumerate(encoding_data): swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] angle_q2 = angles_q2_list[idx] # scalar value angle_q3_values = angles_q3_list[idx, 0, :] # shape: (4,) # 编码一个神经元 encode_group(control_qubits, data_qubits, angle_q2, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[0, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # Apply CNOT entanglement gates for qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 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']) # 第二层:仅编码weights for layer in range(rot_weights.shape[0] - 1): # 每层的内容 layer_second = layer + 1 # 每层完整编码特征值和权重值 for idx, data_set in enumerate(encoding_data): data_qubits = data_set['data_qubits'] angle_q3_values = angles_q3_list[idx, layer_second, :] # shape: (4,) # 编码一个神经元 encode_group_second(control_qubits, data_qubits, angle_q3_values) # 每层编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[layer_second, qubit, :] # shape: (3,) qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # Apply CNOT entanglement gates for qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1]) # 每层每个神经元应用一次swap操作 for data_set in encoding_data: swap_qubit = data_set['swap_qubit'] data_qubits = data_set['data_qubits'] if layer % 2 == 0: apply_controlled_swap(data_qubits['q2'], swap_qubit, data_qubits['q3']) else: apply_controlled_swap(swap_qubit, data_qubits['q2'], data_qubits['q3']) if rot_weights.shape[0] % 2 == 1: measured_qubits = [4, 7, 10, 13] else: measured_qubits = [2, 5, 8, 11] results = [qml.expval(qml.PauliZ(qubit)) for qubit in measured_qubits] return results
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
def init(self, n_qubits, n_layers, num_classes):
super(QuantumNeuralNetworkLayer, self).init()
self.n_qubits = n_qubits
self.n_layers = n_layers
self.num_classes = num_classes
text# Define encoding weights with L2 regularization initializer = tf.keras.initializers.GlorotUniform() regularizer = tf.keras.regularizers.l2(0.01) self.encoding_weights = self.add_weight( shape=(4, self.n_layers, 4), initializer=initializer, regularizer=regularizer, trainable=True, name='encoding_weights', dtype=tf.float32 ) # Define rotation layer weights with L2 regularization self.rot_weights = self.add_weight( shape=(n_layers, n_qubits, 3), initializer=initializer, regularizer=regularizer, trainable=True, name='rot_weights', dtype=tf.float32 ) def call(self, inputs): outputs_list = [] for i in range(tf.shape(inputs)[0]): x = inputs[i] x = tf.cast(x, tf.float32) result = quantum_neural_network(x, self.encoding_weights, self.rot_weights) outputs_list.append(tf.cast(result, tf.float32)) outputs = tf.stack(outputs_list, axis=0) return outputs
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
text# Quantum layer self.quantum_layer = QuantumNeuralNetworkLayer(n_qubits, n_layers, num_classes) # Classical layers self.dense1 = tf.keras.layers.Dense( 16, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.001), dtype=tf.float32 ) self.dense2 = tf.keras.layers.Dense( 8, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.001), dtype=tf.float32 ) # Output layer directly connected to quantum outputs self.output_layer = Dense( num_classes, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2(0.01), dtype=tf.float32 # Ensure the output layer is float32 ) def call(self, inputs): q_output = self.quantum_layer(inputs) x = self.dense1(q_output) x = self.dense2(x) return self.output_layer(x)
def is_quantum_model(model):
for layer in model.layers:
if isinstance(layer, QuantumNeuralNetworkLayer):
return True
elif hasattr(layer, 'layers'):
if is_quantum_model(layer):
return True
return False
def load_seeds_data(url: str, column_names: List[str]) -> pd.DataFrame:
"""Load the Seeds dataset from URL."""
try:
data = pd.read_csv(url, sep='\s+', header=None, names=column_names)
return data
except Exception as e:
print(f"Error loading the Seeds dataset: {e}")
sys.exit(1)
def stratified_split(X: np.ndarray, y: np.ndarray, samples_per_class: dict) -> Tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Perform stratified splitting of data for each class according to specified samples per class.
textArgs: X: Features array y: Labels array (not one-hot encoded) samples_per_class: Dictionary specifying number of samples for train/val/test per class Returns: Tuple of train, validation, and test sets (both features and labels) """ unique_classes = np.unique(y) X_train, y_train = [], [] X_val, y_val = [], [] X_test, y_test = [], [] for class_label in unique_classes: # Get indices for current class class_indices = np.where(y == class_label)[0] np.random.shuffle(class_indices) # Split indices according to specified numbers train_idx = class_indices[:samples_per_class['train']] val_idx = class_indices[samples_per_class['train']:samples_per_class['train'] + samples_per_class['val']] test_idx = class_indices[samples_per_class['train'] + samples_per_class['val']: samples_per_class['train'] + samples_per_class['val'] + samples_per_class['test']] # Add to respective sets X_train.append(X[train_idx]) y_train.append(y[train_idx]) X_val.append(X[val_idx]) y_val.append(y[val_idx]) X_test.append(X[test_idx]) y_test.append(y[test_idx]) return (np.vstack(X_train), np.concatenate(y_train), np.vstack(X_val), np.concatenate(y_val), np.vstack(X_test), np.concatenate(y_test))
if name == "main":
# Set random seed for reproducibility
np.random.seed(42)
tf.random.set_seed(42)
text# Load Seeds dataset url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00236/seeds_dataset.txt' column_names = ['area', 'perimeter', 'compactness', 'length_of_kernel', 'width_of_kernel', 'asymmetry_coefficient', 'length_of_kernel_groove', 'class'] data = load_seeds_data(url, column_names) X = data.iloc[:, :-1].values.astype(np.float32) # Features y = data.iloc[:, -1].values.reshape(-1, 1) # Labels # Define samples per class for each split samples_per_class = { 'train': 42, 'val': 14, 'test': 14 } # Perform stratified split X_train, y_train, X_val, y_val, X_test, y_test = stratified_split(X, y, samples_per_class) # Standardize features (fit only on training data) scaler = StandardScaler() X_train_standardized = scaler.fit_transform(X_train) X_val_standardized = scaler.transform(X_val) X_test_standardized = scaler.transform(X_test) # Perform PCA (fit only on training data) pca = PCA(n_components=4) X_train_reduced = pca.fit_transform(X_train_standardized).astype(np.float32) X_val_reduced = pca.transform(X_val_standardized).astype(np.float32) X_test_reduced = pca.transform(X_test_standardized).astype(np.float32) # One-Hot encode labels encoder = OneHotEncoder(sparse_output=False) y_train_encoded = encoder.fit_transform(y_train).astype(np.float32) y_val_encoded = encoder.transform(y_val).astype(np.float32) y_test_encoded = encoder.transform(y_test).astype(np.float32) num_classes = y_train_encoded.shape[1] # Map features to [0, π/2] range min_max_scaler = MinMaxScaler(feature_range=(0, np.pi / 2)) X_train_mapped = min_max_scaler.fit_transform(X_train_reduced).astype(np.float32) X_val_mapped = min_max_scaler.transform(X_val_reduced).astype(np.float32) X_test_mapped = min_max_scaler.transform(X_test_reduced).astype(np.float32) # Hyperparameters learning_rate = 0.02 epochs = 200 batch_size = 16 n_qubits = 14 n_layers = 2 model = QuantumNeuralNetwork( n_qubits=n_qubits, n_layers=n_layers, num_classes=num_classes ) # Draw the quantum circuit sample_inputs = np.ones(4, dtype=np.float32) * (np.pi / 4) # Inputs mapped to [0, π/2] sample_encoding_weights = np.zeros((4, n_layers, 4), dtype=np.float32) sample_rot_weights = np.zeros((n_layers, n_qubits, 3), dtype=np.float32) sample_entangle_weights = np.zeros((n_layers, n_qubits - 1), dtype=np.float32) qml.drawer.use_style('sketch') print("\nQuantum circuit diagram:") print(qml.draw(quantum_neural_network)(sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights)) qml.draw_mpl(quantum_neural_network)(sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights)[0].savefig('seeds_将CRZ修改为CNOTlr0.02.png') if is_quantum_model(model): print("The model contains quantum neural network (QNN) layers.") else: print("The model does not contain quantum neural network (QNN) layers.") steps_per_epoch = len(X_train_mapped) // batch_size total_steps = epochs * steps_per_epoch # Create dataset dataset = InMemoryDataset( X_train_mapped, y_train_encoded, X_val_mapped, y_val_encoded, categorical=True ) # Initialize reweighting policy and importance sampling reweighting_policy = BiasedReweightingPolicy(k=1.0) wrapped_model = ConstantTimeImportanceTraining(model, score="loss") def custom_sampler(dataset, batch_size, steps_per_epoch, epochs): return ConstantTimeSampler( dataset, reweighting_policy, model=wrapped_model.model, ) wrapped_model.sampler = custom_sampler # Loss function and compilation loss_fn = tf.keras.losses.CategoricalCrossentropy(from_logits=False, reduction=tf.keras.losses.Reduction.NONE) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), loss=loss_fn, metrics=['accuracy'], run_eagerly=True ) # Callbacks class MetricsHistory(tf.keras.callbacks.Callback): def on_train_begin(self, logs=None): self.history = {'loss': [], 'accuracy': [], 'val_loss': [], 'val_accuracy': []} def on_epoch_end(self, epoch, logs=None): self.history['loss'].append(logs.get('loss')) self.history['accuracy'].append(logs.get('accuracy')) self.history['val_loss'].append(logs.get('val_loss')) self.history['val_accuracy'].append(logs.get('val_accuracy')) metrics_history = MetricsHistory() callbacks = [ metrics_history, EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True) ] # Train model history = wrapped_model.fit_dataset( dataset=dataset, batch_size=batch_size, epochs=epochs, steps_per_epoch=steps_per_epoch, verbose=1, callbacks=callbacks ) # Evaluate on test set print("\nEvaluating on test set:") test_loss, test_accuracy = wrapped_model.evaluate((X_test_mapped, y_test_encoded), mode='test') print('Test loss:', test_loss) print('Test accuracy:', test_accuracy) # Plot training history and calculate metrics plot_history(metrics_history) mean_accuracy, fluctuation = calculate_accuracy_fluctuation(metrics_history) if mean_accuracy is not None and fluctuation is not None: print('Validation set mean accuracy:', mean_accuracy) print('Accuracy fluctuation:', fluctuation)
上述代码出现报错
Traceback (most recent call last):
File "G:\Hellyc\确定模型-确定训练方法 - 使用梯度上界-所有数据集\SeedsDataset\seeds_将CRZ修改为CNOT_lr0.02.py", line 475, in <module>
print(qml.draw(quantum_neural_network)(sample_inputs, sample_encoding_weights, sample_rot_weights,
File "G:\anaconda3\envs\pennylane5\lib\site-packages\pennylane\drawer\draw.py", line 269, in wrapper
tapes = qnode.construct(args, kwargs)
File "G:\anaconda3\envs\pennylane5\lib\site-packages\pennylane\workflow\qnode.py", line 888, in construct
self._qfunc_output = self.func(*args, **kwargs)
TypeError: quantum_neural_network() takes 3 positional arguments but 4 were given
是哪句代码出现了问题,简要回答
The error you're encountering:
TypeError: quantum_neural_network() takes 3 positional arguments but 4 were given
is caused by a mismatch between the number of arguments provided when calling the quantum_neural_network function and the number of parameters it actually accepts.
Function Definition:
In your updated code, the quantum_neural_network function is defined to accept three positional arguments:
pythondef quantum_neural_network(inputs, encoding_weights, rot_weights): # Function implementation
Function Call:
However, when you attempt to draw the quantum circuit, you're passing four arguments:
pythonprint(qml.draw(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights ))
Similarly, when saving the circuit diagram using draw_mpl, you're also passing four arguments:
pythonqml.draw_mpl(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights, sample_entangle_weights )[0].savefig('seeds_将CRZ修改为CNOTlr0.02.png')
The quantum_neural_network function is designed to handle only three inputs:
inputsencoding_weightsrot_weightsBy passing a fourth argument (sample_entangle_weights), Python raises a TypeError because the function isn't expecting this extra parameter.
There are two primary ways to resolve this issue, depending on your intentions:
If the quantum_neural_network function no longer requires entangle_weights, you should remove the fourth argument from both the draw and draw_mpl function calls.
Updated Function Calls:
pythonprint(qml.draw(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights )) qml.draw_mpl(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights )[0].savefig('seeds_将CRZ修改为CNOTlr0.02.png')
If entangle_weights is still a necessary part of your quantum circuit, you need to update the quantum_neural_network function to accept this additional parameter.
Updated Function Definition:
pythondef quantum_neural_network(inputs, encoding_weights, rot_weights, entangle_weights): control_qubits = [0, 1] # Rest of your quantum circuit implementation, utilizing entangle_weights as needed # For example, replacing CNOT with parameterized gates using entangle_weights for qubit in range(rot_weights.shape[1] - 1): qml.CNOT(wires=[qubit, qubit + 1]) # Or use entangle_weights to parameterize # Continue with the rest of the circuit
Ensure Consistency:
quantum_neural_network includes the correct number of arguments.entangle_weights as a new parameter, ensure it's properly initialized and integrated within the quantum circuit.Given your latest code snippet, it appears that entangle_weights have been removed from the quantum_neural_network function definition. Therefore, the most straightforward solution is to remove the extra argument from the function calls.
Drawing the Quantum Circuit:
pythonprint("\nQuantum circuit diagram:") print(qml.draw(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights )) qml.draw_mpl(quantum_neural_network)( sample_inputs, sample_encoding_weights, sample_rot_weights )[0].savefig('seeds_将CRZ修改为CNOTlr0.02.png')
This adjustment ensures that the number of arguments passed matches the function's parameters, thereby resolving the TypeError.
quantum_neural_network is called are updated accordingly to prevent similar errors elsewhere.By addressing the argument mismatch, your script should proceed past this point without encountering the TypeError.
除了CNOT门外还有什么门能够进行简单的纠缠从而代替cnot门
除了 CNOT 门之外,还有多种量子门可以用于生成纠缠,从而在量子电路中替代或补充 CNOT 门。以下是一些常见且简单的纠缠门:
pythonqml.CZ(wires=[control_qubit, target_qubit])
pythonqml.CRZ(theta, wires=[control_qubit, target_qubit])
pythonqml.CRX(theta, wires=[control_qubit, target_qubit])
pythonqml.ISWAP(wires=[qubit1, qubit2])
pythonqml.CPhase(theta, wires=[control_qubit, target_qubit])
pythonqml.CH(wires=[control_qubit, target_qubit])
假设你希望在量子电路中使用 CZ 门替代 CNOT 门,可以按如下方式修改你的量子神经网络函数:
python@qml.qnode(dev, interface='tf', diff_method='backprop') def quantum_neural_network(inputs, encoding_weights, rot_weights): control_qubits = [0, 1] # Neuron groups and encoding as before... # 编码旋转门和纠缠门 for qubit in range(rot_weights.shape[1]): rot_angles = rot_weights[0, qubit, :] qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit) # 使用 CZ 门替代 CNOT 门 for qubit in range(rot_weights.shape[1] - 1): qml.CZ(wires=[qubit, qubit + 1]) # 其余部分保持不变... results = [qml.expval(qml.PauliZ(qubit)) for qubit in measured_qubits] return results
虽然 CNOT 门是量子纠缠中最常用的门之一,但根据具体需求和应用场景,其他诸如 CZ、CRZ、CRX、iSWAP 等门也能有效地生成和管理量子纠缠。选择合适的纠缠门有助于优化量子电路的性能和适应性,从而提升量子神经网络的整体表现。
上述模型的损失和准确率的波动范围很大,比如上一个epoch的验证集准确率达到了95%,下一个epoch的验证集准确率却只有88%,这是什么原因
训练过程中验证集的损失和准确率出现显著波动(例如,从95%骤降到88%)可能由多种因素引起,特别是在复杂的混合量子-经典神经网络(如您当前使用的模型)中。以下是可能的原因及相应的解决方案:
原因:您当前设置的学习率为0.02,相对较高。这可能导致优化器在损失函数的地形中跳跃过大,无法稳定收敛,进而引起训练过程中的不稳定性和指标波动。
解决方案:
ReduceLROnPlateau,它会根据验证损失自动调整学习率,帮助模型在训练后期更稳定地收敛。pythonreduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, min_lr=1e-5) callbacks.append(reduce_lr)
原因:混合量子-经典模型具有较高的表达能力,但在小型数据集(如Seeds数据集)上可能导致过拟合,即模型在训练集上表现良好,但在验证集上泛化能力较差,导致指标波动。
解决方案:
n_layers)或经典层的神经元数量,以降低模型复杂度。pythonself.dropout1 = tf.keras.layers.Dropout(0.5) self.dropout2 = tf.keras.layers.Dropout(0.5) def call(self, inputs): q_output = self.quantum_layer(inputs) x = self.dense1(q_output) x = self.dropout1(x) x = self.dense2(x) x = self.dropout2(x) return self.output_layer(x)
原因:使用较小的批量大小(如16)在小型数据集上可能导致梯度估计的高方差,进而引起训练的不稳定性和指标波动。
解决方案:
原因:您使用了ConstantTimeImportanceTraining和ConstantTimeSampler进行重要性采样。重要性采样如果不稳定或与模型当前状态不匹配,可能导致训练过程中的高方差和指标波动。
解决方案:
k值)设置合理。原因:量子电路对参数变化高度敏感,特别是在使用固定的纠缠门(如CNOT)时,可能导致输出的高方差,影响训练稳定性。
解决方案:
原因:不当的权重初始化可能导致模型在训练初期表现不佳,进而影响整体训练过程的稳定性。
解决方案:
pythoninitializer = tf.keras.initializers.HeNormal()
原因:将特征映射到[0, π/2]范围可能导致特征之间的比例失衡,尤其是在PCA降维后。如果某些主成分主导了大部分方差,可能影响模型的学习效果。
解决方案:
原因:使用固定的CNOT门进行纠缠可能限制了模型的表达能力和适应性,尤其是在数据复杂度较高时。
解决方案:
原因:在混合量子-经典模型中,梯度的计算可能受到量子电路复杂性的影响,导致梯度估计的不准确或高方差。
解决方案:
pythonoptimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate, clipnorm=1.0)
原因:使用不同的回调和评估方式可能导致指标计算的不一致,尤其是在自定义训练方法下。
解决方案:
综上所述,您的模型在训练过程中验证集的损失和准确率波动较大,可能是由多种因素共同作用引起的。以下是综合性的建议步骤,以逐步排查和解决问题:
通过逐步实施这些建议,您应能够逐步减少训练过程中验证指标的波动,提高模型的稳定性和泛化能力。如果问题仍然存在,建议深入调试各个组件,特别是量子层的实现和重要性采样策略,确保它们在训练过程中按预期工作。