TensorFlow 2가 TensorFlow 1보다 훨씬 느린 이유는 무엇입니까?


137

그것은 많은 사용자들에 의해 Pytorch로 전환 한 이유로 인용되었지만, 나는 가장 중요한 실제 품질, 속도, 빠른 실행을 희생하기위한 정당화 / 설명을 아직 찾지 못했습니다.

다음은 TF1과 TF2의 코드 벤치마킹 성능입니다. TF1은 47 % ~ 276 % 더 빠르게 실행 됩니다.

내 질문은 : 그래프 또는 하드웨어 수준에서 그렇게 중요한 속도 저하를 일으키는 것은 무엇입니까?


자세한 답변을 찾고-이미 광범위한 개념에 익숙합니다. 관련 힘내

사양 : CUDA 10.0.130, cuDNN 7.4.2, Python 3.7.4, Windows 10, GTX 1070


벤치 마크 결과 :


업데이트 : 아래 코드 당 Eager 실행을 비활성화 하면 도움 이 되지 않습니다 . 그러나 동작은 일관되지 않습니다. 때때로 그래프 모드에서 실행하면 다른 경우에는 Eager에 비해 느리게 실행됩니다 .

TF 개발자가 어디에도 나타나지 않기 때문에이 문제를 직접 조사 할 것입니다-연결된 Github 문제의 진행 상황을 따를 수 있습니다.

업데이트 2 : 설명과 함께 공유 할 수많은 실험 결과; 오늘해야합니다.


벤치 마크 코드 :

# use tensorflow.keras... to benchmark tf.keras; used GPU for all above benchmarks
from keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from keras.layers import Flatten, Dropout
from keras.models import Model
from keras.optimizers import Adam
import keras.backend as K
import numpy as np
from time import time

batch_shape = (32, 400, 16)
X, y = make_data(batch_shape)

model_small = make_small_model(batch_shape)
model_small.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_small.train_on_batch, 200, X, y)

K.clear_session()  # in my testing, kernel was restarted instead

model_medium = make_medium_model(batch_shape)
model_medium.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_medium.train_on_batch, 10, X, y)

사용 된 기능 :

def timeit(func, iterations, *args):
    t0 = time()
    for _ in range(iterations):
        func(*args)
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_small_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 400, strides=4, padding='same')(ipt)
    x     = Flatten()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_medium_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
    x     = LSTM(512, activation='relu', return_sequences=True)(x)
    x     = Conv1D(128, 400, strides=4, padding='same')(x)
    x     = Flatten()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), np.random.randint(0, 2, (batch_shape[0], 1))

cProfile과 같은 도구를 사용하여 어떤 부분을 다르게 만드는지 분석 한 적이 있습니까?
zihaozhihao

@zihaozhihao 나는 이것을 가지고 있지는 않지만; 이전 링크 및 사용자 정의 최적화 프로그램 작성에 따라 이미 전화의 차이점에 익숙하지만, 왜 다른 것보다 느린 지 이해 하지 못합니다 .TF가 아닌 전문가는 소스에서이를 이해할 수 없습니다. 뒤엉킨 혼란은 상대적인 성능을 기록하지 않습니다. 도표 / 하드웨어 수준의 인텔는 (내가 그들을 사용할 수있어 지금까지처럼) 프로파일 러는 제공하지 않습니다, 이는 필요
OverLordGoldDragon

두 테스트에서 numpy 버전이 동일합니까?
chabir

..... 오래된 Keras만으로도 PyTorch보다 상당히 느리다면 지금 상상해보십시오.
Daniel Möller

모델 크기에 따라 문제가 해결됩니까? 또한 다른 OS에서 동일한 벤치 마크를 실행하려고 했습니까?
okawo

답변:


76

업데이트 2/18/2020 : 나는 2.1과 2.1- 밤마다 벤치에 앉았습니다. 결과가 혼합되어 있습니다. 하나의 구성을 제외한 모든 구성 (모델 및 데이터 크기)은 최고 TF2 및 TF1보다 빠르거나 훨씬 빠릅니다. 느리고 급격한 속도는 Large-Large-esp입니다. 그래프 실행에서 ( 1.6x ~ 2.5x 느림 ).

