इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

हैलो, कई दुनिया

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

यह ट्यूटोरियल दिखाता है कि एक क्लासिकल न्यूरल नेटवर्क कैसेट कैलिब्रेशन त्रुटियों को ठीक करना सीख सकता है। यह परिचय Cirq , बनाने, संपादित करने के लिए एक अजगर ढांचे, और शोर मध्यवर्ती स्केल क्वांटम आह्वान (NISQ) सर्किट, और यह दर्शाता है TensorFlow क्वांटम के साथ कैसे Cirq इंटरफेस।

सेट अप

pip install -q tensorflow==2.1.0

TensorFlow क्वांटम स्थापित करें:

pip install -q tensorflow-quantum
ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.

We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.

tensorflow-metadata 0.23.0 requires absl-py<0.9,>=0.7, but you'll have absl-py 0.9.0 which is incompatible.
google-api-core 1.22.1 requires protobuf>=3.12.0, but you'll have protobuf 3.8.0 which is incompatible.

अब 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

1. मूल बातें

1.1 Cirq और परिमाणित क्वांटम सर्किट

TensorFlow Quantum (TFQ) की खोज करने से पहले, आइए कुछ Cirq मूल बातें देखें। Cirq Google से क्वांटम कंप्यूटिंग के लिए एक पायथन लाइब्रेरी है। आप इसका उपयोग स्टैटिक और पैरामीटर गेट सहित सर्किट को परिभाषित करने के लिए करते हैं।

नि: शुल्क मापदंडों का प्रतिनिधित्व करने के लिए Cirq SymPy प्रतीकों का उपयोग करता है।

a, b = sympy.symbols('a b')

निम्न कोड आपके मापदंडों का उपयोग करते हुए दो-क्विट सर्किट बनाता है:

# Create two qubits
q0, q1 = cirq.GridQubit.rect(1, 2)

# Create a circuit on these qubits using the parameters you created above.
circuit = cirq.Circuit(
    cirq.rx(a).on(q0),
    cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1))

SVGCircuit(circuit)
findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.

svg

सर्किट का मूल्यांकन करने के लिए, आप cirq.Simulator इंटरफ़ेस का उपयोग कर सकते हैं। आप cirq.ParamResolver ऑब्जेक्ट में पास करके विशिष्ट संख्या वाले सर्किट में मुक्त मापदंडों को प्रतिस्थापित करते हैं। निम्न कोड आपके पैरामीटर किए गए सर्किट के कच्चे राज्य वेक्टर आउटपुट की गणना करता है:

# Calculate a state vector with a=0.5 and b=-0.5.
resolver = cirq.ParamResolver({a: 0.5, b: -0.5})
output_state_vector = cirq.Simulator().simulate(circuit, resolver).final_state
output_state_vector
array([ 0.9387913 +0.j        , -0.23971277+0.j        ,

        0.        +0.06120872j,  0.        -0.23971277j], dtype=complex64)

स्टेट वैक्टर सिमुलेशन के बाहर सीधे पहुंच योग्य नहीं हैं (ऊपर आउटपुट में जटिल संख्या पर ध्यान दें)। शारीरिक रूप से यथार्थवादी होने के लिए, आपको एक माप निर्दिष्ट करना होगा, जो एक राज्य वेक्टर को एक वास्तविक संख्या में परिवर्तित करता है जिसे शास्त्रीय कंप्यूटर समझ सकते हैं। Cirq पाउली ऑपरेटरों $ \ hat {X} $, $ \ hat {Y} $, और $ \ hat {Z} $ के संयोजन का उपयोग करके माप निर्दिष्ट करता है। दृष्टांत के रूप में, निम्नलिखित कोड $ \ hat {Z} _0 $ और $ \ frac {1} {2} \ टोपी {Z} _0 + \ hat {X} _1 $ को राज्य वेक्टर पर आप केवल नकली मापते हैं:

z0 = cirq.Z(q0)

qubit_map={q0: 0, q1: 1}

z0.expectation_from_wavefunction(output_state_vector, qubit_map).real
0.8775825500488281
z0x1 = 0.5 * z0 + cirq.X(q1)

z0x1.expectation_from_wavefunction(output_state_vector, qubit_map).real
-0.04063427448272705

1.2 क्वांटम सर्किट दसियों के रूप में

TensorFlow Quantum (TFQ) tfq.convert_to_tensor , एक फ़ंक्शन प्रदान करता है जो Cirq ऑब्जेक्ट्स को tfq.convert_to_tensor परिवर्तित करता है। यह आपको हमारी क्वांटम परतों और क्वांटम ऑप्स को Cirq ऑब्जेक्ट भेजने की अनुमति देता है। समारोह को Cirq सर्किट और Cirq Paulis की सूची या सरणियों पर बुलाया जा सकता है:

