จะเพิ่มการทำให้เป็นระเบียบใน TensorFlow ได้อย่างไร?


95

ฉันพบในรหัสเครือข่ายประสาทเทียมที่มีอยู่จำนวนมากที่ใช้งานโดยใช้ TensorFlow ว่าเงื่อนไขการทำให้เป็นมาตรฐานมักจะถูกนำมาใช้โดยการเพิ่มคำเพิ่มเติมด้วยตนเองเพื่อมูลค่าการสูญเสีย

คำถามของฉันคือ:

  1. มีวิธีการทำให้เป็นมาตรฐานที่หรูหรากว่าหรือที่แนะนำมากกว่าการทำด้วยตนเองหรือไม่?

  2. ฉันยังพบว่ามีการโต้แย้งget_variable regularizerควรใช้อย่างไร? จากการสังเกตของฉันถ้าเราส่ง Regularizer ไปที่มัน (เช่นtf.contrib.layers.l2_regularizerเทนเซอร์ที่เป็นตัวแทนของคำศัพท์ปกติจะถูกคำนวณและเพิ่มลงในคอลเลกชันกราฟที่มีชื่อtf.GraphKeys.REGULARIZATOIN_LOSSESTensorFlow จะใช้คอลเล็กชันนั้นโดยอัตโนมัติหรือไม่ (เช่นใช้โดยเครื่องมือเพิ่มประสิทธิภาพเมื่อฝึก) หรือ คาดว่าฉันควรใช้คอลเลกชันนั้นด้วยตัวเองหรือไม่?


1
เป็นวิธีที่จะทำS = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )หรือไม่?
Pinocchio

@Pinocchio คุณคิดออกหรือยัง?
Euler_Salter

2
@Euler_Salter ฉันจำไม่ได้แล้วขอโทษ! ไม่ใช้เทนเซอร์โฟลว์อีกต่อไป!
Pinocchio

คำตอบ:


70

ดังที่คุณพูดในประเด็นที่สองการใช้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)

หวังว่าจะช่วยได้!


2
ขอบคุณคน ฉันคิดว่า TensorFlow จะมีวิธีที่ชาญฉลาดกว่าในการจัดการข้อกำหนด reg ด้วยตนเองดูเหมือนจะไม่ใช่: P
Lifu Huang

14
BTW สองคำแนะนำแก้ไขฉันถ้าฉันผิด (1) ฉันเดาว่าreg_constantอาจไม่จำเป็นเนื่องจาก Regularizers ใน TensorFlow มีข้อโต้แย้งscaleในตัวสร้างของพวกเขาเพื่อให้สามารถควบคุมผลกระทบของข้อกำหนด reg ได้อย่างละเอียดมากขึ้น และ (2) การใช้tf.add_nอาจจะดีกว่าเล็กน้อยsumฉันเดาว่าการใช้ sum อาจสร้างหลายเทนเซอร์ในกราฟเพื่อเก็บผลลัพธ์ระดับกลาง
Lifu Huang

1
ดังนั้นเพื่อให้ชัดเจนสุด ๆ หลังจากที่ฉันใส่ Regularizer ให้กับตัวแปรS = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )แล้วฉันจะใช้รหัสที่คุณแนะนำหรือไม่? เช่นเดียวกับในsum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinocchio

1
สามารถแสดงวิธีทำให้ตัวแปรน้ำหนักเป็นส่วนหนึ่งของคอลเล็กชันที่เรียกคืนได้โดย tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Yu Shen

3
ดูเหมือนว่าtf.reduce_sumควรจะใช้แทนsum?
ComputerScientist

46

