তারিখটা মনে রেখো! গুগল I / O মে 18-20 মে এখনই রেজিস্টার করুন
This page was translated by the Cloud Translation API.
Switch to English

Tf.function সঙ্গে আরও ভাল পারফরম্যান্স

টেনসরফ্লো.অর্গ.এ দেখুন গুগল কোলাবে চালান গিটহাবের উত্স দেখুন নোটবুক ডাউনলোড করুন

টেনসরফ্লো 2-তে, আগ্রহী সম্পাদন ডিফল্টরূপে চালু হয়। ইউজার ইন্টারফেস স্বজ্ঞাত এবং নমনীয় (এক-অফ ক্রিয়াকলাপ চালানো অনেক সহজ এবং দ্রুত) তবে এটি কার্য সম্পাদন এবং শৃঙ্খলাবদ্ধতার ব্যয়ে আসতে পারে।

আপনি আপনার প্রোগ্রামগুলি থেকে গ্রাফ তৈরি করতে tf.function ব্যবহার করতে পারেন। এটি একটি রূপান্তর সরঞ্জাম যা পাইথন কোড থেকে আপনার পাইথন-স্বতন্ত্র ডেটাফ্লো গ্রাফ তৈরি করে। এটি আপনাকে পারফরম্যান্ট এবং পোর্টেবল মডেল তৈরি করতে সহায়তা করবে এবং SavedModel ব্যবহার করা প্রয়োজন।

এই গাইডটি আপনাকে ধারণাটি তৈরি করতে সহায়তা করবে যে tf.function হুডের নীচে কীভাবে কাজ করে যাতে আপনি এটি কার্যকরভাবে ব্যবহার করতে পারেন।

মূল গ্রহণ ও সুপারিশগুলি হ'ল:

  • উত্সাহী মোডে ডিবাগ করুন, তারপরে @tf.function দিয়ে সজ্জিত করুন।
  • পাইথনের পার্শ্ব প্রতিক্রিয়া যেমন অবজেক্ট মিউটেশন বা তালিকা সংযোজনগুলির উপর নির্ভর করবেন না।
  • tf.function অপ্স দিয়ে সবচেয়ে ভাল কাজ করে; নুমপি এবং পাইথন কলগুলি ধ্রুবকগুলিতে রূপান্তরিত হয়।

সেটআপ

import tensorflow as tf

আপনি যে ধরণের ত্রুটির মুখোমুখি হতে পারেন তা প্রদর্শনের জন্য সহায়ক ফাংশনটি সংজ্ঞায়িত করুন:

import traceback
import contextlib

# Some helper code to demonstrate the kinds of errors you might encounter.
@contextlib.contextmanager
def assert_raises(error_class):
  try:
    yield
  except error_class as e:
    print('Caught expected exception \n  {}:'.format(error_class))
    traceback.print_exc(limit=2)
  except Exception as e:
    raise e
  else:
    raise Exception('Expected {} to be raised but no error was raised!'.format(
        error_class))

বুনিয়াদি

ব্যবহার

আপনি যে Function সংজ্ঞায়িত করেছেন (উদাহরণস্বরূপ @tf.function প্রয়োগ করে) ঠিক তেমন একটি টেনসরফ্লো অপারেশন: আপনি এটিকে আগ্রহের সাথে @tf.function করতে পারেন; আপনি গ্রেডিয়েন্ট গণনা করতে পারেন; ইত্যাদি।

@tf.function  # The decorator converts `add` into a `Function`.
def add(a, b):
  return a + b

add(tf.ones([2, 2]), tf.ones([2, 2]))  #  [[2., 2.], [2., 2.]]
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[2., 2.],
       [2., 2.]], dtype=float32)>
v = tf.Variable(1.0)
with tf.GradientTape() as tape:
  result = add(v, 1.0)
tape.gradient(result, v)
<tf.Tensor: shape=(), dtype=float32, numpy=1.0>

আপনি অন্য Function Function ব্যবহার করতে পারেন।

@tf.function
def dense_layer(x, w, b):
  return add(tf.matmul(x, w), b)

dense_layer(tf.ones([3, 2]), tf.ones([2, 2]), tf.ones([2]))
<tf.Tensor: shape=(3, 2), dtype=float32, numpy=
array([[3., 3.],
       [3., 3.],
       [3., 3.]], dtype=float32)>

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

import timeit
conv_layer = tf.keras.layers.Conv2D(100, 3)

@tf.function
def conv_fn(image):
  return conv_layer(image)

image = tf.zeros([1, 200, 200, 100])
# warm up
conv_layer(image); conv_fn(image)
print("Eager conv:", timeit.timeit(lambda: conv_layer(image), number=10))
print("Function conv:", timeit.timeit(lambda: conv_fn(image), number=10))
print("Note how there's not much difference in performance for convolutions")
Eager conv: 0.003693543000053978
Function conv: 0.004675635000012335
Note how there's not much difference in performance for convolutions

ট্র্যাকিং

ভবিষ্যতে পরিবর্তিত হতে পারে এমন বাস্তবায়নের বিবরণ সহ Function কীভাবে হুডের নীচে কাজ করে তা এই বিভাগটি প্রকাশ করে । তবে, একবার যখন আপনি বুঝতে পারবেন কেন এবং কখন ট্রেসিং ঘটে, তখন tf.function কার্যকরভাবে ব্যবহার করা অনেক সহজ!

"ট্রেসিং" কী?

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

আপনার কোডটি দুটি পর্যায়ে আলাদা করে Function এই ব্যবধানটি সরিয়ে দেয়:

1) প্রথম পর্যায়ে, " ট্রেসিং " হিসাবে চিহ্নিত , Function একটি নতুন tf.Graph তৈরি করে। পাইথন কোডটি সাধারণত চালিত হয় তবে সমস্ত টেনসরফ্লো অপারেশন (দুটি টেনার যুক্ত করার মতো) পিছিয়ে যায় : সেগুলি tf.Graph হাতে ধরা tf.Graph এবং চালানো হয় না।

2) দ্বিতীয় পর্যায়ে, একটি tf.Graph যা প্রথম পর্যায়ে মুলতুবি করা হয়েছিল এমন সমস্ত কিছু চালায়। এই স্তরটি ট্রেসিং স্টেজের চেয়ে অনেক দ্রুত।

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

যখন Function ট্রেস করার সিদ্ধান্ত নেয়, তখন ট্রেসিং স্টেজটি তাত্ক্ষণিকভাবে দ্বিতীয় পর্যায়ে অনুসরণ করা হয়, সুতরাং Function কল করা উভয়ই tf.Graph তৈরি করে এবং চালায়। পরে আপনি দেখতে পাবেন কীভাবে আপনি get_concrete_function দিয়ে কেবল ট্রেসিং স্টেজটি চালাতে পারবেন।

