Tại sao TensorFlow 2 chậm hơn nhiều so với TensorFlow 1?


137

Nó được nhiều người dùng trích dẫn là lý do để chuyển sang Pytorch, nhưng tôi vẫn chưa tìm thấy lời biện minh / giải thích cho việc hy sinh chất lượng thực tế quan trọng nhất, tốc độ, để thực hiện háo hức.

Dưới đây là hiệu suất điểm chuẩn mã, TF1 so với TF2 - với TF1 chạy nhanh hơn từ 47% đến 276% .

Câu hỏi của tôi là: nó là gì, ở cấp độ đồ thị hoặc phần cứng, mang lại sự chậm lại đáng kể như vậy?


Tìm kiếm một câu trả lời chi tiết - đã quen thuộc với các khái niệm rộng. Git có liên quan

Thông số kỹ thuật : CUDA 10.0.130, cuDNN 7.4.2, Python 3.7.4, Windows 10, GTX 1070


Kết quả điểm chuẩn :


CẬP NHẬT : Vô hiệu hóa thực thi háo hức cho mỗi mã dưới đây không giúp đỡ. Tuy nhiên, hành vi không nhất quán: đôi khi chạy trong chế độ biểu đồ giúp đáng kể, những lần khác nó chạy chậm hơn so với Eager.

Vì các nhà phát triển TF không xuất hiện ở bất cứ đâu, tôi sẽ tự mình điều tra vấn đề này - có thể theo dõi tiến trình trong vấn đề Github được liên kết.

CẬP NHẬT 2 : tấn kết quả thử nghiệm để chia sẻ, cùng với lời giải thích; nên được thực hiện ngày hôm nay.


Mã điểm chuẩn :

# 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)

Các chức năng được sử dụng :

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))

Bạn đã bao giờ sử dụng cProfile loại công cụ như vậy để phân tích phần nào làm cho chúng khác nhau như vậy chưa?
zihaozhihao 18/10/19

@zihaozhihao Tôi có , mặc dù không phải vì điều này cụ thể; trên mỗi liên kết trước đó và viết một trình tối ưu hóa tùy chỉnh, tôi đã quen với sự khác biệt trong các cuộc gọi, nhưng không hiểu tại sao cái này chậm hơn cái kia - cũng không phải bất kỳ chuyên gia không phải TF nào cũng hiểu nó từ nguồn, mà trên hết là một mớ hỗn độn, không tài liệu biểu diễn tương đối. Yêu cầu intel ở cấp độ đồ thị / phần cứng, mà các trình biên dịch sẽ không cung cấp (theo như tôi có thể sử dụng chúng)
OverLordGoldDragon

phiên bản numpy giống nhau trong cả hai thử nghiệm?
chabir

Ouch .... Nếu một mình Keras cũ đã chậm hơn đáng kể so với PyTorch, hãy tưởng tượng ngay bây giờ.
Daniel Möller

quy mô vấn đề với kích thước mô hình? bạn cũng đã thử chạy điểm chuẩn tương tự trên các hệ điều hành khác chưa?
okawo

Câu trả lời:


76

CẬP NHẬT 18/2/2020 : Tôi đã chuẩn bị 2.1 và 2.1 mỗi đêm; kết quả là hỗn hợp. Tất cả trừ một cấu hình (mô hình & kích thước dữ liệu) đều nhanh bằng hoặc nhanh hơn nhiều so với mức tốt nhất của TF2 & TF1. Cái chậm hơn và chậm hơn đáng kể là Large-Large - đặc biệt. trong thực thi đồ thị ( chậm hơn 1.6x đến 2.5x ).

Hơn nữa, có sự khác biệt về độ tái lập cực kỳ giữa Đồ thị và Háo hức đối với một mô hình lớn mà tôi đã thử nghiệm - một mô hình không thể giải thích được thông qua tính ngẫu nhiên / tính toán song song. Hiện tại tôi không thể trình bày mã có thể lặp lại cho các yêu cầu này theo các ràng buộc về thời gian, vì vậy thay vào đó tôi thực sự khuyên bạn nên thử nghiệm mã này cho các mô hình của riêng bạn.

Chưa mở một vấn đề Git nào về vấn đề này, nhưng tôi đã nhận xét về bản gốc - chưa có phản hồi nào. Tôi sẽ cập nhật (các) câu trả lời sau khi tiến trình được thực hiện.