또한 테스트 한 큰 모델의 경우 Graph와 Eager간에 재현성 차이 가 극도로 높습니다. 이는 임의성 / 계산 병렬화를 통해 설명 할 수 없습니다. 현재 시간당 제약 조건에 대해 이러한 청구에 대한 재현 가능한 코드를 제시 할 수 없으므로 대신 자신의 모델에 대해 테스트하는 것이 좋습니다.

아직 Git 문제를 열지 않았지만 원래 답변 에 대해서는 언급 하지 않았습니다. 진행이 완료되면 답변을 업데이트하겠습니다.


VERDICT : 하고있는 일을 알고 있다면 그렇지 않습니다 . 그러나 그렇지 않으면 평균적으로 몇 번의 GPU 업그레이드와 최악의 경우 여러 GPU로 인해 비용이 많이들 수 있습니다.


이 답변 : 문제에 대한 높은 수준의 설명과 요구 사항에 맞는 교육 구성을 결정하는 방법에 대한 지침을 제공하는 것을 목표로합니다. 모든 벤치마킹 결과 및 사용 된 코드를 포함하는 자세한 저수준 설명에 대해서는 다른 답변을 참조하십시오.

내가 배우면 더 많은 정보가있는 답변을 업데이트 할 것입니다-참조 할 수 있도록이 질문을 북마크 / "스타"할 수 있습니다.


문제 요약 : TensorFlow 개발자 인 Q. Scott Zhu에 의해 확인 된 TF2는 Kera의 Eager 실행 및 긴밀한 통합에 대한 개발에 중점을 두었습니다. 이점 : 처리, 배포, 디버그 및 배포 기능이 크게 확장되었습니다. 그러나 이들 중 일부의 비용은 속도입니다.

그러나이 문제는 상당히 복잡합니다. TF1과 TF2만이 아니라 열차 속도에 큰 차이를 일으키는 요소는 다음과 같습니다.

  1. TF2 대 TF1
  2. 열망 대 그래프 모드
  3. keras vs. tf.keras
  4. numpytf.data.Dataset대 ...
  5. train_on_batch() vs. fit()
  6. GPU와 CPU
  7. model(x)model.predict(x)대 ...

불행히도, 위의 어느 것도 서로 독립적이 아니며, 각각 다른 것에 비해 적어도 두 배의 실행 시간을 가질 수 있습니다. 다행스럽게도, 시스템에서 가장 잘 작동하는 항목과 몇 가지 단축키를 사용하여 확인할 수 있습니다.


어떻게해야합니까? 현재 유일한 방법은 특정 모델, 데이터 및 하드웨어를 실험하는 것입니다. 단일 구성은 항상 최고의 작동하지 않습니다 -하지만 거기에 있다 의는 어떻게하지 검색을 단순화의 수행

>>해야 할 일 :

  • train_on_batch()+ numpy+ tf.keras+ TF1 + 열망 / 그래프
  • train_on_batch()+ numpy+ tf.keras+ TF2 + 그래프
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + 그래프 + 큰 모델 및 데이터

>>하지 마십시오 :

  • fit()중소 모델 및 데이터의 경우 + numpy+keras
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + 열망
  • train_on_batch()+ numpy+ keras+ TF1 + 열망

  • [주요] tf.python.keras ; 10-100 배 느리게 실행될 수 있으며 많은 버그가 있습니다. 더 많은 정보

    • 이것은 포함 layers, models, optimizers, 관련 "아웃 - 오브 - 박스"사용 수입; ops, utils 및 관련 'private'수입품은 괜찮습니다. 그러나 확실하게, alts를 확인하십시오.tf.keras

벤치마킹 설정 예는 다른 답변의 맨 아래에있는 코드를 참조하십시오. 위의 목록은 주로 다른 답변의 "BENCHMARKS"테이블을 기반으로합니다.


