โมเดล Seq2Seq และฟังก์ชันการสูญเสีย (เป็น keras)

ฉันมีปัญหากับโมเดล seq2seq ของฉันในบางกรณี มันก็ใช้ได้ดี แต่ในบางกรณีก็ส่งคืนเป็นผลให้มีเพียงโทเค็นสุดท้ายเท่านั้น

ตัวอย่างเช่น :

For given vector :
[2, #start token
3,
123,
1548, #end token
1548,
1548,
1548,
1548,
1548,
1548]

The model predict :
[1548, 
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548]

ฉันพยายามใช้การโทรกลับ SaveModel จาก keras ที่ติดตาม "การสูญเสีย" แต่ก็ยังให้ผลลัพธ์เหมือนเดิม

ฉันก็เลยคิดว่าบางทีฉันควรใช้ฟังก์ชันการสูญเสียของตัวเอง

ฟังก์ชั่นการสูญเสียอย่างง่ายที่ keras จัดให้:

def mean_absolute_error(y_true, y_pred):
    return K.mean(K.abs(y_pred - y_true), axis=-1)

ทั้ง y_true และ y_pred เป็นวัตถุ tensorflow (เราได้รับเพียงตัวชี้ไปยังอาเรย์จริง) ดังนั้น .. เพื่อสร้างตรรกะบางอย่าง เราจำเป็นต้องรับอาเรย์จาก gpu หรืออัปโหลดอาเรย์ของตัวเองไปยัง gpu ..

ฟังก์ชั่นการสูญเสียที่ฉันต้องการ

def mean_absolute_error(y_true, y_pred):
    sum = 0
    for y , _y in zip(y_true , y_pred):
         if (y == _y) and (y == self.startToken or y == self.endToken):
              continue
         else:
              sum += abs(y - _y)
    return sum

ฉันพยายามใช้ y_true.eval() ซึ่งควรนำอาร์เรย์เป็นวัตถุ numpy ไปยัง cpu (ไม่สามารถประเมินเทนเซอร์โดยใช้ eval(): ไม่มีการลงทะเบียนเซสชันเริ่มต้น)

และฉันไม่สามารถหาวิธีอัปโหลดอาร์เรย์ของตัวเองลงในเทนเซอร์โฟลว์ได้

หากคุณมีวิธีแก้ปัญหาหรือข้อเสนอแนะใด ๆ ฉันยินดีอย่างยิ่งที่จะได้ยินเกี่ยวกับเรื่องนี้

ขอบคุณ..

(ไม่ได้สำคัญมากแต่...)

โมเดลอิงจาก: https://blog.keras.io/a-ten-minutes-introduction-to-sequence-to-sequence-learning-in-keras.html แต่ด้วย one-hot(two dim [Matrix] ) เอาท์พุท


person Ori Yampolsky    schedule 25.03.2018    source แหล่งที่มา
comment
ในลิงก์ที่คุณให้ไว้ พวกเขาจะหยุดคาดการณ์หลังจากเห็นโทเค็นสิ้นสุด โดยเฉพาะในฟังก์ชัน decode_sequence: # Exit condition: either hit max length or find stop character. พวกเขายังเติมอาร์เรย์เอาต์พุตของโมเดลไว้ล่วงหน้าด้วยอักขระเริ่มต้น: # Populate the first character of target sequence with the start character. ฉันสงสัยว่าคุณกำลังใช้ฟังก์ชันที่คล้ายกับฟังก์ชัน decode_sequence หรือไม่   -  person vasilyrud    schedule 26.03.2018
comment
ไม่ มันสามารถทำได้ง่ายกว่ามากด้วย : model.predict([x,x])   -  person Ori Yampolsky    schedule 26.03.2018
comment
นั่นอาจเป็นสาเหตุของปัญหา ลองทำตามฟังก์ชัน decode_sequence ของมันทุกประการ และดูว่าได้ผลก่อนหรือไม่ อาจเป็นวิธีเดียวที่จะทำนายแบบ seq-to-seq ใน Keras   -  person vasilyrud    schedule 26.03.2018
comment
ฉันตรวจสอบแล้ว ... มันก็เหมือนกัน ..   -  person Ori Yampolsky    schedule 27.03.2018


คำตอบ (1)


การใช้ K.eval หรือ if ในฟังก์ชันการสูญเสียไม่ใช่ความคิดที่ดี แนวคิดทั้งหมดเกี่ยวกับเทนเซอร์คือพวกมันมีการเชื่อมต่อภายในที่จัดการโดยเทนเซอร์โฟลว์/เครา ซึ่งทำให้สามารถคำนวณการไล่ระดับสีและสิ่งอื่นๆ ได้

การใช้ eval และการทำงานกับค่าตัวเลขจะทำลายการเชื่อมต่อนี้และทำให้โมเดลเสีย ใช้ eval เพื่อดูผลลัพธ์เท่านั้น ไม่ใช่เพื่อสร้างฟังก์ชัน

