Как сопоставить массив значений для y_true с одним значением, чтобы сравнить с y_pred в функции потерь Tensorflow (Tensorflow/Tensorflow Quantum)

Я пытаюсь реализовать схемы, перечисленные на странице 8 в следующем документе: https://arxiv.org/pdf/1905.10876.pdf, используя Tensorflow Quantum (TFQ). Я сделал это ранее для подмножества схем с использованием Qiskit и в итоге получил точность, которую можно найти на странице 14 в следующем документе: https://arxiv.org/pdf/2003.09887.pdf. В TFQ моя точность сильно снижается. Я думаю, что эта дельта возникает из-за того, что в TFQ я использовал только 1 наблюдаемый оператор Z Паули на первом кубите, и схемы, похоже, не "передают все знания" первому кубиту. Я помещаю это в кавычки, потому что уверен, что есть лучший способ описать это. В Qiskit, с другой стороны, 16 состояний (4^2) отображаются в 2 состояния.

Мой вопрос: как я могу восстановить свою точность?
Возможный ответ а): какой-то метод "передачи всей информации" одному кубиту, потенциально вспомогательному кубиту, и выполнение считывания этого кубита.
Возможный ответ б) размещение наблюдаемой Паули Z на всех кубитах (всего 4), отображение половины из 16 состояний на метку 0, а другую половину на метку 1. Я попытался сделать это в приведенном ниже коде.

Моя попытка ответить б):

У меня есть схема Tensorflow Quantum (TFQ), реализованная в Tensorflow. Схема имеет несколько наблюдаемых, которые я пытаюсь объединить в своей функции потерь. Я предпочитаю использовать как можно больше стандартных компонентов, но мне нужно сопоставить свои квантовые состояния с меткой, чтобы определить потери. Я думаю, что то, чего я пытаюсь достичь, характерно не только для 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 (средняя квадратичная ошибка) я получаю тензор (32, 4) для y_pred. Одна строка может выглядеть как

[-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 в функции потерь тензорного потока?

1 ответ

Похоже, здесь происходит несколько вещей. Чтобы ответить на ваш вопрос

как я могу сопоставить несколько значений y_true с одним числом, чтобы сравнить с одним значением y_pred в функции потерь тензорного потока?

Возможно, вы захотите tf.reduce_* функционировать как tf.reduce_mean или 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] -> 0 против [0,0,0,0] -> 1.

Еще одна вещь, о которой я также упомяну, это то, что если вы хотите ТОЛЬКО сумму этих операторов Pauli в cirq, которые у вас есть в списке по срокам [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

Которые дают довольно хорошее описание того, как выглядят входные и выходные сигнатуры функций, а также формы, которые вы можете от них ожидать.

Другие вопросы по тегам