위의 제한 사항제한 사항 :

  • 이 질문의 제목은 "TF2가 TF1보다 훨씬 느린 이유는 무엇입니까?"이며, 본문은 명시 적으로 훈련에 관한 문제이지만 이에 국한되지 않습니다. 추론 역시 동일한 TF 버전, 가져 오기, 데이터 형식 등에서 속도에 큰 차이가 있을 수 있습니다 . 이 답변을 참조하십시오 .
  • RNN은 TF2에서 개선되었으므로 다른 답변에서 데이터 그리드를 현저하게 변경할 수 있습니다.
  • 모델 주로 사용되지 Conv1DDense- 더 RNNs, 희소 데이터 / 타겟 4 / 5D 입력, 및 기타를 CONFIGS
  • 입력 데이터는 numpy및로 제한 tf.data.Dataset되지만 다른 형식은 많이 있습니다. 다른 답변보기
  • GPU가 사용되었습니다. 결과 CPU마다 다릅니다. 실제로 질문을 할 때 CUDA가 올바르게 구성되지 않았으며 일부 결과는 CPU 기반이었습니다.

TF2가 간절한 실행을 위해 가장 실용적인 품질과 속도를 희생 한 이유는 무엇입니까? 아직 명확하지 않습니다-그래프를 여전히 사용할 수 있습니다. 그러나 질문이 "왜 열망 하는가"라면 :

  • 뛰어난 디버깅 : "중간 레이어 출력을 얻는 방법"또는 "무게를 검사하는 방법"을 묻는 여러 가지 질문이있을 수 있습니다. 간절히, 그것은 (거의)만큼 간단합니다 .__dict__. 이와 대조적으로 그래프는 특수 백엔드 기능에 익숙해야합니다. 이는 디버깅 및 검사의 전체 프로세스를 크게 복잡하게합니다.
  • 더 빠른 프로토 타이핑 : 위와 유사한 아이디어 당; 더 빠른 이해 = 실제 DL에 더 많은 시간이 남았습니다.

EAGER를 활성화 / 비활성화하는 방법은 무엇입니까?

tf.enable_eager_execution()  # TF1; must be done before any model/tensor creation
tf.compat.v1.disable_eager_execution() # TF2; above holds

추가 정보 :

  • _on_batch()TF2의 메소드에 주의하십시오 . TF dev에 따르면, 그들은 여전히 ​​느린 구현을 사용하지만 의도적으로는 아닙니다. 즉 수정되어야합니다. 자세한 내용은 다른 답변을 참조하십시오.

텐서 플로 장치에 대한 요청 :

  1. 를 반복적 train_on_batch()으로 호출하는 성능 측면을 수정하십시오 fit(). 맞춤형 기차 루프는 많은 사람들에게, 특히 나에게 중요합니다.
  2. 사용자 지식에 대한 이러한 성능 차이에 대한 문서 / 문서 문자열 언급을 추가하십시오.
  3. 엿보기가 Pytorch에 호핑되지 않도록 일반 실행 속도를 향상시킵니다.

감사의 말 : 감사합니다


업데이트 :

  • 11 /14/19-Numpy 입력 데이터가있는 모든 * 구성에 대해 TF2 에서 느리게 실행되는 모델 (내 실제 응용 프로그램에서)을 찾았습니다 . 차이는 13-19 %이며 평균 17 %입니다. 그러나 keras와의 차이는 18-40 %tf.keras 로 더 극적이었습니다 . 32 % (TF1 & 2). (*-TF2가 OOM 인 Eager 제외)

  • 11 / 17 / 19- 개발자 on_batch()최근 커밋 에서 업데이트 된 메소드를 사용하여 TF 2.1에서 릴리스 될 속도를 향상 시키거나 현재와 같이 사용할 수 있음을 나타 tf-nightly냅니다. 나는 후자를 뛸 수 없으므로 2.1까지 벤치를 연기합니다.

  • 2/20 / 20- 예측 성능도 벤치마킹 할 가치가 있습니다. 예를 들어, TF2에서 CPU 예측 시간에는 주기적 스파이크 가 포함될 수 있습니다.

