TensorFlow এর @tf.function ডেকোরেটর বোঝা

ভূমিকা

ট্রেনিং লুপের কর্মক্ষমতা উন্নত করা মেশিন লার্নিং মডেলের প্রশিক্ষণের সময় কম্পিউটিং সময় বাঁচাতে পারে। টেনসরফ্লো কোডের কর্মক্ষমতা উন্নত করার একটি উপায় হল ব্যবহার করা tf.function() ডেকোরেটর - একটি সহজ, এক-লাইন পরিবর্তন যা আপনার ফাংশনগুলিকে উল্লেখযোগ্যভাবে দ্রুত চালাতে পারে।

এই সংক্ষিপ্ত গাইডে, আমরা কীভাবে ব্যাখ্যা করব tf.function() কর্মক্ষমতা উন্নত করে এবং কিছু সর্বোত্তম অনুশীলন দেখুন।

পাইথন ডেকোরেটর এবং tf.function()

পাইথনে, একটি ডেকোরেটর হল একটি ফাংশন যা অন্যান্য ফাংশনের আচরণ পরিবর্তন করে। উদাহরণস্বরূপ, ধরুন আপনি একটি নোটবুক কক্ষে নিম্নলিখিত ফাংশনটি কল করেছেন:

import tensorflow as tf

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

def some_costly_computation(x):
    aux = tf.eye(100, dtype=tf.dtypes.float32)
    result = tf.zeros(100, dtype = tf.dtypes.float32)
    for i in range(1,100):
        aux = tf.matmul(x,aux)/i
        result = result + aux
    return result

%timeit some_costly_computation(x)
16.2 ms ± 103 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

যাইহোক, যদি আমরা একটি ব্যয়বহুল ফাংশন পাস করি tf.function():

quicker_computation = tf.function(some_costly_computation)
%timeit quicker_computation(x)

আমরা পেতে quicker_computation() - একটি নতুন ফাংশন যা আগেরটির চেয়ে অনেক দ্রুত কাজ করে:

4.99 ms ± 139 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

সুতরাং, tf.function() পরিবর্তন করে some_costly_computation() এবং আউটপুট quicker_computation() ফাংশন ডেকোরেটরও ফাংশন পরিবর্তন করে, তাই এটি তৈরি করা স্বাভাবিক ছিল tf.function() পাশাপাশি একজন ডেকোরেটর।

ডেকোরেটর স্বরলিপি ব্যবহার কল করার মতই tf.function(function):

@tf.function
def quick_computation(x):
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

%timeit quick_computation(x)
5.09 ms ± 283 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

কিভাবে tf.function() কাজ করে?

কিভাবে আমরা নির্দিষ্ট ফাংশন 2-3x দ্রুত চালাতে পারি?

TensorFlow কোড দুটি মোডে চালানো যেতে পারে: আগ্রহী মোড এবং গ্রাফ মোড. Eager মোড হল কোড চালানোর আদর্শ, ইন্টারেক্টিভ উপায়: আপনি যখনই একটি ফাংশন কল করেন, এটি কার্যকর হয়.

গ্রাফ মোড, তবে, একটু ভিন্ন। গ্রাফ মোডে, ফাংশনটি কার্যকর করার আগে, টেনসরফ্লো একটি গণনা গ্রাফ তৈরি করে, যা ফাংশনটি কার্যকর করার জন্য প্রয়োজনীয় ক্রিয়াকলাপ সমন্বিত একটি ডেটা কাঠামো। গণনা গ্রাফটি টেনসরফ্লোকে গণনাগুলিকে সরল করতে এবং সমান্তরালকরণের সুযোগ খুঁজে পেতে অনুমতি দেয়। গ্রাফটি ওভারলাইং পাইথন কোড থেকে ফাংশনটিকে বিচ্ছিন্ন করে, এটিকে বিভিন্ন ডিভাইসে দক্ষতার সাথে চালানোর অনুমতি দেয়।

একটি ফাংশন দিয়ে সজ্জিত @tf.function দুটি ধাপে কার্যকর করা হয়:

  1. প্রথম ধাপে, TensorFlow ফাংশনের জন্য Python কোড নির্বাহ করে এবং একটি কম্পিউটেশন গ্রাফ কম্পাইল করে, যে কোনো TensorFlow অপারেশনের কার্য সম্পাদনে বিলম্ব করে।
  2. পরে, গণনা গ্রাফ চালানো হয়।

বিঃদ্রঃ: প্রথম ধাপ হিসেবে পরিচিত "ট্রেসিং".

