क्वांटम डेटा

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

में की गई तुलना की बंद बिल्डिंग MNIST ट्यूटोरियल, इस ट्यूटोरियल की हाल ही में काम की पड़ताल हुआंग एट अल। यह दर्शाता है कि विभिन्न डेटासेट प्रदर्शन तुलनाओं को कैसे प्रभावित करते हैं। काम में, लेखक यह समझने की कोशिश करते हैं कि कैसे और कब शास्त्रीय मशीन लर्निंग मॉडल क्वांटम मॉडल के साथ-साथ (या इससे बेहतर) सीख सकते हैं। काम सावधानीपूर्वक तैयार किए गए डेटासेट के माध्यम से शास्त्रीय और क्वांटम मशीन लर्निंग मॉडल के बीच एक अनुभवजन्य प्रदर्शन अलगाव को भी प्रदर्शित करता है। आप:

  1. एक कम आयाम फ़ैशन-एमएनआईएसटी डेटासेट तैयार करें।
  2. डेटासेट को फिर से लेबल करने और अनुमानित क्वांटम कर्नेल सुविधाओं (PQK) की गणना करने के लिए क्वांटम सर्किट का उपयोग करें।
  3. पुन: लेबल किए गए डेटासेट पर शास्त्रीय तंत्रिका नेटवर्क को प्रशिक्षित करें और प्रदर्शन की तुलना उस मॉडल से करें जिसके पास PQK सुविधाओं तक पहुंच है।

सेट अप

pip install tensorflow==2.4.1 tensorflow-quantum
# Update package resources to account for version changes.
import importlib, pkg_resources
importlib.reload(pkg_resources)
import cirq
import sympy
import numpy as np
import tensorflow as tf
import tensorflow_quantum as tfq

# visualization tools
%matplotlib inline
import matplotlib.pyplot as plt
from cirq.contrib.svg import SVGCircuit
np.random.seed(1234)

1. डेटा तैयार करना

आप क्वांटम कंप्यूटर पर चलने के लिए फैशन-एमएनआईएसटी डेटासेट तैयार करके शुरू करेंगे।

1.1 फैशन-एमएनआईएसटी डाउनलोड करें

पहला कदम पारंपरिक फैशन-एमनिस्ट डेटासेट प्राप्त करना है। यह प्रयोग किया जा सकता tf.keras.datasets मॉड्यूल।

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()

# Rescale the images from [0,255] to the [0.0,1.0] range.
x_train, x_test = x_train/255.0, x_test/255.0

print("Number of original training examples:", len(x_train))
print("Number of original test examples:", len(x_test))
Number of original training examples: 60000
Number of original test examples: 10000

केवल टी-शर्ट/टॉप और ड्रेस रखने के लिए डेटासेट को फ़िल्टर करें, अन्य वर्गों को हटा दें। एक ही समय में परिवर्तित लेबल, पर y , बूलियन के लिए: 0 के लिए सच है और झूठी 3 के लिए।

def filter_03(x, y):
    keep = (y == 0) | (y == 3)
    x, y = x[keep], y[keep]
    y = y == 0
    return x,y
x_train, y_train = filter_03(x_train, y_train)
x_test, y_test = filter_03(x_test, y_test)

print("Number of filtered training examples:", len(x_train))
print("Number of filtered test examples:", len(x_test))
Number of filtered training examples: 12000
Number of filtered test examples: 2000
print(y_train[0])

plt.imshow(x_train[0, :, :])
plt.colorbar()
True
<matplotlib.colorbar.Colorbar at 0x7f6db42c3460>

पीएनजी

1.2 छवियों को डाउनस्केल करें

एमएनआईएसटी उदाहरण की तरह, आपको वर्तमान क्वांटम कंप्यूटरों की सीमाओं के भीतर रहने के लिए इन छवियों को कम करना होगा। इस बार हालांकि आप एक पीसीए परिवर्तन का उपयोग करने के बजाय आयाम एक कम करने के लिए होगा tf.image.resize आपरेशन।

