TensorFlow 1.x বনাম TensorFlow 2 - আচরণ এবং API

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub এ দেখুন নোটবুক ডাউনলোড করুন

হুডের নিচে, TensorFlow 2 TF1.x থেকে একটি মৌলিকভাবে ভিন্ন প্রোগ্রামিং প্যারাডাইম অনুসরণ করে।

এই নির্দেশিকাটি TF1.x এবং TF2-এর মধ্যে আচরণ এবং API-এর পরিপ্রেক্ষিতে মৌলিক পার্থক্য বর্ণনা করে এবং কীভাবে এগুলি আপনার মাইগ্রেশন যাত্রার সাথে সম্পর্কিত।

বড় পরিবর্তনের উচ্চ-স্তরের সারাংশ

মৌলিকভাবে, TF1.x এবং TF2 এক্সিকিউশন (TF2-এ আগ্রহী), ভেরিয়েবল, কন্ট্রোল ফ্লো, টেনসর আকৃতি এবং টেনসর সমতা তুলনার আশেপাশে রানটাইম আচরণের একটি ভিন্ন সেট ব্যবহার করে। TF2 সামঞ্জস্যপূর্ণ হতে, আপনার কোডটি অবশ্যই TF2 আচরণের সম্পূর্ণ সেটের সাথে সামঞ্জস্যপূর্ণ হতে হবে। মাইগ্রেশনের সময়, আপনি tf.compat.v1.enable_* বা tf.compat.v1.disable_* API-এর মাধ্যমে পৃথকভাবে এই আচরণগুলির বেশিরভাগ সক্রিয় বা নিষ্ক্রিয় করতে পারেন। একটি ব্যতিক্রম হল সংগ্রহগুলি অপসারণ, যা আগ্রহী সম্পাদনকে সক্ষম/অক্ষম করার একটি পার্শ্ব প্রতিক্রিয়া।

একটি উচ্চ স্তরে, TensorFlow 2:

  • অপ্রয়োজনীয় API গুলি সরিয়ে দেয়।
  • APIগুলিকে আরও সামঞ্জস্যপূর্ণ করে তোলে - উদাহরণস্বরূপ, ইউনিফাইড RNN এবং ইউনিফাইড অপ্টিমাইজার
  • সেশনের চেয়ে ফাংশন পছন্দ করে এবং গ্রাফ এবং সংকলনের জন্য স্বয়ংক্রিয় নিয়ন্ত্রণ নির্ভরতা প্রদান করে tf.function এর সাথে ডিফল্টভাবে সক্রিয় Eager এক্সিকিউশন সহ Python রানটাইমের সাথে আরও ভালভাবে সংহত করে।
  • গ্লোবাল গ্রাফ সংগ্রহকে অবজ্ঞা করে।
  • ReferenceVariables ভেরিয়েবলের উপর ResourceVariables ভেরিয়েবল ব্যবহার করে ভেরিয়েবল কনকারেন্সি শব্দার্থ পরিবর্তন করে।
  • ফাংশন-ভিত্তিক এবং পার্থক্যযোগ্য নিয়ন্ত্রণ প্রবাহ (কন্ট্রোল ফ্লো v2) সমর্থন করে।
  • tf.compat.v1.Dimension অবজেক্টের পরিবর্তে int s ধরে রাখতে TensorShape API-কে সরল করে।
  • টেনসর সমতা মেকানিক্স আপডেট করে। TF1.x এ == টেনসর এবং ভেরিয়েবলের অপারেটর অবজেক্ট রেফারেন্স সমতা পরীক্ষা করে। TF2 এ এটি মান সমতা পরীক্ষা করে। অতিরিক্তভাবে, টেনসর/ভেরিয়েবলগুলি আর হ্যাশেবল নয়, তবে আপনি var.ref() মাধ্যমে তাদের কাছে হ্যাশেবল অবজেক্ট রেফারেন্স পেতে পারেন যদি আপনি সেগুলিকে সেটে বা dict কী হিসাবে ব্যবহার করতে চান।

নীচের বিভাগগুলি TF1.x এবং TF2 এর মধ্যে পার্থক্য সম্পর্কে আরও কিছু প্রসঙ্গ প্রদান করে। TF2 এর পিছনে ডিজাইন প্রক্রিয়া সম্পর্কে আরও জানতে, RFC এবং ডিজাইন ডক্স পড়ুন।

API ক্লিনআপ

অনেক APIs হয় চলে গেছে বা TF2 এ সরানো হয়েছে। কিছু প্রধান পরিবর্তনের মধ্যে রয়েছে tf.app , tf.flags অপসারণ করা এবং এখন ওপেন-সোর্স absl- tf.logging এর পক্ষে tf.contrib , tf.contrib-এ বসবাসকারী প্রকল্পগুলিকে পুনঃস্থাপন করা এবং প্রধান tf.* নামস্থান পরিষ্কার করা tf.math মত সাবপ্যাকেজে কম ব্যবহৃত ফাংশনগুলি সরানো। কিছু API তাদের TF2 সমতুল্য - tf.summary , tf.keras.metrics , এবং tf.keras.optimizers দিয়ে প্রতিস্থাপিত হয়েছে।

tf.compat.v1 : উত্তরাধিকার এবং সামঞ্জস্য API এন্ডপয়েন্ট

tf.compat এবং tf.compat.v1 নামস্থানের অধীনে চিহ্নগুলিকে TF2 API হিসাবে বিবেচনা করা হয় না। এই নেমস্পেসগুলি TF 1.x থেকে সামঞ্জস্যপূর্ণ চিহ্নগুলির পাশাপাশি লিগ্যাসি API এন্ডপয়েন্টগুলির মিশ্রণ প্রকাশ করে৷ এগুলো TF1.x থেকে TF2-এ মাইগ্রেশনে সহায়তা করার উদ্দেশ্যে। যাইহোক, যেহেতু এই compat.v1 API-এর কোনোটিই ইডিওম্যাটিক TF2 API নয়, তাই একেবারে নতুন TF2 কোড লেখার জন্য ব্যবহার করবেন না।