XÁC MINH : không , NẾU bạn biết bạn đang làm gì. Nhưng nếu bạn không , nó có thể khiến bạn mất rất nhiều chi phí - bằng một vài lần nâng cấp GPU trung bình và trong trường hợp xấu nhất là nhiều GPU.


TRẢ LỜI NÀY : nhằm mục đích cung cấp một mô tả cấp cao về vấn đề, cũng như các hướng dẫn về cách quyết định cấu hình đào tạo cụ thể theo nhu cầu của bạn. Để biết mô tả chi tiết, mức độ thấp, bao gồm tất cả các kết quả điểm chuẩn + mã được sử dụng, hãy xem câu trả lời khác của tôi.

Tôi sẽ cập nhật (các) câu trả lời của mình với thông tin khác nếu tôi tìm hiểu bất kỳ - có thể đánh dấu / "sao" câu hỏi này để tham khảo.


TÓM TẮT VẤN ĐỀ : như được xác nhận bởi nhà phát triển TensorFlow, Q. Scott Zhu, TF2 tập trung phát triển vào thực thi Eager & tích hợp chặt chẽ w / Keras, liên quan đến việc quét các thay đổi trong nguồn TF - kể cả ở cấp độ đồ thị. Lợi ích: mở rộng đáng kể khả năng xử lý, phân phối, gỡ lỗi và triển khai. Chi phí của một số trong số này, tuy nhiên, là tốc độ.

Vấn đề, tuy nhiên, là khá phức tạp. Đó không chỉ là TF1 so với TF2 - các yếu tố mang lại sự khác biệt đáng kể về tốc độ tàu hỏa bao gồm:

  1. TF2 so với TF1
  2. Chế độ háo hức so với chế độ đồ thị
  3. keras so với tf.keras
  4. numpyso tf.data.Datasetvới ...
  5. train_on_batch() so với fit()
  6. GPU so với CPU
  7. model(x)so model.predict(x)với ...

Thật không may, hầu như không có cái nào ở trên độc lập với cái kia và mỗi cái ít nhất có thể gấp đôi thời gian thực hiện so với cái khác. May mắn thay, bạn có thể xác định những gì sẽ hoạt động tốt nhất một cách có hệ thống và với một vài phím tắt - như tôi sẽ trình bày.


TÔI NÊN LÀM GÌ? Hiện tại, cách duy nhất là - thử nghiệm cho mô hình, dữ liệu và phần cứng cụ thể của bạn. Không cấu hình duy nhất sẽ luôn luôn làm việc tốt nhất - nhưng có được làm và không là để đơn giản hóa việc tìm kiếm của bạn:

>> LÀM:

  • train_on_batch()+ numpy+ tf.keras+ TF1 + Háo hức / Đồ thị
  • train_on_batch()+ numpy+ tf.keras+ TF2 + Đồ thị
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + Đồ thị + mô hình & dữ liệu lớn

>> KHÔNG:

  • fit()+ numpy+ kerascho các mô hình và dữ liệu vừa và nhỏ
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + Háo hức
  • train_on_batch()+ numpy+ keras+ TF1 + Háo hức

  • [Thiếu tá] tf.python.keras ; nó có thể chạy chậm hơn 10 - 100 lần và có rất nhiều lỗi; thêm thông tin

    • Điều này bao gồm layers, models, optimizers, & liên quan "out-of-box" nhập khẩu sử dụng; ops, utils, và nhập khẩu 'tư nhân' có liên quan đều ổn - nhưng để chắc chắn, hãy kiểm tra alts, và liệu chúng có được sử dụng trongtf.keras

Tham khảo mã ở cuối câu trả lời khác của tôi để biết thiết lập điểm chuẩn mẫu. Danh sách trên chủ yếu dựa trên các bảng "LỢI ÍCH" trong câu trả lời khác.


