TensorFlowを使用して実装された多くの利用可能なニューラルネットワークコードでは、損失値に追加の用語を手動で追加することで正規化用語が実装されることが多いことがわかりました。
私の質問は:
手動で行うよりもエレガントで推奨される正規化の方法はありますか?
また、get_variable
には引数regularizer
があります。どのように使用する必要がありますか?私の観察によれば、レギュラーを渡すと(tf.contrib.layers.l2_regularizer
など、正規化された用語を表すテンソルが計算され、tf.GraphKeys.REGULARIZATOIN_LOSSES
という名前のグラフコレクションに追加されます。そのコレクションはTensorFlowによって自動的に使用されますかそれとも、自分でそのコレクションを使用する必要があると予想されますか?
2番目のポイントで言うように、regularizer
引数を使用することをお勧めします。 get_variable
で使用するか、variable_scope
で一度設定して、すべての変数を正規化できます。
損失はグラフに収集されます。このようなコスト関数に手動で追加する必要があります。
reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
reg_constant = 0.01 # Choose an appropriate one.
loss = my_normal_loss + reg_constant * sum(reg_losses)
お役に立てば幸いです!
既存の答えのいくつかの側面はすぐにはわかりませんでしたので、ここにステップバイステップのガイドがあります:
レギュラーを定義します。これは、正則化定数を設定できる場所です、例:
regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
以下を介して変数を作成します。
weights = tf.get_variable(
name="weights",
regularizer=regularizer,
...
)
同様に、変数は通常のweights = tf.Variable(...)
コンストラクターを使用して作成でき、その後にtf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights)
が続きます。
いくつかのloss
用語を定義し、正規化用語を追加します。
reg_variables = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
reg_term = tf.contrib.layers.apply_regularization(regularizer, reg_variables)
loss += reg_term
注:tf.contrib.layers.apply_regularization
はAddN
として実装されているように見えるため、多かれ少なかれsum(reg_variables)
と同等です。
見つけられなかったので、簡単な正解を提供します。 2つの簡単なステップが必要で、残りはテンソルフローマジックによって行われます。
変数またはレイヤーを作成するときに正則化を追加します。
tf.layers.dense(x, kernel_regularizer=tf.contrib.layers.l2_regularizer(0.001))
# or
tf.get_variable('a', regularizer=tf.contrib.layers.l2_regularizer(0.001))
損失を定義するときに正則化用語を追加します。
loss = ordinary_loss + tf.losses.get_regularization_loss()
contrib.learn
ライブラリを使用してこれを行う別のオプションは、Tensorflow Webサイトの Deep MNIST tutorial に基づいて、次のとおりです。最初に、関連するライブラリ(import tensorflow.contrib.layers as layers
など)をインポートしたと仮定すると、別の方法でネットワークを定義できます。
def easier_network(x, reg):
""" A network based on tf.contrib.learn, with input `x`. """
with tf.variable_scope('EasyNet'):
out = layers.flatten(x)
out = layers.fully_connected(out,
num_outputs=200,
weights_initializer = layers.xavier_initializer(uniform=True),
weights_regularizer = layers.l2_regularizer(scale=reg),
activation_fn = tf.nn.tanh)
out = layers.fully_connected(out,
num_outputs=200,
weights_initializer = layers.xavier_initializer(uniform=True),
weights_regularizer = layers.l2_regularizer(scale=reg),
activation_fn = tf.nn.tanh)
out = layers.fully_connected(out,
num_outputs=10, # Because there are ten digits!
weights_initializer = layers.xavier_initializer(uniform=True),
weights_regularizer = layers.l2_regularizer(scale=reg),
activation_fn = None)
return out
次に、メインメソッドで、次のコードスニペットを使用できます。
def main(_):
mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
# Make a network with regularization
y_conv = easier_network(x, FLAGS.regu)
weights = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'EasyNet')
print("")
for w in weights:
shp = w.get_shape().as_list()
print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
print("")
reg_ws = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES, 'EasyNet')
for w in reg_ws:
shp = w.get_shape().as_list()
print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
print("")
# Make the loss function `loss_fn` with regularization.
cross_entropy = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
loss_fn = cross_entropy + tf.reduce_sum(reg_ws)
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss_fn)
これを機能させるには、先ほどリンクしたMNISTチュートリアルに従って関連するライブラリをインポートする必要がありますが、TensorFlowを学習するのは良い練習であり、正規化が出力にどのように影響するかを簡単に確認できます。引数として正則化を適用すると、次のことがわかります。
- EasyNet/fully_connected/weights:0 shape:[784, 200] size:156800
- EasyNet/fully_connected/biases:0 shape:[200] size:200
- EasyNet/fully_connected_1/weights:0 shape:[200, 200] size:40000
- EasyNet/fully_connected_1/biases:0 shape:[200] size:200
- EasyNet/fully_connected_2/weights:0 shape:[200, 10] size:2000
- EasyNet/fully_connected_2/biases:0 shape:[10] size:10
- EasyNet/fully_connected/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
- EasyNet/fully_connected_1/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
- EasyNet/fully_connected_2/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
正則化部分は、利用可能なアイテムに基づいて3つのアイテムを提供することに注意してください。
0、0.0001、0.01、および1.0の正則化では、それぞれ0.9468、0.9476、0.9183、および0.1135のテスト精度値が得られ、高い正則化項の危険性が示されています。
グラフ内のl2_regularizer
を1つ使用してtf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
とtf.losses.get_regularization_loss()
をテストしたところ、同じ値が返されることがわかりました。値の量を観察することで、reg_constantはtf.contrib.layers.l2_regularizer
のパラメーターを設定することで既に値に意味があると思います。
まだ探している人がいれば、tf.kerasに追加して、レイヤーに引数として渡すことで重みの正規化を追加できます。 Tensorflow Kerasチュートリアルサイトから大量に取得したL2正則化を追加する例:
model = keras.models.Sequential([
keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
activation=tf.nn.relu),
keras.layers.Dense(1, activation=tf.nn.sigmoid)
])
私の知る限り、この方法で正則化損失を手動で追加する必要はありません。
リファレンス: https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#add_weight_regularization
CNNを使用している場合は、次を実行できます。
モデル関数で:
conv = tf.layers.conv2d(inputs=input_layer,
filters=32,
kernel_size=[3, 3],
kernel_initializer='xavier',
kernel_regularizer=tf.contrib.layers.l2_regularizer(1e-5),
padding="same",
activation=None)
...
損失関数で:
onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=num_classes)
loss = tf.losses.softmax_cross_entropy(onehot_labels=onehot_labels, logits=logits)
regularization_losses = tf.losses.get_regularization_losses()
loss = tf.add_n([loss] + regularization_losses)
いくつかの答えは私をより混乱させます。ここでは、明確にするための2つの方法を示します。
#1.adding all regs by hand
var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
var2 = tf.Variable(name='v2',initial_value=1.0,dtype=tf.float32)
regularizer = tf.contrib.layers.l1_regularizer(0.1)
reg_term = tf.contrib.layers.apply_regularization(regularizer,[var1,var2])
#here reg_term is a scalar
#2.auto added and read,but using get_variable
with tf.variable_scope('x',
regularizer=tf.contrib.layers.l2_regularizer(0.1)):
var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
var2 = tf.get_variable(name='v2',shape=[1],dtype=tf.float32)
reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
#here reg_losses is a list,should be summed
それから、それは総損失に加えることができます
cross_entropy = tf.losses.softmax_cross_entropy(
logits=logits, onehot_labels=labels)
l2_loss = weight_decay * tf.add_n(
[tf.nn.l2_loss(tf.cast(v, tf.float32)) for v in tf.trainable_variables()])
loss = cross_entropy + l2_loss
tf.GraphKeys.REGULARIZATION_LOSSES
は自動的に追加されませんが、追加する簡単な方法があります。
reg_loss = tf.losses.get_regularization_loss()
total_loss = loss + reg_loss
tf.losses.get_regularization_loss()
はtf.add_n
を使用して、要素ごとにtf.GraphKeys.REGULARIZATION_LOSSES
のエントリを合計します。 tf.GraphKeys.REGULARIZATION_LOSSES
は、通常、スカラーのリストであり、正規化関数を使用して計算されます。 regularizer
パラメーターが指定されているtf.get_variable
の呼び出しからエントリーを取得します。そのコレクションに手動で追加することもできます。これは、tf.Variable
を使用する場合や、アクティビティレギュラーまたはその他のカスタムレギュライザーを指定する場合に役立ちます。例えば:
#This will add an activity regularizer on y to the regloss collection
regularizer = tf.contrib.layers.l2_regularizer(0.1)
y = tf.nn.sigmoid(x)
act_reg = regularizer(y)
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, act_reg)
(この例では、yが大きなxに対して実際に平坦化されるため、xを正則化する方がおそらくより効果的です。)