我想创建一个网络,其中输入层中的节点仅连接到下一层中的某些节点。这是一个小例子:
到目前为止,我的解决方案是将i1
和h1
之间的边的权重设置为零,并且在每个优化步骤之后,我都将权重与矩阵相乘(我称此矩阵掩码矩阵)其中每个条目都是1,除了i1
和h1
之间的边的权重条目。
(请参见下面的代码)
这种方法正确吗?还是对GradientDescent有影响?是否有另一种方法可以在TensorFlow中创建这种网络?
import tensorflow as tf
import tensorflow.contrib.eager as tfe
import numpy as np
tf.enable_eager_execution()
model = tf.keras.Sequential([
tf.keras.layers.Dense(2, activation=tf.sigmoid, input_shape=(2,)), # input shape required
tf.keras.layers.Dense(2, activation=tf.sigmoid)
])
#set the weights
weights=[np.array([[0, 0.25],[0.2,0.3]]),np.array([0.35,0.35]),np.array([[0.4,0.5],[0.45, 0.55]]),np.array([0.6,0.6])]
model.set_weights(weights)
model.get_weights()
features = tf.convert_to_tensor([[0.05,0.10 ]])
labels = tf.convert_to_tensor([[0.01,0.99 ]])
mask =np.array([[0, 1],[1,1]])
#define the loss function
def loss(model, x, y):
y_ = model(x)
return tf.losses.mean_squared_error(labels=y, predictions=y_)
#define the gradient calculation
def grad(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return loss_value, tape.gradient(loss_value, model.trainable_variables)
#create optimizer an global Step
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
global_step = tf.train.get_or_create_global_step()
#optimization step
loss_value, grads = grad(model, features, labels)
optimizer.apply_gradients(zip(grads, model.variables),global_step)
#masking the optimized weights
weights=(model.get_weights())[0]
masked_weights=tf.multiply(weights,mask)
model.set_weights([masked_weights])
答案 0 :(得分:2)
如果您要为所提供的特定示例寻求解决方案,则只需使用lines = f"hi {name}"
功能API并定义两个密集层,其中一层连接到上一层的两个神经元,而另一个仅连接连接到其中一个神经元:
tf.keras
答案 1 :(得分:0)
您在这里有多个选择。
首先,您可以在示例中使用动态屏蔽方法。我相信这会按预期进行,因为渐变w.r.t.被掩盖的参数将为零(更改未使用的参数时,输出是恒定的)。这种方法很简单,即使在训练过程中面罩不固定时也可以使用。
第二,如果您事先知道哪些权重始终为零,则可以使用tf.get_variable
构成权重矩阵以获取一个子矩阵,然后将其与tf.constant
张量连接起来,例如:>
weights_sub = tf.get_variable("w", [dim_in, dim_out - 1])
zeros = tf.zeros([dim_in, 1])
weights = tf.concat([weights_sub, zeros], axis=1)
此示例将使您的权重矩阵的一列始终为零。
最后,如果蒙版更加复杂,则可以在展平的矢量上使用tf.get_variable
,然后使用所用索引上的变量值组成一个tf.SparseTensor
:
weights_used = tf.get_variable("w", [num_used_vars])
indices = ... # get your indices in a 2-D matrix of shape [num_used_vars, 2]
dense_shape = tf.constant([dim_in, dim_out]) # this is the final shape of the weight matrix
weights = tf.SparseTensor(indices, weights_used, dense_shape)
编辑:这可能无法与Keras的set_weights
方法结合使用,因为它期望使用Numpy数组,而不是张量。
答案 2 :(得分:0)
您的解决方案以及本文中其他答案所提出的其他一些问题是,他们没有防止训练这种体重。它们允许梯度下降训练不存在的权重,然后追溯覆盖它。这将导致该位置的网络在所需位置为零,但会对您的训练过程产生负面影响,因为反向传播计算将不会看到掩盖步骤,因为它不是TensorFlow图的一部分,因此梯度下降将随之而来包含以下假设的路径:该权重确实会对结果产生影响(没有影响)。
一个更好的解决方案是将掩蔽步骤包括在TensorFlow图中,以便可以将其作为梯度下降因素。由于屏蔽步骤只是您的稀疏二进制martix NUMBER(5, 0)
的逐元素乘法,因此可以使用mask
将mask
矩阵作为元素逐个矩阵乘法包含在图形定义中。
遗憾的是,这意味着告别用户友好的keras,分层方法,并采用TensorFlow的更多细节。我看不到使用Layers API的明显方法。
请参阅下面的实现,我尝试提供注释来解释每个阶段发生的情况。
tf.multiply
或使用 today 提供的答案来获得适合keras的选项。