# Rank 1 tensor containing 1 circuit.
circuit_tensor = tfq.convert_to_tensor([circuit])

print(circuit_tensor.shape)
print(circuit_tensor.dtype)
(1,)
<dtype: 'string'>

यह Cirq ऑब्जेक्ट्स को tf.string रूप में एन्कोड करता है, जो tfq ऑपरेशंस आवश्यकतानुसार डिकोड करता है।

# Rank 1 tensor containing 2 Pauli operators.
pauli_tensor = tfq.convert_to_tensor([z0, z0x1])
pauli_tensor.shape
TensorShape([2])

1.3 बैचिंग सर्किट सिमुलेशन

TFQ उम्मीद के मूल्यों, नमूनों और राज्य वैक्टर की गणना के लिए तरीके प्रदान करता है। अभी के लिए, आइए अपेक्षाओं के मूल्यों पर ध्यान दें।

अपेक्षा मूल्यों की गणना के लिए उच्चतम स्तर का इंटरफ़ेस tfq.layers.Expectation layer है, जो tf.keras.Layer । अपने सरलतम रूप में, यह परत कई cirq.ParamResolvers पर एक पैरामीटर सर्किट का अनुकरण करने के बराबर है; हालांकि, TFQ TensorFlow शब्दार्थ के बाद बैचिंग की अनुमति देता है, और सर्किट कुशल C ++ कोड का उपयोग करके सिम्युलेटेड होते हैं।

मूल्यों का एक बैच बनाने के लिए हमारे लिए स्थानापन्न करने a और b पैरामीटर:

batch_vals = np.array(np.random.uniform(0, 2 * np.pi, (5, 2)), dtype=np.float32)

Cirq में पैरामीटर मानों पर सर्किट निष्पादन को एक लूप की आवश्यकता होती है:

cirq_results = []
cirq_simulator = cirq.Simulator()

for vals in batch_vals:
    resolver = cirq.ParamResolver({a: vals[0], b: vals[1]})
    final_state = cirq_simulator.simulate(circuit, resolver).final_state
    cirq_results.append(
        [z0.expectation_from_wavefunction(final_state, {
            q0: 0,
            q1: 1
        }).real])

print('cirq batch results: \n {}'.format(np.array(cirq_results)))
cirq batch results: 
 [[-0.83266681]
 [ 0.99945712]
 [-0.93167216]
 [-0.0446538 ]
 [ 0.81493288]]

एक ही ऑपरेशन TFQ में सरलीकृत किया गया है:

tfq.layers.Expectation()(circuit,
                         symbol_names=[a, b],
                         symbol_values=batch_vals,
                         operators=z0)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[-0.83266693],
       [ 0.9994572 ],
       [-0.9316722 ],
       [-0.04465387],
       [ 0.81493276]], dtype=float32)>

2. हाइब्रिड क्वांटम-शास्त्रीय अनुकूलन

अब जब आप मूल बातें देख चुके हैं, तो हाइब्रिड क्वांटम-क्लासिकल न्यूरल नेट बनाने के लिए TensorFlow क्वांटम का उपयोग करें। आप एक एकल qubit को नियंत्रित करने के लिए एक शास्त्रीय तंत्रिका जाल को प्रशिक्षित करेंगे। एक व्यवस्थित व्यवस्थित अंशांकन त्रुटि पर काबू पाने के लिए नियंत्रण को 0 या 1 राज्य में सही ढंग से तैयार करने के लिए अनुकूलित किया जाएगा। यह आंकड़ा वास्तुकला को दर्शाता है:

तंत्रिका नेटवर्क के बिना भी यह हल करने के लिए एक सीधी समस्या है, लेकिन विषय वास्तविक क्वांटम नियंत्रण समस्याओं के समान है जिसे आप TFQ का उपयोग करके हल कर सकते हैं। यह एक tf.keras.Model अंदर tfq.layers.ControlledPQC (Parametrized क्वांटम सर्किट) परत का उपयोग करके एक क्वांटम-शास्त्रीय संगणना के अंत-से-अंत उदाहरण को tf.keras.Model

इस ट्यूटोरियल के कार्यान्वयन के लिए, यह आर्किटेक्चर 3 भागों में विभाजित है:

  • इनपुट सर्किट या डेटापॉइंट सर्किट : पहले तीन $ आर $ गेट्स।
  • नियंत्रित सर्किट : अन्य तीन $ आर $ गेट्स।
  • नियंत्रक : शास्त्रीय तंत्रिका-नेटवर्क नियंत्रित सर्किट के मापदंडों की स्थापना।