def truncate_x(x_train, x_test, n_components=10):
  """Perform PCA on image dataset keeping the top `n_components` components."""
  n_points_train = tf.gather(tf.shape(x_train), 0)
  n_points_test = tf.gather(tf.shape(x_test), 0)

  # Flatten to 1D
  x_train = tf.reshape(x_train, [n_points_train, -1])
  x_test = tf.reshape(x_test, [n_points_test, -1])

  # Normalize.
  feature_mean = tf.reduce_mean(x_train, axis=0)
  x_train_normalized = x_train - feature_mean
  x_test_normalized = x_test - feature_mean

  # Truncate.
  e_values, e_vectors = tf.linalg.eigh(
      tf.einsum('ji,jk->ik', x_train_normalized, x_train_normalized))
  return tf.einsum('ij,jk->ik', x_train_normalized, e_vectors[:,-n_components:]), \
    tf.einsum('ij,jk->ik', x_test_normalized, e_vectors[:, -n_components:])
DATASET_DIM = 10
x_train, x_test = truncate_x(x_train, x_test, n_components=DATASET_DIM)
print(f'New datapoint dimension:', len(x_train[0]))
New datapoint dimension: 10

अंतिम चरण डेटासेट के आकार को केवल 1000 प्रशिक्षण डेटा बिंदुओं और 200 परीक्षण डेटा बिंदुओं तक कम करना है।

N_TRAIN = 1000
N_TEST = 200
x_train, x_test = x_train[:N_TRAIN], x_test[:N_TEST]
y_train, y_test = y_train[:N_TRAIN], y_test[:N_TEST]
print("New number of training examples:", len(x_train))
print("New number of test examples:", len(x_test))
New number of training examples: 1000
New number of test examples: 200

2. PQK सुविधाओं को फिर से लेबल करना और कंप्यूटिंग करना

अब आप क्वांटम घटकों को शामिल करके और ऊपर बनाए गए काटे गए फ़ैशन-MNIST डेटासेट को फिर से लेबल करके एक "स्टिल्टेड" क्वांटम डेटासेट तैयार करेंगे। क्वांटम और शास्त्रीय विधियों के बीच सबसे अधिक पृथक्करण प्राप्त करने के लिए, आप पहले पीक्यूके सुविधाओं को तैयार करेंगे और फिर उनके मूल्यों के आधार पर आउटपुट को फिर से लेबल करेंगे।

2.1 क्वांटम एन्कोडिंग और पीक्यूके विशेषताएं

आप पर आधारित है, सुविधाओं का एक नया सेट पैदा करेगा x_train , y_train , x_test और y_test यह सब qubits पर 1-RDM होने के लिए परिभाषित किया गया है:

\(V(x_{\text{train} } / n_{\text{trotter} }) ^ {n_{\text{trotter} } } U_{\text{1qb} } | 0 \rangle\)

कहाँ \(U_\text{1qb}\) एकल qubit रोटेशन और की एक दीवार है \(V(\hat{\theta}) = e^{-i\sum_i \hat{\theta_i} (X_i X_{i+1} + Y_i Y_{i+1} + Z_i Z_{i+1})}\)

सबसे पहले, आप सिंगल क्वाइब रोटेशन की दीवार उत्पन्न कर सकते हैं:

def single_qubit_wall(qubits, rotations):
  """Prepare a single qubit X,Y,Z rotation wall on `qubits`."""
  wall_circuit = cirq.Circuit()
  for i, qubit in enumerate(qubits):
    for j, gate in enumerate([cirq.X, cirq.Y, cirq.Z]):
      wall_circuit.append(gate(qubit) ** rotations[i][j])

  return wall_circuit

आप सर्किट को देखकर इस काम को जल्दी से सत्यापित कर सकते हैं:

SVGCircuit(single_qubit_wall(
    cirq.GridQubit.rect(1,4), np.random.uniform(size=(4, 3))))

