الهضاب القاحلة

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

في هذا المثال سوف تستكشف نتيجة McClean، 2019 التي تقول أنه ليس فقط أي بنية شبكة عصبية كمومية ستعمل بشكل جيد عندما يتعلق الأمر بالتعلم. على وجه الخصوص ، سترى أن مجموعة كبيرة معينة من الدوائر الكمومية العشوائية لا تعمل كشبكات عصبية كمومية جيدة ، لأن لها تدرجات تتلاشى في كل مكان تقريبًا. في هذا المثال لن تقوم بتدريب أي نماذج لمشكلة تعليمية معينة ، ولكن بدلاً من ذلك ستركز على المشكلة الأبسط المتمثلة في فهم سلوكيات التدرجات.

يثبت

pip install tensorflow==2.7.0

تثبيت TensorFlow Quantum:

pip install tensorflow-quantum
# Update package resources to account for version changes.
import importlib, pkg_resources
importlib.reload(pkg_resources)
<module 'pkg_resources' from '/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/pkg_resources/__init__.py'>

الآن قم باستيراد TensorFlow وتبعيات الوحدة النمطية:

import tensorflow as tf
import tensorflow_quantum as tfq

import cirq
import sympy
import numpy as np

# visualization tools
%matplotlib inline
import matplotlib.pyplot as plt
from cirq.contrib.svg import SVGCircuit

np.random.seed(1234)
2022-02-04 12:15:43.355568: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

1. ملخص

دارات كمومية عشوائية بها العديد من الكتل التي تبدو بهذا الشكل (\(R_{P}(\theta)\) هو دوران باولي العشوائي):