স্বতন্ত্র tf.compat.v1 চিহ্নগুলি TF2 সামঞ্জস্যপূর্ণ হতে পারে কারণ তারা TF2 আচরণের সাথেও কাজ করে চলেছে (যেমন tf.compat.v1.losses.mean_squared_error ), যখন অন্যরা TF2 (যেমন tf.compat.v1) এর সাথে বেমানান tf.compat.v1.metrics.accuracy )। অনেক compat.v1 চিহ্ন (যদিও সব নয়) তাদের ডকুমেন্টেশনে ডেডিকেটেড মাইগ্রেশন তথ্য ধারণ করে যা TF2 আচরণের সাথে তাদের সামঞ্জস্যের মাত্রা ব্যাখ্যা করে, সেইসাথে কীভাবে সেগুলিকে TF2 API-এ স্থানান্তর করতে হয়।

TF2 আপগ্রেড স্ক্রিপ্ট অনেক compat.v1 API চিহ্নকে সমতুল্য TF2 API-তে ম্যাপ করতে পারে যেখানে তারা উপনাম হয় বা একই যুক্তি থাকে কিন্তু ভিন্ন ক্রম সহ। আপনি স্বয়ংক্রিয়ভাবে TF1.x API-এর নাম পরিবর্তন করতে আপগ্রেড স্ক্রিপ্ট ব্যবহার করতে পারেন।

মিথ্যা বন্ধু APIs

TF2 tf নেমস্পেস ( compat.v1 এর অধীনে নয়) পাওয়া "মিথ্যা-বন্ধু" চিহ্নের একটি সেট রয়েছে যা আসলে TF2 আচরণকে উপেক্ষা করে, এবং/অথবা TF2 আচরণের সম্পূর্ণ সেটের সাথে পুরোপুরি সামঞ্জস্যপূর্ণ নয়। যেমন, এই APIগুলি সম্ভবত নীরব উপায়ে TF2 কোডের সাথে খারাপ আচরণ করতে পারে।

  • tf.estimator.* : অনুমানকারীরা হুডের নিচে গ্রাফ এবং সেশন তৈরি করে এবং ব্যবহার করে। যেমন, এগুলিকে TF2-সামঞ্জস্যপূর্ণ হিসাবে বিবেচনা করা উচিত নয়। যদি আপনার কোড অনুমানকারী চালায় তবে এটি TF2 আচরণ ব্যবহার করছে না।
  • keras.Model.model_to_estimator(...) : এটি হুডের নিচে একটি এস্টিমেটর তৈরি করে, যা উপরে উল্লিখিত TF2-সামঞ্জস্যপূর্ণ নয়।
  • tf.Graph().as_default() : এটি TF1.x গ্রাফ আচরণে প্রবেশ করে এবং আদর্শ TF2-সামঞ্জস্যপূর্ণ tf.function আচরণ অনুসরণ করে না। যে কোডগুলি এইরকম গ্রাফগুলিতে প্রবেশ করে সেগুলি সাধারণত সেশনের মাধ্যমে চালানো হবে এবং TF2-সামঞ্জস্যপূর্ণ বলে বিবেচিত হবে না৷
  • tf.feature_column.* বৈশিষ্ট্য কলাম API গুলি সাধারণত TF1-স্টাইল tf.compat.v1.get_variable ভেরিয়েবল তৈরির উপর নির্ভর করে এবং ধরে নেয় যে তৈরি ভেরিয়েবলগুলি বিশ্বব্যাপী সংগ্রহের মাধ্যমে অ্যাক্সেস করা হবে। যেহেতু TF2 সংগ্রহগুলিকে সমর্থন করে না, তাই APIগুলি সঠিকভাবে কাজ নাও করতে পারে যখন সেগুলিকে TF2 আচরণ সক্ষম করে চালানো হয়।

অন্যান্য API পরিবর্তন

  • TF2 ডিভাইস প্লেসমেন্ট অ্যালগরিদমগুলিতে উল্লেখযোগ্য উন্নতির বৈশিষ্ট্য রয়েছে যা tf.colocate_with অপ্রয়োজনীয় ব্যবহারকে রেন্ডার করে। যদি এটি অপসারণের ফলে কর্মক্ষমতা হ্রাস পায় তাহলে অনুগ্রহ করে একটি বাগ ফাইল করুন

  • tf.config থেকে সমতুল্য ফাংশন দিয়ে tf.v1.ConfigProto এর সমস্ত ব্যবহার প্রতিস্থাপন করুন।

উদগ্রীব মৃত্যুদন্ড

TF1.x-এর জন্য আপনাকে ম্যানুয়ালি tf.* API কল করে একটি বিমূর্ত সিনট্যাক্স ট্রি (গ্রাফ) একসাথে সেলাই করতে হবে এবং তারপরে একটি session.run কলে আউটপুট টেনসর এবং ইনপুট টেনসরগুলির একটি সেট পাস করে ম্যানুয়ালি অ্যাবস্ট্রাক্ট সিনট্যাক্স ট্রি কম্পাইল করতে হবে। TF2 সাগ্রহে সম্পাদন করে (যেমন পাইথন সাধারণত করে) এবং গ্রাফ এবং সেশনগুলি বাস্তবায়নের বিবরণের মতো অনুভব করে।

আগ্রহী সম্পাদনের একটি উল্লেখযোগ্য উপজাত হল যে tf.control_dependencies আর প্রয়োজন নেই, কারণ কোডের সমস্ত লাইন ক্রমানুসারে কার্যকর হয় (একটি tf.function এর মধ্যে, পার্শ্ব প্রতিক্রিয়া সহ কোড লিখিত ক্রমে কার্যকর হয়)।

আর বিশ্বব্যাপী নেই

TF1.x নিহিত গ্লোবাল নেমস্পেস এবং সংগ্রহের উপর ব্যাপকভাবে নির্ভর করে। আপনি যখন tf.Variable , তখন এটি ডিফল্ট গ্রাফে একটি সংগ্রহে রাখা হবে এবং এটি সেখানেই থাকবে, এমনকি যদি আপনি পাইথন ভেরিয়েবলের দিকে নির্দেশ করে তার ট্র্যাক হারিয়ে ফেলেন। তারপরে আপনি সেই tf.Variable পুনরুদ্ধার করতে পারেন, কিন্তু শুধুমাত্র যদি আপনি জানেন যে নামটি দিয়ে এটি তৈরি করা হয়েছে। আপনি ভেরিয়েবলের সৃষ্টির নিয়ন্ত্রণে না থাকলে এটি করা কঠিন ছিল। ফলস্বরূপ, আপনার ভেরিয়েবলগুলিকে আবার খুঁজে পেতে এবং ব্যবহারকারীর তৈরি ভেরিয়েবলগুলি খুঁজে পেতে ফ্রেমওয়ার্কগুলির জন্য আপনাকে সাহায্য করার জন্য সমস্ত ধরণের প্রক্রিয়া প্রসারিত হয়েছে। এর মধ্যে কয়েকটির মধ্যে রয়েছে: পরিবর্তনশীল স্কোপ, গ্লোবাল কালেকশন, সহায়ক পদ্ধতি যেমন tf.get_global_step এবং tf.global_variables_initializer , অপ্টিমাইজাররা সমস্ত প্রশিক্ষনযোগ্য ভেরিয়েবলের উপর নিহিতভাবে গ্রেডিয়েন্ট গণনা করে এবং আরও অনেক কিছু। TF2 ডিফল্ট মেকানিজমের পক্ষে এই সমস্ত মেকানিজম ( ভেরিয়েবল 2.0 RFC ) বাদ দেয় - আপনি আপনার ভেরিয়েবলের উপর নজর রাখেন। আপনি যদি একটি tf.Variable এর ট্র্যাক হারিয়ে ফেলেন, তাহলে এটি আবর্জনা সংগ্রহ করে।