যখন আমরা কোনও Function বিভিন্ন ধরণের আর্গুমেন্টগুলি পাস করি, তখন উভয় পর্যায়ে চালিত হয়:

@tf.function
def double(a):
  print("Tracing with", a)
  return a + a

print(double(tf.constant(1)))
print()
print(double(tf.constant(1.1)))
print()
print(double(tf.constant("a")))
print()
Tracing with Tensor("a:0", shape=(), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)

Tracing with Tensor("a:0", shape=(), dtype=float32)
tf.Tensor(2.2, shape=(), dtype=float32)

Tracing with Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'aa', shape=(), dtype=string)

মনে রাখবেন যে আপনি যদি বার বার একই আর্গুমেন্ট প্রকারের সাথে কোনও Function কল করেন তবে টেনসরফ্লো ট্রেসিং স্টেজটি এড়িয়ে যাবেন এবং পূর্ববর্তী ট্রেস করা গ্রাফটি পুনরায় ব্যবহার করবেন, কারণ উত্পন্ন গ্রাফটি অভিন্ন হবে।

# This doesn't print 'Tracing with ...'
print(double(tf.constant("b")))
tf.Tensor(b'bb', shape=(), dtype=string)

উপলভ্য সমস্ত ট্রেস দেখতে আপনি pretty_printed_concrete_signatures() ব্যবহার করতে পারেন:

print(double.pretty_printed_concrete_signatures())
double(a)
  Args:
    a: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()

double(a)
  Args:
    a: string Tensor, shape=()
  Returns:
    string Tensor, shape=()

double(a)
  Args:
    a: int32 Tensor, shape=()
  Returns:
    int32 Tensor, shape=()

এখনও অবধি, আপনি দেখেছেন যে tf.function এর গ্রাফ ট্রেসিং লজিকের উপর একটি ক্যাশেড, গতিশীল প্রেরণ স্তর তৈরি করে। পরিভাষা সম্পর্কে আরও সুনির্দিষ্ট হতে:

  • একটি tf.Graph হ'ল একটি tf.Graph কাঁচা, ভাষা- tf.Graph , বহনযোগ্য উপস্থাপনা।
  • একজন ConcreteFunction একটি গোপন tf.Graph
  • একটি Function ConcreteFunction Function ক্যাশে পরিচালনা করে এবং আপনার ইনপুটগুলির জন্য সঠিকটিকে বেছে নেয়।
  • tf.function একটি পাইথন ফাংশন মোড়ানো, একটি Function অবজেক্ট ফিরে।
  • ট্রেস একটি সৃষ্টি tf.Graph এবং এটা গোপন ConcreteFunction , এছাড়াও একটি ট্রেস হিসাবে পরিচিত।

ট্রেসিংয়ের নিয়ম

একটি Function নির্ধারণ করে যে কোনও ইনপুট এর আরোগুলি এবং কাওয়ার্গেস থেকে একটি ক্যাশে কী গণনা করে ট্রেসড ConcreteFunction Function পুনরায় ব্যবহার করতে হবে। ক্যাশে কী এমন একটি কী যা নিম্নলিখিত বিধি অনুসারে (যা পরিবর্তিত হতে পারে) Function কলের ইনপুট আরগস এবং কাওয়ার্গসের উপর ভিত্তি করে একটি ConcreteFunction Function সনাক্ত করে:

  • tf.Tensor জন্য উত্পন্ন কীটি এর আকৃতি এবং টাইপ।
  • একটি tf.Variable . পরিবর্তনশীল জন্য উত্পন্ন কীটি একটি অনন্য পরিবর্তনশীল আইডি।
  • পাইথন আদিম (যেমন int , float , str ) এর জন্য উত্পন্ন কীটি এর মান।
  • জন্য নেস্টেড উত্পন্ন কী dict এস, list S, tuple এস, namedtuple s, এবং attr গুলি পাতার কি-সংকলন (দেখতে একরকমের চ্যাপ্টা tuple হয়nest.flatten )। (এই সমতলকরণের ফলস্বরূপ, ট্রেসিংয়ের সময় ব্যবহৃত একটির চেয়ে আলাদা বাসা বাঁধার কাঠামো সহ একটি কংক্রিটের ফাংশন কল করার ফলে টাইপআরারের ফলাফল আসবে)।
  • অন্যান্য পাইথন ধরণের জন্য, কীগুলি অবজেক্ট id() এর উপর ভিত্তি করে তৈরি হয় যাতে কোনও শ্রেণীর প্রতিটি উদাহরণের জন্য পদ্ধতিগুলি স্বাধীনভাবে চিহ্নিত করা যায়।

Retracing নিয়ন্ত্রণ করা হচ্ছে

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

ট্রেসিং আচরণটি নিয়ন্ত্রণ করতে, আপনি নিম্নলিখিত কৌশলগুলি ব্যবহার করতে পারেন:

  • ট্রেসিং সীমাবদ্ধ করতে input_signaturetf.function নির্দিষ্ট করুন।
@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32),))
def next_collatz(x):
  print("Tracing with", x)
  return tf.where(x % 2 == 0, x // 2, 3 * x + 1)

print(next_collatz(tf.constant([1, 2])))
# We specified a 1-D tensor in the input signature, so this should fail.
with assert_raises(ValueError):
  next_collatz(tf.constant([[1, 2], [3, 4]]))

# We specified an int32 dtype in the input signature, so this should fail.
with assert_raises(ValueError):
  next_collatz(tf.constant([1.0, 2.0]))
Tracing with Tensor("x:0", shape=(None,), dtype=int32)
tf.Tensor([4 1], shape=(2,), dtype=int32)
Caught expected exception 
  <class 'ValueError'>:
Caught expected exception 
  <class 'ValueError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-20f544b8adbf>", line 9, in <module>
    next_collatz(tf.constant([[1, 2], [3, 4]]))
ValueError: Python inputs incompatible with input_signature:
  inputs: (
    tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32))
  input_signature: (
    TensorSpec(shape=(None,), dtype=tf.int32, name=None))
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-20f544b8adbf>", line 13, in <module>
    next_collatz(tf.constant([1.0, 2.0]))
ValueError: Python inputs incompatible with input_signature:
  inputs: (
    tf.Tensor([1. 2.], shape=(2,), dtype=float32))
  input_signature: (
    TensorSpec(shape=(None,), dtype=tf.int32, name=None))
  • ট্রেস পুনরায় ব্যবহারের ক্ষেত্রে নমনীয়তার জন্য tf.TensorSpec একটি [কিছুই নয়] মাত্রা নির্দিষ্ট করুন।

    যেহেতু টেনসরফ্লো তাদের আকৃতির উপর ভিত্তি করে টেনারগুলির সাথে মেলে, ওয়াইল্ডকার্ড হিসাবে কোনও None মাত্রা ব্যবহার করে Function ভেরিয়েবল-আকারের ইনপুটটির জন্য ট্রেসগুলি পুনরায় ব্যবহার করতে দেয়। আপনার বিভিন্ন দৈর্ঘ্যের ক্রম বা প্রতিটি ব্যাচের বিভিন্ন আকারের চিত্র থাকলে উদাহরণস্বরূপ আকারের ইনপুটটি ঘটতে পারে (উদাহরণস্বরূপ ট্রান্সফরমার এবং ডিপ ড্রিম টিউটোরিয়াল দেখুন)।