एसवीजी

इसके बाद आप तैयार कर सकते हैं \(V(\hat{\theta})\) की मदद से tfq.util.exponential जो किसी भी आवागमन exponentiate कर सकते हैं cirq.PauliSum वस्तुओं:

def v_theta(qubits):
  """Prepares a circuit that generates V(\theta)."""
  ref_paulis = [
      cirq.X(q0) * cirq.X(q1) + \
      cirq.Y(q0) * cirq.Y(q1) + \
      cirq.Z(q0) * cirq.Z(q1) for q0, q1 in zip(qubits, qubits[1:])
  ]
  exp_symbols = list(sympy.symbols('ref_0:'+str(len(ref_paulis))))
  return tfq.util.exponential(ref_paulis, exp_symbols), exp_symbols

इस सर्किट को देखकर सत्यापित करना थोड़ा कठिन हो सकता है, लेकिन क्या हो रहा है यह देखने के लिए आप अभी भी दो क्विट केस की जांच कर सकते हैं:

test_circuit, test_symbols = v_theta(cirq.GridQubit.rect(1, 2))
print(f'Symbols found in circuit:{test_symbols}')
SVGCircuit(test_circuit)
Symbols found in circuit:[ref_0]

एसवीजी

अब आपके पास अपने पूर्ण एन्कोडिंग सर्किट को एक साथ रखने के लिए आवश्यक सभी बिल्डिंग ब्लॉक हैं:

def prepare_pqk_circuits(qubits, classical_source, n_trotter=10):
  """Prepare the pqk feature circuits around a dataset."""
  n_qubits = len(qubits)
  n_points = len(classical_source)

  # Prepare random single qubit rotation wall.
  random_rots = np.random.uniform(-2, 2, size=(n_qubits, 3))
  initial_U = single_qubit_wall(qubits, random_rots)

  # Prepare parametrized V
  V_circuit, symbols = v_theta(qubits)
  exp_circuit = cirq.Circuit(V_circuit for t in range(n_trotter))

  # Convert to `tf.Tensor`
  initial_U_tensor = tfq.convert_to_tensor([initial_U])
  initial_U_splat = tf.tile(initial_U_tensor, [n_points])

  full_circuits = tfq.layers.AddCircuit()(
      initial_U_splat, append=exp_circuit)
  # Replace placeholders in circuits with values from `classical_source`.
  return tfq.resolve_parameters(
      full_circuits, tf.convert_to_tensor([str(x) for x in symbols]),
      tf.convert_to_tensor(classical_source*(n_qubits/3)/n_trotter))

कुछ क्वैबिट चुनें और डेटा एन्कोडिंग सर्किट तैयार करें:

qubits = cirq.GridQubit.rect(1, DATASET_DIM + 1)
q_x_train_circuits = prepare_pqk_circuits(qubits, x_train)
q_x_test_circuits = prepare_pqk_circuits(qubits, x_test)

इसके बाद, गणना PQK ऊपर डाटासेट सर्किट के 1-RDM के आधार पर सुविधाओं और परिणाम में स्टोर rdm , एक tf.Tensor आकार के साथ [n_points, n_qubits, 3] । में प्रविष्टियों rdm[i][j][k] = \(\langle \psi_i | OP^k_j | \psi_i \rangle\) जहां i datapoints से अधिक अनुक्रमित, j qubits और अधिक अनुक्रमित k से अधिक अनुक्रमित \(\lbrace \hat{X}, \hat{Y}, \hat{Z} \rbrace\) ।

def get_pqk_features(qubits, data_batch):
  """Get PQK features based on above construction."""
  ops = [[cirq.X(q), cirq.Y(q), cirq.Z(q)] for q in qubits]
  ops_tensor = tf.expand_dims(tf.reshape(tfq.convert_to_tensor(ops), -1), 0)
  batch_dim = tf.gather(tf.shape(data_batch), 0)
  ops_splat = tf.tile(ops_tensor, [batch_dim, 1])
  exp_vals = tfq.layers.Expectation()(data_batch, operators=ops_splat)
  rdm = tf.reshape(exp_vals, [batch_dim, len(qubits), -1])
  return rdm