ভেরিয়েবল ট্র্যাক করার প্রয়োজনীয়তা কিছু অতিরিক্ত কাজ তৈরি করে, কিন্তু মডেলিং শিমস এবং tf.Module s এবং tf.keras.layers.Layer s-এ অন্তর্নিহিত অবজেক্ট-ওরিয়েন্টেড ভেরিয়েবল সংগ্রহের মতো আচরণের মতো সরঞ্জামগুলির সাহায্যে বোঝা কমানো হয়।

ফাংশন, সেশন নয়

একটি session.run কল প্রায় একটি ফাংশন কলের মতো: আপনি ইনপুট এবং কল করার ফাংশন নির্দিষ্ট করেন এবং আপনি আউটপুটগুলির একটি সেট ফিরে পাবেন। TF2-এ, আপনি JIT সংকলনের জন্য চিহ্নিত করার জন্য tf.function ব্যবহার করে একটি পাইথন ফাংশন সাজাতে পারেন যাতে TensorFlow এটিকে একটি একক গ্রাফ হিসাবে চালায় ( ফাংশন 2.0 RFC )। এই প্রক্রিয়াটি TF2 কে গ্রাফ মোডের সমস্ত সুবিধা পেতে দেয়:

  • কর্মক্ষমতা: ফাংশন অপ্টিমাইজ করা যেতে পারে (নোড ছাঁটাই, কার্নেল ফিউশন, ইত্যাদি)
  • পোর্টেবিলিটি: ফাংশনটি রপ্তানি/পুনরায় আমদানি করা যেতে পারে ( সংরক্ষিত মডেল 2.0 RFC ), আপনাকে মডুলার টেনসরফ্লো ফাংশনগুলি পুনরায় ব্যবহার এবং ভাগ করার অনুমতি দেয়।
# TF1.x
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TF2
outputs = f(input)

পাইথন এবং টেনসরফ্লো কোডকে অবাধে ছেদ করার ক্ষমতা সহ, আপনি পাইথনের অভিব্যক্তির সুবিধা নিতে পারেন। যাইহোক, পোর্টেবল TensorFlow কোনো পাইথন ইন্টারপ্রেটার ছাড়াই প্রেক্ষাপটে চালায়, যেমন মোবাইল, C++ এবং জাভাস্ক্রিপ্ট। tf.function যোগ করার সময় আপনার কোড পুনর্লিখন এড়াতে সাহায্য করার জন্য, Python কনস্ট্রাক্টের একটি উপসেটকে তাদের TensorFlow সমতুল্যগুলিতে রূপান্তর করতে AutoGraph ব্যবহার করুন:

  • for / while -> tf.while_loop ( break এবং continue যাওয়া সমর্থিত)
  • if -> tf.cond
  • for _ in dataset -> dataset.reduce

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

TF 2.x আচরণ পরিবর্তনের সাথে মানিয়ে নেওয়া

আপনি TF2 আচরণের সম্পূর্ণ সেটে স্থানান্তরিত হলেই TF2 তে আপনার স্থানান্তর সম্পূর্ণ হয়। আচরণের সম্পূর্ণ সেট tf.compat.v1.enable_v2_behaviors এবং tf.compat.v1.disable_v2_behaviors এর মাধ্যমে সক্ষম বা নিষ্ক্রিয় করা যেতে পারে। নীচের বিভাগগুলি প্রতিটি প্রধান আচরণের পরিবর্তন নিয়ে বিস্তারিত আলোচনা করে।

tf.function s ব্যবহার করে

মাইগ্রেশনের সময় আপনার প্রোগ্রামগুলিতে সবচেয়ে বড় পরিবর্তনগুলি সম্ভবত মৌলিক প্রোগ্রামিং মডেলের দৃষ্টান্ত থেকে গ্রাফ এবং সেশন থেকে আগ্রহী এক্সিকিউশন এবং tf.function এ স্থানান্তরিত হতে পারে। তাদের সাথে সামঞ্জস্যপূর্ণ এপিআই-এ আগ্রহী এক্সিকিউশন এবং tf.function এর সাথে বেমানান API থেকে সরানোর বিষয়ে আরও জানতে TF2 মাইগ্রেশন গাইড দেখুন।

নিচে কিছু সাধারণ প্রোগ্রাম প্যাটার্ন আছে যেগুলো কোনো একটি API-এর সাথে আবদ্ধ নয় যেগুলো tf.function s এবং tf.compat.v1.Session s থেকে tf.Graph s-এর সাথে স্যুইচ করার সময় সমস্যা সৃষ্টি করতে পারে।

প্যাটার্ন 1: পাইথন অবজেক্ট ম্যানিপুলেশন এবং ভেরিয়েবল ক্রিয়েশন যা শুধুমাত্র একবার করা হবে একাধিকবার চালানো হবে

TF1.x প্রোগ্রামগুলিতে যেগুলি গ্রাফ এবং সেশনের উপর নির্ভর করে, সাধারণত প্রত্যাশা করা হয় যে আপনার প্রোগ্রামের সমস্ত পাইথন লজিক শুধুমাত্র একবারই চলবে। যাইহোক, উদগ্রীব এক্সিকিউশন এবং tf.function এটা আশা করা ন্যায্য যে আপনার Python লজিক অন্তত একবার চালানো হবে, কিন্তু সম্ভবত আরও বার (হয় একাধিকবার সাগ্রহে, অথবা বিভিন্ন tf.function ট্রেস জুড়ে একাধিকবার)। কখনও কখনও, tf.function একই ইনপুটে দুবার ট্রেস করবে, যার ফলে অপ্রত্যাশিত আচরণ হবে (উদাহরণ 1 এবং 2 দেখুন)। আরো বিস্তারিত জানার জন্য tf.function গাইড পড়ুন।