@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32),))
def g(x):
  print('Tracing with', x)
  return x

# No retrace!
print(g(tf.constant([1, 2, 3])))
print(g(tf.constant([1, 2, 3, 4, 5])))
Tracing with Tensor("x:0", shape=(None,), dtype=int32)
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)
  • ট্র্যাকারগুলি হ্রাস করতে টেনারগুলিতে পাইথন আর্গুমেন্টগুলি কাস্ট করুন।

    প্রায়শই পাইথন আর্গুমেন্টগুলি হাইপারপ্যারামিটার এবং গ্রাফ num_layers=10 নিয়ন্ত্রণ করতে ব্যবহৃত হয় - উদাহরণস্বরূপ, num_layers=10 বা training=True বা nonlinearity='relu' । সুতরাং পাইথন যুক্তি পরিবর্তিত হলে, এটি গ্রাফটি আবার সরিয়ে ফেলতে হবে তা বোঝা যায়।

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

def train_one_step():
  pass

@tf.function
def train(num_steps):
  print("Tracing with num_steps = ", num_steps)
  tf.print("Executing with num_steps = ", num_steps)
  for _ in tf.range(num_steps):
    train_one_step()

print("Retracing occurs for different Python arguments.")
train(num_steps=10)
train(num_steps=20)

print()
print("Traces are reused for Tensor arguments.")
train(num_steps=tf.constant(10))
train(num_steps=tf.constant(20))
Retracing occurs for different Python arguments.
Tracing with num_steps =  10
Executing with num_steps =  10
Tracing with num_steps =  20
Executing with num_steps =  20

Traces are reused for Tensor arguments.
Tracing with num_steps =  Tensor("num_steps:0", shape=(), dtype=int32)
Executing with num_steps =  10
Executing with num_steps =  20

আপনার যদি জোর করে প্রত্যাহার করতে হয় তবে একটি নতুন Function তৈরি করুন। পৃথক Function অবজেক্টগুলি ট্রেস ভাগ না করার গ্যারান্টিযুক্ত।

def f():
  print('Tracing!')
  tf.print('Executing')

tf.function(f)()
tf.function(f)()
Tracing!
Executing
Tracing!
Executing

কংক্রিট কার্যাবলী অর্জন

প্রতিবার কোনও ফাংশনটি সনাক্ত করা হলে একটি নতুন কংক্রিট ফাংশন তৈরি করা হয়। get_concrete_function ব্যবহার করে আপনি সরাসরি একটি কংক্রিটের কাজ করতে পারেন।

print("Obtaining concrete trace")
double_strings = double.get_concrete_function(tf.constant("a"))
print("Executing traced function")
print(double_strings(tf.constant("a")))
print(double_strings(a=tf.constant("b")))
Obtaining concrete trace
Executing traced function
tf.Tensor(b'aa', shape=(), dtype=string)
tf.Tensor(b'bb', shape=(), dtype=string)
# You can also call get_concrete_function on an InputSpec
double_strings_from_inputspec = double.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.string))
print(double_strings_from_inputspec(tf.constant("c")))
Tracing with Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'cc', shape=(), dtype=string)

একটি ConcreteFunction মুদ্রণ করা এর ইনপুট আর্গুমেন্টগুলির (সংক্ষিপ্তসার) এবং এর আউটপুট ধরণের সংক্ষিপ্তসার প্রদর্শন করে।

print(double_strings)
ConcreteFunction double(a)
  Args:
    a: string Tensor, shape=()
  Returns:
    string Tensor, shape=()

আপনি সরাসরি একটি কংক্রিট ফাংশনের স্বাক্ষর পুনরুদ্ধার করতে পারেন।

print(double_strings.structured_input_signature)
print(double_strings.structured_outputs)
((TensorSpec(shape=(), dtype=tf.string, name='a'),), {})
Tensor("Identity:0", shape=(), dtype=string)

অসামঞ্জস্যপূর্ণ ধরণের সাথে একটি কংক্রিট ট্রেস ব্যবহার করা ত্রুটি ছুঁড়ে দেবে

with assert_raises(tf.errors.InvalidArgumentError):
  double_strings(tf.constant(1))
Caught expected exception 
  <class 'tensorflow.python.framework.errors_impl.InvalidArgumentError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-e4e2860a4364>", line 2, in <module>
    double_strings(tf.constant(1))
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute __inference_double_162 as input #0(zero-based) was expected to be a string tensor but is a int32 tensor [Op:__inference_double_162]

আপনি খেয়াল করতে পারেন পাইথন যুক্তিগুলি একটি কংক্রিট ফাংশনের ইনপুট স্বাক্ষরে বিশেষ চিকিত্সা দেওয়া হয়। টেনসরফ্লো ২.৩ এর আগে পাইথন যুক্তিগুলি সহজেই কংক্রিটের ফাংশনের স্বাক্ষর থেকে সরানো হয়েছিল। টেনসরফ্লো ২.৩ দিয়ে শুরু করে পাইথন আর্গুমেন্টগুলি স্বাক্ষরে থেকে যায় তবে ট্রেসিংয়ের সময় মান সেট নিতে বাধ্য হয়।

@tf.function
def pow(a, b):
  return a ** b

square = pow.get_concrete_function(a=tf.TensorSpec(None, tf.float32), b=2)
print(square)
ConcreteFunction pow(a, b=2)
  Args:
    a: float32 Tensor, shape=<unknown>
  Returns:
    float32 Tensor, shape=<unknown>
assert square(tf.constant(10.0)) == 100

with assert_raises(TypeError):
  square(tf.constant(10.0), b=3)
Caught expected exception 
  <class 'TypeError'>:
Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 1683, in _call_impl
    cancellation_manager)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 1728, in _call_with_flat_signature
    self._flat_signature_summary(), ", ".join(sorted(kwargs))))
TypeError: pow(a) got unexpected keyword arguments: b.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-d163f3d206cb>", line 4, in <module>
    square(tf.constant(10.0), b=3)
TypeError: ConcreteFunction pow(a, b) was constructed with int value 2 in b, but was called with int value 3

গ্রাফ প্রাপ্ত

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

graph = double_strings.graph
for node in graph.as_graph_def().node:
  print(f'{node.input} -> {node.name}')
[] -> a
['a', 'a'] -> add
['add'] -> Identity

ডিবাগিং