२.१ नियंत्रित सर्किट परिभाषा

एक शिक्षाप्रद एकल बिट रोटेशन को परिभाषित करें, जैसा कि ऊपर की आकृति में इंगित किया गया है। यह हमारे नियंत्रित सर्किट के अनुरूप होगा।

# Parameters that the classical NN will feed values into.
control_params = sympy.symbols('theta_1 theta_2 theta_3')

# Create the parameterized circuit.
qubit = cirq.GridQubit(0, 0)
model_circuit = cirq.Circuit(
    cirq.rz(control_params[0])(qubit),
    cirq.ry(control_params[1])(qubit),
    cirq.rx(control_params[2])(qubit))

SVGCircuit(model_circuit)

svg

2.2 नियंत्रक

अब नियंत्रक नेटवर्क को परिभाषित करें:

# The classical neural network layers.
controller = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='elu'),
    tf.keras.layers.Dense(3)
])

आदेशों के एक बैच को देखते हुए, नियंत्रक नियंत्रित सर्किट के लिए नियंत्रण संकेतों के एक बैच को आउटपुट करता है।

नियंत्रक यादृच्छिक रूप से आरंभिक है, इसलिए ये आउटपुट उपयोगी नहीं हैं, फिर भी।

controller(tf.constant([[0.0],[1.0]])).numpy()
array([[0.        , 0.        , 0.        ],
       [0.54516   , 0.22012806, 0.09697416]], dtype=float32)

2.3 कंट्रोलर को सर्किट से कनेक्ट करें

नियंत्रक को नियंत्रित सर्किट से जोड़ने के लिए tfq का उपयोग करें, एक एकल keras.Model

मॉडल की इस शैली के बारे में अधिक जानने के लिए केरस कार्यात्मक एपीआई गाइड देखें।

पहले मॉडल के इनपुट को परिभाषित करें:

# This input is the simulated miscalibration that the model will learn to correct.
circuits_input = tf.keras.Input(shape=(),
                                # The circuit-tensor has dtype `tf.string` 
                                dtype=tf.string,
                                name='circuits_input')

# Commands will be either `0` or `1`, specifying the state to set the qubit to.
commands_input = tf.keras.Input(shape=(1,),
                                dtype=tf.dtypes.float32,
                                name='commands_input')

अगला उन संगणनाओं के लिए प्रचालनों को लागू करता है, गणना को परिभाषित करने के लिए।

dense_2 = controller(commands_input)

# TFQ layer for classically controlled circuits.
expectation_layer = tfq.layers.ControlledPQC(model_circuit,
                                             # Observe Z
                                             operators = cirq.Z(qubit))
expectation = expectation_layer([circuits_input, dense_2])

अब इस गणना को tf.keras.Model रूप में पैकेज करें:

# The full Keras model is built from our layers.
model = tf.keras.Model(inputs=[circuits_input, commands_input],
                       outputs=expectation)

नेटवर्क आर्किटेक्चर नीचे दिए गए मॉडल के प्लॉट द्वारा इंगित किया गया है। शुद्धता को सत्यापित करने के लिए इस मॉडल प्लॉट की वास्तुकला आरेख से तुलना करें।

tf.keras.utils.plot_model(model, show_shapes=True, dpi=70)

png

यह मॉडल दो इनपुट लेता है: नियंत्रक के लिए कमांड, और इनपुट-सर्किट जिसका आउटपुट कंट्रोलर सही करने का प्रयास कर रहा है।

2.4 डेटासेट

मॉडल प्रत्येक कमांड के लिए $ $ हैट {Z} $ के सही सही माप मूल्य को आउटपुट करने का प्रयास करता है। आदेश और सही मान नीचे दिए गए हैं।

# The command input values to the classical NN.
commands = np.array([[0], [1]], dtype=np.float32)

# The desired Z expectation value at output of quantum circuit.
expected_outputs = np.array([[1], [-1]], dtype=np.float32)

यह इस कार्य के लिए संपूर्ण प्रशिक्षण डेटासेट नहीं है। डेटासेट में प्रत्येक डेटापॉइंट को एक इनपुट सर्किट की भी आवश्यकता होती है।

२.४ इनपुट सर्किट परिभाषा

नीचे दिया गया इनपुट-सर्किट यादृच्छिक मिसलिब्रेशन को परिभाषित करता है जिसे मॉडल सही करना सीखेगा।