3
무엇에 대해 fit_generator? ... 나는 사실상 결코 원치 않으며 train_on_batch배치 전체에서 자체 교육 루프를 관리하는 것은 큰 비용으로도 피할 수있는 거대하고 거대한 안티 패턴입니다.
ely

@ely 다른 답변에서 언급했듯이 테스트를 계속해야하지만 fit작은 추가 데이터 처리 오버 헤드 가있는 것으로 예상되는 경우 . 기차 루프에 관해서는, 나는 궁극적으로 일종의 API로 바뀌는 내 자신의 맞춤형을 작성했습니다. fit_generator내성, 커스터마이즈 가능성, 저장 /로드가 부족하여 절대 절제 할 수 없습니다. 결국 Github에서 트레이닝 루프를 게시 할 예정입니다.
OverLordGoldDragon

부족한 내성 및 사용자 정의 가능성은 버그가 아닌 나를위한 기능입니다. IDK는 저장 /로드 주석이 무엇을 말하는가? 데이터 생성기에 의해 제어되지 않는 루프 동안 중간 저장 /로드? (또한 콜백에만 의존하여 개인적으로 행복하며 훈련 루프가 잘못 설계된 코드 냄새로 더 많은 사용자 정의가 필요하다고 생각합니다).
ely

@ely 간단하지는 않지만 복잡한 입력 데이터 파이프 라인, 목적 함수 및 비 API 모델 구성 (예 : 앙상블)을 학습하는 데 필요합니다. 내부 검사는 많은 디버깅 및 기능 엔지니어링 목적에 필수적입니다. 외부 저장 /로드 부족, 계산 비용이 많이 드는 모델에 대한 루프 일시 중지재개 가능성 부족 -악몽. 어쨌든, 궁극적으로 특정 요구 사항에 따라 달라지고 주제를 벗어납니다. fit_generator응용 프로그램에서 성능을 테스트하는 가장 확실한 방법 은 테스트하는 것입니다.
OverLordGoldDragon

47

이 답변 : TF2 대 TF1 트레인 루프, 입력 데이터 프로세서 및 Eager 대 그래프 모드 실행을 포함하여 문제에 대한 자세한 그래프 / 하드웨어 수준 설명을 제공하는 것을 목표로합니다. 문제 요약 및 해결 지침은 다른 답변을 참조하십시오.


성능 검증 : 구성에 따라 때로는 하나가 더 빠르거나 때로는 다른 것이 더 빠릅니다. TF2와 TF1의 차이는 평균적으로 비슷하지만 중요한 구성 기반 차이가 존재하며 TF1이 TF2보다 더 자주 TF2보다 우선합니다. 아래의 "벤치마킹"을 참조하십시오.


EAGER VS. GRAPH : 일부에 대한이 전체 답변의 고기 : 내 테스트에 따르면 TF2의 열망은 TF1보다 느립니다 . 자세한 내용은 아래를 참조하십시오.

이 둘의 근본적인 차이점은 다음과 같습니다. Graph는 사전에 계산 네트워크를 설정하고 '말할 때'실행하지만 Eager는 생성시 모든 것을 실행합니다. 그러나 이야기는 여기서 시작됩니다.

  • Eager는 Graph가 없으며 실제로 예상과 달리 대부분 Graph 일 수 있습니다 . 그것은 크게 실행됩니다. Graph- 여기에는 그래프 의 많은 부분을 포함하는 모델 및 최적화 가중치가 포함됩니다.

  • Eager는 실행시 자체 그래프의 일부를 재구성합니다 . Graph가 완전히 구축되지 않은 직접적인 결과-프로파일 러 결과 참조. 여기에는 계산 오버 헤드가 있습니다.

  • Numpy 입력으로 느리게 느림 ; 당 이 망할 놈의 주석 및 코드, 열망에서 NumPy와 입력은 CPU에서 GPU로 텐서를 복사하는 오버 헤드 비용을 포함한다. 소스 코드를 단계별로 살펴보면 데이터 처리 차이점이 분명합니다. Eager는 Numpy를 직접 전달하고 Graph는 텐서를 통과 한 다음 Numpy로 평가합니다. 정확한 프로세스는 확실하지 않지만 후자는 GPU 수준 최적화를 포함해야합니다.

  • TF2 Eager가 TF1 Eager보다 느리다 -이것은 예상치 못한 것이다. 아래 벤치마킹 결과를 참조하십시오. 차이는 무시할 수있는 수준에서 의미있는 수준까지 다양하지만 일관성이 있습니다. 왜 그런지 잘 모르겠습니다. TF 개발자가 설명하면 답변을 업데이트합니다.