সাধারণভাবে, ডিবাগিং কোডটি tf.function অভ্যন্তরের চেয়ে অধীর মোডে সহজ। আপনার কোডটি tf.function দিয়ে tf.function আগে উত্সাহী মোডে ত্রুটি-মুক্ত কার্যকর করেছে তা নিশ্চিত করা উচিত। ডিবাগিং প্রক্রিয়াটিতে সহায়তা করার জন্য, আপনি বিশ্বব্যাপী অক্ষম করতে এবং পুনরায় সক্ষম করার জন্য tf.function tf.config.run_functions_eagerly(True) কল করতে পারেন।

কেবল tf.function মধ্যে উপস্থিত সমস্যাগুলি সন্ধান করার tf.function , এখানে কয়েকটি টিপস দেওয়া হয়েছে:

  • সরল পুরাতন পাইথন print কলগুলি কেবল ট্রেসিংয়ের সময় কার্যকর করা হয়, যখন আপনার ফাংশনটি (পুনরায়) পাওয়া গেলে আপনাকে ট্র্যাক ডাউন করতে সহায়তা করে।
  • tf.print কলগুলি প্রতিবার কার্যকর করা হবে এবং কার্যকর করার সময় মধ্যবর্তী মানগুলি ট্র্যাক করতে সহায়তা করতে পারে।
  • tf.debugging.enable_check_numerics যেখানে NaNs এবং ইনফ তৈরি করা হয়েছে তা ট্র্যাক করার একটি সহজ উপায়।
  • pdb সময় কী হচ্ছে তা বুঝতে pdb আপনাকে সহায়তা করতে পারে। (ক্যাভিয়েট: পিডিবি আপনাকে অটোগ্রাফ-ট্রান্সফর্মড সোর্স কোডে ফেলে দেবে))

অটোগ্রাফ রূপান্তরকরণ

অটোগ্রাফ একটি লাইব্রেরি যা ডিফল্টরূপে tf.functiontf.function এবং পাইথন আগ্রহী কোডের একটি উপসেটকে গ্রাফ-সামঞ্জস্যপূর্ণ tf.function রূপান্তরিত করে। এই মত নিয়ন্ত্রণ প্রবাহ অন্তর্ভুক্ত if , for , while

tf.cond এবং tf.while_loop tf.cond মত কাজ করা চালিয়ে যায়, তবে tf.while_loop নিয়ন্ত্রণ প্রবাহটি প্রায়শই লেখা এবং বোঝা সহজ হয়।

# Simple loop

@tf.function
def f(x):
  while tf.reduce_sum(x) > 1:
    tf.print(x)
    x = tf.tanh(x)
  return x

f(tf.random.uniform([5]))
[0.150836706 0.575092077 0.530339956 0.492499471 0.696070552]
[0.149703071 0.519089103 0.485640883 0.456198 0.601867676]
[0.148594663 0.476996601 0.450749785 0.426980466 0.538377285]
[0.147510558 0.44383505 0.422515154 0.402794749 0.491758645]
[0.146449849 0.416818231 0.399047196 0.382337689 0.45561108]
[0.145411745 0.394246608 0.379133403 0.364735901 0.42650038]
[0.144395441 0.375015408 0.361954659 0.349378705 0.402392507]
[0.143400162 0.358370811 0.346934587 0.3358244 0.381994188]
[0.142425224 0.343778163 0.333654165 0.323744506 0.364438057]
[0.141469926 0.330846161 0.321800381 0.312888771 0.34911716]
[0.140533626 0.319280863 0.311133921 0.303062797 0.335592359]
[0.139615685 0.308856487 0.301468313 0.294112951 0.323536754]
[0.13871555 0.299396455 0.292655736 0.285915941 0.312701344]
[0.137832627 0.290760159 0.28457731 0.278371543 0.302892596]
[0.136966363 0.282834291 0.277136147 0.271397203 0.293957472]
[0.136116222 0.275526226 0.270252436 0.264924437 0.285773188]
[0.135281757 0.268759459 0.263859689 0.258895695 0.278239816]
[0.134462461 0.262470126 0.257902056 0.253262341 0.271275192]
[0.133657902 0.256604493 0.252332211 0.24798286 0.264810979]
[0.132867619 0.251116842 0.247109696 0.243021563 0.258789837]
[0.132091209 0.245968238 0.242199793 0.238347709 0.253163248]
[0.131328285 0.241125017 0.237572461 0.233934492 0.247889832]
[0.130578429 0.236558065 0.233201504 0.229758516 0.242934018]
[0.129841298 0.232242063 0.229064062 0.225799173 0.238265097]
[0.129116505 0.228154778 0.22514002 0.222038344 0.233856365]
[0.128403738 0.224276677 0.221411601 0.218459949 0.229684487]
[0.127702653 0.220590457 0.217863053 0.215049684 0.225728899]
<tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.12701295, 0.21708074, 0.21448033, 0.21179478, 0.22197153],
      dtype=float32)>

আপনি যদি আগ্রহী হন তবে আপনি অটোগ্রাফ উত্পন্ন কোডটি পরিদর্শন করতে পারেন।

