Keras เวลาคาดการณ์ที่ไม่สอดคล้องกัน


17

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

import time
import numpy as np
from sklearn.datasets import make_classification
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

# Make a dummy classification problem
X, y = make_classification()

# Make a dummy model
model = Sequential()
model.add(Dense(10, activation='relu',name='input',input_shape=(X.shape[1],)))
model.add(Dense(2, activation='softmax',name='predictions'))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

model.fit(X, y, verbose=0, batch_size=20, epochs=100)

for i in range(1000):
    # Pick a random sample
    sample = np.expand_dims(X[np.random.randint(99), :], axis=0)
    # Record the prediction time 10x and then take the average
    start = time.time()
    for j in range(10):
        y_pred = model.predict_classes(sample)
    end = time.time()
    print('%d, %0.7f' % (i, (end-start)/10))

เวลาไม่ขึ้นอยู่กับตัวอย่าง (กำลังสุ่มเลือก) หากการทดสอบซ้ำดัชนีในลูปที่การทำนายใช้เวลานานจะเป็น (เกือบ) เหมือนเดิมอีกครั้ง

ป้อนคำอธิบายรูปภาพที่นี่

ฉันกำลังใช้:

tensorflow 2.0.0
python 3.7.4

สำหรับใบสมัครของฉันฉันจำเป็นต้องรับประกันการใช้งานในเวลาที่กำหนด อย่างไรก็ตามนี่เป็นสิ่งที่เป็นไปไม่ได้เมื่อพิจารณาถึงพฤติกรรมนั้น เกิดอะไรขึ้น? มันเป็นข้อบกพร่องใน Keras หรือข้อผิดพลาดในแบ็กเอนด์เทนโฟลว์?

แก้ไข: predict_on_batchแสดงพฤติกรรมเดียวกัน แต่กระจัดกระจายมากขึ้น: ป้อนคำอธิบายรูปภาพที่นี่

y_pred = model(sample, training=False).numpy() แสดงค่าผิดปกติบางอย่างเช่นกัน แต่จะไม่เพิ่มขึ้น ป้อนคำอธิบายรูปภาพที่นี่

แก้ไข 2: ฉันปรับลดรุ่นเป็น tensorflow 1 เวอร์ชันล่าสุด (1.15) ไม่เพียง แต่ปัญหาจะไม่มีอยู่อีกต่อไป แต่ยังมีการทำนายเวลา "ปกติ" ที่ดีขึ้นอย่างมาก! ฉันไม่เห็นหนามแหลมสองตัวเป็นปัญหาเนื่องจากไม่ปรากฏขึ้นเมื่อฉันทำการทดสอบซ้ำ (อย่างน้อยก็ไม่ได้ที่ดัชนีเดียวกันและเพิ่มขึ้นเป็นเส้นตรง) และมีค่าร้อยละไม่ใหญ่เท่ากับในพล็อตแรก ป้อนคำอธิบายรูปภาพที่นี่

เราสามารถสรุปได้ว่านี่เป็นปัญหาที่เกิดขึ้นกับ tensorflow 2.0 ซึ่งแสดงพฤติกรรมที่คล้ายคลึงกันในสถานการณ์อื่น ๆ เช่น @OverLordGoldDragon กล่าวถึง


พฤติกรรมนั้นฟังดูเหมือนว่าจะเป็นการคาดเดา .... การเพิ่มขึ้นนั้นเป็นเส้นตรง หากคุณรวมพฤติกรรมนี้ไว้ในการคำนวณเวลาของคุณจะไม่เกิดขึ้นหรือไม่ --- ฉันไม่รู้ว่าเกิดอะไรขึ้นที่นั่น .... แต่จะเกิดอะไรขึ้นถ้าคุณลองทำpredict_on_batchแทน
Daniel Möller

ความพยายามอีกครั้งเกิดอะไรขึ้นกับy_pred = model(sample).numpy()และด้วยy_pred = model(sample, training=False).numpy()?
Daniel Möller

ฉันเพิ่มสิ่งที่ค้นพบของฉัน เวอร์ชันที่ดูเหมือนจะไม่แสดงพฤติกรรม
ga97dil

แต่predict_classesก็ยังเร็วที่สุด .... ดูเหมือนว่า เกี่ยวกับpredictอะไร
Daniel Möller

