এই জবাব : টিএফ 2 বনাম টিএফ 1 ট্রেন লুপস, ইনপুট ডেটা প্রসেসর এবং ইজিয়ার বনাম গ্রাফ মোড মৃত্যুদন্ড সহ ইস্যুটির একটি বিশদ, গ্রাফ / হার্ডওয়্যার-স্তরের বর্ণনা সরবরাহ করার লক্ষ্য। ইস্যুটির সংক্ষিপ্তসার এবং সমাধানের দিকনির্দেশগুলির জন্য, আমার অন্যান্য উত্তর দেখুন।
পারফরম্যান্স ভারডিক্ট : কনফিগারেশনের উপর নির্ভর করে কখনও কখনও একটি দ্রুত হয়, কখনও কখনও অন্যটি। টিএফ 2 বনাম টিএফ 1 যতদূর যায়, তারা গড়ে প্রায় সমান, তবে উল্লেখযোগ্য কনফিগারেশন ভিত্তিক পার্থক্য রয়েছে এবং টিএফ 1 টিএফ 2 এর বিপরীতে প্রায়শই ট্রাম্প করে। নীচে "বেনমার্কিং" দেখুন।
ইগর ভি.এস. গ্রাফ : কারওর জন্য এই পুরো উত্তরের মাংস: আমার পরীক্ষার অনুসারে টিএফ 2 এর উত্সাহ টিএফ 1 এর চেয়ে ধীর । আরও নিচে বিশদ।
উভয়ের মধ্যে মৌলিক পার্থক্য হ'ল গ্রাফ একটি গণনামূলক নেটওয়ার্ককে সক্রিয়ভাবে সেট আপ করে, এবং 'যখন' বলা হয় তখন কার্যকর করে - যেখানে অ্যাজিয়ার সমস্ত কিছু তৈরির পরে চালায়। তবে গল্পটি এখানেই শুরু হয়:
আগ্রহী গ্রাফ থেকে বঞ্চিত নয় এবং বাস্তবে প্রত্যাশার বিপরীতে বেশিরভাগ গ্রাফ হতে পারে । এটি মূলত যা হয়, তা কার্যকর করা হয় গ্রাফ - এর মধ্যে গ্রাফের একটি দুর্দান্ত অংশ সমন্বিত মডেল এবং অপ্টিমাইজার ওজন অন্তর্ভুক্ত।
উত্সাহী কার্যকর করার সময় নিজস্ব গ্রাফের কিছু অংশ পুনর্নির্মাণ করে ; গ্রাফ সম্পূর্ণরূপে নির্মিত না হওয়ার প্রত্যক্ষ পরিণতি - প্রোফাইলার ফলাফল দেখুন। এটি একটি গণনামূলক ওভারহেড আছে
আগ্রহী ধীর ডাব্লু / নম্পি ইনপুট ; প্রতি এই গীত মন্তব্য & কোড, উৎসুক মধ্যে Numpy ইনপুট CPU- র থেকে GPU এ tensors অনুলিপি ওভারহেড খরচ অন্তর্ভুক্ত। উত্স কোডের মাধ্যমে পদক্ষেপ, ডেটা হ্যান্ডলিংয়ের পার্থক্য পরিষ্কার; আগ্রহী সরাসরি নম্পিকে পাস করেন, যখন গ্রাফ টেনারগুলি পাস করেন যা নম্পিকে মূল্যায়ন করে; সঠিক প্রক্রিয়া সম্পর্কে অনিশ্চিত, তবে পরে জিপিইউ-স্তরীয় অপ্টিমাইজেশান জড়িত করা উচিত
TF2 আগ্রহী ধীর TF1 উৎসুক চেয়ে - এই অপ্রত্যাশিত হয় ...। নীচে বেঞ্চমার্কিং ফলাফল দেখুন। পার্থক্যগুলি নগন্য থেকে তাৎপর্যপূর্ণ পর্যন্ত বিস্তৃত, তবে ধারাবাহিক। বিষয়টি কেন নিশ্চিত না - যদি কোনও টিএফ দেব স্পষ্ট করে, উত্তর আপডেট করবে।
টিএফ 2 বনাম টিএফ 1 : কোনও টিএফ দেবের প্রাসঙ্গিক অংশের উদ্ধৃতি দিয়ে, প্র। স্কট জু এর প্রতিক্রিয়া - আমার জোরের কিছুটা / পুনর্নির্মাণ:
আগ্রহীভাবে, রানটাইমের জন্য অপ্সটি কার্যকর করতে হবে এবং পাইথন কোডের প্রতিটি লাইনের সংখ্যাসূচক মানটি ফিরিয়ে আনতে হবে। একক পদক্ষেপ কার্যকরকরণের প্রকৃতি এটিকে ধীর করে দেয় ।
টিএফ 2-এ, কেরাস প্রশিক্ষণ, স্পষ্ট এবং পূর্বাভাসের জন্য এর গ্রাফটি তৈরি করতে tf.function ব্যবহার করে। আমরা তাদেরকে মডেলটির জন্য "এক্সিকিউশন ফাংশন" বলি। টিএফ 1 এ, "এক্সিকিউশন ফাংশন" ছিল একটি ফানকগ্রাফ, যা কিছু সাধারণ উপাদানকে টিএফ ফাংশন হিসাবে ভাগ করে নিয়েছিল, তবে এটির একটি আলাদা বাস্তবায়ন রয়েছে।
প্রক্রিয়া চলাকালীন, আমরা কোনওভাবে ট্রেন_ন_বাচ (), টেস্ট_ন_বাচ () এবং ভবিষ্যদ্বাণী_অন_বাচে () এর জন্য একটি ভুল বাস্তবায়ন রেখে দিয়েছি । তারা এখনও সংখ্যাগতভাবে সঠিক , তবে x_on_batch এর জন্য এক্সিকিউশন ফাংশনটি একটি tf.function মোড়ক পাইথন ফাংশনটির পরিবর্তে খাঁটি পাইথন ফাংশন। এর ফলে মন্থরতা দেখা দেবে
টিএফ 2-তে, আমরা সমস্ত ইনপুট ডেটাকে tf.data.Dataset এ রূপান্তর করি, যার মাধ্যমে আমরা একক প্রকারের ইনপুটগুলি পরিচালনা করতে আমাদের এক্সিকিউশন ফাংশনটি একীভূত করতে পারি। ডেটাসেট রূপান্তরটিতে কিছু ওভারহেড থাকতে পারে এবং আমি মনে করি যে এটি প্রতি-ব্যাচের ব্যয়ের পরিবর্তে এক সময়ের একমাত্র ওভারহেড is
উপরের শেষ অনুচ্ছেদের শেষ বাক্য এবং নীচের অনুচ্ছেদের শেষ ধারা সহ:
উত্সাহী মোডে অলসতা কাটিয়ে উঠতে, আমাদের কাছে @ tf.function আছে, যা একটি অজগর ফাংশনটিকে গ্রাফে পরিণত করবে। যখন এনপি অ্যারের মত সংখ্যাসূচক মান ফিড করা হয়, তখন tf.function এর বডিটি স্ট্যাটিক গ্রাফে রূপান্তরিত হয়, অনুকূলিত হয় এবং চূড়ান্ত মানটি ফেরত দেয় যা দ্রুত এবং TF1 গ্রাফ মোডের মতো অনুরূপ পারফরম্যান্স থাকা উচিত।
আমি একমত নই - আমার প্রোফাইলিং ফলাফল অনুসারে, যা গ্রাহকের চেয়ে ইনগ্রের ডেটা প্রসেসিং যথেষ্ট গতিতে দেখায়। এছাড়াও, tf.data.Dataset
বিশেষভাবে সম্পর্কে অনিশ্চিত , তবে ইজিগার বারবার একই ডেটা রূপান্তর পদ্ধতির একাধিক কল করেন - প্রোফাইলার দেখুন।
শেষ অবধি, দেবের সংযুক্ত প্রতিশ্রুতি: কেরাস ভি 2 লুপগুলিকে সমর্থন করার জন্য উল্লেখযোগ্য সংখ্যক পরিবর্তন ।
ট্রেন লুপস : উপর নির্ভর করে (1) আগ্রহী বনাম গ্রাফ; (২) ইনপুট ডেটা ফর্ম্যাট, প্রশিক্ষণ একটি স্বতন্ত্র ট্রেন লুপের সাথে এগিয়ে যাবে - টিএফ 2 _select_training_loop()
, প্রশিক্ষণ.পি , এর মধ্যে একটি:
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
প্রতিটি সম্পদের বরাদ্দকে আলাদাভাবে পরিচালনা করে এবং কার্য সম্পাদন এবং সক্ষমতার উপর পরিণতি বহন করে।
ট্রেন লুপস: fit
বনাম train_on_batch
, keras
বনামtf.keras
: চারটি প্রত্যেকেই পৃথক ট্রেনের লুপ ব্যবহার করে, যদিও সম্ভবত প্রতিটি সম্ভাব্য সংমিশ্রণে তা নয়। keras
' fit
, উদাহরণস্বরূপ, একটি ফর্ম ব্যবহার করে fit_loop
, যেমন training_arrays.fit_loop()
, এবং এটি train_on_batch
ব্যবহার করতে পারে K.function()
।tf.keras
পূর্ববর্তী বিভাগে অংশে বর্ণিত আরও পরিশীলিত শ্রেণিবিন্যাস রয়েছে।
ট্রেন লুপস: ডকুমেন্টেশন - প্রাসঙ্গিক বিভিন্ন কার্যকরকরণ পদ্ধতির কয়েকটিতে উত্স ডক্ট্রিং :
অন্যান্য টেনসরফ্লো অপারেশনের মতো আমরা পাইথন সংখ্যাসূচক ইনপুটগুলিকে টেনসারে রূপান্তর করি না। অধিকন্তু, প্রতিটি স্বতন্ত্র পাইথন সংখ্যাসূচক মানের জন্য একটি নতুন গ্রাফ তৈরি করা হয়
function
ইনপুট আকার এবং ডেটাটাইপগুলির প্রতিটি অনন্য সেটের জন্য একটি পৃথক গ্রাফ ইনস্ট্যান্ট করে ।
একটি একক tf.function অবজেক্ট হুড অধীনে একাধিক গণনা গ্রাফ মানচিত্র করা প্রয়োজন হতে পারে। এটি কেবল পারফরম্যান্স হিসাবে দৃশ্যমান হওয়া উচিত (ট্রেসিং গ্রাফগুলির একটি ননজারো কম্পিউটেশনাল এবং মেমরির ব্যয় রয়েছে )
ইনপুট ডেটা প্রসেসর : উপরের মতো, প্রসেসর কেস-বাই-কেস নির্বাচিত হয়, রানটাইম কনফিগারেশন (এক্সিকিউশন মোড, ডেটা ফর্ম্যাট, বিতরণ কৌশল) অনুযায়ী সেট করা অভ্যন্তরীণ পতাকাগুলির উপর নির্ভর করে case ইজিয়ারের সাথে সবচেয়ে সহজ কেসটি সরাসরি ডাব্লু / নম্পি অ্যারে কাজ করে। কিছু নির্দিষ্ট উদাহরণের জন্য, এই উত্তরটি দেখুন ।
মডেল সাইজ, ডেটা সাইজ:
- সিদ্ধান্ত গ্রহণকারী; কোনও একক কনফিগারেশন সমস্ত মডেল এবং ডেটা মাপের উপরে নিজেকে মুকুটযুক্ত করে না।
- মডেলের আকারের সাথে সম্পর্কিত ডেটার আকার গুরুত্বপূর্ণ; ছোট ডেটা এবং মডেলের জন্য, ডেটা ট্রান্সফার (যেমন সিপিইউতে জিপিইউ) ওভারহেড আধিপত্য করতে পারে। তেমনিভাবে, ছোট ওভারহেড প্রসেসরগুলি ডেমোর রূপান্তর সময়কে প্রাধান্য দিয়ে বড় ডেটার উপর ধীর গতিতে চলতে পারে (
convert_to_tensor
"প্রোফিলার" দেখুন)
- প্রতি ট্রেনের লুপ 'এবং ইনপুট ডেটা প্রসেসরের' সংস্থানগুলি সংস্থান করার বিভিন্ন উপায়ের সাথে গতি আলাদা হয়।
বেঞ্চমার্কস : পিষিত মাংস - ওয়ার্ড ডকুমেন্ট - এক্সেল স্প্রেডশিট
পরিভাষা :
- % -বিহীন সংখ্যাগুলি সমস্ত সেকেন্ড
- % হিসাবে গণনা
(1 - longer_time / shorter_time)*100
; যুক্তিপূর্ণ: আমরা আগ্রহী হন ফ্যাক্টর কি দ্বারা অন্য একটি তুলনায় দ্রুততর হয়; shorter / longer
আসলে একটি অ-রৈখিক সম্পর্ক, সরাসরি তুলনার জন্য কার্যকর নয়
- % স্বাক্ষর সংকল্প:
- টিএফ 2 বনাম টিএফ 1: টিএফ 2
+
দ্রুত হলে
- জিভিই (গ্রাফ বনাম আগ্রহী): গ্রাফটি
+
যদি দ্রুত হয়
- টিএফ 2 = টেনসরফ্লো ২.০.০ + কেরাস ২.৩.১; টিএফ 1 = টেনসরফ্লো 1.14.0 + কেরাস 2.2.5
প্রোফিলার :
প্রোফেলার - ব্যাখ্যা : স্পাইডার 3.3.6 আইডিই প্রোফাইলার।
কিছু ফাংশন অন্যের বাসাতে পুনরাবৃত্তি হয়; অতএব, "ডেটা প্রক্রিয়াকরণ" এবং "প্রশিক্ষণ" ফাংশনগুলির মধ্যে সঠিক বিভাজনটি সন্ধান করা শক্ত, সুতরাং কিছুটা ওভারল্যাপ থাকবে - যেমনটি খুব শেষ ফলাফলে উচ্চারণ করা হয়েছে।
% পরিসংখ্যান গণনা করা আর্ট রানটাইম মাইনাস বিল্ড টাইম
- 1 বা 2 বার ডাকা হত এমন সমস্ত (অনন্য) রানটাইমকে সংযুক্ত করে সময় তৈরির সময় নির্ধারণ করুন
- ট্রেনের সময়কে সমস্ত (অনন্য) রানটাইম সংযুক্ত করে গণনা করা হয় যা পুনরাবৃত্তির # এর সমান # বার বলা হত, এবং তাদের কিছু নেস্টের রানটাইম
- দুর্ভাগ্যক্রমে (যেমন প্রোফাইল হিসাবে চিহ্নিত করা হবে ) তাদের মূল নামগুলি অনুসারে ফাংশনগুলি প্রোফাইল করা হয় , যা নির্মাণের সময় মিশে যায় - সুতরাং এটি বাদ দিতে হবে
_func = func
func
পরীক্ষার পরিবেশ :
- নীচে ডাব্লু / ন্যূনতম পটভূমির কাজগুলি চালিত কোড
- এই পোস্টে প্রস্তাবিত সময় অনুসারে পুনরাবৃত্তির আগে জিপিইউ "ওয়ার্ম আপ" হয়েছিল / পুনরুদ্ধার করার কয়েক ঘন্টা আগে ite
- CUDA 10.0.130, cuDNN 7.6.0, টেনসরফ্লো 1.14.0, এবং টেনসরফ্লো 2.0.0 উত্স থেকে নির্মিত, অ্যানাকোন্ডা
- পাইথন 3.7.4, স্পাইডার 3.3.6 আইডিই
- জিটিএক্স 1070, উইন্ডোজ 10, 24 জিবি ডিডিআর 4 2.4-মেগাহার্টজ র্যাম, আই 7-7700 এইচকিউ 2.8-গিগাহার্টজ সিপিইউ
পদ্ধতি :
- বেঞ্চমার্ক 'ছোট', 'মাঝারি', এবং 'বৃহত্তর' মডেল এবং ডেটা মাপ
- ইনপুট ডেটার আকারের চেয়ে পৃথক প্রতিটি মডেলের আকারের জন্য পরামিতিগুলির # ঠিক করুন
- "বৃহত্তর" মডেলের আরও পরামিতি এবং স্তর রয়েছে
- "বৃহত্তর" ডেটার দীর্ঘতর ক্রম রয়েছে তবে একই
batch_size
এবংnum_channels
- মডেল শুধুমাত্র ব্যবহার
Conv1D
, Dense
'learnable' স্তর; প্রতি টিএফ-সংস্করণ প্রয়োগের জন্য আরএনএনগুলি এড়ানো হয়েছে। পার্থক্য
- মডেল এবং অপ্টিমাইজার গ্রাফ বিল্ডিং বাদ দিতে সর্বদা একটি ট্রেন বেঞ্চমার্কিং লুপের বাইরে চলে
- স্পার্স ডেটা (উদাঃ
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)