print(tf.autograph.to_code(f.python_function))
def tf__f(x):
    with ag__.FunctionScope('f', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope:
        do_return = False
        retval_ = ag__.UndefinedReturnValue()

        def get_state():
            return (x,)

        def set_state(vars_):
            nonlocal x
            (x,) = vars_

        def loop_body():
            nonlocal x
            ag__.converted_call(ag__.ld(tf).print, (ag__.ld(x),), None, fscope)
            x = ag__.converted_call(ag__.ld(tf).tanh, (ag__.ld(x),), None, fscope)

        def loop_test():
            return (ag__.converted_call(ag__.ld(tf).reduce_sum, (ag__.ld(x),), None, fscope) > 1)
        ag__.while_stmt(loop_test, loop_body, get_state, set_state, ('x',), {})
        try:
            do_return = True
            retval_ = ag__.ld(x)
        except:
            do_return = False
            raise
        return fscope.ret(retval_, do_return)

শর্তসাপেক্ষ

if <condition> বিবৃতিটিকে সমতুল্য tf.cond কলগুলিতে রূপান্তর if <condition> অটোগ্রাফ কিছুটিকে রূপান্তর করবে। <condition> একটি টেনসর হলে এই প্রতিস্থাপনটি করা হয়। অন্যথায়, if স্টেটমেন্টটি পাইথন শর্তসাপেক্ষ হিসাবে কার্যকর করা হয়।

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

tf.cond গ্রাফটিতে শর্তাধীন উভয় শাখাকে চিহ্নিত করে এবং tf.cond সময় tf.cond একটি শাখা নির্বাচন করে। ট্রেসিংয়ের অনিচ্ছাকৃত পার্শ্ব প্রতিক্রিয়া হতে পারে; আরও জন্য অটোগ্রাফ ট্রেসিং প্রভাব দেখুন।

@tf.function
def fizzbuzz(n):
  for i in tf.range(1, n + 1):
    print('Tracing for loop')
    if i % 15 == 0:
      print('Tracing fizzbuzz branch')
      tf.print('fizzbuzz')
    elif i % 3 == 0:
      print('Tracing fizz branch')
      tf.print('fizz')
    elif i % 5 == 0:
      print('Tracing buzz branch')
      tf.print('buzz')
    else:
      print('Tracing default branch')
      tf.print(i)

fizzbuzz(tf.constant(5))
fizzbuzz(tf.constant(20))
Tracing for loop
Tracing fizzbuzz branch
Tracing fizz branch
Tracing buzz branch
Tracing default branch
1
2
fizz
4
buzz
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz

বিবৃতি যদি অটোগ্রাফ-রূপান্তরিত অতিরিক্ত বিধিনিষেধের জন্য রেফারেন্স ডকুমেন্টেশন দেখুন।

লুপস

অটোগ্রাফ কিছু রূপান্তর করবে for এবং while সমতুল্য TensorFlow মধ্যে বিবৃতি অপস লুপিং মত tf.while_loop । যদি রূপান্তরিত না হয় তবে এর for বা while লুপটি পাইথন লুপ হিসাবে কার্যকর হয়।

এই প্রতিস্থাপন নিম্নলিখিত পরিস্থিতিতে তৈরি করা হয়:

  • for x in y : যদি y একটি টেনসর হয় তবে tf.while_loop . tf.while_loop রূপান্তর করুন। বিশেষ ক্ষেত্রে যেখানে সালে y একটি হলtf.data.Dataset , সংমিশ্রণtf.data.Dataset অপস তৈরি হয়।
  • while <condition> : যদি <condition> একটি টেনসর হয় তবে tf.while_loop . tf.while_loop রূপান্তর করুন।

পাইথন লুপটি ট্রেসিংয়ের সময় সঞ্চালন করে, লুপের প্রতিটি পুনরাবৃত্তির জন্য tf.Graph র অতিরিক্ত অপস যুক্ত করে।

একটি টেনসরফ্লো লুপ লুপটির শরীরে ট্রেস করে এবং কার্যকরভাবে নির্বাহের সময় কতগুলি পুনরাবৃত্তি চালাতে হয় তা গতিশীলভাবে নির্বাচন করে। লুপের বডিটি কেবল একবার উত্পন্ন tf.Graph

দেখুন রেফারেন্স ডকুমেন্টেশন উপর অটোগ্রাফ-রূপান্তরিত অতিরিক্ত বিধিনিষেধ জন্য for এবং while বিবৃতি।

পাইথন ডেটার উপর লুপিং

একটি সাধারণ ফাঁদ একটি মধ্যে পাইথন / Numpy ডেটার উপর লুপ হয় tf.function । এই লুপটি ট্রেসিং প্রক্রিয়া চলাকালীন কার্যকর হবে এবং tf.Graph প্রতিটি পুনরাবৃত্তির জন্য tf.Graph আপনার মডেলের একটি অনুলিপি যুক্ত করবে।

আপনি যদি পুরো প্রশিক্ষণ লুপটি tf.functiontf.function রাখতে চান তবে এটি করার সবচেয়ে নিরাপদ উপায় হল আপনারtf.data.Dataset হিসাবে মোড়ানো করা যাতে অটোগ্রাফটি গতিশীলভাবে প্রশিক্ষণ লুপটিকে আনরোল করে দেয়।

def measure_graph_size(f, *args):
  g = f.get_concrete_function(*args).graph
  print("{}({}) contains {} nodes in its graph".format(
      f.__name__, ', '.join(map(str, args)), len(g.as_graph_def().node)))

@tf.function
def train(dataset):
  loss = tf.constant(0)
  for x, y in dataset:
    loss += tf.abs(y - x) # Some dummy computation.
  return loss

small_data = [(1, 1)] * 3
big_data = [(1, 1)] * 10
measure_graph_size(train, small_data)
measure_graph_size(train, big_data)

measure_graph_size(train, tf.data.Dataset.from_generator(
    lambda: small_data, (tf.int32, tf.int32)))
measure_graph_size(train, tf.data.Dataset.from_generator(
    lambda: big_data, (tf.int32, tf.int32)))
train([(1, 1), (1, 1), (1, 1)]) contains 11 nodes in its graph
train([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1)]) contains 32 nodes in its graph
train(<FlatMapDataset shapes: (<unknown>, <unknown>), types: (tf.int32, tf.int32)>) contains 10 nodes in its graph
train(<FlatMapDataset shapes: (<unknown>, <unknown>), types: (tf.int32, tf.int32)>) contains 10 nodes in its graph

ডেটাসেটে পাইথন / নম্পি ডেটা মোড়ানোর সময়, tf.data.Dataset.from_generator বনাম tf.data.Dataset.from_tensors মনে tf.data.Dataset.from_tensors । প্রাক্তনটি পাইথনে ডেটা রাখবে এবং এটি tf.py_function মাধ্যমে tf.py_function যার কার্য সম্পাদনের প্রভাব থাকতে পারে, তবে পরবর্তীকালে গ্রাফের মধ্যে একটি বৃহত tf.constant() নোড হিসাবে ডেটার অনুলিপি বান্ডিল করা হবে, এতে মেমরির প্রভাব থাকতে পারে।

TFRecordDataset / CSvDataset / ইত্যাদির মাধ্যমে ফাইল থেকে ডেটা পড়া। ডেটা গ্রাহনের সবচেয়ে কার্যকর উপায়, কারণ টেনসরফ্লো নিজেই পাইথনকে জড়িত না করে অ্যাসিনক্রোনাস লোডিং এবং উপাত্ত উপস্থাপন পরিচালনা করতে পারে। আরও জানতে, দেখুন tf.data গাইড

একটি লুপে মান একত্রিত করা

একটি সাধারণ প্যাটার্ন হ'ল লুপ থেকে মধ্যবর্তী মান সংগ্রহ করা। সাধারণত, এটি পাইথন তালিকায় যুক্ত বা পাইথন অভিধানে এন্ট্রি যুক্ত করে সম্পন্ন হয়। তবে, এগুলি পাইথনের পার্শ্ব প্রতিক্রিয়া হিসাবে, এগুলি গতিশীলভাবে অনিবন্ধিত লুপে প্রত্যাশার মতো কাজ করবে না। ডায়নামিক্যালি tf.TensorArray লুপ থেকে ফলাফল সংগ্রহ করতে tf.TensorArray ব্যবহার করুন।

batch_size = 2
seq_len = 3
feature_size = 4

def rnn_step(inp, state):
  return inp + state

@tf.function
def dynamic_rnn(rnn_step, input_data, initial_state):
  # [batch, time, features] -> [time, batch, features]
  input_data = tf.transpose(input_data, [1, 0, 2])
  max_seq_len = input_data.shape[0]

  states = tf.TensorArray(tf.float32, size=max_seq_len)
  state = initial_state
  for i in tf.range(max_seq_len):
    state = rnn_step(input_data[i], state)
    states = states.write(i, state)
  return tf.transpose(states.stack(), [1, 0, 2])