x_train_pqk = get_pqk_features(qubits, q_x_train_circuits)
x_test_pqk = get_pqk_features(qubits, q_x_test_circuits)
print('New PQK training dataset has shape:', x_train_pqk.shape)
print('New PQK testing dataset has shape:', x_test_pqk.shape)
New PQK training dataset has shape: (1000, 11, 3)
New PQK testing dataset has shape: (200, 11, 3)

2.2 PQK सुविधाओं के आधार पर पुन: लेबलिंग

अब आप में इन क्वांटम उत्पन्न विशेषताएं हैं कि x_train_pqk और x_test_pqk , यह फिर से लेबल डाटासेट का समय है। क्वांटम और शास्त्रीय प्रदर्शन आप कर सकते हैं के बीच अधिकतम जुदाई को प्राप्त करने के स्पेक्ट्रम जानकारी के आधार पर डाटासेट फिर से लेबल में पाया x_train_pqk और x_test_pqk

def compute_kernel_matrix(vecs, gamma):
  """Computes d[i][j] = e^ -gamma * (vecs[i] - vecs[j]) ** 2 """
  scaled_gamma = gamma / (
      tf.cast(tf.gather(tf.shape(vecs), 1), tf.float32) * tf.math.reduce_std(vecs))
  return scaled_gamma * tf.einsum('ijk->ij',(vecs[:,None,:] - vecs) ** 2)

def get_spectrum(datapoints, gamma=1.0):
  """Compute the eigenvalues and eigenvectors of the kernel of datapoints."""
  KC_qs = compute_kernel_matrix(datapoints, gamma)
  S, V = tf.linalg.eigh(KC_qs)
  S = tf.math.abs(S)
  return S, V
S_pqk, V_pqk = get_spectrum(
    tf.reshape(tf.concat([x_train_pqk, x_test_pqk], 0), [-1, len(qubits) * 3]))

S_original, V_original = get_spectrum(
    tf.cast(tf.concat([x_train, x_test], 0), tf.float32), gamma=0.005)

print('Eigenvectors of pqk kernel matrix:', V_pqk)
print('Eigenvectors of original kernel matrix:', V_original)
Eigenvectors of pqk kernel matrix: tf.Tensor(
[[-2.09569391e-02  1.05973557e-02  2.16634180e-02 ...  2.80352887e-02
   1.55521873e-02  2.82677952e-02]
 [-2.29303762e-02  4.66355234e-02  7.91163836e-03 ... -6.14174758e-04
  -7.07804322e-01  2.85902526e-02]
 [-1.77853629e-02 -3.00758495e-03 -2.55225878e-02 ... -2.40783971e-02
   2.11018627e-03  2.69009806e-02]
 ...
 [ 6.05797209e-02  1.32483775e-02  2.69536003e-02 ... -1.38843581e-02
   3.05043962e-02  3.85345481e-02]
 [ 6.33309558e-02 -3.04112374e-03  9.77444276e-03 ...  7.48321265e-02
   3.42793856e-03  3.67484428e-02]
 [ 5.86028099e-02  5.84433973e-03  2.64811981e-03 ...  2.82612257e-02
  -3.80136147e-02  3.29943895e-02]], shape=(1200, 1200), dtype=float32)
Eigenvectors of original kernel matrix: tf.Tensor(
[[ 0.03835681  0.0283473  -0.01169789 ...  0.02343717  0.0211248
   0.03206972]
 [-0.04018159  0.00888097 -0.01388255 ...  0.00582427  0.717551
   0.02881948]
 [-0.0166719   0.01350376 -0.03663862 ...  0.02467175 -0.00415936
   0.02195409]
 ...
 [-0.03015648 -0.01671632 -0.01603392 ...  0.00100583 -0.00261221
   0.02365689]
 [ 0.0039777  -0.04998879 -0.00528336 ...  0.01560401 -0.04330755
   0.02782002]
 [-0.01665728 -0.00818616 -0.0432341  ...  0.00088256  0.00927396
   0.01875088]], shape=(1200, 1200), dtype=float32)