উদাহরণ 1: পরিবর্তনশীল সৃষ্টি

নীচের উদাহরণটি বিবেচনা করুন, যেখানে কল করার সময় ফাংশন একটি পরিবর্তনশীল তৈরি করে:

def f():
  v = tf.Variable(1.0)
  return v

with tf.Graph().as_default():
  with tf.compat.v1.Session() as sess:
    res = f()
    sess.run(tf.compat.v1.global_variables_initializer())
    sess.run(res)

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

@tf.function
def f():
  print("trace") # This will print twice because the python body is run twice
  v = tf.Variable(1.0)
  return v

try:
  f()
except ValueError as e:
  print(e)

একটি সমাধান হল প্রথম কলে তৈরি হওয়ার পর ভেরিয়েবলটিকে ক্যাশে করা এবং পুনরায় ব্যবহার করা।

class Model(tf.Module):
  def __init__(self):
    self.v = None

  @tf.function
  def __call__(self):
    print("trace") # This will print twice because the python body is run twice
    if self.v is None:
      self.v = tf.Variable(0)
    return self.v

m = Model()
m()

উদাহরণ 2: tf.function কারণে সুযোগের বাইরের টেনসর

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

class Model(tf.Module):
  def __init__(self):
    self.dataset = None

  @tf.function
  def __call__(self):
    print("trace") # This will print once: only traced once
    if self.dataset is None:
      self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
    it = iter(self.dataset)
    return next(it)

m = Model()
m()

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

class Model(tf.Module):
  def __init__(self):
    self.v = None
    self.dataset = None

  @tf.function
  def __call__(self):
    print("trace") # This will print twice because the python body is run twice
    if self.v is None:
      self.v = tf.Variable(0)
    if self.dataset is None:
      self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
    it = iter(self.dataset)
    return [self.v, next(it)]

m = Model()
try:
  m()
except TypeError as e:
  print(e) # <tf.Tensor ...> is out of scope and cannot be used here.

সবচেয়ে সহজ সমাধান হল পরিবর্তনশীল সৃষ্টি এবং ডেটাসেট তৈরি উভয়ই tf.funciton কলের বাইরে রয়েছে তা নিশ্চিত করা। উদাহরণ স্বরূপ:

class Model(tf.Module):
  def __init__(self):
    self.v = None
    self.dataset = None

  def initialize(self):
    if self.dataset is None:
      self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])
    if self.v is None:
      self.v = tf.Variable(0)

  @tf.function
  def __call__(self):
    it = iter(self.dataset)
    return [self.v, next(it)]

m = Model()
m.initialize()
m()

যাইহোক, কখনও কখনও tf.function এ ভেরিয়েবল তৈরি করা এড়ানো যায় না (যেমন কিছু TF keras অপ্টিমাইজারের স্লট ভেরিয়েবল)। তবুও, আমরা tf.function কলের বাইরে সরাতে পারি। আমরা এটির উপর নির্ভর করতে পারি কারণ tf.function একটি অন্তর্নিহিত ইনপুট হিসাবে ডেটাসেট গ্রহণ করবে এবং উভয় গ্রাফই এটি সঠিকভাবে অ্যাক্সেস করতে পারে।

class Model(tf.Module):
  def __init__(self):
    self.v = None
    self.dataset = None

  def initialize(self):
    if self.dataset is None:
      self.dataset = tf.data.Dataset.from_tensors([1, 2, 3])

  @tf.function
  def __call__(self):
    if self.v is None:
      self.v = tf.Variable(0)
    it = iter(self.dataset)
    return [self.v, next(it)]

m = Model()
m.initialize()
m()

উদাহরণ 3: ডিক্ট ব্যবহারের কারণে অপ্রত্যাশিত টেনসরফ্লো বস্তুর পুনঃসৃষ্টি

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

class Model(tf.Module):
  def __init__(self):
    self.datasets = {}
    self.iterators = {}

  def __call__(self, key):
    if key not in self.datasets:
      self.datasets[key] = tf.compat.v1.data.Dataset.from_tensor_slices([1, 2, 3])
      self.iterators[key] = self.datasets[key].make_initializable_iterator()
    return self.iterators[key]

with tf.Graph().as_default():
  with tf.compat.v1.Session() as sess:
    m = Model()
    it = m('a')
    sess.run(it.initializer)
    for _ in range(3):
      print(sess.run(it.get_next())) # prints 1, 2, 3

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

class Model(tf.Module):
  def __init__(self):
    self.datasets = {}
    self.iterators = {}

  @tf.function
  def __call__(self, key):
    if key not in self.datasets:
      self.datasets[key] = tf.data.Dataset.from_tensor_slices([1, 2, 3])
      self.iterators[key] = iter(self.datasets[key])
    return self.iterators[key]

m = Model()
for _ in range(3):
  print(next(m('a'))) # prints 1, 1, 1

আমরা প্রত্যাশিত আচরণ অর্জন করতে, গ্রাফের বাইরে ডেটাসেট এবং পুনরাবৃত্তিকারী তৈরি করতে tf.init_scope ব্যবহার করতে পারি:

class Model(tf.Module):
  def __init__(self):
    self.datasets = {}
    self.iterators = {}

  @tf.function
  def __call__(self, key):
    if key not in self.datasets:
      # Lifts ops out of function-building graphs
      with tf.init_scope():
        self.datasets[key] = tf.data.Dataset.from_tensor_slices([1, 2, 3])
        self.iterators[key] = iter(self.datasets[key])
    return self.iterators[key]

m = Model()
for _ in range(3):
  print(next(m('a'))) # prints 1, 2, 3

থাম্বের সাধারণ নিয়ম হল আপনার যুক্তিতে পাইথনের পার্শ্বপ্রতিক্রিয়াগুলির উপর নির্ভর করা এড়াতে এবং শুধুমাত্র আপনার চিহ্নগুলি ডিবাগ করতে সেগুলি ব্যবহার করুন৷

উদাহরণ 4: একটি গ্লোবাল পাইথন তালিকা ম্যানিপুলেট করা