dynamic_rnn(rnn_step,
            tf.random.uniform([batch_size, seq_len, feature_size]),
            tf.zeros([batch_size, feature_size]))
<tf.Tensor: shape=(2, 3, 4), dtype=float32, numpy=
array([[[0.6345552 , 0.3862481 , 0.8089291 , 0.397156  ],
        [0.8435192 , 0.46313608, 1.2150625 , 1.2924602 ],
        [0.84762645, 0.9920107 , 1.6375196 , 1.8461396 ]],

       [[0.44864273, 0.8552673 , 0.36585057, 0.88470626],
        [0.6609589 , 1.4641674 , 0.79369175, 1.0593072 ],
        [0.8057562 , 2.4129076 , 1.5868478 , 1.8529567 ]]], dtype=float32)>

সীমাবদ্ধতা

TensorFlow Function নকশা যে আপনি যখন একটি একটি পাইথন ফাংশন রূপান্তর সচেতন হওয়া উচিত দ্বারা কয়েক সীমাবদ্ধতা উপস্থিত রয়েছে Function

পাইথনের পার্শ্ব প্রতিক্রিয়াগুলি কার্যকর করা

পার্শ্ব প্রতিক্রিয়া, যেমন মুদ্রণ, তালিকাগুলিতে সংযোজন এবং গ্লোবালগুলিকে পরিবর্তন করা, কোনও Function অভ্যন্তরে অপ্রত্যাশিতভাবে আচরণ করতে পারে, কখনও কখনও দু'বার সম্পাদিত হয় বা সমস্ত কিছু না। আপনি কেবল ইনপুটগুলির সেট দিয়ে কোনও Function কল করার সময় এগুলি ঘটে। এরপরে, পাইথন কোডটি কার্যকর না করে সনাক্ত করা tf.Graph পুনরায় tf.Graph হয়।

থাম্বের সাধারণ নিয়মটি হ'ল আপনার যুক্তিতে পাইথনের পার্শ্ব প্রতিক্রিয়াগুলির উপর নির্ভর করা এড়ানো এবং কেবলমাত্র এটি আপনার ট্রেস ডিবাগ করতে ব্যবহার করুন। অন্যথায়, tf.data যেমন tf.data , tf.print , tf.summary , tf.Variable.assign , এবং tf.TensorArray আপনার কোডটি প্রতিটি কল দিয়ে টেনসরফ্লো রানটাইম দ্বারা কার্যকর করা হবে তা নিশ্চিত করার সেরা উপায়।

@tf.function
def f(x):
  print("Traced with", x)
  tf.print("Executed with", x)

f(1)
f(1)
f(2)
Traced with 1
Executed with 1
Executed with 1
Traced with 2
Executed with 2

যদি আপনি কোনও Function প্রতিটি tf.py_function সময় পাইথন কোডটি কার্যকর করতে চান তবে tf.py_function হ'ল একটি প্রস্থান হ্যাচ। tf.py_function এর অপূর্ণতা tf.py_function এটি পোর্টেবল বা বিশেষত পারফরম্যান্ট নয়, সেভডমোডেল দিয়ে সংরক্ষণ করা যায় না এবং বিতরণকৃত (মাল্টি-জিপিইউ, টিপিইউ) সেটআপগুলিতে ভাল কাজ করে না। এছাড়াও, যেহেতু tf.py_function গ্রাফের সাথে তারযুক্ত করতে হয়, তাই এটি সমস্ত ইনপুট / আউটপুট tf.py_function কাস্ট করে।

পাইথন গ্লোবাল এবং ফ্রি ভেরিয়েবল পরিবর্তন করা

পাইথন গ্লোবাল এবং ফ্রি ভেরিয়েবল পরিবর্তন করা পাইথন পার্শ্ব প্রতিক্রিয়া হিসাবে গণনা করা হয়, সুতরাং এটি কেবল ট্রেসিংয়ের সময় ঘটে।

external_list = []

@tf.function
def side_effect(x):
  print('Python side effect')
  external_list.append(x)

side_effect(1)
side_effect(1)
side_effect(1)
# The list append only happened once!
assert len(external_list) == 1
Python side effect

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

আপনি কিছু ক্ষেত্রে, ক্যাপচার এবং tf.Variable করতে পারেন যদি এটি tf.Variable হয় তবে tf.Variable । এভাবেই Keras মডেলের ওজন একই পুনরাবৃত্তি কল সহ আপডেট করা হয় ConcreteFunction

পাইথন পুনরুক্তি এবং জেনারেটর ব্যবহার করে

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

@tf.function
def buggy_consume_next(iterator):
  tf.print("Value:", next(iterator))

iterator = iter([1, 2, 3])
buggy_consume_next(iterator)
# This reuses the first value from the iterator, rather than consuming the next value.
buggy_consume_next(iterator)
buggy_consume_next(iterator)
Value: 1
Value: 1
Value: 1

tf.TensorArray কীভাবে তালিকা tf.TensorArray জন্য একটি বিশেষ tf.data.Iterator রয়েছে ঠিক tf.data.Iterator পুনরাবৃত্তি tf.data.Iterator জন্য একটি বিশেষ tf.data.Iterator রয়েছে tf.data.Iterator ওভারভিউর জন্য অটোগ্রাফ ট্রান্সফর্মেশনগুলির বিভাগটি দেখুন। এছাড়াও, tf.data API জেনারেটরের নিদর্শনগুলি প্রয়োগ করতে সহায়তা করতে পারে:

@tf.function
def good_consume_next(iterator):
  # This is ok, iterator is a tf.data.Iterator
  tf.print("Value:", next(iterator))

ds = tf.data.Dataset.from_tensor_slices([1, 2, 3])
iterator = iter(ds)
good_consume_next(iterator)
good_consume_next(iterator)
good_consume_next(iterator)
Value: 1
Value: 2
Value: 3

Function কলগুলির মধ্যে tf.Wariables মুছে ফেলা হচ্ছে

আর একটি ত্রুটি আপনি মুখোমুখি হতে পারেন হ'ল একটি আবর্জনা-সংগৃহীত চলক। ConcreteFunction শুধুমাত্র বজায় রাখা র WeakRefs তারা ঘনিষ্ঠ উপর ভেরিয়েবল, তাই যদি আপনি কোন ভেরিয়েবল একটি রেফারেন্স রাখা আবশ্যক।

external_var = tf.Variable(3)
@tf.function
def f(x):
  return x * external_var

traced_f = f.get_concrete_function(4)
print("Calling concrete function...")
print(traced_f(4))

# The original variable object gets garbage collected, since there are no more
# references to it.
external_var = tf.Variable(4)
print()
print("Calling concrete function after garbage collecting its closed Variable...")
with assert_raises(tf.errors.FailedPreconditionError):
  traced_f(4)
