0

我正在尝试实现以下论文第 8 页中列出的电路:https : //arxiv.org/pdf/1905.10876.pdf 使用 Tensorflow Quantum (TFQ)。我之前已经为使用 Qiskit 的电路子集这样做了,最终得到的精度可以在以下论文的第 14 页上找到:https ://arxiv.org/pdf/2003.09887.pdf 。在 TFQ 中,我的准确率下降了很多。我认为这个 delta 的起源是因为在 TFQ 中,我只在第一个量子位上使用了 1 个可观察泡利 Z 算子,并且电路似乎没有将所有知识“转移”到第一个量子位。我把它放在引号中,因为我确信有更好的方法来描述它。另一方面,在 Qiskit 中,16 个状态 (4^2) 被映射到 2 个状态。

我的问题:我怎样才能恢复我的准确性?
可能的答案 a):将所有信息“传输”到单个量子位(可能是辅助量子位)并对该量子位进行读数的某种方法。
可能的答案 b) 在所有量子位(总共 4 个)上放置一个 Pauli Z 可观察对象,将 16 个状态中的一半映射到标签 0,另一半映射到标签 1。我在下面的代码中尝试了这个。

我对答案 b) 的尝试:

我有一个在 Tensorflow 中实现的 Tensorflow Quantum (TFQ) 电路。该电路有多个可观察量,我尝试将它们组合到我的损失函数中。我更喜欢使用尽可能多的标准组件,但需要将我的量子状态映射到标签以确定损失。我认为我想要达到的目标并不是 TFQ 独有的。我通过以下方式定义我的模型:

def circuit():
  data_qubits = cirq.GridQubit.rect(4, 1)  
  circuit = cirq.Circuit()
  ...
  return circuit, [cirq.Z(data_qubits[0]), cirq.Z(data_qubits[1]), cirq.Z(data_qubits[2]), cirq.Z(data_qubits[3])]
model_circuit, model_readout = circuit()

model = tf.keras.Sequential([
  tf.keras.layers.Input(shape=(), dtype=tf.string),
  # The PQC layer returns the expected value of the readout gate, range [-1,1].
  tfq.layers.PQC(model_circuit, model_readout),
])

# compile model
model.compile(
  loss = loss_mse,
  optimizer=tf.keras.optimizers.Adam(learning_rate=0.01),
  metrics=[])

在 loss_mse(均方误差)中,我收到 y_pred 的 (32, 4) 张量。一排可能看起来像

[-0.2, 0.33, 0.6, 0.3]

这必须首先从 [-1,1] 映射到 [0,1] 的二值化版本,因此它看起来像:

[0, 1, 1, 1]

现在,需要进行表查找,以判断此组合是 0 还是 1。最后,可以由该行执行常规 (y_true-y_pred)^2,然后对所有行执行 np.sum。我试图实现这一点:

def get_label(measurement):
  if measurement == [0,0,0,0]: return 0
  ...
  elif measurement == [1,1,1,1]: return 0
  else: return -1

def py_call(y_true, y_pred):
  # cast tensor to numpy
  y_pred_np = np.asarray(y_pred)
  loss = np.zeros((len(y_pred))) # could be a single variable with += within the loop
  # evalaute all 32 samples
  for pred in range(len(y_pred_np)):
      # map, binarize and lookup
      y_labelled = get_label([0 if y<0 else 1 for y in y_pred_np[pred]])
      # regular loss comparison
      loss[pred] = (y_labelled - y_true[pred])**2
  # reduce
  loss = np.sum(loss)/len(y_true)
return loss

@tf.function
def loss_mse(y_true, y_pred):
  external_list = []
  loss = tf.py_function(py_call, inp=[y_true, y_pred], Tout=[tf.float64])
  return loss

然而,系统似乎仍然期望 (32,4) 张量。我原以为我可以简单地提供一个损失值(浮点数)。我的问题:如何将 y_true 的多个值映射到单个数字,以便与张量流损失函数中的单个 y_pred 值进行比较?

4

1 回答 1

0

所以看起来这里发生了一些事情。回答你的问题

如何将 y_true 的多个值映射到单个数字,以便与张量流损失函数中的单个 y_pred 值进行比较?

您可能想要的是某种tf.reduce_*函数,例如tf.reduce_meanor tf.reduce_sum。此函数将允许您在给定的张量轴上应用此归约操作,从而允许您将形状为 (32, 4) 的张量转换为形状为 (32,) 的张量或形状为 (4,) 的张量。这是一个快速的片段:

@tf.function
def my_loss(y_true, y_pred):
  # y_true is shape (32, 4)
  # y_pred is shape (32, 4)

  # Scale from [-1, 1] to [0, 1]
  y_true += 1
  y_true /= 2
  y_pred += 1
  y_pred /= 2

  # These are now both (32,) with the reduction of taking the mean applied along
  # the second axis.
  reduced_true = tf.reduce_mean(y_true, axis=1)
  reduced_pred = tf.reduce_mean(y_pred, axis=1)

  # Now a scalar loss.
  loss = tf.reduce_mean((reduce_true - reduced_pred) ** 2)
  return loss

现在上面的内容并不完全是你想要的,因为至少我不太清楚你在考虑使用类似[0,1,1,1] -> 0vs的东西时有什么确切的减少规则[0,0,0,0] -> 1

我还要提到的另一件事是,如果您只想要 cirq 中这些 Pauli 运算符的总和,并且您在列表中逐项列出[cirq.Z(data_qubits[0]), cirq.Z(data_qubits[1]), cirq.Z(data_qubits[2]), cirq.Z(data_qubits[3])]并且您关心的是这些期望的最终总和,您可以轻松地执行以下操作:

my_operator = sum([cirq.Z(data_qubits[0]), cirq.Z(data_qubits[1]),
  cirq.Z(data_qubits[2]), cirq.Z(data_qubits[3])])

print(my_op)

应该给出如下内容: cirq.PauliSum(cirq.LinearDict({frozenset({(cirq.GridQubit(0, 0), cirq.Z)}): (1+0j), frozenset({(cirq.GridQubit(0, 1), cirq.Z)}): (1+0j), frozenset({(cirq.GridQubit(0, 2), cirq.Z)}): (1+0j), frozenset({(cirq.GridQubit(0, 3), cirq.Z)}): (1+0j)}))

这也与 PQC 层中的读出操作兼容。最后,如果建议您阅读此处的一些片段和示例: https ://www.tensorflow.org/quantum/api_docs/python/tfq/layers/PQC

和这里:

https://www.tensorflow.org/quantum/api_docs/python/tfq/layers/Expectation

这很好地描述了函数的输入和输出签名的外观以及您可以从它们中获得的形状。

于 2020-07-10T01:44:04.717 回答