การใช้ ifs จะไม่ทำงานเนื่องจากไม่มีค่าของเทนเซอร์ แต่มีฟังก์ชัน keras เช่น K.switch, K.greater, K.less ฯลฯ ทั้งหมดแสดงอยู่ในเอกสารแบ็กเอนด์ .

คุณสามารถสร้างฟังก์ชันของคุณใหม่ได้โดยใช้ฟังก์ชันเหล่านั้น

แต่จริงๆ แล้ว ฉันคิดว่าคุณควรไปสวมหน้ากากหรือถ่วงน้ำหนักชั้นเรียนแทน

การมาสก์ (โซลูชัน 1)

หากคุณใช้เลเยอร์การฝัง คุณสามารถจงใจสงวนค่าศูนย์ไว้โดยไม่ให้อะไรเลยหลังจากสิ้นสุด

จากนั้นคุณสามารถใช้ mask_zero=True ในเลเยอร์ที่ฝังและมี อินพุต เช่นนี้:

[2, #start token
3,
123,
1548, #end token
0, #nothing, value to be masked
0,
0,
0,
0,
0]

อีกทางเลือกหนึ่งคือไม่มีโทเค็นสิ้นสุดและใช้ศูนย์แทน

การถ่วงน้ำหนักชั้นเรียน (โซลูชัน 2)

เนื่องจากสิ่งนี้อาจเกิดขึ้นได้มากเนื่องจากคุณมีโทเค็นสิ้นสุดมากกว่าสิ่งอื่นใดในเอาต์พุตที่คุณต้องการ คุณจึงสามารถลดความเกี่ยวข้องของโทเค็นสิ้นสุดได้

นับแต่ละคลาสที่เกิดขึ้นในเอาต์พุตของคุณและคำนวณอัตราส่วนสำหรับโทเค็นสิ้นสุด ตัวอย่าง:

  • คำนวณค่าเฉลี่ยของการเกิดขึ้นของคลาสอื่นๆ ทั้งหมด
  • นับจำนวนครั้งของโทเค็นสิ้นสุด
  • ratio = other_classes_mean / end_token_occurences

จากนั้นในเมธอด fit ให้ใช้:

class_weight = {0:1, 1:1, 2:1, ...., 1548:ratio, 1549:1,1550:1,...}

สามารถทำได้ง่ายๆ ด้วย:

class_weight = {i:1. for i in range(totalTokens)}
class_weight[1548] = ratio
model.fit(...,...,....., class_weight = class_weight,...)

(ตรวจสอบให้แน่ใจว่าคุณมีคลาสที่เป็นไปได้ 0 ในกรณีนี้ หรือเปลี่ยนดัชนีเป็น 1)

ฟังก์ชันการสูญเสียที่คล้ายกัน (โซลูชัน 3)

โปรดสังเกตว่า y_pred จะไม่เท่ากับ y_true

  • y_pred เป็นตัวแปร ต่อเนื่อง และหาอนุพันธ์ได้
  • y_true เป็นค่าที่แน่นอนและคงที่

สำหรับการเปรียบเทียบ คุณควรใช้ argmax ซึ่งคล้ายกับดัชนีคลาสมาก (หากไม่ตรงทั้งหมด)

def mean_absolute_error(y_true, y_pred):

    #for comparing, let's take exact values
    y_true_max = K.argmax(y_true)
    y_pred_max = K.argmax(y_pred)

    #compare with a proper tensor function
    equal_mask = K.equal(y_true_max,y_pred_max)
    is_start = K.equal(y_true_max, self.startTokenAsIndex)
    is_end = K.equal(y_true_max, self.endTokenAsIndex)

    #cast to float for multiplying and summing
    equal_mask = K.cast(equal_mask, K.floatx()) 
    is_start = K.cast(is_start, K.floatx())
    is_end = K.cast(is_end, K.floatx())
        #these are tensors with 0 (false) and 1 (true) as float
    
    #entire condition as you wanted
    condition = (is_start + is_end) * equal_mask
        # sum = or ||| multiply = and
        # we don't have to worry about the sum resulting in 2
            # because you will never have startToken == endToken

    #reverse condition:
    condition = 1 - condition

    #result
    return condition * K.mean(K.abs(y_pred - y_true), axis=-1)
person Daniel Möller    schedule 02.04.2018
comment
ว้าว คุณสุดยอดมาก .. ฉันไม่เคยรู้เกี่ยวกับตัวเลือกน้ำหนักเลย และฉันอยากจะมีส่วนร่วมในฝั่งเซิร์ฟเวอร์ของ Keras เพื่อให้คุณช่วยได้มาก.. ขอบคุณ - person Ori Yampolsky; 03.04.2018