บางแง่มุมของคำตอบที่มีอยู่ไม่ชัดเจนสำหรับฉันในทันทีดังนั้นนี่คือคำแนะนำทีละขั้นตอน:

  1. กำหนด Regularizer นี่คือที่ที่สามารถกำหนดค่าคงที่การทำให้เป็นระเบียบเช่น:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
    
  2. สร้างตัวแปรผ่าน:

        weights = tf.get_variable(
            name="weights",
            regularizer=regularizer,
            ...
        )
    

    เท่าตัวแปรที่สามารถสร้างขึ้นผ่านทางปกติคอนสตรัคตามด้วยweights = tf.Variable(...)tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights)

  3. กำหนด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จะใช้งานเป็น an AddNดังนั้นจะเทียบเท่ากับsum(reg_variables)ไฟล์.


10
ฉันคิดว่าคุณใช้ Regularizer สองครั้ง - ทั้งในขั้นตอนและขั้นตอนที่ 3 apply_regularizationไม่จำเป็นหากคุณระบุ Regularizer ไว้แล้วเมื่อสร้างตัวแปร
interjay

2
@interjay โปรดยกตัวอย่างคำตอบทั้งหมดนี้ไม่ชัดเจนมาก! เนื่องจากมีคนอย่างน้อยหนึ่งคนเขียนความคิดเห็นไว้ข้างใต้โดยบอกว่าคำตอบข้างต้นมีบางอย่างผิดปกติ
Euler_Salter

1
@interjay ฉันค่อนข้างมั่นใจว่าการทำทั้งสองอย่างนั้นจำเป็นในครั้งสุดท้ายที่ฉันทดสอบสิ่งนี้ ฉันไม่แน่ใจว่าสิ่งนี้มีการเปลี่ยนแปลงหรือไม่
bluenote10

1
ไม่นั่นไม่สมเหตุสมผลเพราะคุณไม่จำเป็นต้องส่งตัวปรับแต่งปกติเดียวกันไปยังสองฟังก์ชัน เอกสารประกอบ (และชื่อ) ทำให้ชัดเจนว่าREGULARIZATION_LOSSESเป็นการสูญเสียทั้งหมดที่ได้รับคืนจากตัวควบคุมปกติดังนั้นคุณจึงต้องโทรregularizer(regularizer(weight))ติดต่อ
interjay

1
ฉันคิดว่าความสับสนนี้เกิดจากส่วนที่ "เทียบเท่า" เขาอธิบายวิธีการสองวิธีที่แตกต่างกันและคุณเลือกวิธีหนึ่งไม่ใช่วิธีเดียวที่เกี่ยวข้องกับการทำให้เป็นระเบียบสองครั้ง
gcp

28

ฉันจะให้คำตอบง่ายๆที่ถูกต้องเนื่องจากฉันไม่พบคำตอบ คุณต้องใช้สองขั้นตอนง่ายๆส่วนที่เหลือทำได้โดยมายากลเทนเซอร์โฟลว์:

  1. เพิ่ม Regularizers เมื่อสร้างตัวแปรหรือเลเยอร์:

    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))
    
  2. เพิ่มเงื่อนไขการทำให้เป็นมาตรฐานเมื่อกำหนดการสูญเสีย:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
    

ถ้าฉันสร้าง Regularizer op โดย regularizer = tf.contrib.layers.l2_regularizer (0.001) ฉันสามารถส่งต่อไปยังการเริ่มต้นหลายเลเยอร์ได้หรือไม่ หรือฉันต้องสร้าง Regularizer แยกต่างหากสำหรับแต่ละเลเยอร์เช่นไม่สม่ำเสมอ 1 = tf.contrib.layers.l2_regularizer (0.001), regularizer2 = ................. regularizer3 = .... .. ไปเรื่อย ๆ ?
MiloMinderbinder

@Nitin คุณสามารถใช้เครื่องควบคุมมาตรฐานเดียวกันได้ เป็นเพียงฟังก์ชัน python ที่ใช้การสูญเสียน้ำหนักเป็นอาร์กิวเมนต์
alyaxey