1
ผมถือว่านี้อาจจะมีบางชนิดของการทำความสะอาดหน่วยความจำ ....
แดเนียลMöller

คำตอบ:


10

TF2 โดยทั่วไปการจัดแสดงนิทรรศการจัดการหน่วยความจำไม่ดีและข้อผิดพลาดเหมือนในหลายกรณีที่ฉันได้พบ - คำอธิบายสั้น ๆที่นี่และที่นี่ ด้วยการทำนายโดยเฉพาะวิธีการให้อาหารที่มีประสิทธิภาพที่สุดคือผ่านทางmodel(x)โดยตรง - ดูที่นี่และการอภิปรายที่เชื่อมโยงกัน

สรุป: model(x)ทำหน้าที่ของมันผ่าน__call__วิธีการ (ซึ่งสืบทอดจากbase_layer.Layer) ในขณะที่predict(), predict_classes()ฯลฯ เกี่ยวข้องกับฟังก์ชั่นห่วงโดยเฉพาะผ่านทาง_select_training_loop(); แต่ละวิธีใช้ข้อมูลก่อนและหลังการประมวลผลที่แตกต่างกันซึ่งเหมาะสำหรับกรณีการใช้งานที่แตกต่างกันและmodel(x)ใน 2.1 ได้รับการออกแบบมาโดยเฉพาะเพื่อให้ได้ประสิทธิภาพขนาดเล็กรุ่น / ชุดเล็กเร็วที่สุด (และอาจขนาดใดก็ได้)

การอ้างอิงTensorFlow devจากการสนทนาที่เชื่อมโยง:

คุณสามารถทำนายผลลัพธ์โดยใช้การเรียกใช้โมเดลไม่ใช่การทำนายโมเดลคือการโทรmodel(x)จะทำให้เร็วกว่านี้มากเพราะไม่มีส่วน "การแปลงเป็นชุดข้อมูล" และยังเรียกใช้แคชtf.functionโดยตรง

หมายเหตุ : นี่ควรเป็นปัญหาน้อยกว่าใน 2.1 และโดยเฉพาะ 2.2 - แต่ทดสอบแต่ละวิธีต่อไป นอกจากนี้ฉันรู้ว่านี่ไม่ได้ตอบคำถามของคุณโดยตรงกับเวลาที่แหลม ฉันสงสัยว่ามันเกี่ยวข้องกับกลไกการแคชของ Eager แต่วิธีที่แน่นอนที่สุดในการพิจารณาคือผ่านTF Profilerซึ่งใช้งานไม่ได้ใน 2.1


อัปเดต : เกี่ยวกับการเพิ่มที่เพิ่มขึ้น , การควบคุมปริมาณ GPU ที่เป็นไปได้; คุณทำเสร็จแล้ว ~ 1,000 iters ลอง 10,000 แทน - ในที่สุดการเพิ่มควรหยุด ตามที่คุณบันทึกไว้ในความคิดเห็นของคุณสิ่งนี้จะไม่เกิดขึ้นกับmodel(x); เหมาะสมแล้วที่ขั้นตอน GPU น้อยลงเกี่ยวข้อง ("แปลงเป็นชุดข้อมูล")

Update2 : คุณสามารถบั๊ก devs ที่นี่เกี่ยวกับมันหากคุณประสบปัญหานี้ ส่วนใหญ่ฉันร้องเพลงที่นั่น


นี่เป็นคำตอบที่ดีสำหรับสาเหตุที่วิธีการหนึ่งช้ากว่า แต่ไม่ได้อธิบายการเพิ่มเวลารันของการรันหลายครั้ง
LLSv2.0

1
@ LLSv2.0 ไม่แน่ใจว่าตัวเองทั้งหมด แต่คำตอบที่อัปเดต - ฉันยังคงรอการตอบสนองจาก devs เมื่อฉันยกปัญหานี้เองที่นี่
OverLordGoldDragon

1
@ ga97dil ใช่แล้วฉันไม่มีคำอธิบาย - ลองถาม Github แม้ว่าคุณอาจเผชิญกับการตอบสนองที่ยาวนาน
OverLordGoldDragon