حيث إذا تم تعريف \(f(x)\) على أنها قيمة التوقع wrt \(Z_{a}Z_{b}\) لأي كيوبت \(a\) و \(b\)، فإن هناك مشكلة أن \(f'(x)\) لها متوسط ​​قريب جداً من الصفر ولا يختلف كثيراً. سترى هذا أدناه:

2. توليد دوائر عشوائية

البناء من الورقة واضح ومباشر. تنفذ ما يلي وظيفة بسيطة تنشئ دائرة كمومية عشوائية - يشار إليها أحيانًا بالشبكة العصبية الكمية (QNN) - بعمق معين على مجموعة من البتات الكمومية:

def generate_random_qnn(qubits, symbol, depth):
    """Generate random QNN's with the same structure from McClean et al."""
    circuit = cirq.Circuit()
    for qubit in qubits:
        circuit += cirq.ry(np.pi / 4.0)(qubit)

    for d in range(depth):
        # Add a series of single qubit rotations.
        for i, qubit in enumerate(qubits):
            random_n = np.random.uniform()
            random_rot = np.random.uniform(
            ) * 2.0 * np.pi if i != 0 or d != 0 else symbol
            if random_n > 2. / 3.:
                # Add a Z.
                circuit += cirq.rz(random_rot)(qubit)
            elif random_n > 1. / 3.:
                # Add a Y.
                circuit += cirq.ry(random_rot)(qubit)
            else:
                # Add a X.
                circuit += cirq.rx(random_rot)(qubit)

        # Add CZ ladder.
        for src, dest in zip(qubits, qubits[1:]):
            circuit += cirq.CZ(src, dest)

    return circuit


generate_random_qnn(cirq.GridQubit.rect(1, 3), sympy.Symbol('theta'), 2)

يبحث المؤلفون في التدرج اللوني لمعامل واحد \(\theta_{1,1}\). دعنا نتبع ذلك بوضع رمز sympy.Symbol في الدائرة حيث سيكون \(\theta_{1,1}\) . نظرًا لأن المؤلفين لا يحللون الإحصائيات الخاصة بأي رموز أخرى في الدائرة ، فلنستبدلها بقيم عشوائية الآن بدلاً من لاحقًا.

3. تشغيل الدوائر

قم بإنشاء عدد قليل من هذه الدوائر جنبًا إلى جنب مع ما يمكن ملاحظته لاختبار الادعاء بأن التدرجات لا تختلف كثيرًا. أولاً ، قم بإنشاء مجموعة من الدوائر العشوائية. اختر ZZ عشوائيًا يمكن ملاحظته وحساب الدُفعة التدرجات والتباين باستخدام TensorFlow Quantum.

3.1 حساب تباين الدُفعة

لنكتب دالة مساعدة تحسب التباين في التدرج اللوني الذي يمكن ملاحظته على مجموعة من الدوائر:

def process_batch(circuits, symbol, op):
    """Compute the variance of a batch of expectations w.r.t. op on each circuit that 
    contains `symbol`. Note that this method sets up a new compute graph every time it is
    called so it isn't as performant as possible."""

    # Setup a simple layer to batch compute the expectation gradients.
    expectation = tfq.layers.Expectation()

    # Prep the inputs as tensors
    circuit_tensor = tfq.convert_to_tensor(circuits)
    values_tensor = tf.convert_to_tensor(
        np.random.uniform(0, 2 * np.pi, (n_circuits, 1)).astype(np.float32))

    # Use TensorFlow GradientTape to track gradients.
    with tf.GradientTape() as g:
        g.watch(values_tensor)
        forward = expectation(circuit_tensor,
                              operators=op,
                              symbol_names=[symbol],
                              symbol_values=values_tensor)

    # Return variance of gradients across all circuits.
    grads = g.gradient(forward, values_tensor)
    grad_var = tf.math.reduce_std(grads, axis=0)
    return grad_var.numpy()[0]

3.1 الإعداد والتشغيل

اختر عدد الدوائر العشوائية التي سيتم إنشاؤها جنبًا إلى جنب مع عمقها ومقدار البتات التي يجب أن تعمل عليها. ثم ارسم النتائج.

n_qubits = [2 * i for i in range(2, 7)
           ]  # Ranges studied in paper are between 2 and 24.
depth = 50  # Ranges studied in paper are between 50 and 500.
n_circuits = 200
theta_var = []

for n in n_qubits:
    # Generate the random circuits and observable for the given n.
    qubits = cirq.GridQubit.rect(1, n)
    symbol = sympy.Symbol('theta')
    circuits = [
        generate_random_qnn(qubits, symbol, depth) for _ in range(n_circuits)
    ]
    op = cirq.Z(qubits[0]) * cirq.Z(qubits[1])
    theta_var.append(process_batch(circuits, symbol, op))

plt.semilogy(n_qubits, theta_var)
plt.title('Gradient Variance in QNNs')
plt.xlabel('n_qubits')
plt.xticks(n_qubits)
plt.ylabel('$\\partial \\theta$ variance')
plt.show()
WARNING:tensorflow:5 out of the last 5 calls to <function Adjoint.differentiate_analytic at 0x7f9e3b5c68c0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.

بي إن جي

تُظهر هذه المؤامرة أنه بالنسبة لمشاكل التعلم الآلي الكمي ، لا يمكنك ببساطة تخمين أنساتز QNN العشوائية والأمل في الأفضل. يجب أن تكون بعض الهياكل موجودة في الدائرة النموذجية حتى تتغير التدرجات إلى النقطة التي يمكن أن يحدث فيها التعلم.

4. الاستدلال

يتيح برنامج Grant ، 2019 ، وهو دليل مثير للاهتمام ، أن يبدأ المرء قريبًا جدًا من العشوائية ، ولكن ليس تمامًا. باستخدام نفس الدوائر مثل McClean et al. ، اقترح المؤلفون تقنية تهيئة مختلفة لمعلمات التحكم الكلاسيكية لتجنب الهضاب القاحلة. تبدأ تقنية التهيئة بعض الطبقات بمعلمات تحكم عشوائية تمامًا - ولكن ، في الطبقات التالية مباشرة ، اختر معلمات بحيث يتم التراجع عن التحويل الأولي الذي تم إجراؤه بواسطة الطبقات القليلة الأولى. المؤلفون يسمون هذا كتلة الهوية .

ميزة هذا الاستدلال هو أنه من خلال تغيير معلمة واحدة فقط ، ستظل جميع الكتل الأخرى خارج الكتلة الحالية هي الهوية - وتأتي إشارة التدرج أقوى بكثير من ذي قبل. يتيح ذلك للمستخدم انتقاء واختيار المتغيرات والكتل التي يجب تعديلها للحصول على إشارة متدرجة قوية. لا يمنع هذا الاستدلال المستخدم من الوقوع في هضبة قاحلة أثناء مرحلة التدريب (ويقيد تحديثًا متزامنًا بالكامل) ، إنه يضمن فقط أنه يمكنك البدء خارج منطقة ثابتة.

4.1 إنشاءات QNN الجديدة

الآن قم ببناء وظيفة لإنشاء كتلة هوية QNNs. هذا التنفيذ يختلف قليلاً عن ذلك من الورق. في الوقت الحالي ، انظر إلى سلوك التدرج اللوني لمعامل واحد بحيث يكون متسقًا مع McClean et al ، لذلك يمكن إجراء بعض التبسيط.

لإنشاء كتلة هوية وتدريب النموذج ، تحتاج عمومًا إلى \(U1(\theta_{1a}) U1(\theta_{1b})^{\dagger}\) وليس \(U1(\theta_1) U1(\theta_1)^{\dagger}\). في البداية \(\theta_{1a}\) و \(\theta_{1b}\) هي نفس الزوايا ولكن يتم تعلمهما بشكل مستقل. خلاف ذلك ، ستحصل دائمًا على الهوية حتى بعد التدريب. اختيار عدد كتل الهوية تجريبي. كلما كانت الكتلة أعمق ، كان التباين في منتصف الكتلة أصغر. ولكن في بداية الكتلة ونهايتها ، يجب أن يكون تباين تدرجات المعلمات كبيرًا.

def generate_identity_qnn(qubits, symbol, block_depth, total_depth):
    """Generate random QNN's with the same structure from Grant et al."""
    circuit = cirq.Circuit()

    # Generate initial block with symbol.
    prep_and_U = generate_random_qnn(qubits, symbol, block_depth)
    circuit += prep_and_U

    # Generate dagger of initial block without symbol.
    U_dagger = (prep_and_U[1:])**-1
    circuit += cirq.resolve_parameters(
        U_dagger, param_resolver={symbol: np.random.uniform() * 2 * np.pi})

    for d in range(total_depth - 1):
        # Get a random QNN.
        prep_and_U_circuit = generate_random_qnn(
            qubits,
            np.random.uniform() * 2 * np.pi, block_depth)

        # Remove the state-prep component
        U_circuit = prep_and_U_circuit[1:]

        # Add U
        circuit += U_circuit

        # Add U^dagger
        circuit += U_circuit**-1

    return circuit


generate_identity_qnn(cirq.GridQubit.rect(1, 3), sympy.Symbol('theta'), 2, 2)

4.2 المقارنة

هنا يمكنك أن ترى أن الاستدلال يساعد في الحفاظ على تباين التدرج اللوني من التلاشي بسرعة:

block_depth = 10
total_depth = 5

heuristic_theta_var = []

for n in n_qubits:
    # Generate the identity block circuits and observable for the given n.
    qubits = cirq.GridQubit.rect(1, n)
    symbol = sympy.Symbol('theta')
    circuits = [
        generate_identity_qnn(qubits, symbol, block_depth, total_depth)
        for _ in range(n_circuits)
    ]
    op = cirq.Z(qubits[0]) * cirq.Z(qubits[1])
    heuristic_theta_var.append(process_batch(circuits, symbol, op))

plt.semilogy(n_qubits, theta_var)
plt.semilogy(n_qubits, heuristic_theta_var)
plt.title('Heuristic vs. Random')
plt.xlabel('n_qubits')
plt.xticks(n_qubits)
plt.ylabel('$\\partial \\theta$ variance')
plt.show()
WARNING:tensorflow:6 out of the last 6 calls to <function Adjoint.differentiate_analytic at 0x7f9e3b5c68c0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.

بي إن جي

يعد هذا تحسنًا كبيرًا في الحصول على إشارات متدرجة أقوى من شبكات QNN العشوائية (القريبة).