নিম্নলিখিত TF1.x কোডটি ক্ষতির একটি বিশ্বব্যাপী তালিকা ব্যবহার করে যা এটি শুধুমাত্র বর্তমান প্রশিক্ষণ পদক্ষেপের দ্বারা উত্পন্ন ক্ষতির তালিকা বজায় রাখতে ব্যবহার করে। উল্লেখ্য যে পাইথন লজিক যেটি তালিকায় ক্ষতি যোগ করে তা শুধুমাত্র একবার কল করা হবে তা নির্বিশেষে যে সেশনটি কতগুলি প্রশিক্ষণের জন্য চালানো হয়েছে।

all_losses = []

class Model():
  def __call__(...):
    ...
    all_losses.append(regularization_loss)
    all_losses.append(label_loss_a)
    all_losses.append(label_loss_b)
    ...

g = tf.Graph()
with g.as_default():
  ...
  # initialize all objects
  model = Model()
  optimizer = ...
  ...
  # train step
  model(...)
  total_loss = tf.reduce_sum(all_losses)
  optimizer.minimize(total_loss)
  ...
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)  

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

all_losses = []

class Model():
  def __call__(...):
    ...
    all_losses.append(regularization_loss)
    all_losses.append(label_loss_a)
    all_losses.append(label_loss_b)
    ...

# initialize all objects
model = Model()
optimizer = ...

def train_step(...)
  ...
  model(...)
  total_loss = tf.reduce_sum(all_losses) # global list is never cleared,
  # Accidentally accumulates sum loss across all training steps
  optimizer.minimize(total_loss)
  ...

প্যাটার্ন 2: একটি সিম্বলিক টেনসর যা TF1.x-এর প্রতিটি ধাপে পুনঃগণনা করা হয় তা আকস্মিকভাবে প্রাথমিক মান সহ ক্যাশে করা হয় যখন উৎসুক এ স্যুইচ করা হয়।

এই প্যাটার্নটি সাধারণত tf.functions-এর বাইরে সাগ্রহে চালানোর সময় আপনার কোডকে নীরবে খারাপ আচরণ করতে দেয়, কিন্তু একটি tf.function InaccessibleTensorError ভিতরে প্রাথমিক মান ক্যাশিং ঘটে। যাইহোক, সচেতন থাকুন যে উপরের প্যাটার্ন 1 এড়ানোর জন্য আপনি প্রায়শই অসাবধানতাবশত আপনার কোডটিকে এমনভাবে গঠন করবেন যাতে এই প্রাথমিক মান ক্যাশিংটি যে কোনও tf.function এর বাইরে ঘটবে যা একটি ত্রুটি বাড়াতে সক্ষম হবে। সুতরাং, অতিরিক্ত যত্ন নিন যদি আপনি জানেন যে আপনার প্রোগ্রাম এই প্যাটার্নের জন্য সংবেদনশীল হতে পারে।

এই প্যাটার্নের সাধারণ সমাধান হল কোডটি পুনর্গঠন করা বা প্রয়োজনে পাইথন কলেবল ব্যবহার করা যাতে দুর্ঘটনাক্রমে ক্যাশে হওয়ার পরিবর্তে প্রতিবার মানটি পুনরায় গণনা করা হয়।

উদাহরণ 1: শেখার হার/হাইপারপ্যারামিটার/ইত্যাদি। সময়সূচী যা বিশ্বব্যাপী পদক্ষেপের উপর নির্ভর করে

নিম্নলিখিত কোড স্নিপেটে, প্রত্যাশা হল যে প্রতিবার সেশনটি চালানো হলে সাম্প্রতিকতম global_step মানটি পড়া হবে এবং একটি নতুন শেখার হার গণনা করা হবে।

g = tf.Graph()
with g.as_default():
  ...
  global_step = tf.Variable(0)
  learning_rate = 1.0 / global_step
  opt = tf.compat.v1.train.GradientDescentOptimizer(learning_rate)
  ...
  global_step.assign_add(1)
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)

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

global_step = tf.Variable(0)
learning_rate = 1.0 / global_step # Wrong! Only computed once!
opt = tf.keras.optimizers.SGD(learning_rate)

def train_step(...):
  ...
  opt.apply_gradients(...)
  global_step.assign_add(1)
  ...

যেহেতু এই নির্দিষ্ট উদাহরণটি একটি সাধারণ প্যাটার্ন এবং প্রতিটি প্রশিক্ষণের ধাপের পরিবর্তে অপ্টিমাইজারগুলি শুধুমাত্র একবার শুরু করা উচিত, TF2 অপ্টিমাইজারগুলি tf.keras.optimizers.schedules.LearningRateSchedule সময়সূচী বা পাইথন কলেবলকে শেখার হার এবং অন্যান্য হাইপারপ্যারামিটারের যুক্তি হিসাবে সমর্থন করে।

উদাহরণ 2: অবজেক্ট অ্যাট্রিবিউট হিসেবে বরাদ্দ করা প্রতীকী র্যান্ডম সংখ্যার শুরু তারপর পয়েন্টারের মাধ্যমে পুনঃব্যবহার করার সময় আকস্মিকভাবে ক্যাশ হয়ে যায়।

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

class NoiseAdder(tf.Module):
  def __init__(shape, mean):
    self.noise_distribution = tf.random.normal(shape=shape, mean=mean)
    self.trainable_scale = tf.Variable(1.0, trainable=True)

  def add_noise(input):
    return (self.noise_distribution + input) * self.trainable_scale

TF1.x এ নিম্নরূপ এটি ব্যবহার করলে প্রতিবার সেশন চালানোর সময় একটি নতুন র্যান্ডম নয়েজ টেনসর গণনা করা হবে:

g = tf.Graph()
with g.as_default():
  ...
  # initialize all variable-containing objects
  noise_adder = NoiseAdder(shape, mean)
  ...
  # computation pass
  x_with_noise = noise_adder.add_noise(x)
  ...
...
sess = tf.compat.v1.Session(graph=g)
sess.run(...)

যাইহোক, noise_adder চালু করার ফলে noise_distribution শুধুমাত্র একবার গণনা করা হবে এবং সমস্ত প্রশিক্ষণ ধাপের জন্য হিমায়িত হবে:

...
# initialize all variable-containing objects
noise_adder = NoiseAdder(shape, mean) # Freezes `self.noise_distribution`!
...
# computation pass
x_with_noise = noise_adder.add_noise(x)
...

