TensorFlow Quantum量子神经网络输入参数训练异常问题咨询
问题分析与解决方案
嘿,我一眼就看出你卡在哪了——直接把TensorFlow张量作为Cirq门的参数传入电路,这会彻底切断TensorFlow自动求导的追踪链路,量子神经网络自然就没法训练了。
为啥普通参数能正常训练?
你正常训练的代码里,theta_g是普通的Python数值,生成的电路参数都是固定死的数值,这时候判别器的可训练参数是自身PQC层里的theta符号参数,TFQ能完美追踪这个参数的梯度,训练自然顺顺当当。
为啥用tf.constant就不行?
当你把theta_g定义成tf.constant,还把它和其他张量运算的结果直接传给Cirq门的参数时,Cirq根本识别不了TF张量里的梯度信息,tfq.convert_to_tensor转出来的电路张量会丢掉所有梯度追踪的线索,整个网络的梯度传不下去,训练当然就卡壳了。
给你改好的正确实现方式
要让输入电路的参数能被训练,你得用sympy符号来定义电路里的可训练参数,然后把这些参数的TF变量值和电路分开传给TFQ的层,保证梯度能被正确追踪。下面是调整后的代码:
生成带可训练参数的输入电路
# 把theta_g改成TF变量(要训练的参数必须是Variable,不能是constant) theta_g = tf.Variable([1.0], trainable=True) blob_size = abs(1 - 4) / 5 spread_x = np.random.uniform(-blob_size, blob_size) spread_y = np.random.uniform(-blob_size, blob_size) # 把随机值转成TF张量(保持运算在TF图内) spread_x_tf = tf.constant(spread_x, dtype=tf.float32) spread_y_tf = tf.constant(spread_y, dtype=tf.float32) # 用sympy符号定义电路的参数,这是TFQ能追踪梯度的关键 angle_sym = sympy.Symbol('angle') x_sym = sympy.Symbol('x') qubit = cirq.GridQubit(0, 0) # 创建带符号参数的电路,不用硬塞数值进去 cir = cirq.Circuit( cirq.ry(-angle_sym)(qubit), cirq.rx(-x_sym)(qubit) ) # 计算参数的实际值(TF运算,保留梯度追踪) angle_val = theta_g + spread_y_tf # 把电路转成TFQ能处理的张量 cir_tensor = tfq.convert_to_tensor([cir]) # 准备参数输入:把符号对应的数值拼起来 params = tf.concat([angle_val, [spread_x_tf]], axis=0)
调整判别器以支持带参数的输入电路
如果你的目标是让theta_g作为生成器的可训练参数,同时让判别器能处理这种带参数的输入电路,得改一改判别器的结构,让它同时接收电路张量和参数张量:
def discriminator(): # 判别器自己的可训练参数 theta_d = sympy.Symbol('theta_d') # 和输入电路对应的符号参数 angle_sym = sympy.Symbol('angle') x_sym = sympy.Symbol('x') # 先拼上输入电路的结构,再加上判别器的量子层 input_circuit = cirq.Circuit( cirq.ry(-angle_sym)(qubit), cirq.rx(-x_sym)(qubit) ) q_model = input_circuit + cirq.Circuit(cirq.ry(theta_d)(qubit)) # 输入变成两个:电路张量 + 参数张量 q_data_input = tf.keras.Input(shape=(), dtype=tf.dtypes.string) params_input = tf.keras.Input(shape=(2,), dtype=tf.float32) # PQC层要同时接收电路和参数 expectation = tfq.layers.PQC(q_model, cirq.Z(qubit)) expectation_output = expectation([q_data_input, params_input]) classifier = tf.keras.layers.Dense(1, activation=tf.keras.activations.sigmoid) classifier_output = classifier(expectation_output) model = tf.keras.Model(inputs=[q_data_input, params_input], outputs=classifier_output) return model
使用修改后的判别器
discriminator_net = discriminator() # 同时传入电路张量和参数张量 output = discriminator_net([cir_tensor, params])
几个关键提醒
- Cirq门参数优先用sympy符号:TFQ的梯度追踪全靠符号参数和TF变量绑定,直接塞TF张量等于自断后路。
- 可训练参数必须是tf.Variable:要是某个参数需要被训练,一定要定义成
tf.Variable,tf.constant是固定值,没法被优化。 - 电路和参数要分开传:带可训练参数的电路,不能把参数直接嵌进电路里,得把电路张量和参数张量分别作为输入传给模型。
内容的提问来源于stack exchange,提问作者sty
相关产品推荐
相关产品推荐