अब आपके पास डेटासेट को फिर से लेबल करने के लिए आवश्यक सब कुछ है! डेटासेट को फिर से लेबल करते समय प्रदर्शन पृथक्करण को अधिकतम करने के तरीके को बेहतर ढंग से समझने के लिए अब आप फ़्लोचार्ट से परामर्श कर सकते हैं:

आदेश मात्रा और शास्त्रीय मॉडल के बीच अलगाव को अधिकतम करने के लिए, आप मूल डाटासेट के बीच ज्यामितीय अंतर को अधिकतम करने का प्रयास करेंगे और PQK गिरी मैट्रिक्स सुविधाओं \(g(K_1 || K_2) = \sqrt{ || \sqrt{K_2} K_1^{-1} \sqrt{K_2} || _\infty}\) का उपयोग कर S_pqk, V_pqk और S_original, V_original । का एक बड़ा मूल्य \(g\) सुनिश्चित आप शुरू में क्वांटम मामले में एक भविष्यवाणी लाभ की दिशा में प्रवाह संचित्र नीचे में सही करने के लिए ले जाने के है।

def get_stilted_dataset(S, V, S_2, V_2, lambdav=1.1):
  """Prepare new labels that maximize geometric distance between kernels."""
  S_diag = tf.linalg.diag(S ** 0.5)
  S_2_diag = tf.linalg.diag(S_2 / (S_2 + lambdav) ** 2)
  scaling = S_diag @ tf.transpose(V) @ \
            V_2 @ S_2_diag @ tf.transpose(V_2) @ \
            V @ S_diag

  # Generate new lables using the largest eigenvector.
  _, vecs = tf.linalg.eig(scaling)
  new_labels = tf.math.real(
      tf.einsum('ij,j->i', tf.cast(V @ S_diag, tf.complex64), vecs[-1])).numpy()
  # Create new labels and add some small amount of noise.
  final_y = new_labels > np.median(new_labels)
  noisy_y = (final_y ^ (np.random.uniform(size=final_y.shape) > 0.95))
  return noisy_y
y_relabel = get_stilted_dataset(S_pqk, V_pqk, S_original, V_original)
y_train_new, y_test_new = y_relabel[:N_TRAIN], y_relabel[N_TRAIN:]

3. मॉडल की तुलना करना

अब जब आपने अपना डेटासेट तैयार कर लिया है, तो यह मॉडल के प्रदर्शन की तुलना करने का समय है। आप दो छोटे feedforward तंत्रिका नेटवर्क बना सकते हैं और प्रदर्शन की तुलना जब वे PQK के लिए उपयोग दिया जाता है में पाया सुविधाओं होगा x_train_pqk

3.1 PQK एन्हांस्ड मॉडल बनाएं

मानक का उपयोग tf.keras अब आप बना सकते हैं पुस्तकालय सुविधाओं और एक ट्रेन पर एक मॉडल x_train_pqk और y_train_new datapoints:

#docs_infra: no_execute
def create_pqk_model():
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Dense(32, activation='sigmoid', input_shape=[len(qubits) * 3,]))
    model.add(tf.keras.layers.Dense(16, activation='sigmoid'))
    model.add(tf.keras.layers.Dense(1))
    return model

pqk_model = create_pqk_model()
pqk_model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.003),
              metrics=['accuracy'])