এটি ঠিক করার জন্য, প্রতিবার একই টেনসর বস্তুর উল্লেখ না করে প্রতিবার একটি নতুন র্যান্ডম টেনসর প্রয়োজন হলে প্রতিবার tf.random.normal কল করতে রিফ্যাক্টর NoiseAdder

class NoiseAdder(tf.Module):
  def __init__(shape, mean):
    self.noise_distribution = lambda: tf.random.normal(shape=shape, mean=mean)
    self.trainable_scale = tf.Variable(1.0, trainable=True)

  def add_noise(input):
    return (self.noise_distribution() + input) * self.trainable_scale

প্যাটার্ন 3: TF1.x কোড সরাসরি নির্ভর করে এবং নাম অনুসারে টেনসর দেখায়

TF1.x কোড পরীক্ষার জন্য গ্রাফে কোন টেনসর বা ক্রিয়াকলাপ রয়েছে তা পরীক্ষা করার উপর নির্ভর করা সাধারণ। কিছু বিরল ক্ষেত্রে, মডেলিং কোড নামের এই লুকআপগুলির উপরও নির্ভর করবে।

tf.function এর বাইরে সাগ্রহে চালানোর সময় টেনসরের নাম তৈরি হয় না, তাই tf.Tensor.name-এর সমস্ত ব্যবহার অবশ্যই tf.Tensor.name এর ভিতরে ঘটতে tf.function । মনে রাখবেন প্রকৃত জেনারেট করা নামগুলি TF1.x এবং TF2-এর মধ্যে একই tf.function এর মধ্যেও আলাদা হতে পারে এবং API গ্যারান্টিগুলি TF সংস্করণ জুড়ে জেনারেট করা নামের স্থায়িত্ব নিশ্চিত করে না।

প্যাটার্ন 4: TF1.x সেশন বাছাইকৃতভাবে জেনারেট করা গ্রাফের শুধুমাত্র অংশ চালায়

TF1.x-এ, আপনি একটি গ্রাফ তৈরি করতে পারেন এবং তারপরে গ্রাফের প্রতিটি অপশন চালানোর প্রয়োজন হয় না এমন ইনপুট এবং আউটপুটগুলির একটি সেট বেছে নিয়ে একটি সেশনের সাথে শুধুমাত্র নির্বাচিতভাবে এটির একটি উপসেট চালানোর জন্য বেছে নিতে পারেন।

উদাহরণস্বরূপ, আপনার একটি একক গ্রাফের ভিতরে একটি জেনারেটর এবং একটি বৈষম্যকারী উভয়ই থাকতে পারে এবং শুধুমাত্র বৈষম্যকারীকে প্রশিক্ষণ দেওয়া বা শুধুমাত্র জেনারেটরকে প্রশিক্ষণের মধ্যে বিকল্প করার জন্য পৃথক tf.compat.v1.Session.run কল ব্যবহার করুন৷

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

সুতরাং, আপনাকে হয় প্রোগ্রামের বিভিন্ন অংশ সম্বলিত একাধিক tf.function ব্যবহার করতে হবে, অথবা আপনি যে tf.function এ ব্রাঞ্চ করেন তার জন্য শর্তসাপেক্ষ আর্গুমেন্ট ব্যবহার করতে হবে যাতে আপনি আসলে যে জিনিসগুলি চালাতে চান তা চালানোর জন্য।

সংগ্রহ অপসারণ

যখন উদগ্রীব এক্সিকিউশন সক্ষম করা হয়, তখন গ্রাফ সংগ্রহ-সম্পর্কিত compat.v1 API (যারা tf.compat.v1.trainable_variables এর মতো হুডের অধীনে সংগ্রহে পড়তে বা লিখতে পারে) আর উপলব্ধ থাকে না। কেউ কেউ ValueError s বাড়াতে পারে, আবার কেউ কেউ নীরবে খালি তালিকা ফেরত দিতে পারে।

TF1.x-এ সংগ্রহের সবচেয়ে মানক ব্যবহার হল ইনিশিয়ালাইজার, গ্লোবাল স্টেপ, ওজন, রেগুলারাইজেশন লস, মডেল আউটপুট লস, এবং পরিবর্তনশীল আপডেটগুলি বজায় রাখা যা BatchNormalization লেয়ার থেকে চালানো দরকার।

এই স্ট্যান্ডার্ড ব্যবহারগুলির প্রতিটি পরিচালনা করতে:

  1. ইনিশিয়ালাইজার - উপেক্ষা করুন। ম্যানুয়াল ভেরিয়েবল ইনিশিয়ালাইজেশনের প্রয়োজন হয় না যাতে এক্সিকিউশন সক্রিয় থাকে।
  2. বিশ্বব্যাপী পদক্ষেপ - মাইগ্রেশন নির্দেশাবলীর জন্য tf.compat.v1.train.get_or_create_global_step এর ডকুমেন্টেশন দেখুন।
  3. ওজন - আপনার মডেলগুলিকে tf.Module s/ tf.keras.layers.Layer s/ tf.keras.Model s-এ ম্যাপ করুন মডেল ম্যাপিং গাইডের নির্দেশিকা অনুসরণ করে এবং তারপর তাদের নিজ নিজ ওজন-ট্র্যাকিং প্রক্রিয়া যেমন tf.module.trainable_variables
  4. নিয়মিতকরণের ক্ষতি - মডেল ম্যাপিং গাইডে নির্দেশিকা অনুসরণ করে tf.Module s/ tf.keras.layers.Layer s/ tf.keras.Model s-এ আপনার মডেল ম্যাপ করুন এবং তারপর tf.keras.losses ব্যবহার করুন। বিকল্পভাবে, আপনি নিজেও আপনার নিয়মিতকরণের ক্ষতিগুলি ট্র্যাক করতে পারেন।
  5. মডেল আউটপুট ক্ষতি - tf.keras.Model ক্ষতি ব্যবস্থাপনা পদ্ধতি ব্যবহার করুন বা সংগ্রহ ব্যবহার না করে আলাদাভাবে আপনার ক্ষতি ট্র্যাক করুন।
  6. ওজন আপডেট - এই সংগ্রহ উপেক্ষা করুন. আগ্রহী সম্পাদন এবং tf.function (অটোগ্রাফ এবং স্বয়ংক্রিয়-নিয়ন্ত্রণ-নির্ভরতার সাথে) মানে সমস্ত পরিবর্তনশীল আপডেট স্বয়ংক্রিয়ভাবে চালিত হবে। সুতরাং, শেষ পর্যন্ত আপনাকে স্পষ্টভাবে সমস্ত ওজন আপডেট চালাতে হবে না, তবে মনে রাখবেন যে ওজন আপডেটগুলি আপনার TF1.x কোডের তুলনায় ভিন্ন সময়ে ঘটতে পারে, আপনি কীভাবে নিয়ন্ত্রণ নির্ভরতা ব্যবহার করছেন তার উপর নির্ভর করে।
  7. সারাংশ - মাইগ্রেটিং সারাংশ API নির্দেশিকা পড়ুন।