TF2 대 TF1 하십시오 TF dev에의, Q. 스콧 Zhu의의의 관련 부분을 인용 응답 - w / 내 중점 및 새로운 표현의 비트를 :

간절히 런타임은 ops를 실행하고 모든 파이썬 코드 라인의 숫자 값을 반환해야합니다. 단일 단계 실행 의 특성상 속도가 느려집니다 .

TF2에서 Keras는 tf.function을 활용하여 훈련, 평가 및 예측을위한 그래프를 작성합니다. 이를 모델의 "실행 기능"이라고합니다. TF1에서 "실행 기능"은 FuncGraph로, 일부 공통 구성 요소를 TF 기능으로 공유하지만 구현 방식이 다릅니다.

프로세스 중에 train_on_batch (), test_on_batch () 및 predict_on_batch ()에 대해 잘못된 구현이 남았습니다 . 여전히 수치 적으로 정확 하지만 x_on_batch의 실행 함수는 tf.function 래핑 된 파이썬 함수가 아닌 순수한 파이썬 함수입니다. 이됩니다 속도 저하의 원인이

TF2에서는 모든 입력 데이터를 tf.data.Dataset으로 변환하여 단일 유형의 입력을 처리하기 위해 실행 함수를 통합 할 수 있습니다. 데이터 세트 변환에 약간의 오버 헤드 가있을 수 있으며 이것이 일괄 처리 비용이 아닌 일회성 오버 헤드라고 생각합니다.

위의 마지막 단락의 마지막 문장과 아래 단락의 마지막 문장으로 :

열망 모드에서 속도 저하를 극복하기 위해 @ tf.function을 사용하여 파이썬 함수를 그래프로 변환합니다. np 배열과 같은 숫자 값을 피드하면 tf.function의 본문이 정적 그래프로 변환되어 최적화되고 최종 값을 반환합니다.이 값은 빠르고 TF1 그래프 모드와 유사한 성능을 가져야합니다.

프로파일 링 결과에 동의하지 않습니다.이 결과는 Eager의 입력 데이터 처리가 그래프보다 상당히 느리다는 것을 보여줍니다. 또한 확실 tf.data.Dataset하지 않지만 Eager는 동일한 데이터 변환 방법을 여러 번 반복해서 호출합니다 (프로파일 러 참조).

마지막으로, dev의 링크 된 커밋 : Keras v2 루프를 지원하기위한 많은 변경 .


기차 루프 : (1) 열망 대 그래프; (2) 입력 데이터 형식, 훈련은 다음 중 하나 인 TF2 _select_training_loop(), training.py 에서 독특한 기차 루프로 진행됩니다 .

training_v2.Loop()
training_distributed.DistributionMultiWorkerTrainingLoop(
              training_v2.Loop()) # multi-worker mode
# Case 1: distribution strategy
training_distributed.DistributionMultiWorkerTrainingLoop(
            training_distributed.DistributionSingleWorkerTrainingLoop())
# Case 2: generator-like. Input is Python generator, or Sequence object,
# or a non-distributed Dataset or iterator in eager execution.
training_generator.GeneratorOrSequenceTrainingLoop()
training_generator.EagerDatasetOrIteratorTrainingLoop()
# Case 3: Symbolic tensors or Numpy array-like. This includes Datasets and iterators 
# in graph mode (since they generate symbolic tensors).
training_generator.GeneratorLikeTrainingLoop() # Eager
training_arrays.ArrayLikeTrainingLoop() # Graph

