Как сопоставить массив значений для 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
Которые дают довольно хорошее описание того, как выглядят входные и выходные сигнатуры функций, а также формы, которые вы можете от них ожидать.