Calling concrete function...
tf.Tensor(12, shape=(), dtype=int32)

Calling concrete function after garbage collecting its closed Variable...
Caught expected exception 
  <class 'tensorflow.python.framework.errors_impl.FailedPreconditionError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-9a93d2e07632>", line 16, in <module>
    traced_f(4)
tensorflow.python.framework.errors_impl.FailedPreconditionError: 2 root error(s) found.
  (0) Failed precondition:  Error while reading resource variable _AnonymousVar3 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar3/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-1-9a93d2e07632>:4) ]]
  (1) Failed precondition:  Error while reading resource variable _AnonymousVar3 from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/_AnonymousVar3/N10tensorflow3VarE does not exist.
     [[node ReadVariableOp (defined at <ipython-input-1-9a93d2e07632>:4) ]]
     [[ReadVariableOp/_2]]
0 successful operations.
0 derived errors ignored. [Op:__inference_f_782]

Function call stack:
f -> f

জ্ঞাত সমস্যা

যদি আপনার Function সঠিকভাবে মূল্যায়ন না করে তবে ভবিষ্যতে স্থির করার পরিকল্পনা করা এই জ্ঞাত সমস্যাগুলির দ্বারা ত্রুটিটি ব্যাখ্যা করা যেতে পারে।

পাইথন গ্লোবাল এবং ফ্রি ভেরিয়েবলের উপর নির্ভর করে

পাইথন আর্গুমেন্টের নতুন মান সহ কল ​​করা হলে Function একটি নতুন ConcreteFunction তৈরি করে। তবে পাইথন বন্ধ, গ্লোবাল বা সেই Function ননলোকালগুলির জন্য এটি তা করে না। তাদের মূল্য কল মধ্যে পরিবর্তন Function , Function এখনও মান তারা ছিল যখন এটি আঁকা ছিল ব্যবহার করবে। পাইথন কীভাবে নিয়মিত কাজ করে তার থেকে এটি আলাদা।

সেই কারণে, আমরা একটি কার্যকরী প্রোগ্রামিং শৈলীর প্রস্তাব দিই যা বাইরের নামগুলি বন্ধ করার পরিবর্তে যুক্তি ব্যবহার করে।

@tf.function
def buggy_add():
  return 1 + foo

@tf.function
def recommended_add(foo):
  return 1 + foo

foo = 1
print("Buggy:", buggy_add())
print("Correct:", recommended_add(foo))
Buggy: tf.Tensor(2, shape=(), dtype=int32)
Correct: tf.Tensor(2, shape=(), dtype=int32)
print("Updating the value of `foo` to 100!")
foo = 100
print("Buggy:", buggy_add())  # Did not change!
print("Correct:", recommended_add(foo))
Updating the value of `foo` to 100!
Buggy: tf.Tensor(2, shape=(), dtype=int32)
Correct: tf.Tensor(101, shape=(), dtype=int32)

আপনি যতক্ষণ না তাদের মানগুলি আপডেট না করেন ততক্ষণ আপনি বাইরের নামগুলি বন্ধ করতে পারেন।

পাইথন অবজেক্টের উপর নির্ভর করে

পাইথন অবজেক্টগুলিকে আর্গুমেন্ট হিসাবে tf.function পাস করার সুপারিশে tf.function জ্ঞাত সমস্যা রয়েছে যা ভবিষ্যতে স্থির করা হবে বলে আশা করা হচ্ছে। সাধারণভাবে, আপনি সামঞ্জস্যপূর্ণ হদিশ উপর নির্ভর আপনি একটি পাইথন আদিম বা ব্যবহার করতে পারেন tf.nest একটি আর্গুমেন্ট হিসাবে -compatible কাঠামো বা একটি মধ্যে একটি বস্তুর একটি ভিন্ন উদাহরণস্বরূপ মধ্যে পাস Function । তবে, আপনি একই বস্তুটি পাস করার পরে কেবল তার বৈশিষ্ট্যগুলি পরিবর্তন করলে Function কোনও নতুন ট্রেস তৈরি করবে না

class SimpleModel(tf.Module):
  def __init__(self):
    # These values are *not* tf.Variables.
    self.bias = 0.
    self.weight = 2.

@tf.function
def evaluate(model, x):
  return model.weight * x + model.bias