আরও জটিল সংগ্রহের ব্যবহার (যেমন কাস্টম সংগ্রহগুলি ব্যবহার করা) এর জন্য হয় আপনার নিজস্ব গ্লোবাল স্টোরগুলি বজায় রাখার জন্য বা এটিকে বিশ্বব্যাপী স্টোরের উপর একেবারেই নির্ভর না করার জন্য আপনার কোড রিফ্যাক্টর করতে হবে।

ReferenceVariables ভেরিয়েবলের পরিবর্তে ResourceVariables ভেরিয়েবল

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

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

আপনার কোডের উপর এই আচরণ পরিবর্তনের প্রভাবকে আলাদা করতে, যদি উদগ্রীব এক্সিকিউশন অক্ষম করা হয় তাহলে আপনি tf.compat.v1.disable_resource_variables() এবং tf.compat.v1.enable_resource_variables() ব্যবহার করে এই আচরণ পরিবর্তনকে বিশ্বব্যাপী নিষ্ক্রিয় বা সক্ষম করতে পারেন। ResourceVariables সর্বদা ব্যবহার করা হবে যদি উদগ্রীব সম্পাদন সক্ষম করা হয়।

নিয়ন্ত্রণ প্রবাহ v2

TF1.x-এ, নিয়ন্ত্রণ ফ্লো অপারেশন যেমন tf.cond এবং tf.while_loop ইনলাইন নিম্ন-স্তরের অপস যেমন Switch , Merge ইত্যাদি। TF2 উন্নত কার্যকরী নিয়ন্ত্রণ ফ্লো অপ্স প্রদান করে যা প্রতিটি শাখা এবং সমর্থনের জন্য পৃথক tf.function ট্রেস সহ প্রয়োগ করা হয়। উচ্চ ক্রম পার্থক্য

আপনার কোডের উপর এই আচরণের পরিবর্তনের প্রভাবকে আলাদা করতে, যদি উদগ্রীব সম্পাদন অক্ষম করা হয় তাহলে আপনি tf.compat.v1.disable_control_flow_v2() এবং tf.compat.v1.enable_control_flow_v2() ব্যবহার করে এই আচরণ পরিবর্তনটি বিশ্বব্যাপী নিষ্ক্রিয় বা সক্ষম করতে পারেন। যাইহোক, আপনি শুধুমাত্র কন্ট্রোল ফ্লো v2 অক্ষম করতে পারেন যদি আগ্রহী এক্সিকিউশনও অক্ষম থাকে। এটি সক্ষম হলে, নিয়ন্ত্রণ প্রবাহ v2 সর্বদা ব্যবহার করা হবে।

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

  • অপারেটর এবং টেনসর নামের উপর নির্ভরশীল কোড
  • সেই শাখার বাইরে থেকে টেনসরফ্লো কন্ট্রোল ফ্লো শাখার মধ্যে তৈরি করা টেনসরকে নির্দেশ করে কোড। এটি একটি InaccessibleTensorError তৈরি করতে পারে

এই আচরণ পরিবর্তনটি কার্যক্ষমতা নিরপেক্ষ থেকে ইতিবাচক হওয়ার উদ্দেশ্যে করা হয়েছে, কিন্তু আপনি যদি এমন একটি সমস্যায় পড়েন যেখানে নিয়ন্ত্রণ প্রবাহ v2 আপনার জন্য TF1.x নিয়ন্ত্রণ প্রবাহের চেয়ে খারাপ কাজ করে তাহলে অনুগ্রহ করে প্রজনন পদক্ষেপের সাথে একটি সমস্যা ফাইল করুন।

TensorShape API আচরণ পরিবর্তন

TensorShape tf.compat.v1.Dimension অবজেক্টের পরিবর্তে int s ধরে রাখার জন্য সরলীকৃত করা হয়েছিল। তাই int পেতে .value কল করার দরকার নেই।

পৃথক tf.compat.v1.Dimension .মাত্রা অবজেক্ট এখনও tf.TensorShape.dims থেকে অ্যাক্সেসযোগ্য।

আপনার কোডে এই আচরণ পরিবর্তনের প্রভাবকে আলাদা করতে, আপনি tf.compat.v1.disable_v2_tensorshape() এবং tf.compat.v1.enable_v2_tensorshape() ) ব্যবহার করতে পারেন এই আচরণ পরিবর্তনটিকে বিশ্বব্যাপী নিষ্ক্রিয় বা সক্ষম করতে৷

নিম্নলিখিত TF1.x এবং TF2 এর মধ্যে পার্থক্য প্রদর্শন করে।

import tensorflow as tf
# Create a shape and choose an index
i = 0
shape = tf.TensorShape([16, None, 256])
shape
TensorShape([16, None, 256])

আপনার যদি এটি TF1.x-এ থাকে:

value = shape[i].value

তারপর TF2 এ এটি করুন:

value = shape[i]
value
16

আপনার যদি এটি TF1.x-এ থাকে:

for dim in shape:
    value = dim.value
    print(value)

তারপর, TF2 এ এটি করুন:

for value in shape:
  print(value)
16
None
256

যদি আপনার এটি TF1.x-এ থাকে (বা অন্য কোনো মাত্রা পদ্ধতি ব্যবহার করা হয়):

dim = shape[i]
dim.assert_is_compatible_with(other_dim)

তারপর TF2 এ এটি করুন:

other_dim = 16
Dimension = tf.compat.v1.Dimension

if shape.rank is None:
  dim = Dimension(None)
else:
  dim = shape.dims[i]
dim.is_compatible_with(other_dim) # or any other dimension method
True
shape = tf.TensorShape(None)

if shape:
  dim = shape.dims[i]
  dim.is_compatible_with(other_dim) # or any other dimension method

একটি tf.TensorShape এর বুলিয়ান মান True যদি র‍্যাঙ্কটি জানা থাকে, অন্যথায় False

