অনুর্বর মালভূমি

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন নোটবুক ডাউনলোড করুন

এই উদাহরণে আপনি McClean, 2019 -এর ফলাফল অন্বেষণ করবেন যা বলে যে শুধুমাত্র কোনো কোয়ান্টাম নিউরাল নেটওয়ার্ক গঠনই শেখার ক্ষেত্রে ভালো করবে না। বিশেষ করে আপনি দেখতে পাবেন যে র্যান্ডম কোয়ান্টাম সার্কিটগুলির একটি নির্দিষ্ট বড় পরিবার ভাল কোয়ান্টাম নিউরাল নেটওয়ার্ক হিসাবে কাজ করে না, কারণ তাদের গ্রেডিয়েন্ট রয়েছে যা প্রায় সর্বত্র অদৃশ্য হয়ে যায়। এই উদাহরণে আপনি একটি নির্দিষ্ট শেখার সমস্যার জন্য কোনও মডেলকে প্রশিক্ষণ দেবেন না, বরং গ্রেডিয়েন্টের আচরণ বোঝার সহজ সমস্যাটির উপর ফোকাস করবেন।

সেটআপ

pip install tensorflow==2.7.0

টেনসরফ্লো কোয়ান্টাম ইনস্টল করুন:

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)\) কে যেকোন qubits \(a\) এবং \(b\)placeholder5-এর জন্য প্রত্যাশা মান wrt \(Z_{a}Z_{b}\) হিসাবে সংজ্ঞায়িত করা হয়, তাহলে একটি সমস্যা আছে যে \(f'(x)\) এর গড় 0-এর খুব কাছাকাছি এবং খুব বেশি পরিবর্তিত হয় না। আপনি নীচে এটি দেখতে পাবেন:

2. এলোমেলো সার্কিট তৈরি করা

কাগজ থেকে নির্মাণ অনুসরণ সহজবোধ্য. নিম্নলিখিতগুলি একটি সাধারণ ফাংশন প্রয়োগ করে যা একটি এলোমেলো কোয়ান্টাম সার্কিট তৈরি করে — কখনও কখনও কোয়ান্টাম নিউরাল নেটওয়ার্ক (QNN) হিসাবে উল্লেখ করা হয় - qubits এর একটি সেটে প্রদত্ত গভীরতা সহ:

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}\)এর গ্রেডিয়েন্ট তদন্ত করেন। সার্কিটে যেখানে \(\theta_{1,1}\) হবে সেখানে একটি sympy.Symbol বসিয়ে অনুসরণ করা যাক। যেহেতু লেখকরা সার্কিটের অন্য কোনো চিহ্নের পরিসংখ্যান বিশ্লেষণ করেন না, তাই আসুন এখনই সেগুলোকে পরে পরিবর্তে র্যান্ডম মান দিয়ে প্রতিস্থাপন করি।

3. সার্কিট চলমান

গ্রেডিয়েন্ট খুব বেশি পরিবর্তিত হয় না দাবিটি পরীক্ষা করার জন্য একটি পর্যবেক্ষণযোগ্য সহ এই কয়েকটি সার্কিট তৈরি করুন। প্রথমত, র্যান্ডম সার্কিটের একটি ব্যাচ তৈরি করুন। একটি এলোমেলো ZZ পর্যবেক্ষণযোগ্য চয়ন করুন এবং ব্যাচ টেনসরফ্লো কোয়ান্টাম ব্যবহার করে গ্রেডিয়েন্ট এবং প্রকরণ গণনা করে।

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.

png

এই প্লটটি দেখায় যে কোয়ান্টাম মেশিন লার্নিং সমস্যার জন্য, আপনি কেবল একটি এলোমেলো QNN ansatz অনুমান করতে পারবেন না এবং সেরাটির জন্য আশা করতে পারবেন না। কিছু কাঠামো মডেল সার্কিটে উপস্থিত থাকতে হবে যাতে গ্রেডিয়েন্টগুলি যেখানে শেখা হতে পারে সেখানে পরিবর্তিত হয়।

4. হিউরিস্টিকস

গ্রান্টের একটি আকর্ষণীয় হিউরিস্টিক, 2019 একজনকে এলোমেলোভাবে খুব কাছাকাছি শুরু করতে দেয়, কিন্তু পুরোপুরি নয়। McClean et al. হিসাবে একই সার্কিট ব্যবহার করে, লেখক অনুর্বর মালভূমি এড়াতে শাস্ত্রীয় নিয়ন্ত্রণ পরামিতিগুলির জন্য একটি ভিন্ন প্রাথমিক কৌশল প্রস্তাব করেছেন। ইনিশিয়ালাইজেশন টেকনিক সম্পূর্ণ র্যান্ডম কন্ট্রোল প্যারামিটার সহ কিছু লেয়ার শুরু করে-কিন্তু, তৎক্ষণাৎ পরবর্তী স্তরগুলিতে, প্যারামিটারগুলি বেছে নিন যাতে প্রথম কয়েকটি স্তর দ্বারা তৈরি প্রাথমিক রূপান্তর পূর্বাবস্থায় চলে যায়। লেখক এটি একটি পরিচয় ব্লক কল.

এই হিউরিস্টিকটির সুবিধা হল যে শুধুমাত্র একটি একক প্যারামিটার পরিবর্তন করে, বর্তমান ব্লকের বাইরের সমস্ত ব্লকের পরিচয় থাকবে-এবং গ্রেডিয়েন্ট সিগন্যাল আগের থেকে অনেক বেশি শক্তিশালী হয়ে আসে। এটি ব্যবহারকারীকে একটি শক্তিশালী গ্রেডিয়েন্ট সিগন্যাল পেতে কোন ভেরিয়েবল এবং ব্লকগুলি পরিবর্তন করতে হবে তা বেছে নিতে এবং বেছে নিতে দেয়। এই হিউরিস্টিকটি প্রশিক্ষণ পর্বের সময় ব্যবহারকারীকে অনুর্বর মালভূমিতে পড়তে বাধা দেয় না (এবং একটি সম্পূর্ণ যুগপত আপডেট সীমাবদ্ধ করে), এটি কেবল গ্যারান্টি দেয় যে আপনি একটি মালভূমির বাইরে শুরু করতে পারেন।

4.1 নতুন QNN নির্মাণ

এখন পরিচয় ব্লক QNN তৈরি করতে একটি ফাংশন তৈরি করুন। এই বাস্তবায়ন কাগজ থেকে এক তুলনায় সামান্য ভিন্ন. আপাতত, একটি একক প্যারামিটারের গ্রেডিয়েন্টের আচরণ দেখুন যাতে এটি 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.

png

এটি (নিকটে) র্যান্ডম QNN থেকে শক্তিশালী গ্রেডিয়েন্ট সংকেত পাওয়ার ক্ষেত্রে একটি দুর্দান্ত উন্নতি।