මෙම පිළිතුර : TF2 එදිරිව TF1 දුම්රිය ලූප, ආදාන දත්ත සකසන සහ ඊජර් එදිරිව ප්රස්ථාර ප්රකාර ක්රියාත්මක කිරීම ඇතුළුව ගැටළුව පිළිබඳ සවිස්තරාත්මක, ප්රස්තාර / දෘඩාංග මට්ටමේ විස්තරයක් සැපයීමට අපේක්ෂා කරයි. ගැටළු සාරාංශයක් සහ විසඳුම් මාර්ගෝපදේශ සඳහා, මගේ අනෙක් පිළිතුර බලන්න.
කාර්යසාධන සත්යාපනය : සමහර විට එකක් වේගවත් වේ, සමහර විට වින්යාසය අනුව වෙනස් වේ. TF2 එදිරිව TF1 යන තාක් දුරට, ඒවා සාමාන්යයෙන් සමාන වේ, නමුත් සැලකිය යුතු වින්යාසය මත පදනම් වූ වෙනස්කම් පවතින අතර TF1 TF2 තුරන් කරන්නේ අනෙක් අතට වඩා බොහෝ විට ය. පහත "BENCHMARKING" බලන්න.
ඊගර් වී. ග්රැෆ් : සමහරුන්ට මෙම සම්පූර්ණ පිළිතුරේ මස්: මගේ පරීක්ෂණයට අනුව, ටීඑෆ් 2 හි උනන්දුව ටීඑෆ් 1 ට වඩා මන්දගාමී ය. විස්තර තවදුරටත් පහළට.
ඒ දෙක අතර මූලික වෙනස වන්නේ: ප්රස්තාරය ඉතා පරිගණකමය ජාලය සකසනු ලබයි සක්රීය ලෙස , හා ඉටු කරන 'වෙත පවසා' විට - ෙහයින්ද, හැම දෙයක්ම නිර්මාණය මත ආසක්ත ඉටු. නමුත් කතාව ආරම්භ වන්නේ මෙතැනින් පමණි:
ඊජර් ප්රස්ථාරයෙන් බැහැර නොවන අතර ඇත්ත වශයෙන්ම අපේක්ෂාවට පටහැනිව බොහෝ විට ප්රස්ථාරය විය හැකිය . එය බොහෝ දුරට ක්රියාත්මක වන ප්රස්ථාරය - මෙයට ප්රස්ථාරයේ විශාල කොටසක් ඇතුළත් වන ආකෘති සහ ප්රශස්තිකරණ බර ඇතුළත් වේ.
උනන්දුවෙන් ක්රියාත්මක කිරීමේදී තමන්ගේම ප්රස්ථාරයක කොටසක් නැවත ගොඩනඟයි ; ප්රස්ථාරය සම්පූර්ණයෙන් ගොඩනගා නොතිබීමේ සෘජු ප්රතිවිපාකය - පැතිකඩ ප්රති .ල බලන්න. මෙය පරිගණකමය පොදු කාර්යයක් ඇත.
උනන්දුව මන්දගාමී w / Numpy යෙදවුම් ; එක් මෙම Git අදහස් සහ කේතය, ආසක්ත දී Numpy යෙදවුම් දක්වන GPU CPU ගෙන් tensors පිටපත් කිරීමේ පොදු කාර්ය පිරිවැය වේ. ප්රභව කේතය හරහා පියවර, දත්ත හැසිරවීමේ වෙනස්කම් පැහැදිලිය; ඊජර් කෙලින්ම නැම්පි පසුකර යන අතර ප්රස්ථාරය ආතතීන් පසුකර නැම්පි වෙත තක්සේරු කරයි; නිශ්චිත ක්රියාවලිය පිළිබඳ අවිනිශ්චිත, නමුත් දෙවැන්න GPU මට්ටමේ ප්රශස්තිකරණයට සම්බන්ධ විය යුතුය
TF2 Eager TF1 Eager වලට වඩා මන්දගාමී වේ - මෙය ... අනපේක්ෂිතයි. මිණුම් සලකුණු ප්රති results ල පහත බලන්න. වෙනස්කම් නොසැලකිලිමත් සිට සැලකිය යුතු දක්වා විහිදේ, නමුත් අනුකූල වේ. එය එසේ වන්නේ මන්දැයි සැක සහිතයි - TF dev පැහැදිලි කරන්නේ නම්, පිළිතුර යාවත්කාලීන වේ.
TF2 එදිරිව TF1 : TF dev ගේ, Q. ස්කොට් ෂුගේ, ප්රතිචාර - මගේ අවධාරණයෙන් හා නැවත ලිවීමේ අදාළ කොටස් උපුටා දක්වමින් :
උනන්දුවෙන්, ධාවන කාලයට ඔප්ස් ක්රියාත්මක කර පයිතන් කේතයේ සෑම පේළියක් සඳහාම සංඛ්යාත්මක අගය ලබා දිය යුතුය. තනි පියවර ක්රියාත්මක කිරීමේ ස්වභාවය එය මන්දගාමී වීමට හේතු වේ .
TF2 හි, කෙරස් පුහුණුව, එවාල් සහ පුරෝකථනය සඳහා සිය ප්රස්ථාරය තැනීම සඳහා tf.function භාවිතා කරයි. අපි ඒවා ආකෘතිය සඳහා "ක්රියාත්මක කිරීමේ කාර්යය" ලෙස හඳුන්වමු. TF1 හි, “ක්රියාත්මක කිරීමේ කාර්යය” යනු FuncGraph එකක් වන අතර එය TF ශ්රිතය ලෙස පොදු අංගයක් බෙදා ගත් නමුත් වෙනස් ක්රියාත්මක කිරීමක් ඇත.
ක්රියාවලිය අතරතුර, අපි කෙසේ හෝ දුම්රිය_ඔන්_බැච් (), ටෙස්ට්_ඕන්_බැච් () සහ අනාවැකි_ඔබ_බැච් () සඳහා වැරදි ක්රියාත්මක කිරීමක් අතහැර දැමුවෙමු . ඒවා තවමත් සංඛ්යාත්මකව නිවැරදි ය , නමුත් x_on_batch සඳහා ක්රියාත්මක කිරීමේ කාර්යය tf.function ඔතා ඇති පයිතන් ශ්රිතයට වඩා පිරිසිදු පයිතන් ශ්රිතයකි. මෙය මන්දගාමී වීමට හේතු වේ
TF2 හි, අපි සියලු ආදාන දත්ත tf.data.Dataset බවට පරිවර්තනය කරමු, එමඟින් අපට එක් ආකාරයක යෙදවුම් හැසිරවීමට අපගේ ක්රියාත්මක කිරීමේ කාර්යය ඒකාබද්ධ කළ හැකිය. දත්ත සමුදා පරිවර්තනයේ යම්කිසි පොදු කාර්යයක් තිබිය හැකි අතර , මම සිතන්නේ මෙය එක් කණ්ඩායමකට යන වියදමට වඩා එක් වරක් පමණක් පොදු කාර්යයක් බවයි
ඉහත ඡේදයේ අවසාන වාක්යය සහ පහත ඡේදයේ අවසාන වගන්තිය සමඟ:
උනන්දුවක් දක්වන මාදිලියේ මන්දගාමී බව මඟහරවා ගැනීම සඳහා, අපට @ tf.function ඇත, එය පයිතන් ශ්රිතයක් ප්රස්ථාරයක් බවට පත් කරයි. Np අරාව වැනි සංඛ්යාත්මක අගය පෝෂණය කරන විට, tf.function හි සිරුර ස්ථිතික ප්රස්ථාරයක් බවට පරිවර්තනය කර, ප්රශස්තිකරණය කර, අවසාන අගය ආපසු ලබා දෙන අතර එය වේගවත් වන අතර TF1 ප්රස්ථාර මාදිලිය හා සමාන කාර්ය සාධනයක් තිබිය යුතුය.
මම එකඟ නොවෙමි - මගේ පැතිකඩ ප්රති results ල අනුව, ඊජර්ගේ ආදාන දත්ත සැකසීම ප්රස්ථාරයට වඩා සැලකිය යුතු ලෙස මන්දගාමී බව පෙන්නුම් කරයි. එසේම, tf.data.Dataset
විශේෂයෙන් සැක සහිත නමුත් ඊජර් එකම දත්ත පරිවර්තන ක්රම කිහිපයකින් නැවත නැවත අමතයි - පැතිකඩ බලන්න.
අවසාන වශයෙන්, දේව්ගේ සම්බන්ධිත කැපවීම: කෙරස් 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
සෑම එකක්ම සම්පත් වෙන් කිරීම වෙනස් ලෙස හසුරුවන අතර කාර්ය සාධනය සහ හැකියාව මත ප්රතිවිපාක දරයි.
දුම්රිය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 වස්තුවකට හුඩ් යටතේ බහු ගණනය කිරීමේ ප්රස්තාර සිතියම් ගත කිරීමට අවශ්ය විය හැකිය. මෙය දෘශ්යමාන විය යුත්තේ කාර්ය සාධනය ලෙස පමණි (ප්රස්ථාර සොයා ගැනීම සඳහා ගණනය කළ නොහැකි හා මතක පිරිවැයක් ඇත )
ආදාන දත්ත සකසනයන් : ඉහත සඳහන් කළ ආකාරයටම, ක්රියාකරවන්නන් තෝරාගනු ලබන්නේ ධාවන කාල වින්යාසයන්ට අනුව සකසන ලද අභ්යන්තර ධජ මත පදනම්ව (ක්රියාත්මක කිරීමේ ආකාරය, දත්ත ආකෘතිය, බෙදා හැරීමේ උපාය). සරලම නඩුව ඊජර් සමඟ වන අතර එය කෙලින්ම w / Numpy අරා ක්රියා කරයි. සමහර නිශ්චිත උදාහරණ සඳහා, මෙම පිළිතුර බලන්න .
මොඩල් ප්රමාණය, දත්ත ප්රමාණය:
- තීරණාත්මක ය; සියලුම මාදිලි සහ දත්ත ප්රමාණයන් මත තනි වින්යාසයක් ඔටුනු නොලැබේ.
- ආකෘති ප්රමාණයට සාපේක්ෂව දත්ත ප්රමාණය වැදගත් ය; කුඩා දත්ත සහ ආකෘති සඳහා, දත්ත හුවමාරුව (උදා: CPU සිට GPU දක්වා) ඉහළින් ආධිපත්යය දරයි. ඒ හා සමානව, කුඩා පරිවර්තන සකසනයකට දත්ත පරිවර්තනය කිරීමේ වේලාව ආධිපත්යය අනුව විශාල දත්ත මත මන්දගාමීව ධාවනය කළ හැකිය (
convert_to_tensor
"ප්රොෆයිලර්" හි බලන්න )
- දුම්රිය ලූප සහ වේගය ආදාන දත්ත සකසනයෙහි වේගය වෙනස් වේ.
බෙන්ච්මාර්ක්ස් : අඹරන ලද මස්. - වචන ලේඛනය - එක්සෙල් පැතුරුම්පත
පාරිභාෂිතය :
- % රහිත සංඛ්යා සියල්ල තත්පර වේ
- % ලෙස ගණනය කර ඇත
(1 - longer_time / shorter_time)*100
; තාර්කිකත්වය: එක් සාධකයක් අනෙකට වඩා වේගවත් වන්නේ කුමන සාධකය නිසාද යන්න අපි උනන්දු වෙමු ; shorter / longer
ඇත්ත වශයෙන්ම රේඛීය නොවන සම්බන්ධතාවයක් වන අතර එය සෘජු සංසන්දනය සඳහා ප්රයෝජනවත් නොවේ
- % සං sign ා නිර්ණය:
- TF2 එදිරිව TF1:
+
TF2 වේගවත් නම්
- GvE (ප්රස්ථාර එදිරිව ඊජර්):
+
ප්රස්ථාරය වේගවත් නම්
- TF2 = TensorFlow 2.0.0 + Keras 2.3.1; TF1 = TensorFlow 1.14.0 + Keras 2.2.5
පැතිකඩ :
පැතිකඩ - පැහැදිලි කිරීම : ස්පයිඩර් 3.3.6 IDE පැතිකඩ.
සමහර කාර්යයන් අනෙක් අයගේ කූඩු වල පුනරාවර්තනය වේ; එබැවින්, "දත්ත සැකසුම්" සහ "පුහුණු" කාර්යයන් අතර නිශ්චිත වෙන්වීම සොයා ගැනීම දුෂ්කර ය, එබැවින් අතිච්ඡාදනය වනු ඇත - අවසාන ප්රති .ලයෙන් උච්චාරණය කළ පරිදි.
% සංඛ්යා ගණනය කරන ලද wrt ධාවන කාලය us ණ ගොඩනැගීමේ කාලය
- 1 හෝ 2 වතාවක් හැඳින්වූ සියලුම (අද්විතීය) ධාවන වේලාවන් සාරාංශ කිරීමෙන් ගණනය කළ කාලය ගොඩනඟන්න
- පුනරාවර්තන # හා සමාන # වාර ගණනක් සහ ඒවායේ සමහර කැදලි ධාවන වේලාවන් ලෙස හැඳින්වෙන සියලුම (අද්විතීය) ධාවන වේලාවන් සාරාංශ කිරීමෙන් දුම්රිය කාලය ගණනය කෙරේ.
- කාර්යයන් ඒවායේ මුල් නම් අනුව
_func = func
පැතිකඩ කර ඇත , අවාසනාවකට (එනම් පැතිකඩ ලෙස func
), එය ගොඩනැගීමේ කාලය සමඟ මිශ්ර වේ - එබැවින් එය බැහැර කිරීමේ අවශ්යතාවය
පරිසරය පරීක්ෂා කිරීම :
- අවම w / අවම පසුබිම් කාර්යයන් ක්රියාත්මක වන කේතය ක්රියාත්මක කිරීම
- දක්වන GPU w / ඒ අනුකරණ කිහිපයක් කාලය අනුකරණ පෙර, යෝජනා ලෙස "උණුසුම්" විය මෙම පශ්චාත්
- CUDA 10.0.130, cuDNN 7.6.0, TensorFlow 1.14.0, සහ TensorFlow 2.0.0 ප්රභවයෙන් සාදන ලද අතර ඇනකොන්ඩා
- පයිතන් 3.7.4, ස්පයිඩර් 3.3.6 IDE
- GTX 1070, Windows 10, 24GB DDR4 2.4-MHz RAM, i7-7700HQ 2.8-GHz CPU
ක්රමවේදය :
- 'කුඩා', 'මධ්යම', සහ 'විශාල' ආකෘතිය සහ දත්ත ප්රමාණ
- ආදාන දත්ත ප්රමාණයෙන් ස්වාධීනව එක් එක් ආකෘති ප්රමාණය සඳහා පරාමිති # නිවැරදි කරන්න
- "විශාල" ආකෘතියට වැඩි පරාමිතීන් සහ ස්ථර ඇත
- "විශාල" දත්ත වලට දිගු අනුක්රමයක් ඇත, නමුත් සමාන
batch_size
සහnum_channels
- ආකෘති භාවිතා කරන්නේ
Conv1D
, Dense
'ඉගෙන ගත හැකි' ස්ථර පමණි; ටී.එෆ්-අනුවාදයේ එක් එක් ආර්.එම්.එන්. වෙනස්කම්
- මාදිලිය සහ ප්රශස්තිකරණ ප්රස්ථාර ගොඩනැගීම මඟ හැරීම සඳහා සෑම විටම මිණුම් සලකුණු ලූපයෙන් පිටත එක් දුම්රිය සුදුසුකමක් ධාවනය කරන්න
- විරල දත්ත (උදා
layers.Embedding()
) හෝ විරල ඉලක්ක භාවිතා නොකිරීම (උදාSparseCategoricalCrossEntropy()
සීමාවන් : “සම්පූර්ණ” පිළිතුරක් මගින් හැකි සෑම දුම්රිය පුඩුවක්ම සහ නැවත ක්රියාකරවන්නෙකුම පැහැදිලි කරනු ඇත, නමුත් එය නිසැකවම මගේ කාල හැකියාවෙන්, නොපැමිණෙන වැටුපෙන් හෝ සාමාන්ය අවශ්යතාවයෙන් ඔබ්බට ය. ප්රති results ල ක්රමවේදය තරම්ම හොඳය - විවෘත මනසකින් අර්ථ නිරූපණය කරන්න.
කේතය :
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 == 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)