print(bool(tf.TensorShape([])))      # Scalar
print(bool(tf.TensorShape([0])))     # 0-length vector
print(bool(tf.TensorShape([1])))     # 1-length vector
print(bool(tf.TensorShape([None])))  # Unknown-length vector
print(bool(tf.TensorShape([1, 10, 100])))       # 3D tensor
print(bool(tf.TensorShape([None, None, None]))) # 3D tensor with no known dimensions
print()
print(bool(tf.TensorShape(None)))  # A tensor with unknown rank.
True
True
True
True
True
True

False

TensorShape পরিবর্তনের কারণে সম্ভাব্য ত্রুটি

TensorShape আচরণের পরিবর্তনগুলি নীরবে আপনার কোড ভাঙার সম্ভাবনা কম। যাইহোক, আপনি দেখতে পারেন আকৃতি-সম্পর্কিত কোড int s হিসাবে AttributeError s বাড়াতে শুরু করেছে এবং None tf.compat.v1.Dimension এর মতো কোনো বৈশিষ্ট্য নেই। নিচে এই AttributeError এর কিছু উদাহরণ দেওয়া হল:

try:
  # Create a shape and choose an index
  shape = tf.TensorShape([16, None, 256])
  value = shape[0].value
except AttributeError as e:
  # 'int' object has no attribute 'value'
  print(e)
'int' object has no attribute 'value'
try:
  # Create a shape and choose an index
  shape = tf.TensorShape([16, None, 256])
  dim = shape[1]
  other_dim = shape[2]
  dim.assert_is_compatible_with(other_dim)
except AttributeError as e:
  # 'NoneType' object has no attribute 'assert_is_compatible_with'
  print(e)
'NoneType' object has no attribute 'assert_is_compatible_with'

মান দ্বারা টেনসর সমতা

ভেরিয়েবল এবং টেনসরের বাইনারি == এবং != অপারেটরগুলিকে TF1.x এর মত বস্তুর রেফারেন্স দ্বারা তুলনা করার পরিবর্তে TF2-তে মান অনুসারে তুলনা করার জন্য পরিবর্তন করা হয়েছিল। অতিরিক্তভাবে, টেনসর এবং ভেরিয়েবলগুলি আর সরাসরি হ্যাশযোগ্য বা সেট বা ডিক্ট কীগুলিতে ব্যবহারযোগ্য নয়, কারণ মান অনুসারে সেগুলি হ্যাশ করা সম্ভব নাও হতে পারে। পরিবর্তে, তারা একটি .ref() পদ্ধতি প্রকাশ করে যা আপনি টেনসর বা ভেরিয়েবলের হ্যাশেবল রেফারেন্স পেতে ব্যবহার করতে পারেন।

এই আচরণ পরিবর্তনের প্রভাবকে আলাদা করতে, আপনি tf.compat.v1.disable_tensor_equality() এবং tf.compat.v1.enable_tensor_equality() ব্যবহার করে এই আচরণ পরিবর্তনটিকে বিশ্বব্যাপী নিষ্ক্রিয় বা সক্ষম করতে পারেন৷

উদাহরণস্বরূপ, TF1.x-এ, আপনি যখন == অপারেটর ব্যবহার করেন তখন একই মান সহ দুটি ভেরিয়েবল মিথ্যা দেখাবে:

tf.compat.v1.disable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)

x == y
False

TF2 এ টেনসর সমতা চেক সক্রিয় থাকাকালীন, x == y ফেরত দেবে True

tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)

x == y
<tf.Tensor: shape=(), dtype=bool, numpy=True>

সুতরাং, TF2-এ, যদি আপনি অবজেক্ট রেফারেন্স দ্বারা তুলনা করতে চান তবে নিশ্চিত করুন যে এটি ব্যবহার is হয়েছে এবং is not

tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)
y = tf.Variable(0.0)

x is y
False

হ্যাশিং টেনসর এবং ভেরিয়েবল

TF1.x আচরণের মাধ্যমে আপনি ডেটা স্ট্রাকচারে সরাসরি ভেরিয়েবল এবং টেনসর যোগ করতে সক্ষম হতেন যার জন্য হ্যাশিং প্রয়োজন, যেমন set এবং dict কী।

tf.compat.v1.disable_tensor_equality()
x = tf.Variable(0.0)
set([x, tf.constant(2.0)])
{<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>,
 <tf.Tensor: shape=(), dtype=float32, numpy=2.0>}

যাইহোক, TF2-এ টেনসর সমতা সক্ষম করে, == এবং != অপারেটর শব্দার্থ মানের সমতা পরীক্ষায় পরিবর্তিত হওয়ার কারণে টেনসর এবং ভেরিয়েবলগুলিকে আনহ্যাশেবল করা হয়েছে।

tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)

try:
  set([x, tf.constant(2.0)])
except TypeError as e:
  # TypeError: Variable is unhashable. Instead, use tensor.ref() as the key.
  print(e)
Variable is unhashable. Instead, use tensor.ref() as the key.

সুতরাং, TF2-এ যদি আপনাকে টেনসর বা পরিবর্তনশীল বস্তুগুলিকে কী বা বিষয়বস্তু set হিসাবে ব্যবহার করতে হয়, আপনি একটি হ্যাশেবল রেফারেন্স পেতে tensor.ref() ব্যবহার করতে পারেন যা একটি কী হিসাবে ব্যবহার করা যেতে পারে:

tf.compat.v1.enable_tensor_equality()
x = tf.Variable(0.0)

tensor_set = set([x.ref(), tf.constant(2.0).ref()])
assert x.ref() in tensor_set

tensor_set
{<Reference wrapping <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>>,
 <Reference wrapping <tf.Tensor: shape=(), dtype=float32, numpy=2.0>>}

প্রয়োজন হলে, আপনি reference.deref() ব্যবহার করে রেফারেন্স থেকে টেনসর বা পরিবর্তনশীল পেতে পারেন :

referenced_var = x.ref().deref()
assert referenced_var is x
referenced_var
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>

সম্পদ এবং আরও পড়া

  • TF1.x থেকে TF2- এ স্থানান্তরিত করার বিষয়ে আরও পড়তে TF2-এ মাইগ্রেট করুন বিভাগে যান।
  • সরাসরি TF2 এ কাজ করার জন্য আপনার TF1.x মডেলের ম্যাপিং সম্পর্কে আরও জানতে মডেল ম্যাপিং গাইড পড়ুন।