simple_model = SimpleModel()
x = tf.constant(10.)
print(evaluate(simple_model, x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
simple_model.bias += 5.0
print(evaluate(simple_model, x))  # Didn't change :(
Adding bias!
tf.Tensor(20.0, shape=(), dtype=float32)

মডেলটির আপডেট হওয়া উদাহরণটি মূল্যায়নের জন্য একই Function ব্যবহার করা বাগি হবে কারণ আপডেট হওয়া মডেলটির মূল মডেলের মতো একই ক্যাশে কী রয়েছে

সেই কারণে, আমরা আপনাকে সুপারিশ করব যে পরিবর্তনীয় অবজেক্ট বৈশিষ্ট্যের উপর নির্ভর করে বা নতুন অবজেক্ট তৈরি করতে আপনি আপনার Function লিখুন।

যদি সেটা সম্ভব না হয়, এক কার্যসংক্রান্ত নতুন করা হয় Function প্রতিটি সময় আপনি বল ফিরে দেখা করার জন্য আপনার বস্তুর পরিবর্তন S:

def evaluate(model, x):
  return model.weight * x + model.bias

new_model = SimpleModel()
evaluate_no_bias = tf.function(evaluate).get_concrete_function(new_model, x)
# Don't pass in `new_model`, `Function` already captured its state during tracing.
print(evaluate_no_bias(x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
new_model.bias += 5.0
# Create new Function and ConcreteFunction since you modified new_model.
evaluate_with_bias = tf.function(evaluate).get_concrete_function(new_model, x)
print(evaluate_with_bias(x)) # Don't pass in `new_model`.
Adding bias!
tf.Tensor(25.0, shape=(), dtype=float32)

যেমন retracing ব্যয়বহুল হতে পারে , আপনি tf.Variable গুলি অবজেক্ট বৈশিষ্ট্য হিসাবে ব্যবহার করতে পারেন, যা একটি tf.Variable প্রয়োজন ছাড়াই অনুরূপ প্রভাবের জন্য পরিবর্তিত (তবে পরিবর্তিত, সাবধান!) হতে পারে can

class BetterModel:

  def __init__(self):
    self.bias = tf.Variable(0.)
    self.weight = tf.Variable(2.)

@tf.function
def evaluate(model, x):
  return model.weight * x + model.bias

better_model = BetterModel()
print(evaluate(better_model, x))
tf.Tensor(20.0, shape=(), dtype=float32)
print("Adding bias!")
better_model.bias.assign_add(5.0)  # Note: instead of better_model.bias += 5
print(evaluate(better_model, x))  # This works!
Adding bias!
tf.Tensor(25.0, shape=(), dtype=float32)

Tf.Wariables তৈরি করা হচ্ছে

Function কেবল একবার কল করা হলে, এবং তারপরে পুনরায় ব্যবহার করার পরে কেবল একবার ভেরিয়েবলগুলি তৈরি করে supports আপনি নতুন ট্রেসগুলিতে tf.Variables . পরিবর্তনশীল তৈরি করতে পারবেন না। পরবর্তী কলগুলিতে নতুন ভেরিয়েবল তৈরি করা বর্তমানে অনুমোদিত নয় তবে ভবিষ্যতে হবে।

উদাহরণ:

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

with assert_raises(ValueError):
  f(1.0)
Caught expected exception 
  <class 'ValueError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-8a0913e250e0>", line 7, in <module>
    f(1.0)
ValueError: in user code:

    <ipython-input-1-8a0913e250e0>:3 f  *
        v = tf.Variable(1.0)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:262 __call__  **
        return cls._variable_v2_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:256 _variable_v2_call
        shape=shape)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:67 getter
        return captured_getter(captured_previous, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py:731 invalid_creator_scope
        "tf.function-decorated function tried to create "

    ValueError: tf.function-decorated function tried to create variables on non-first call.

আপনি যখন কোনও Function অভ্যন্তরে ভেরিয়েবল তৈরি করতে পারেন ততক্ষণ এই ভেরিয়েবলগুলি প্রথমবার ফাংশনটি সম্পাদন করার সময় তৈরি হয়।

class Count(tf.Module):
  def __init__(self):
    self.count = None

  @tf.function
  def __call__(self):
    if self.count is None:
      self.count = tf.Variable(0)
    return self.count.assign_add(1)

c = Count()
print(c())
print(c())
tf.Tensor(1, shape=(), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)

একাধিক কেরাস অপ্টিমাইজারের সাথে ব্যবহার করা

আপনি ValueError: tf.function-decorated function tried to create variables on non-first call. মুখোমুখি হতে পারেন ValueError: tf.function-decorated function tried to create variables on non-first call. tf.function সহ একাধিক কেরাস অপ্টিমাইজার ব্যবহার করার সময়। এই ত্রুটিটি ঘটে কারণ অপ্টিমাইজাররা প্রথমবারের জন্য গ্রেডিয়েন্ট প্রয়োগ করার সময় অভ্যন্তরীণভাবে tf.Variables তৈরি করে।

opt1 = tf.keras.optimizers.Adam(learning_rate = 1e-2)
opt2 = tf.keras.optimizers.Adam(learning_rate = 1e-3)

@tf.function
def train_step(w, x, y, optimizer):
   with tf.GradientTape() as tape:
       L = tf.reduce_sum(tf.square(w*x - y))
   gradients = tape.gradient(L, [w])
   optimizer.apply_gradients(zip(gradients, [w]))

w = tf.Variable(2.)
x = tf.constant([-1.])
y = tf.constant([2.])

train_step(w, x, y, opt1)
print("Calling `train_step` with different optimizer...")
with assert_raises(ValueError):
  train_step(w, x, y, opt2)
Calling `train_step` with different optimizer...
Caught expected exception 
  <class 'ValueError'>:
Traceback (most recent call last):
  File "<ipython-input-1-73d0ca52e838>", line 8, in assert_raises
    yield
  File "<ipython-input-1-d3d3937dbf1a>", line 18, in <module>
    train_step(w, x, y, opt2)
ValueError: in user code:

    <ipython-input-1-d3d3937dbf1a>:9 train_step  *
        optimizer.apply_gradients(zip(gradients, [w]))
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:604 apply_gradients  **
        self._create_all_weights(var_list)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:781 _create_all_weights
        _ = self.iterations
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:788 __getattribute__
        return super(OptimizerV2, self).__getattribute__(name)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:926 iterations
        aggregation=tf_variables.VariableAggregation.ONLY_FIRST_REPLICA)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/optimizer_v2.py:1132 add_weight
        aggregation=aggregation)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/base.py:810 _add_variable_with_custom_getter
        **kwargs_for_getter)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer_utils.py:142 make_variable
        shape=variable_shape if variable_shape else None)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:260 __call__
        return cls._variable_v1_call(*args, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:221 _variable_v1_call
        shape=shape)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/variables.py:67 getter
        return captured_getter(captured_previous, **kwargs)
    /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py:731 invalid_creator_scope
        "tf.function-decorated function tried to create "

    ValueError: tf.function-decorated function tried to create variables on non-first call.

প্রশিক্ষণের সময় যদি আপনাকে অপ্টিমাইজারটি পরিবর্তন করতে হয়, তবে প্রতিটি অপটিমাইজারের জন্য সরাসরি ConcreteFunction কল করে একটি নতুন Function তৈরি করা একটি কর্মপরিকল্পনা।

opt1 = tf.keras.optimizers.Adam(learning_rate = 1e-2)
opt2 = tf.keras.optimizers.Adam(learning_rate = 1e-3)

# Not a tf.function.
def train_step(w, x, y, optimizer):
   with tf.GradientTape() as tape:
       L = tf.reduce_sum(tf.square(w*x - y))
   gradients = tape.gradient(L, [w])
   optimizer.apply_gradients(zip(gradients, [w]))

w = tf.Variable(2.)
x = tf.constant([-1.])
y = tf.constant([2.])

# Make a new Function and ConcreteFunction for each optimizer.
train_step_1 = tf.function(train_step).get_concrete_function(w, x, y, opt1)
train_step_2 = tf.function(train_step).get_concrete_function(w, x, y, opt2)
for i in range(10):
  if i % 2 == 0:
    train_step_1(w, x, y) # `opt1` is not used as a parameter. 
  else:
    train_step_2(w, x, y) # `opt2` is not used as a parameter.

একাধিক কেরাস মডেল ব্যবহার করে

আপনি ValueError: tf.function-decorated function tried to create variables on non-first call. মুখোমুখি হতে পারেন ValueError: tf.function-decorated function tried to create variables on non-first call. একই Function বিভিন্ন মডেল উদাহরণগুলি পাস করার সময়।

এই ত্রুটিটি ঘটে কারণ কেরাস মডেলগুলি (যার ইনপুট শেপটি সংজ্ঞায়িত করা হয় না ) এবং কেরাস স্তরগুলি যখন প্রথম বলা হয় তখন tf.Variables গুলি তৈরি করে। আপনি কোনও Function ভিতরে সেই ভেরিয়েবলগুলি আরম্ভ করার চেষ্টা করছেন যা ইতিমধ্যে বলা হয়েছে। এই ত্রুটিটি এড়াতে, মডেলকে প্রশিক্ষণের আগে সমস্ত ওজন সূচনা করতে model.build(input_shape) কল করার চেষ্টা করুন।

আরও পড়া

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