GIỚI HẠN của DO & DON'T trên:

  • Câu hỏi này có tiêu đề "Tại sao TF2 chậm hơn nhiều so với TF1?", Và trong khi cơ thể của nó liên quan đến việc đào tạo một cách rõ ràng, vấn đề không giới hạn ở nó; suy luận cũng vậy, có thể có sự khác biệt lớn về tốc độ, ngay cả trong cùng một phiên bản TF, nhập, định dạng dữ liệu, v.v. - xem câu trả lời này .
  • Các RNN có khả năng thay đổi đáng kể lưới dữ liệu trong câu trả lời khác, vì chúng đã được cải thiện trong TF2
  • Các mô hình được sử dụng chủ yếu Conv1DDense- không có RNN, dữ liệu / mục tiêu thưa thớt, đầu vào 4 / 5D và các cấu hình khác
  • Dữ liệu đầu vào giới hạn numpytf.data.Dataset, trong khi nhiều định dạng khác tồn tại; xem câu trả lời khác
  • GPU đã được sử dụng; kết quả sẽ khác nhau trên CPU. Trong thực tế, khi tôi đặt câu hỏi, CUDA của tôi không được cấu hình đúng và một số kết quả dựa trên CPU.

Tại sao TF2 hy sinh chất lượng, tốc độ thực tế nhất để thực hiện háo hức? Rõ ràng là không có - đồ thị vẫn có sẵn. Nhưng nếu câu hỏi là "tại sao háo hức cả":

  • Gỡ lỗi cao cấp : bạn có thể gặp vô số câu hỏi hỏi "làm thế nào để tôi có được kết quả đầu ra của lớp trung gian" hoặc "làm cách nào để kiểm tra trọng số"; với sự háo hức, nó (gần như) đơn giản như .__dict__. Ngược lại, đồ thị đòi hỏi phải làm quen với các chức năng phụ trợ đặc biệt - làm phức tạp đáng kể toàn bộ quá trình gỡ lỗi & hướng nội.
  • Tạo mẫu nhanh hơn : theo ý tưởng tương tự như trên; hiểu nhanh hơn = nhiều thời gian hơn cho DL thực tế.

LÀM THẾ NÀO ĐỂ ENAGER / DISABLE?

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

THÔNG TIN BỔ SUNG :

  • Cẩn thận với _on_batch()các phương pháp trong TF2; Theo nhà phát triển TF, họ vẫn sử dụng triển khai chậm hơn, nhưng không cố ý - tức là nó đã được sửa. Xem câu trả lời khác để biết chi tiết.

YÊU CẦU ĐỂ THIẾT BỊ TENSORFLOW :

  1. Vui lòng sửa train_on_batch()và khía cạnh hiệu suất của việc gọi fit()lặp; vòng lặp tàu tùy chỉnh là quan trọng đối với nhiều người, đặc biệt là đối với tôi.
  2. Thêm tài liệu / tài liệu đề cập đến những khác biệt về hiệu suất này cho kiến ​​thức của người dùng.
  3. Cải thiện tốc độ thực hiện chung để giữ cho peeps không nhảy sang Pytorch.

LỜI CẢM ƠN : Nhờ


