张量流中未完全连接的层

时间:2018-12-19 12:50:43

标签: python tensorflow machine-learning keras neural-network

我想创建一个网络,其中输入层中的节点仅连接到下一层中的某些节点。这是一个小例子:

enter image description here

到目前为止,我的解决方案是将i1h1之间的边的权重设置为零,并且在每个优化步骤之后,我都将权重与矩阵相乘(我称此矩阵掩码矩阵)其中每个条目都是1,除了i1h1之间的边的权重条目。 (请参见下面的代码)

这种方法正确吗?还是对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])

3 个答案:

答案 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)的逐元素乘法,因此可以使用maskmask矩阵作为元素逐个矩阵乘法包含在图形定义中。

遗憾的是,这意味着告别用户友好的keras,分层方法,并采用TensorFlow的更多细节。我看不到使用Layers API的明显方法。

请参阅下面的实现,我尝试提供注释来解释每个阶段发生的情况。

tf.multiply

或使用 today 提供的答案来获得适合keras的选项。