クランプ機能はclamp(x, min, max) = min if x < min, max if x > max, else x
クランプ関数のように動作する関数が必要ですが、滑らかです (つまり、連続微分があります)。
クランプ機能はclamp(x, min, max) = min if x < min, max if x > max, else x
クランプ関数のように動作する関数が必要ですが、滑らかです (つまり、連続微分があります)。
通常のクランプ:
np.clip(x, mi, mx)
Smoothclamp (x < min および x > max の通常のクランプと一致することが保証されています):
def smoothclamp(x, mi, mx): return mi + (mx-mi)*(lambda t: np.where(t < 0 , 0, np.where( t <= 1 , 3*t**2-2*t**3, 1 ) ) )( (x-mi)/(mx-mi) )
Sigmoid (クランプの近似値、最小値よりも小さくはなく、最大値よりも大きくなることはありません)
def sigmoid(x,mi, mx): return mi + (mx-mi)*(lambda t: (1+200**(-t+0.5))**(-1) )( (x-mi)/(mx-mi) )
Sigmoid は可逆関数であり、情報が失われないため、目的によっては Sigmoid の方が Smoothclamp よりも優れています。
他の目的のために、すべてのx > xmaxに対してf(x) = xmaxであることを確認する必要がある場合があります。その場合は、Smoothclamp の方が適しています。また、別の回答で述べたように、Smoothclamp 関数のファミリ全体がありますが、ここで指定したものは私の目的には十分です (スムーズな導関数以外の特別なプロパティは必要ありません)。
それらをプロットします:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
x = np.linspace(-4,7,1000)
ax.plot(x, np.clip(x, -1, 4),'k-', lw=2, alpha=0.8, label='clamp')
ax.plot(x, smoothclamp(x, -1, 4),'g-', lw=3, alpha=0.5, label='smoothclamp')
ax.plot(x, sigmoid(x, -1, 4),'b-', lw=3, alpha=0.5, label='sigmoid')
plt.legend(loc='upper left')
plt.show()
また、これら 2 つの算術平均も使用できる可能性があります。
def clampoid(x, mi, mx): return mi + (mx-mi)*(lambda t: 0.5*(1+200**(-t+0.5))**(-1) + 0.5*np.where(t < 0 , 0, np.where( t <= 1 , 3*t**2-2*t**3, 1 ) ) )( (x-mi)/(mx-mi) )