복붙노트

[PYTHON] TFRecordReader가 매우 느리게 보이고 멀티 스레드 읽기가 작동하지 않습니다.

PYTHON

TFRecordReader가 매우 느리게 보이고 멀티 스레드 읽기가 작동하지 않습니다.

내 훈련 과정은 기차 및 평가 데이터 세트에 tfrecord 형식을 사용합니다.

필자는 독자의 벤치 마크 테스트를 8000 건 / 초 밖에하지 않습니다. 및 io 속도 (iotop 명령에서 볼 수 있음)는 단지 400KB-500KB / s입니다.

protobuf의 cpp 버전을 사용하고 있습니다.

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/g3doc/get_started/os_setup.md#protobuf-library-related-issues

가능한 경우 최소한의 재현 가능한 예제를 제공하십시오 (일반적으로 수백 줄의 코드를 읽을 시간이 없습니다)

def read_and_decode(filename_queue):
     reader = tf.TFRecordReader()
    _, serialized_example = reader.read(filename_queue)
    return serialized_example
  serialized_example = read_and_decode(filename_queue)
  batch_serialized_example = tf.train.shuffle_batch(
      [serialized_example],
      batch_size=batch_size,
      num_threads=thread_number,
      capacity=capacity,
      min_after_dequeue=min_after_dequeue)
  features = tf.parse_example(
      batch_serialized_example,
      features={
          "label": tf.FixedLenFeature([], tf.float32),
          "ids": tf.VarLenFeature(tf.int64),
          "values": tf.VarLenFeature(tf.float32),
      })

시도한 다른 시도한 해결책은 무엇입니까?

tf.train.shuffle_batch에서 num_threads를 설정하려고했지만 작동하지 않습니다.

그것은 2 스레드로 설정하면, 그것은 8000records / s에서, 스레드 번호를 확대하면, 그것은 느리게 얻을 것으로 보인다. (나는 CPU를 소모하는 모든 연산을 제거한다. 단지 데이터를 읽는다.)

내 서버는 24 코어 CPU입니다.

해결법

  1. ==============================

    1.여기서 문제는 각 session.run에 대한 고정 비용 오버 헤드가 있으며 대기열에 많은 예제가있는 대기열을 채우는 것이 느려지 게된다는 것입니다.

    여기서 문제는 각 session.run에 대한 고정 비용 오버 헤드가 있으며 대기열에 많은 예제가있는 대기열을 채우는 것이 느려지 게된다는 것입니다.

    특히 각 session.run은 약 100-200 usec이므로 초당 약 5k-10k session.run 호출 만 수행 할 수 있습니다.

    파이썬 프로파일 링 (파이썬 -m cProfile)을 수행하는 경우이 문제는 명백하지만 타임 라인 프로파일 또는 CPU 프로파일에서 시작하는 경우보기가 어렵습니다.

    해결 방법은 enqueue_many를 사용하여 대기열에 일괄 적으로 항목을 추가하는 것입니다. 나는 당신의 벤치 마크를 https://gist.github.com/ericyue/7705407a88e643f7ab380c6658f641e8에서 가져 와서 .run 호출마다 많은 항목을 대기열에 넣기 위해 수정했다. 그리고 그것은 10 배의 속도 향상을 준다.

    수정은 다음과 같이 tf.batch 호출을 수정하는 것입니다.

    if enqueue_many:
        reader = tf.TFRecordReader(options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB))
        queue_batch = []
        for i in range(enqueue_many_size):
            _, serialized_example = reader.read(filename_queue)
            queue_batch.append(serialized_example)
        batch_serialized_example = tf.train.shuffle_batch(
            [queue_batch],
            batch_size=batch_size,
            num_threads=thread_number,
            capacity=capacity,
            min_after_dequeue=min_after_dequeue,
            enqueue_many=True)
    

    전체 소스를 보려면 여기를 확인하십시오. https://github.com/yaroslavvb/stuff/blob/master/ericyue-slowreader/benchmark.py

    이제 대부분의 시간이 대기열 작업에 소요되기 때문에 훨씬 빠르게 진행되도록 최적화하는 것은 어렵습니다. 정수를 대기열에 추가하는 버드 다운 버전을 보면 비슷한 속도를 얻을 수 있으며 타임 라인을 볼 때 대기열에서 대기하는 데 소요되는 시간을 알 수 있습니다.

    각 dequeue op에는 약 60 usec가 소요되지만 병렬로 실행되는 평균 5 개이므로 dequeue 당 12 usec가 발생합니다. 즉, 최상의 경우 초당 200,000 개 이하의 예제를 얻을 수 있습니다.

  2. ==============================

    2.다음은 야로 슬라브 (Yaroslav)의 대답에 대한 간단한 속도 향상 건물입니다.

    다음은 야로 슬라브 (Yaroslav)의 대답에 대한 간단한 속도 향상 건물입니다.

    Tensorflow에는 tf.TFRecordReader.read_up_to 함수가 내장되어있어 각 session.run () 호출에서 여러 레코드를 읽으며 여러 호출로 인해 발생하는 초과 오버 헤드를 제거합니다.

    enqueue_many_size = SOME_ENQUEUE_MANY_SIZE
    reader = tf.TFRecordReader(options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB))
    _, queue_batch = reader.read_up_to(filename_queue, enqueue_many_size)
    batch_serialized_example = tf.train.shuffle_batch(
        [queue_batch],
        batch_size=batch_size,
        num_threads=thread_number,
        capacity=capacity,
        min_after_dequeue=min_after_dequeue,
        enqueue_many=True)
    

    Yaroslav의 답변에서와 같이 배치 함수가 여러 레코드를 받아들이도록 enqueue_many = True를 설정해야합니다.

    제 유스 케이스에서는 매우 빨랐습니다.

  3. ==============================

    3.야로 슬라브의 대답에 대한 부록 : tf.python_io.tf_record_iterator를 사용하여 예제를 반복하여 목록에 추가하면 enquue_many = true로 tf.train.shuffle_batch에 전달할 수 있습니다.

    야로 슬라브의 대답에 대한 부록 : tf.python_io.tf_record_iterator를 사용하여 예제를 반복하여 목록에 추가하면 enquue_many = true로 tf.train.shuffle_batch에 전달할 수 있습니다.

    queue_batch = []
    for serialized_example in tf.python_io.tf_record_iterator(filename,options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB)):
        queue_batch.append(serialized_example)
    batch_serialized_example = tf.train.shuffle_batch(
        [queue_batch],
        batch_size=batch_size,
        num_threads=thread_number,
        capacity=capacity,
        min_after_dequeue=min_after_dequeue,
        enqueue_many=True)
    

    reader.read ()를 사용하여 예제를 반복 할 경우 일괄 처리 당 하나의 읽기가 발생합니다. 즉, n 번째 배치는 batch_num 많은 고유 레코드보다는 n 번째 레코드의 batch_num 사본이됩니다.

  4. from https://stackoverflow.com/questions/41647784/tfrecordreader-seems-extremely-slow-and-multi-threads-reading-not-working by cc-by-sa and MIT license