CẬP NHẬT :

  • 14/11/19 - đã tìm thấy một mô hình (trong ứng dụng thực tế của tôi) chạy chậm hơn trên TF2 cho tất cả các cấu hình * với dữ liệu đầu vào Numpy. Sự khác biệt dao động 13-19%, trung bình 17%. Sự khác biệt giữa kerastf.keras, tuy nhiên, kịch tính hơn: 18-40% , avg. 32% (cả TF1 & 2). (* - ngoại trừ Háo hức, mà TF2 OOM'd)

  • 17/11/19 - các nhà phát triển đã cập nhật on_batch()các phương thức trong một cam kết gần đây , cho biết đã cải thiện tốc độ - sẽ được phát hành trong TF 2.1, hoặc hiện có sẵn dưới dạng tf-nightly. Vì tôi không thể chạy sau, sẽ trì hoãn việc chuẩn bị cho đến 2.1.

  • 20/2/20 - hiệu suất dự đoán cũng có giá trị; trong TF2, ví dụ, thời gian dự đoán CPU có thể liên quan đến đột biến định kỳ

3
Thế còn fit_generator? ... Tôi hầu như không bao giờ muốn train_on_batchvà quản lý vòng lặp đào tạo của riêng mình qua các đợt là một mô hình chống lớn, rất lớn cần phải tránh ngay cả với chi phí lớn.
ely

@ely Nó vẫn còn phải được kiểm tra, như đã lưu ý trong câu trả lời khác của tôi - nhưng nếu có bất cứ điều gì tôi dự đoán thì nó sẽ là fitchi phí xử lý dữ liệu bổ sung nhỏ. Đối với các vòng lặp xe lửa, tôi đã viết một tùy chỉnh của riêng mình mà cuối cùng đã biến thành một loại API; fit_generatorthiếu tính hướng nội, khả năng tùy biến và lưu / tải - vì vậy tôi không phải là một người tuyệt đối. Cuối cùng tôi sẽ xuất bản vòng lặp đào tạo của mình, trên Github.
OverLordGoldDragon

Thiếu nội tâm và khả năng tùy biến là một tính năng đối với tôi, không phải là một lỗi. IDK những gì bình luận lưu / tải đang đề cập đến? Lưu / tải trung gian trong một vòng lặp không được điều khiển bởi trình tạo dữ liệu? (Cá nhân tôi cũng rất vui khi chỉ dựa vào các cuộc gọi lại cho điều đó, và sẽ thấy cần bất kỳ khả năng tùy chỉnh nào nữa vì mùi mã mà vòng lặp đào tạo của tôi được thiết kế sai).
ely

@ely Điều đó không đơn giản, nhưng nó cần thiết cho việc đào tạo các đường ống dữ liệu đầu vào phức tạp, các hàm mục tiêu và các cấu hình mô hình không API (ví dụ như các bản hòa tấu). Introspection là phải cho nhiều mục đích kỹ thuật gỡ lỗi và tính năng. Thiếu một lưu / tải bên ngoài, và khả năng tạm dừng vòng lặp & khả năng phục hồi cho các mô hình đắt tiền tính toán - một cơn ác mộng. Bất kể, cuối cùng phụ thuộc vào nhu cầu cụ thể của bạn, và lạc đề; cách chắc chắn nhất để kiểm tra hiệu năng với fit_generatorứng dụng của bạn là, kiểm tra nó.
OverLordGoldDragon

47

TRẢ LỜI NÀY : nhằm mục đích cung cấp một mô tả chi tiết, mức độ đồ thị / phần cứng của vấn đề - bao gồm các vòng lặp TF2 so với TF1, bộ xử lý dữ liệu đầu vào và thực thi chế độ Eager so với đồ thị. Để biết tóm tắt về vấn đề và hướng dẫn giải quyết, hãy xem câu trả lời khác của tôi.


XÁC MINH THỰC HIỆN : đôi khi cái này nhanh hơn, đôi khi cái kia, tùy thuộc vào cấu hình. Theo như TF2 so với TF1, họ trung bình ngang nhau, nhưng sự khác biệt đáng kể dựa trên cấu hình vẫn tồn tại và TF1 vượt qua TF2 thường xuyên hơn so với ngược lại. Xem "LỢI ÍCH" bên dưới.


EAGER VS. GRAPH : phần cốt lõi của toàn bộ câu trả lời này đối với một số người: Sự háo hức của TF2 chậm hơn so với TF1, theo thử nghiệm của tôi. Chi tiết tiếp tục xuống.

Sự khác biệt cơ bản giữa hai loại này là: Đồ thị thiết lập một mạng tính toán một cách chủ động và thực thi khi được 'nói với' - trong khi Eager thực thi mọi thứ khi tạo. Nhưng câu chuyện chỉ bắt đầu từ đây:

  • Háo hức KHÔNG phải là không có đồ thị , và trên thực tế có thể chủ yếu là đồ thị, trái với dự đoán. Phần lớn là gì, được thực hiện Biểu đồ - bao gồm trọng lượng mô hình & tối ưu hóa, bao gồm một phần lớn của biểu đồ.

  • Háo hức xây dựng lại một phần của đồ thị riêng khi thực hiện ; hậu quả trực tiếp của đồ thị không được xây dựng đầy đủ - xem kết quả hồ sơ. Điều này có một chi phí tính toán.

  • Háo hức là đầu vào w / Numpy chậm hơn ; theo nhận xét và mã Git này , các đầu vào Numpy trong Eager bao gồm chi phí đầu tư sao chép các bộ căng từ CPU sang GPU. Bước qua mã nguồn, sự khác biệt xử lý dữ liệu là rõ ràng; Háo hức trực tiếp vượt qua Numpy, trong khi đồ thị vượt qua các tenxơ mà sau đó đánh giá thành Numpy; không chắc chắn về quy trình chính xác, nhưng sau đó sẽ liên quan đến tối ưu hóa mức GPU

  • TF2 Eager chậm hơn TF1 Eager - điều này ... thật bất ngờ. Xem kết quả điểm chuẩn dưới đây. Sự khác biệt kéo dài từ không đáng kể đến đáng kể, nhưng là nhất quán. Không chắc chắn tại sao lại như vậy - nếu một nhà phát triển TF làm rõ, sẽ cập nhật câu trả lời.


TF2 so với TF1 : trích dẫn các phần có liên quan của một nhà phát triển TF, Q. Scott Zhu, phản hồi - với sự nhấn mạnh và viết lại của tôi:

Trong háo hức, bộ thực thi cần thực thi các op và trả về giá trị số cho mỗi dòng mã python. Bản chất của thực hiện bước đơn làm cho nó bị chậm .

Trong TF2, Keras tận dụng tf.feft để xây dựng biểu đồ của nó để đào tạo, đánh giá và dự đoán. Chúng tôi gọi chúng là "hàm thực thi" cho mô hình. Trong TF1, "hàm thực thi" là một FuncGraph, chia sẻ một số thành phần phổ biến là hàm TF, nhưng có cách triển khai khác.

Trong quá trình này, bằng cách nào đó, chúng tôi đã để lại một triển khai không chính xác cho train_on_batch (), test_on_batch () và dự đoán_on_batch () . Chúng vẫn đúng về mặt số , nhưng hàm thực thi cho x_on_batch là một hàm python thuần, chứ không phải là hàm python được bọc bởi tf.feft. Điều này sẽ gây ra sự chậm chạp

Trong TF2, chúng tôi chuyển đổi tất cả dữ liệu đầu vào thành tf.data.Dataset, qua đó chúng tôi có thể thống nhất chức năng thực thi của mình để xử lý loại đầu vào duy nhất. Có thể có một số chi phí trong quá trình chuyển đổi tập dữ liệu và tôi nghĩ rằng đây chỉ là chi phí một lần duy nhất, thay vì chi phí mỗi đợt

Với câu cuối cùng của đoạn cuối ở trên và mệnh đề cuối của đoạn dưới đây:

Để khắc phục sự chậm chạp trong chế độ háo hức, chúng ta có @ tf.feft, nó sẽ biến một hàm python thành một biểu đồ. Khi cung cấp giá trị số như mảng np, phần thân của tf.feft được chuyển đổi thành biểu đồ tĩnh, được tối ưu hóa và trả về giá trị cuối cùng, nhanh và có hiệu suất tương tự như chế độ đồ thị TF1.

Tôi không đồng ý - theo kết quả hồ sơ của tôi, cho thấy quá trình xử lý dữ liệu đầu vào của Đại bàng chậm hơn đáng kể so với đồ thị. Ngoài ra, không chắc chắn về tf.data.Datasetcụ thể, nhưng Eager liên tục gọi nhiều phương thức chuyển đổi dữ liệu giống nhau - xem hồ sơ.

Cuối cùng, cam kết được liên kết của dev: Số lượng thay đổi đáng kể để hỗ trợ các vòng lặp Keras v2 .


Vòng lặp xe lửa : tùy thuộc vào (1) Háo hức so với đồ thị; (2) định dạng dữ liệu đầu vào, đào tạo sẽ tiến hành một vòng lặp tàu riêng biệt - trong TF2 _select_training_loop(),, training.py , một trong:

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

Mỗi xử lý phân bổ tài nguyên khác nhau và chịu hậu quả về hiệu suất và khả năng.


Vòng lặp xe lửa: fitvs train_on_batch, kerasvstf.keras .: mỗi trong số bốn vòng sử dụng các vòng tàu khác nhau, mặc dù có lẽ không phải trong mọi kết hợp có thể. keras' fit, ví dụ, sử dụng một dạng fit_loop, ví dụ training_arrays.fit_loop(), và nó train_on_batchcó thể sử dụng K.function(). tf.kerascó một hệ thống phân cấp phức tạp hơn được mô tả một phần trong phần trước.


Train Loops: tài liệu - chuỗi tài liệu nguồn có liên quan trên một số phương thức thực hiện khác nhau:

Không giống như các hoạt động khác của TensorFlow, chúng tôi không chuyển đổi đầu vào số python thành tenxơ. Hơn nữa, một biểu đồ mới được tạo cho mỗi giá trị số python riêng biệt

function khởi tạo một biểu đồ riêng cho mỗi bộ hình dạng và kiểu dữ liệu đầu vào duy nhất .

Một đối tượng tf.feft có thể cần ánh xạ tới nhiều biểu đồ tính toán dưới mui xe. Điều này chỉ được hiển thị khi hiệu suất (biểu đồ theo dõi có chi phí tính toán và bộ nhớ khác không )


Bộ xử lý dữ liệu đầu vào : tương tự như trên, bộ xử lý được chọn theo từng trường hợp, tùy thuộc vào các cờ bên trong được đặt theo cấu hình thời gian chạy (chế độ thực thi, định dạng dữ liệu, chiến lược phân phối). Trường hợp đơn giản nhất với Eager, hoạt động trực tiếp với mảng Numpy. Đối với một số ví dụ cụ thể, xem câu trả lời này .


KÍCH THƯỚC MÔ HÌNH, KÍCH THƯỚC SỐ LIỆU:

  • Là người quyết đoán; không có cấu hình duy nhất đăng quang chính nó trên tất cả các kích thước mô hình và dữ liệu.
  • Kích thước dữ liệu liên quan đến kích thước mô hình là quan trọng; đối với dữ liệu & mô hình nhỏ, chi phí truyền dữ liệu (ví dụ: CPU sang GPU) có thể chiếm ưu thế. Tương tự, các bộ xử lý nhỏ có thể chạy chậm hơn trên dữ liệu lớn trên mỗi lần thống trị thời gian chuyển đổi dữ liệu (xem convert_to_tensortrong "HỒ SƠ")
  • Tốc độ khác nhau trên các phương tiện xử lý tài nguyên khác nhau của các vòng lặp và bộ xử lý dữ liệu đầu vào.

LỢI ÍCH : thịt xay. - Tài liệu Word - Bảng tính Excel


Thuật ngữ :

  • % -less số là tất cả giây
  • % được tính là (1 - longer_time / shorter_time)*100; lý do: chúng tôi quan tâm bởi yếu tố nào nhanh hơn yếu tố kia; shorter / longerthực sự là một mối quan hệ phi tuyến tính, không hữu ích để so sánh trực tiếp
  • % xác định dấu hiệu:
    • TF2 so với TF1: +nếu TF2 nhanh hơn
    • GvE (Biểu đồ so với háo hức): +nếu Biểu đồ nhanh hơn
  • TF2 = TensorFlow 2.0.0 + Máy ảnh 2.3.1; TF1 = TensorFlow 1.14.0 + Máy ảnh 2.2.5

HỒ SƠ :


HỒ SƠ - Giải thích : Trình biên dịch Spyder 3.3.6 IDE.

  • Một số chức năng được lặp lại trong tổ của những người khác; do đó, thật khó để theo dõi sự phân tách chính xác giữa các chức năng "xử lý dữ liệu" và "đào tạo", do đó sẽ có một số sự chồng chéo - như được phát âm trong kết quả cuối cùng.

  • % số liệu tính toán thời gian chạy wrt trừ thời gian xây dựng

  • Xây dựng thời gian được tính bằng cách tính tổng tất cả các thời gian chạy (duy nhất) được gọi là 1 hoặc 2 lần
  • Thời gian đào tạo được tính bằng cách tính tổng tất cả các thời gian chạy (duy nhất) được gọi là cùng số lần với số lần lặp và một số thời gian chạy của tổ của chúng
  • Các hàm được định hình theo tên gốc của chúng , thật không may (nghĩa là _func = funcsẽ cấu hình như func), kết hợp trong thời gian xây dựng - do đó cần phải loại trừ nó

MÔI TRƯỜNG KIỂM TRA :

  • Mã được thực thi ở dưới cùng với các tác vụ nền tối thiểu đang chạy
  • GPU đã được "làm nóng" với một vài lần lặp trước khi lặp lại thời gian, như được đề xuất trong bài viết này
  • CUDA 10.0.130, cuDNN 7.6.0, TensorFlow 1.14.0 và TensorFlow 2.0.0 được xây dựng từ nguồn, cộng với Anaconda
  • Python 3.7.4, IDE Spyder 3.3.6
  • GTX 1070, Windows 10, RAM 24 GB DDR4 2,4 MHz, CPU i7-7700HQ 2,8 GHz

PHƯƠNG PHÁP :

  • Kích thước mô hình & kích thước dữ liệu 'nhỏ', 'trung bình' và 'lớn'
  • Sửa # tham số cho từng kích thước mô hình, không phụ thuộc vào kích thước dữ liệu đầu vào
  • Mô hình "Lớn hơn" có nhiều tham số và lớp hơn
  • Dữ liệu "Lớn hơn" có chuỗi dài hơn, nhưng giống nhau batch_sizenum_channels
  • Mô hình chỉ sử dụng Conv1D, Densecác lớp 'có thể học được'; RNNs tránh trên mỗi phiên bản TF. sự khác biệt
  • Luôn luôn chạy một chuyến tàu phù hợp bên ngoài vòng lặp điểm chuẩn, để bỏ qua mô hình & trình tối ưu hóa xây dựng biểu đồ
  • Không sử dụng dữ liệu thưa thớt (ví dụ layers.Embedding()) hoặc các mục tiêu thưa thớt (ví dụ:SparseCategoricalCrossEntropy()

GIỚI HẠN : một câu trả lời "hoàn chỉnh" sẽ giải thích mọi vòng lặp và vòng lặp đào tạo có thể, nhưng điều đó chắc chắn vượt quá khả năng thời gian của tôi, tiền lương không tồn tại hoặc sự cần thiết chung. Các kết quả chỉ tốt như phương pháp - giải thích với một tâm trí cởi mở.


:

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)

Tôi không chắc chắn nếu mã của bạn là chính xác. Tôi nghĩ rằng các mô hình của bạn luôn chạy trong chế độ biểu đồ kể từ khi bạn gọi model.compilemà không có run_eagerly=Trueđối số. Nếu ở chế độ háo hức, bạn có thể chạy một phần mã của mình ở chế độ biểu đồ bằng cách sử dụng tf.function. Do đó, tôi nghĩ rằng việc triển khai mặc định compilelà tạo ra biểu đồ tính toán thay vì chạy nó háo hức vì lý do hiệu suất. Cũng lưu ý rằng nếu mô hình của bạn là tích chập thì bạn không thấy tăng tốc trong chế độ đồ thị vì tương tác python là tối thiểu. Nếu bạn làm nhiều phép toán hơn nó có thể tạo ra sự khác biệt lớn (cũng trong việc sử dụng bộ nhớ).
dùng2781994

@OverLordGoldDragon nhưng trong TF 2, chế độ háo hức theo mặc định nhưng model.compilekhông run_eagerly=Trueđảm bảo chế độ đồ thị, hay không?
dùng2781994

@OverLordGoldDragon Tôi đồng ý rằng không phải tất cả các phương thức nhập khẩu đều chạy trong chế độ biểu đồ nhưng tôi nghĩ rằng model.compilehoặc model.fitphải đảm bảo rằng đào tạo chạy trong chế độ biểu đồ bên trong.
dùng2781994

@OverLordGoldDragon TRUE - "tf.keras.Model.compile có ba đối số quan trọng: ... Ngoài ra, để đảm bảo mô hình đào tạo và đánh giá một cách háo hức, bạn có thể đảm bảo chuyển run_eagerly=Truethành tham số để biên dịch." (nguồn tenorflow.org/guide/keras/overview ) Vì vậy, nếu tôi không vượt qua run_eagerly=Truemô hình thì có thể chạy ở chế độ đồ thị. Tôi không chắc yếu tố quyết định là gì nhưng tại sao nó không chạy trong chế độ đồ thị nếu nó hiệu quả hơn háo hức.
dùng2781994

Bạn có muốn thêm bằng chứng? :) "Theo mặc định, chúng tôi sẽ cố gắng biên dịch mô hình của bạn thành một biểu đồ tĩnh để mang lại hiệu suất thực thi tốt nhất." ( github.com/tensorflow/tensorflow/blob/r2.0/tensorflow/python/
mẹo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.