如何在隐藏的密集层上设置 Max-Min 约束?

Posted

技术标签:

【中文标题】如何在隐藏的密集层上设置 Max-Min 约束?【英文标题】:How to put a Max-Min constraint on a hidden Dense Layer? 【发布时间】:2021-05-31 23:30:59 【问题描述】:

我正在尝试了解如何在如下模型中的密集隐藏层上施加约束。

我想开发函数 applyConstraint,它可以在最小值和最大值之间重新调整 params 中包含的值。

你会怎么做?

inp = tfl.Input((10,))
dense = tfl.Dense(16, activation = 'relu')(inp)
dense = tfl.Dense(8, activation = 'relu')(dense)
params = tfl.Dense(3, activation = 'relu')(dense)
params_max_min = applyConstraint(params, min, max)
concat = tfl.Concatenate()([dense, params])
dense = tfl.Dense(16, activation = 'relu')(concat)
dense = tfl.Dense(8, activation = 'relu')(dense)
dense = tfl.Dense(1, activation = None)(dense)
model = tf.keras.Model(inputs = inp, outputs = dense)
model_params = tf.keras.Model(inputs = inp, outputs = params_max_min)
model.compile(optimizer = 'adam', loss = 'mse')

【问题讨论】:

如果你想在 [0,1] 内重新缩放,我认为一个简单的 sigmoid 就足够了 我希望它是一个通用的重新缩放。而且,通过使用 sigmoid,我还改变了结果的分布,这是我不想要的。 我认为你让事情变得更加困难......看来你只需要缩放你的目标(比如说在 [0,1] 中使用 minmaxscaler),然后使用 sigmoid 激活来输出。最后,您将能够轻松逆转您的预测 我明白你的意思,但我担心的是 sigmoid 不是线性激活,这意味着它的值更可能接近 1 和 0 而不是 0.5。所以我知道它会起作用,但性能可能会受到影响。 【参考方案1】:

您可以继承 tf.keras.constraints.Constraint 并自定义您自己的操作来做您想做的事情。

定义约束

import numpy as np
import tensorflow as tf

from tensorflow.keras.constraints import Constraint


class MinMaxConstraint(Constraint):
    """constrain model weights between [x_min, x_max]."""
    def __init__(self, x_min=0.0, x_max=1.0):
        super().__init__()
        self.x_min = x_min
        self.x_max = x_max
        # TODO: add sanity check if x_max == x_min or w_max == w_min
    
    def __call__(self, w):
        w_min = tf.minimum(tf.math.reduce_min(w), self.x_min)
        w_max = tf.maximum(tf.math.reduce_max(w), self.x_max)
        scale = (self.x_max - self.x_min) / (w_max - w_min)
        m = self.x_min - w_min * scale
        w = w * scale
        return w + m

测试默认情况

# random data
X = tf.random.normal([10, 2])
y = tf.random.normal([10])

# optimizer
m_opt = tf.keras.optimizers.Adam(1e-3)

# network definition
x_in = tf.keras.Input([2])
x = tf.keras.layers.Dense(4, kernel_constraint=MinMaxConstraint())(x_in)
x_out = tf.keras.layers.Dense(1)(x)

# model definition
model = tf.keras.models.Model(x_in, x_out)

# do a forward pass and update
with tf.GradientTape() as tape:
    y_hat = model(X)
    loss = tf.math.reduce_mean(tf.losses.MSE(y, y_hat))
  
m_vars = model.trainable_variables
m_grads = tape.gradient(loss, m_vars)
m_opt.apply_gradients(zip(m_grads, m_vars))

# check weights
assert np.all(model.get_weights()[0] >= 0.0)
assert np.all(model.get_weights()[0] <= 1.0)
# passes!

在 [-2, 2] 上测试

# reset network
x_in = tf.keras.Input([2])
x = tf.keras.layers.Dense(4, kernel_constraint=MinMaxConstraint(-2.0, 2.0))(x_in)
x_out = tf.keras.layers.Dense(1)(x)

# reset model
model = tf.keras.models.Model(x_in, x_out)

# do a forward pass and update
with tf.GradientTape() as tape:
    y_hat = model(X)
    loss = tf.math.reduce_mean(tf.losses.MSE(y, y_hat))
  
m_vars = model.trainable_variables
m_grads = tape.gradient(loss, m_vars)
m_opt.apply_gradients(zip(m_grads, m_vars))

# check weights again
assert np.all(model.get_weights()[0] >= -2.0)
assert np.all(model.get_weights()[0] <= 2.0)
# passes!

【讨论】:

只是一个修正,不叫重载而是继承。 你好。感谢您的回答!不过只有一条评论。如果我理解得很好,通过这种方式我对权重的值施加了约束,而我想对一个特定层的神经元的输出施加约束。你明白我的意思吗?一个 您的问题是“对隐藏...的约束”。这些是网络内部的权重。您的评论仅描述了一个激活函数。 是的,我用不好的方式解释了自己,对不起。可能这会使任务变得更简单......你将如何编写一个激活函数来做到这一点? 在我的解决方案中基本上只写_ _call_ _方法下的内容,然后把它变成一个函数。然后通过activation arg 将层的输出通过该函数放在您正在使用的任何层中。【参考方案2】:

试试这个:

import tensorflow as tf
params = tf.random.uniform((2, 3))
min, max = 4., 5.
def applyConstraint(params, min, max):
  mn = tf.reduce_min(params)
  mx = tf.reduce_max(params)
  mult = (max-min)/(mx-mn)
  p = min + (params - mn) * mult
  return p

output = applyConstraint(params, min, max)

【讨论】:

以上是关于如何在隐藏的密集层上设置 Max-Min 约束?的主要内容,如果未能解决你的问题,请参考以下文章

如何用ps给图片打上细密均匀的线条

如何为 Xib 设置单元格动态高度的约束...?

如何使用约束设置本端视图高度?

如何在 UIStackView 中保留隐藏视图的约束

自动布局:隐藏工具栏后重置底部约束

如果设置隐藏,iOS UIStackView 无法同时满足约束