pqk_model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 32)                1088      
_________________________________________________________________
dense_1 (Dense)              (None, 16)                528       
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 17        
=================================================================
Total params: 1,633
Trainable params: 1,633
Non-trainable params: 0
_________________________________________________________________
#docs_infra: no_execute
pqk_history = pqk_model.fit(tf.reshape(x_train_pqk, [N_TRAIN, -1]),
          y_train_new,
          batch_size=32,
          epochs=1000,
          verbose=0,
          validation_data=(tf.reshape(x_test_pqk, [N_TEST, -1]), y_test_new))

3.2 एक शास्त्रीय मॉडल बनाएं

ऊपर दिए गए कोड के समान अब आप एक क्लासिकल मॉडल भी बना सकते हैं जिसकी आपके स्टिल्टेड डेटासेट में PQK सुविधाओं तक पहुंच नहीं है। इस मॉडल का उपयोग कर प्रशिक्षित किया जा सकता x_train और y_label_new

#docs_infra: no_execute
def create_fair_classical_model():
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Dense(32, activation='sigmoid', input_shape=[DATASET_DIM,]))
    model.add(tf.keras.layers.Dense(16, activation='sigmoid'))
    model.add(tf.keras.layers.Dense(1))
    return model

model = create_fair_classical_model()
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.03),
              metrics=['accuracy'])

model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_3 (Dense)              (None, 32)                352       
_________________________________________________________________
dense_4 (Dense)              (None, 16)                528       
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 17        
=================================================================
Total params: 897
Trainable params: 897
Non-trainable params: 0
_________________________________________________________________
#docs_infra: no_execute
classical_history = model.fit(x_train,
          y_train_new,
          batch_size=32,
          epochs=1000,
          verbose=0,
          validation_data=(x_test, y_test_new))

3.3 प्रदर्शन की तुलना करें

अब जब आपने दो मॉडलों को प्रशिक्षित कर लिया है तो आप दोनों के बीच सत्यापन डेटा में प्रदर्शन अंतराल को जल्दी से प्लॉट कर सकते हैं। आमतौर पर दोनों मॉडल प्रशिक्षण डेटा पर> 0.9 सटीकता प्राप्त करेंगे। हालाँकि सत्यापन डेटा पर यह स्पष्ट हो जाता है कि केवल PQK सुविधाओं में मिली जानकारी मॉडल को अनदेखी उदाहरणों के लिए अच्छी तरह से सामान्य बनाने के लिए पर्याप्त है।

#docs_infra: no_execute
plt.figure(figsize=(10,5))
plt.plot(classical_history.history['accuracy'], label='accuracy_classical')
plt.plot(classical_history.history['val_accuracy'], label='val_accuracy_classical')
plt.plot(pqk_history.history['accuracy'], label='accuracy_quantum')
plt.plot(pqk_history.history['val_accuracy'], label='val_accuracy_quantum')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
<matplotlib.legend.Legend at 0x7f6d846ecee0>

पीएनजी

4. महत्वपूर्ण निष्कर्ष

वहाँ कई महत्वपूर्ण निष्कर्ष आप इस और से आकर्षित कर सकते हैं कर रहे हैं MNIST प्रयोगों:

  1. यह बहुत कम संभावना है कि आज के क्वांटम मॉडल शास्त्रीय डेटा पर शास्त्रीय मॉडल के प्रदर्शन को मात देंगे। विशेष रूप से आज के शास्त्रीय डेटासेट पर जिसमें एक मिलियन से अधिक डेटापॉइंट हो सकते हैं।

  2. सिर्फ इसलिए कि डेटा एक कठिन से शास्त्रीय रूप से क्वांटम सर्किट का अनुकरण करने के लिए आ सकता है, जरूरी नहीं कि डेटा को शास्त्रीय मॉडल के लिए सीखना कठिन हो।

  3. डेटासेट (अंततः प्रकृति में क्वांटम) जो क्वांटम मॉडल के लिए सीखना आसान है और शास्त्रीय मॉडल के लिए सीखना कठिन है, मॉडल आर्किटेक्चर या उपयोग किए गए प्रशिक्षण एल्गोरिदम की परवाह किए बिना मौजूद हैं।