我有一个DNN学习XOR的示例(右键单击以在新选项卡中打开):https://colab.research.google.com/drive/1M5xFp4gaXPCbnejM8-5_yLp1B6UvwdL8
我对这两行感到困惑(与反向传播有关:
Grads = T.gradient(Loss,[W1,B1,W2,B2]);
Optim.apply_gradients(zip(Grads,[W1,B1,W2,B2]));
我猜向后循环在T.gradient
,因为它们是与损耗有关的梯度值,但我仍不清楚。问题是:
T.gradient
还是Optim.apply_gradients
?[W1,B1,W2,B2]
的顺序重要吗?我相信,例如。改组后的[B1,W2,B2,W1]
不能相同,因为反向传播需要从输出到输入的层顺序。根据我的尝试,在调整变量数组中权重和偏差的顺序时,优化过程仍然有效。 但是反向传播需要从输出到输入的层顺序,我不明白这一点。
源代码:
#!pip install tensorflow==2.0.0rc2
%tensorflow_version 2.x
%reset -f
#libs
import tensorflow as tf;
#data
X = [[0,0],[0,1],[1,0],[1,1]];
Y = [[0], [1], [1], [0] ];
X = tf.convert_to_tensor(X,tf.float32);
Y = tf.convert_to_tensor(Y,tf.float32);
#model
W1 = tf.Variable(tf.random.uniform([2,20],-1,1));
B1 = tf.Variable(tf.random.uniform([ 20],-1,1));
W2 = tf.Variable(tf.random.uniform([20,1],-1,1));
B2 = tf.Variable(tf.random.uniform([ 1],-1,1));
@tf.function
def feedforward(X):
H1 = tf.nn.leaky_relu(tf.matmul(X,W1) + B1);
Out = tf.sigmoid(tf.matmul(H1,W2) + B2);
return Out;
#end def
#train
Optim = tf.keras.optimizers.SGD(1e-1);
Steps = 1000;
for I in range(Steps):
if I%(Steps/10)==0:
Out = feedforward(X);
Loss = tf.reduce_sum(tf.square(Y-Out));
print("Loss:",Loss.numpy());
#end if
with tf.GradientTape() as T:
Out = feedforward(X);
Loss = tf.reduce_sum(tf.square(Y-Out));
#end with
#BACKPROPAGATION HERE?
Grads = T.gradient(Loss,[W1,B1,W2,B2]);
Optim.apply_gradients(zip(Grads,[W1,B1,W2,B2]));
#end for
Out = feedforward(X);
Loss = tf.reduce_sum(tf.square(Y-Out));
print("Loss:",Loss.numpy(),"(Last)");
print("\nDone.");
#eof
让我们一次迈出这一步。
步骤1:梯度计算:
Grads = T.gradient(Loss,[W1,B1,W2,B2])
这里,我们根据提供的列表中的变量计算损耗的梯度。基于变量的索引来索引渐变列表。这意味着Grads[0]
将是相对于W1
的渐变,依此类推。
步骤2:接下来,我们执行更新。这是在以下位置完成的:
Optim.apply_gradients(zip(Grads,[W1,B1,W2,B2]))
这里,Grads[0]
用于更新W1
,Grads[1]
用于更新B1
,依此类推。
注意,梯度计算和更新步骤是分别执行的。因此,只要变量在两个列表中以相同的顺序出现,就不会有任何问题。
此外,GradientTape
必须与急切执行一起使用。