random_rotations = np.random.uniform(0, 2 * np.pi, 3)
noisy_preparation = cirq.Circuit(
  cirq.rx(random_rotations[0])(qubit),
  cirq.ry(random_rotations[1])(qubit),
  cirq.rz(random_rotations[2])(qubit)
)
datapoint_circuits = tfq.convert_to_tensor([
  noisy_preparation
] * 2)  # Make two copied of this circuit

सर्किट की दो प्रतियां हैं, प्रत्येक डेटापॉइंट के लिए एक।

datapoint_circuits.shape
TensorShape([2])

2.5 प्रशिक्षण

परिभाषित इनपुट्स के साथ आप tfq मॉडल को टेस्ट-रन कर सकते हैं।

model([datapoint_circuits, commands]).numpy()
array([[ 0.00428568],
       [-0.13666134]], dtype=float32)

अब इन मानों को expected_outputs ओर समायोजित करने के लिए एक मानक प्रशिक्षण प्रक्रिया चलाएं।

optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
loss = tf.keras.losses.MeanSquaredError()
model.compile(optimizer=optimizer, loss=loss)
history = model.fit(x=[datapoint_circuits, commands],
                    y=expected_outputs,
                    epochs=30,
                    verbose=0)
plt.plot(history.history['loss'])
plt.title("Learning to Control a Qubit")
plt.xlabel("Iterations")
plt.ylabel("Error in Control")
plt.show()

png

इस प्लॉट से आप देख सकते हैं कि तंत्रिका नेटवर्क ने व्यवस्थित मिसलिब्रेशन पर काबू पाना सीख लिया है।

2.6 आउटपुट सत्यापित करें

अब क्वैब अंशांकन त्रुटियों को ठीक करने के लिए, प्रशिक्षित मॉडल का उपयोग करें। Cirq के साथ:

def check_error(command_values, desired_values):
  """Based on the value in `command_value` see how well you could prepare
  the full circuit to have `desired_value` when taking expectation w.r.t. Z."""
  params_to_prepare_output = controller(command_values).numpy()
  full_circuit = noisy_preparation + model_circuit

  # Test how well you can prepare a state to get expectation the expectation
  # value in `desired_values`
  for index in [0, 1]:
    state = cirq_simulator.simulate(
        full_circuit,
        {s:v for (s,v) in zip(control_params, params_to_prepare_output[index])}
    ).final_state
    expectation = z0.expectation_from_wavefunction(state, {qubit: 0}).real
    print(f'For a desired output (expectation) of {desired_values[index]} with'
          f' noisy preparation, the controller\nnetwork found the following '
          f'values for theta: {params_to_prepare_output[index]}\nWhich gives an'
          f' actual expectation of: {expectation}\n')


check_error(commands, expected_outputs)
For a desired output (expectation) of [1.] with noisy preparation, the controller
network found the following values for theta: [ 0.6296288  1.1365356 -1.5962224]
Which gives an actual expectation of: 0.9621249437332153

For a desired output (expectation) of [-1.] with noisy preparation, the controller
network found the following values for theta: [1.0543389 1.18372   0.7693251]
Which gives an actual expectation of: -0.9606054425239563


प्रशिक्षण के दौरान हानि फ़ंक्शन का मूल्य मॉडल का कितना अच्छा तरीका है, इसका एक मोटा विचार प्रदान करता है। कम नुकसान, उपरोक्त सेल में अपेक्षा मूल्यों के करीब desired_values । यदि आप पैरामीटर मानों से संबंधित नहीं हैं, तो आप हमेशा tfq का उपयोग करके ऊपर से आउटपुट की जांच कर सकते हैं:

model([datapoint_circuits, commands])
<tf.Tensor: shape=(2, 1), dtype=float32, numpy=
array([[ 0.9621245 ],
       [-0.96060544]], dtype=float32)>

3 अलग-अलग संचालकों के स्वदेशी तैयार करना सीखना

$ 1 pm \ hat {Z} $ eigenstates की पसंद 1 और 0 के अनुरूप थी। आप $ + \ हैट {Z} $ eigenstate और 0 के साथ $ - \ hat {X} $ eigenstate के अनुरूप करने के लिए आसानी से 1 चाहते थे। इसे पूरा करने का एक तरीका प्रत्येक कमांड के लिए एक अलग माप ऑपरेटर निर्दिष्ट करके है, जैसा कि नीचे दिए गए आंकड़े में दिखाया गया है:

इसके लिए tfq.layers.Expectation उपयोग की आवश्यकता है। अब आपके इनपुट में तीन ऑब्जेक्ट्स शामिल हो गए हैं: सर्किट, कमांड और ऑपरेटर। आउटपुट अभी भी उम्मीद का मूल्य है।