একটি নতুন গণনা গ্রাফ তৈরি করার প্রয়োজন না হলে প্রথম ধাপটি বাদ দেওয়া হবে। এটি ফাংশনের কর্মক্ষমতা উন্নত করে কিন্তু এর মানে হল যে ফাংশনটি নিয়মিত পাইথন কোডের মতো কার্যকর হবে না (যেটিতে প্রতিটি এক্সিকিউটেবল লাইন চালানো হয়)। উদাহরণস্বরূপ, আমাদের আগের ফাংশন পরিবর্তন করা যাক:

@tf.function
def quick_computation(x):
  print('Only prints the first time!')
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

quick_computation(x)
quick_computation(x)

এর ফলে:

Only prints the first time!

সার্জারির print() ট্রেসিং ধাপের সময় শুধুমাত্র একবার কার্যকর করা হয়, যখন নিয়মিত পাইথন কোড চালানো হয়। ফাংশনের পরবর্তী কলগুলি শুধুমাত্র গণনা গ্রাফ (টেনসরফ্লো অপারেশন) থেকে TenforFlow অপারেশনগুলি চালায়।

তবে আমরা যদি ব্যবহার করি tf.print() পরিবর্তে:

@tf.function
def quick_computation_with_print(x):
  tf.print("Prints every time!")
  aux = tf.eye(100, dtype=tf.dtypes.float32)
  result = tf.zeros(100, dtype = tf.dtypes.float32)
  for i in range(1,100):
    aux = tf.matmul(x,aux)/i
    result = result + aux
  return result

quick_computation_with_print(x)
quick_computation_with_print(x)

সেরা-অভ্যাস, শিল্প-স্বীকৃত মান এবং অন্তর্ভুক্ত চিট শীট সহ গিট শেখার জন্য আমাদের হ্যান্ডস-অন, ব্যবহারিক গাইড দেখুন। গুগলিং গিট কমান্ড এবং আসলে বন্ধ করুন শেখা এটা!

Prints every time!
Prints every time!

টেনসরফ্লো অন্তর্ভুক্ত tf.print() এর গণনা গ্রাফে এটি একটি টেনসরফ্লো অপারেশন - একটি নিয়মিত পাইথন ফাংশন নয়।

সতর্কতা: সমস্ত পাইথন কোড সজ্জিত একটি ফাংশনের প্রতিটি কলে কার্যকর করা হয় না @tf.function. ট্রেসিংয়ের পরে, শুধুমাত্র কম্পিউটেশনাল গ্রাফ থেকে অপারেশন চালানো হয়, যার মানে আমাদের কোডে কিছু যত্ন নেওয়া আবশ্যক।

সঙ্গে সেরা অনুশীলন @tf.function

টেনসরফ্লো অপারেশন সহ কোড লেখা

আমরা যেমন দেখিয়েছি, কোডের কিছু অংশ গণনা গ্রাফ দ্বারা উপেক্ষা করা হয়। এটি "স্বাভাবিক" পাইথন কোডের সাথে কোড করার সময় ফাংশনের আচরণের ভবিষ্যদ্বাণী করা কঠিন করে তোলে, যেমনটি আমরা এইমাত্র দেখেছি print(). অপ্রত্যাশিত আচরণ এড়াতে প্রযোজ্য হলে টেনসরফ্লো অপারেশনের সাথে আপনার ফাংশন কোড করা ভাল।

এই ক্ষেত্রে, for এবং while loops সমতুল্য TensorFlow লুপে রূপান্তরিত হতে পারে বা নাও হতে পারে। অতএব, সম্ভব হলে আপনার "ফর" লুপটিকে ভেক্টরাইজড অপারেশন হিসাবে লিখতে ভাল। এটি আপনার কোডের কর্মক্ষমতা উন্নত করবে এবং নিশ্চিত করবে যে আপনার ফাংশন সঠিকভাবে ট্রেস করছে।

একটি উদাহরণ হিসাবে, নিম্নলিখিত বিবেচনা করুন:

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

@tf.function
def function_with_for(x):
    summ = float(0)
    for row in x:
      summ = summ + tf.reduce_mean(row)
    return summ

@tf.function
def vectorized_function(x):
  result = tf.reduce_mean(x, axis=0)
  return tf.reduce_sum(result)


print(function_with_for(x))
print(vectorized_function(x))

%timeit function_with_for(x)
%timeit vectorized_function(x)
tf.Tensor(0.672811, shape=(), dtype=float32)
tf.Tensor(0.67281103, shape=(), dtype=float32)
1.58 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
440 µs ± 8.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

টেনসরফ্লো অপারেশনের কোডটি যথেষ্ট দ্রুত।

গ্লোবাল ভেরিয়েবলের রেফারেন্স এড়িয়ে চলুন

নিম্নলিখিত কোড বিবেচনা করুন:

x = tf.Variable(2, dtype=tf.dtypes.float32)
y = 2