1
@ ga97dil ที่จริงแล้ว TF1 นั้นเร็วกว่า TF2 มากแม้ว่า TF 2.1 นั้นคุ้มค่าที่จะลองใช้กับโมเดลขนาดเล็กและชุดข้อมูลเนื่องจากมันเป็นการฝึกอบรมที่เร็วที่สุดในมาตรฐานของฉัน (ไม่คาดการณ์) ที่สำคัญกว่านั้นถ้าคุณเคยใช้ TF2 ผมขอแนะนำให้คุณทดสอบความสามารถในการทำซ้ำในกราฟกับความกระตือรือร้น ผลลัพธ์อาจแตกต่างกันอย่างมากใน TF 2.1
OverLordGoldDragon

1
ฉันได้เพิ่มโพสต์ของคุณไปยังกระทู้ Gitและโพสต์ TF2 ของฉันกับ TF1 ขอบคุณที่แจ้งให้ฉันทราบว่าปัญหาหายไปใน TF 1
OverLordGoldDragon

2

ในขณะที่ฉันไม่สามารถอธิบายความไม่สอดคล้องกันในเวลาดำเนินการได้ฉันสามารถแนะนำให้คุณลองแปลงแบบจำลองของคุณเป็น TensorFlow Lite เพื่อเพิ่มความเร็วในการทำนายการบันทึกข้อมูลเดี่ยวหรือแบทช์ขนาดเล็ก

ฉันใช้มาตรฐานในรุ่นนี้:

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(384, activation='elu', input_shape=(256,)),
    tf.keras.layers.Dense(384, activation='elu'),
    tf.keras.layers.Dense(256, activation='elu'),
    tf.keras.layers.Dense(128, activation='elu'),
    tf.keras.layers.Dense(32, activation='tanh')
])

เวลาที่คาดการณ์สำหรับบันทึกเดียวคือ:

  1. model.predict(input): 18ms
  2. model(input): 1.3 มิลลิวินาที
  3. โมเดลถูกแปลงเป็น TensorFlow Lite: 43us

เวลาในการแปลงโมเดลคือ 2 วินาที

คลาสด้านล่างแสดงวิธีการแปลงและใช้โมเดลและจัดเตรียมpredictวิธีการเหมือนกับโมเดล Keras โปรดทราบว่าจะต้องมีการปรับเปลี่ยนเพื่อใช้กับรุ่นที่ไม่ได้มีเพียงอินพุต 1-D เดียวและเอาต์พุต 1-D เดียว

class LiteModel:

    @classmethod
    def from_file(cls, model_path):
        return LiteModel(tf.lite.Interpreter(model_path=model_path))

    @classmethod
    def from_keras_model(cls, kmodel):
        converter = tf.lite.TFLiteConverter.from_keras_model(kmodel)
        tflite_model = converter.convert()
        return LiteModel(tf.lite.Interpreter(model_content=tflite_model))

    def __init__(self, interpreter):
        self.interpreter = interpreter
        self.interpreter.allocate_tensors()
        input_det = self.interpreter.get_input_details()[0]
        output_det = self.interpreter.get_output_details()[0]
        self.input_index = input_det["index"]
        self.output_index = output_det["index"]
        self.input_shape = input_det["shape"]
        self.output_shape = output_det["shape"]
        self.input_dtype = input_det["dtype"]
        self.output_dtype = output_det["dtype"]

    def predict(self, inp):
        inp = inp.astype(self.input_dtype)
        count = inp.shape[0]
        out = np.zeros((count, self.output_shape[1]), dtype=self.output_dtype)
        for i in range(count):
            self.interpreter.set_tensor(self.input_index, inp[i:i+1])
            self.interpreter.invoke()
            out[i] = self.interpreter.get_tensor(self.output_index)[0]
        return out

    def predict_single(self, inp):
        """ Like predict(), but only for a single record. The input data can be a Python list. """
        inp = np.array([inp], dtype=self.input_dtype)
        self.interpreter.set_tensor(self.input_index, inp)
        self.interpreter.invoke()
        out = self.interpreter.get_tensor(self.output_index)
        return out[0]

รหัสมาตรฐานที่สมบูรณ์และพล็อตสามารถพบได้ที่นี่: https://medium.com/@micwurm/using-tensorflow-lite-to-speed-up-predictions-a3954886eb98


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