각각 리소스 할당을 다르게 처리하고 성능 및 기능에 영향을 미칩니다.


Train Loops : fitvs train_on_batch, kerasvs.tf.keras : 네 가지 각각은 서로 다른 기차 루프를 사용하지만 모든 가능한 조합이 아닐 수도 있습니다. keras' fit예를 들어, 사용의 형태 fit_loop예를 training_arrays.fit_loop(), 그은 train_on_batch사용할 수있다 K.function(). tf.keras이전 섹션에서 부분적으로 설명 된보다 정교한 계층 구조가 있습니다.


Train Loops : documentation- 몇 가지 다른 실행 방법에 대한 관련 소스 docstring :

다른 TensorFlow 작업과 달리 Python 숫자 입력을 텐서로 변환하지 않습니다. 또한, 각각의 개별 파이썬 숫자 값에 대해 새로운 그래프가 생성됩니다.

function 모든 고유 한 입력 모양 및 데이터 유형 집합에 대해 별도의 그래프를 인스턴스화합니다 .

단일 tf.function 객체는 후드 아래의 여러 계산 그래프에 매핑해야 할 수도 있습니다. 이것은 성능으로 만 볼 수 있어야합니다 (추적 그래프는 0이 아닌 계산 및 메모리 비용을 가짐 )


입력 데이터 프로세서 : 위와 유사하게 프로세서는 런타임 구성 (실행 모드, 데이터 형식, 배포 전략)에 따라 설정된 내부 플래그에 따라 사례별로 선택됩니다. Numpy 어레이와 직접 작동하는 Eager의 가장 간단한 사례입니다. 구체적인 예는 이 답변을 참조하십시오 .


모델 크기, 데이터 크기 :

  • 결정적입니다. 모든 모델 및 데이터 크기 위에 단일 구성이 적용되지 않았습니다.
  • 모델 크기에 상대적인 데이터 크기 가 중요합니다. 작은 데이터 및 모델의 경우 데이터 전송 (예 : CPU에서 GPU로) 오버 헤드가 지배적입니다. 마찬가지로, 작은 오버 헤드 프로세서는 데이터 변환 시간에 비해 큰 데이터에서 느리게 실행될 수 있습니다 ( convert_to_tensor"프로파일 러" 참조 ).
  • 열차 루프 및 입력 데이터 프로세서의 다양한 리소스 처리 수단에 따라 속도가 다릅니다.

벤치 마크 : 갈은 고기. - 워드 문서 - 엑셀 스프레드 시트


용어 :

  • % 이하의 숫자는 모두 초입니다
  • %는 다음과 같이 계산됩니다 (1 - longer_time / shorter_time)*100. 이론적 근거 : 우리는 어떤 요소 가 다른 요소 보다 빠른지에 관심 이 있습니다 . shorter / longer실제로 비선형 관계이며 직접 비교에 유용하지 않습니다.
  • % 부호 결정 :
    • TF2 vs TF1 : +TF2가 더 빠른 경우
    • GvE (Graph vs. Eager) : +그래프가 더 빠른 경우
  • TF2 = 텐서 플로우 2.0.0 + 케 라스 2.3.1; TF1 = TensorFlow 1.14.0 + Keras 2.2.5

프로파일 러 :


프로파일-설명 : Spyder 3.3.6 IDE 프로파일 러.

  • 일부 기능은 다른 기능의 둥지에서 반복됩니다. 따라서 "데이터 처리"와 "트레이닝"기능 사이의 정확한 분리를 추적하기가 어렵 기 때문에 마지막 결과에서 뚜렷한 차이가 있습니다.

  • 계산 된 wrt 런타임 에서 빌드 시간을 뺀 수치

  • 1 회 또는 2 회 호출 된 모든 (고유 한) 런타임을 합산하여 계산 된 빌드 시간
  • 반복 횟수와 동일한 횟수로 호출 된 모든 (고유 한) 런타임과 일부 중첩 런타임을 합산하여 계산 한 열차 시간
  • 함수는 불행히도 원래 이름 에 따라 프로파일 링됩니다 (예 : _func = func로 프로파일 func링됨). 빌드 시간이 혼합되어 제외해야합니다.

