如何在隐藏的密集层上设置 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 约束?的主要内容,如果未能解决你的问题,请参考以下文章