@tf.function
def power(x):
  return tf.pow(x,y)

print(power(x))

y = 3

print(power(x))
tf.Tensor(4.0, shape=(), dtype=float32)
tf.Tensor(4.0, shape=(), dtype=float32)

প্রথমবার সজ্জিত ফাংশন power() বলা হয়েছিল, আউটপুট মানটি প্রত্যাশিত 4 ছিল। যাইহোক, দ্বিতীয়বার, ফাংশনটি উপেক্ষা করেছে যে এর মান y পরিবর্তন করা হয়. এটি ঘটে কারণ পাইথন গ্লোবাল ভেরিয়েবলের মান ট্রেসিংয়ের পরে ফাংশনের জন্য হিমায়িত হয়।

একটি ভাল উপায় ব্যবহার করা হবে tf.Variable() আপনার সমস্ত ভেরিয়েবলের জন্য এবং আপনার ফাংশনে আর্গুমেন্ট হিসাবে উভয় পাস করুন।

x = tf.Variable(2, dtype=tf.dtypes.float32)
y = tf.Variable(2, dtype = tf.dtypes.float32)

@tf.function
def power(x,y):
  return tf.pow(x,y)

print(power(x,y))

y.assign(3)

print(power(x,y))
tf.Tensor(4.0, shape=(), dtype=float32)
tf.Tensor(8.0, shape=(), dtype=float32)

ডিবাগ করা [ইমেল সুরক্ষিত]_s

সাধারণভাবে, আপনি আপনার ফাংশনটি উদগ্রীব মোডে ডিবাগ করতে চান এবং তারপর সেগুলিকে সাজাতে চান @tf.function আপনার কোড সঠিকভাবে চলার পরে কারণ আগ্রহী মোডে ত্রুটি বার্তাগুলি আরও তথ্যপূর্ণ।

কিছু সাধারণ সমস্যা হল টাইপ ত্রুটি এবং আকৃতি ত্রুটি। টাইপ ত্রুটি ঘটবে যখন একটি অপারেশনে জড়িত ভেরিয়েবলের প্রকারের মধ্যে অমিল থাকে:

x = tf.Variable(1, dtype = tf.dtypes.float32)
y = tf.Variable(1, dtype = tf.dtypes.int32)

z = tf.add(x,y)
InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2]

টাইপ ত্রুটিগুলি সহজে হামাগুড়ি দেয়, এবং একটি ভিন্ন প্রকারে একটি ভেরিয়েবল কাস্ট করে সহজেই ঠিক করা যায়:

y = tf.cast(y, tf.dtypes.float32)
z = tf.add(x, y) 
tf.print(z) 

আকৃতির ত্রুটিগুলি ঘটে যখন আপনার টেনসরগুলির আপনার অপারেশনের জন্য প্রয়োজনীয় আকৃতি থাকে না:

x = tf.random.uniform(shape=[100, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)
y = tf.random.uniform(shape=[1, 100], minval=-1, maxval=1, dtype=tf.dtypes.float32)

z = tf.matmul(x,y)
InvalidArgumentError: Matrix size-incompatible: In[0]: [100,100], In[1]: [1,100] [Op:MatMul]

উভয় ধরণের ত্রুটি ঠিক করার জন্য একটি সুবিধাজনক টুল হল ইন্টারেক্টিভ পাইথন ডিবাগার, যা ব্যবহার করে আপনি জুপিটার নোটবুকে স্বয়ংক্রিয়ভাবে কল করতে পারেন %pdb. এটি ব্যবহার করে, আপনি আপনার ফাংশন কোড করতে পারেন এবং কিছু সাধারণ ব্যবহারের ক্ষেত্রে এটি চালাতে পারেন। যদি একটি ত্রুটি থাকে, একটি ইন্টারেক্টিভ প্রম্পট খোলে। এই প্রম্পটটি আপনাকে আপনার কোডের বিমূর্তকরণ স্তরগুলি উপরে এবং নীচে যেতে এবং আপনার টেনসরফ্লো ভেরিয়েবলের মান, প্রকার এবং আকারগুলি পরীক্ষা করতে দেয়।

উপসংহার

আমরা দেখেছি কিভাবে TensorFlow এর tf.function() আপনার ফাংশন আরো দক্ষ করে তোলে, এবং কিভাবে @tf.function ডেকোরেটর আপনার নিজের ফাংশন প্রয়োগ করে.

এই স্পিড-আপ ফাংশনগুলিতে উপযোগী যেগুলিকে অনেকবার কল করা হবে, যেমন মেশিন লার্নিং মডেলগুলির জন্য কাস্টম প্রশিক্ষণের পদক্ষেপ৷

সময় স্ট্যাম্প:

থেকে আরো Stackabuse