3.1 नई मॉडल परिभाषा

इस कार्य को पूरा करने के लिए मॉडल पर एक नज़र डालें:

# Define inputs.
commands_input = tf.keras.layers.Input(shape=(1),
                                       dtype=tf.dtypes.float32,
                                       name='commands_input')
circuits_input = tf.keras.Input(shape=(),
                                # The circuit-tensor has dtype `tf.string` 
                                dtype=tf.dtypes.string,
                                name='circuits_input')
operators_input = tf.keras.Input(shape=(1,),
                                 dtype=tf.dtypes.string,
                                 name='operators_input')

यहाँ नियंत्रक नेटवर्क है:

# Define classical NN.
controller = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='elu'),
    tf.keras.layers.Dense(3)
])

सर्किट और नियंत्रक को एक ही keras.Model tfq

dense_2 = controller(commands_input)

# Since you aren't using a PQC or ControlledPQC you must append
# your model circuit onto the datapoint circuit tensor manually.
full_circuit = tfq.layers.AddCircuit()(circuits_input, append=model_circuit)
expectation_output = tfq.layers.Expectation()(full_circuit,
                                              symbol_names=control_params,
                                              symbol_values=dense_2,
                                              operators=operators_input)

# Contruct your Keras model.
two_axis_control_model = tf.keras.Model(
    inputs=[circuits_input, commands_input, operators_input],
    outputs=[expectation_output])

3.2 डेटासेट

अब आप उन संचालकों को भी शामिल करेंगे जिन्हें आप प्रत्येक datapoint के लिए मापना चाहते हैं जिसे आप model_circuit लिए आपूर्ति करते हैं:

# The operators to measure, for each command.
operator_data = tfq.convert_to_tensor([[cirq.X(qubit)], [cirq.Z(qubit)]])

# The command input values to the classical NN.
commands = np.array([[0], [1]], dtype=np.float32)

# The desired expectation value at output of quantum circuit.
expected_outputs = np.array([[1], [-1]], dtype=np.float32)

३.३ प्रशिक्षण

अब जब आपके पास अपने नए इनपुट और आउटपुट हैं तो आप एक बार फिर से केर का उपयोग करके प्रशिक्षित कर सकते हैं।

optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
loss = tf.keras.losses.MeanSquaredError()

two_axis_control_model.compile(optimizer=optimizer, loss=loss)

history = two_axis_control_model.fit(
    x=[datapoint_circuits, commands, operator_data],
    y=expected_outputs,
    epochs=30,
    verbose=1)
Train on 2 samples
Epoch 1/30
2/2 [==============================] - 1s 311ms/sample - loss: 1.0348
Epoch 2/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.6338
Epoch 3/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.4026
Epoch 4/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.3120
Epoch 5/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.2221
Epoch 6/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.1057
Epoch 7/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0341
Epoch 8/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0091
Epoch 9/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0020
Epoch 10/30
2/2 [==============================] - 0s 2ms/sample - loss: 6.2119e-04
Epoch 11/30
2/2 [==============================] - 0s 2ms/sample - loss: 0.0038
Epoch 12/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0114
Epoch 13/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0174
Epoch 14/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0158
Epoch 15/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0115
Epoch 16/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0119
Epoch 17/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0179
Epoch 18/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0245
Epoch 19/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0272
Epoch 20/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0247
Epoch 21/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0189
Epoch 22/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0125
Epoch 23/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0076
Epoch 24/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0047
Epoch 25/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0033
Epoch 26/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0025
Epoch 27/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0019
Epoch 28/30
2/2 [==============================] - 0s 1ms/sample - loss: 0.0013
Epoch 29/30
2/2 [==============================] - 0s 1ms/sample - loss: 8.3354e-04
Epoch 30/30
2/2 [==============================] - 0s 1ms/sample - loss: 5.6316e-04

plt.plot(history.history['loss'])
plt.title("Learning to Control a Qubit")
plt.xlabel("Iterations")
plt.ylabel("Error in Control")
plt.show()

png

हानि समारोह शून्य हो गया है।

controller एक स्टैंड-अलोन मॉडल के रूप में उपलब्ध है। नियंत्रक को कॉल करें, और प्रत्येक कमांड सिग्नल पर इसकी प्रतिक्रिया की जांच करें। random_rotations की सामग्री को इन आउटपुट की सही तुलना करने में कुछ काम random_rotations

controller.predict(np.array([0,1]))
array([[ 1.9317125 , -0.03036583, -0.46449944],
       [ 2.1391845 ,  1.4074974 , -0.42245713]], dtype=float32)