1
นี่ดูเหมือนวิธีแก้ปัญหาที่หรูหราที่สุด แต่มันได้ผลจริงหรือ? สิ่งนี้แตกต่างจาก say reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) อย่างไร reg_term = tf.contrib.layers.apply_regularization (regularizer, reg_variables) loss + = reg_term
GeorgeOfTheRF

1
ฉันแค่ต้องการพูดถึงว่า tf.contrib.layers.fully_connected สามารถแทนที่ tf.layers.dense ได้และนอกจากนี้ยังเพิ่มฟังก์ชันการทำงานอื่น ๆ อ้างถึงเหล่านี้: นี้ , นี้และนี้
Osama Salah

16

อีกทางเลือกหนึ่งในการดำเนินการกับcontrib.learnไลบรารีมีดังต่อไปนี้โดยอ้างอิงจากบทช่วยสอน Deep MNISTบนเว็บไซต์ Tensorflow ขั้นแรกสมมติว่าคุณได้นำเข้าไลบรารีที่เกี่ยวข้อง (เช่น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

สังเกตว่าส่วนการทำให้เป็นมาตรฐานจะให้คุณสามรายการตามรายการที่มี

ด้วยการทำให้เป็นมาตรฐาน 0, 0.0001, 0.01 และ 1.0 ฉันได้รับค่าความแม่นยำในการทดสอบ 0.9468, 0.9476, 0.9183 และ 0.1135 ตามลำดับซึ่งแสดงให้เห็นถึงอันตรายของเงื่อนไขการทำให้เป็นมาตรฐานสูง


2
ตัวอย่างละเอียดจริงๆ
stackoverflowuser2010

5

หากใครยังคงมองหาอยู่ฉันแค่อยากจะเพิ่มสิ่งนั้นใน tf.keras คุณอาจเพิ่มการกำหนดน้ำหนักให้เป็นมาตรฐานโดยส่งเป็นอาร์กิวเมนต์ในเลเยอร์ของคุณ ตัวอย่างของการเพิ่มการทำให้เป็นมาตรฐาน L2 ที่นำมาจากการขายส่งจากเว็บไซต์ Tensorflow Keras Tutorials:

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


4

ฉันทดสอบtf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)และtf.losses.get_regularization_loss()ใช้หนึ่งl2_regularizerในกราฟและพบว่าค่าเหล่านี้ส่งคืนค่าเดียวกัน โดยการสังเกตปริมาณค่าของฉันเดา reg_constant tf.contrib.layers.l2_regularizerมีอยู่แล้วให้ความรู้สึกกับค่าโดยการตั้งค่าพารามิเตอร์ของ


3

หากคุณมี 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)

1

คำตอบบางคำทำให้ฉันสับสนมากขึ้นที่นี่ฉันให้สองวิธีที่จะทำให้ชัดเจน

#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 

จากนั้นสามารถบวกเข้าไปในผลขาดทุนทั้งหมด


1
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

1
ขอบคุณสำหรับข้อมูลโค้ดนี้ซึ่งอาจให้ความช่วยเหลือเฉพาะบางอย่างได้ทันที คำอธิบายที่เหมาะสมจะช่วยเพิ่มมูลค่าในระยะยาวได้อย่างมากโดยแสดงให้เห็นว่าเหตุใดจึงเป็นวิธีแก้ปัญหาที่ดีและจะทำให้มีประโยชน์มากขึ้นสำหรับผู้อ่านในอนาคตด้วยคำถามอื่น ๆ ที่คล้ายคลึงกัน โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงสมมติฐานที่คุณตั้งขึ้น
Maximilian Peters

1

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ที่มีการregularizerระบุพารามิเตอร์ คุณยังสามารถเพิ่มลงในคอลเล็กชันนั้นด้วยตนเอง สิ่งนี้จะมีประโยชน์เมื่อใช้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)

(ในตัวอย่างนี้น่าจะมีประสิทธิภาพมากกว่าในการทำให้ x สม่ำเสมอเนื่องจาก y จะทำให้ x ใหญ่แบนลง)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.