테스트 환경 :

  • 최소한의 백그라운드 작업을 실행하면서 맨 아래에서 실행 된 코드
  • 이 게시물 에서 제안한 것처럼 GPU는 타이밍 반복 전에 몇 번의 반복으로 "워밍업" 되었습니다.
  • 소스에서 빌드 된 CUDA 10.0.130, cuDNN 7.6.0, TensorFlow 1.14.0 및 TensorFlow 2.0.0 및 Anaconda
  • Python 3.7.4, Spyder 3.3.6 IDE
  • GTX 1070, Windows 10, 24GB DDR4 2.4MHz RAM, i7-7700HQ 2.8GHz CPU

방법론 :

  • 벤치 마크 '작은', '중간'및 '대형'모델 및 데이터 크기
  • 입력 데이터 크기와 무관하게 각 모델 크기에 대한 매개 변수 수 수정
  • "큰"모델에는 더 많은 매개 변수와 레이어가 있습니다
  • "큰"데이터가 더 이상 순서를 가지고 있지만, 같은 batch_sizenum_channels
  • 모델만을 사용 Conv1D, Dense'학습 가능'층; RNN은 TF- 버전 임 렘당 피했다. 차이점
  • 모델 및 옵티 마이저 그래프 작성을 생략하기 위해 벤치마킹 루프 외부에서 항상 하나의 트레인을 실행했습니다.
  • 스파 스 데이터 (예 layers.Embedding():) 또는 스파 스 대상 (예 :SparseCategoricalCrossEntropy()

제한 사항 : "완전한"답변은 가능한 모든 열차 루프 및 반복자를 설명하지만, 그것은 확실히 내 시간 능력, 존재하지 않는 월급 또는 일반적인 필요성을 넘어서는 것입니다. 결과는 방법론만큼이나 우수합니다. 열린 마음으로 해석하십시오.


코드 :

import numpy as np
import tensorflow as tf
import random
from termcolor import cprint
from time import time

from tensorflow.keras.layers import Input, Dense, Conv1D
from tensorflow.keras.layers import Dropout, GlobalAveragePooling1D
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import tensorflow.keras.backend as K
#from keras.layers import Input, Dense, Conv1D
#from keras.layers import Dropout, GlobalAveragePooling1D
#from keras.models import Model 
#from keras.optimizers import Adam
#import keras.backend as K

#tf.compat.v1.disable_eager_execution()
#tf.enable_eager_execution()

def reset_seeds(reset_graph_with_backend=None, verbose=1):
    if reset_graph_with_backend is not None:
        K = reset_graph_with_backend
        K.clear_session()
        tf.compat.v1.reset_default_graph()
        if verbose:
            print("KERAS AND TENSORFLOW GRAPHS RESET")

    np.random.seed(1)
    random.seed(2)
    if tf.__version__[0] == '2':
        tf.random.set_seed(3)
    else:
        tf.set_random_seed(3)
    if verbose:
        print("RANDOM SEEDS RESET")

print("TF version: {}".format(tf.__version__))
reset_seeds()

def timeit(func, iterations, *args, _verbose=0, **kwargs):
    t0 = time()
    for _ in range(iterations):
        func(*args, **kwargs)
        print(end='.'*int(_verbose))
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_model_small(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 40, strides=4, padding='same')(ipt)
    x     = GlobalAveragePooling1D()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_medium(batch_shape):
    ipt = Input(batch_shape=batch_shape)
    x = ipt
    for filters in [64, 128, 256, 256, 128, 64]:
        x  = Conv1D(filters, 20, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_large(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(64,  400, strides=4, padding='valid')(ipt)
    x     = Conv1D(128, 200, strides=1, padding='valid')(x)
    for _ in range(40):
        x = Conv1D(256,  12, strides=1, padding='same')(x)
    x     = Conv1D(512,  20, strides=2, padding='valid')(x)
    x     = Conv1D(1028, 10, strides=2, padding='valid')(x)
    x     = Conv1D(256,   1, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)    
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), \
           np.random.randint(0, 2, (batch_shape[0], 1))

def make_data_tf(batch_shape, n_batches, iters):
    data = np.random.randn(n_batches, *batch_shape),
    trgt = np.random.randint(0, 2, (n_batches, batch_shape[0], 1))
    return tf.data.Dataset.from_tensor_slices((data, trgt))#.repeat(iters)

batch_shape_small  = (32, 140,   30)
batch_shape_medium = (32, 1400,  30)
batch_shape_large  = (32, 14000, 30)

batch_shapes = batch_shape_small, batch_shape_medium, batch_shape_large
make_model_fns = make_model_small, make_model_medium, make_model_large
iterations = [200, 100, 50]
shape_names = ["Small data",  "Medium data",  "Large data"]
model_names = ["Small model", "Medium model", "Large model"]

def test_all(fit=False, tf_dataset=False):
    for model_fn, model_name, iters in zip(make_model_fns, model_names, iterations):
        for batch_shape, shape_name in zip(batch_shapes, shape_names):
            if (model_fn is make_model_large) and (batch_shape is batch_shape_small):
                continue
            reset_seeds(reset_graph_with_backend=K)
            if tf_dataset:
                data = make_data_tf(batch_shape, iters, iters)
            else:
                data = make_data(batch_shape)
            model = model_fn(batch_shape)

            if fit:
                if tf_dataset:
                    model.train_on_batch(data.take(1))
                    t0 = time()
                    model.fit(data, steps_per_epoch=iters)
                    print("Time/iter: %.4f sec" % ((time() - t0) / iters))
                else:
                    model.train_on_batch(*data)
                    timeit(model.fit, iters, *data, _verbose=1, verbose=0)
            else:
                model.train_on_batch(*data)
                timeit(model.train_on_batch, iters, *data, _verbose=1)
            cprint(">> {}, {} done <<\n".format(model_name, shape_name), 'blue')
            del model

test_all(fit=True, tf_dataset=False)

코드가 올바른지 확실하지 않습니다. 인수 model.compile하지 않고 호출하기 때문에 모델이 항상 그래프 모드로 실행된다고 생각합니다 run_eagerly=True. 열망 모드 인 경우을 사용하여 코드의 일부를 그래프 모드로 실행할 수 있습니다 tf.function. 따라서 기본 구현은 compile성능상의 이유로 열심히 실행하는 대신 계산 그래프를 만드는 것입니다. 또한 모델이 컨볼 루션 인 경우 파이썬 상호 작용이 최소화되므로 그래프 모드에서 속도가 향상되지 않습니다. 많은 수학 연산을 수행하면 큰 차이를 만들 수 있습니다 (메모리 활용도).
user2781994

@OverLordGoldDragon 그러나 TF 2에서 열망 모드는 기본적으로 있지만 그래프 모드 model.compilerun_eagerly=True보장하지 않습니까?
user2781994

@OverLordGoldDragon 나는 모든 수입 방법은 그래프 모드에서 실행 동의하지만 중 하나라고 생각 model.compile하거나 model.fit그 그래프 모드에서 훈련 실행이 내부적으로 확인해야합니다.
user2781994

@OverLordGoldDragon TRUE- "tf.keras.Model.compile은 세 가지 중요한 인수를 취합니다. ... 또한 모델이 학습하고 열심히 평가하는지 확인하기 run_eagerly=True위해 컴파일 할 매개 변수로 전달할 수 있습니다 ." (source tensorflow.org/guide/keras/overview ) 따라서 run_eagerly=True그래프 모드에서 CAN 모델 실행을 통과하지 못하면 결정 요인이 무엇인지 확실하지 않지만 열망보다 효율적인 경우 그래프 모드에서 실행되지 않는 이유는 무엇입니까?
user2781994

더 많은 증거를 원하십니까? :) "기본적으로 최상의 실행 성능을 제공하기 위해 모델을 정적 그래프로 컴파일하려고 시도합니다." ( github.com/tensorflow/tensorflow/blob/r2.0/tensorflow/python/… )
user2781994
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.