গ্রেডিয়েন্টের ভূমিকা এবং স্বয়ংক্রিয় পার্থক্য

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

স্বয়ংক্রিয় পার্থক্য এবং গ্রেডিয়েন্ট

স্বয়ংক্রিয় পার্থক্য মেশিন লার্নিং অ্যালগরিদম যেমন স্নায়ু নেটওয়ার্ক প্রশিক্ষণের জন্য ব্যাকপ্রোপগেশন বাস্তবায়নের জন্য দরকারী।

এই নির্দেশিকায়, আপনি TensorFlow-এর সাথে গ্রেডিয়েন্ট গণনা করার উপায়গুলি অন্বেষণ করবেন, বিশেষ করে উদগ্রীবভাবে সম্পাদনের ক্ষেত্রে।

সেটআপ

import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf

কম্পিউটিং গ্রেডিয়েন্ট

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

গ্রেডিয়েন্ট টেপ

TensorFlow স্বয়ংক্রিয় পার্থক্যের জন্য tf.GradientTape API প্রদান করে; অর্থাৎ, কিছু ইনপুটের সাপেক্ষে একটি গণনার গ্রেডিয়েন্ট গণনা করা, সাধারণত tf.Variable s. TensorFlow "রেকর্ড" প্রাসঙ্গিক অপারেশন একটি "টেপ" উপর একটি tf.GradientTape . GradientTape এর প্রেক্ষাপটের ভিতরে সম্পাদিত। TensorFlow তারপর রিভার্স মোড ডিফারেন্সিয়েশন ব্যবহার করে একটি "রেকর্ড করা" গণনার গ্রেডিয়েন্ট গণনা করতে সেই টেপটি ব্যবহার করে।

এখানে একটি সহজ উদাহরণ:

x = tf.Variable(3.0)

with tf.GradientTape() as tape:
  y = x**2

একবার আপনি কিছু ক্রিয়াকলাপ রেকর্ড করার পরে, কিছু উত্স (প্রায়শই মডেলের ভেরিয়েবল) এর সাথে সম্পর্কিত কিছু লক্ষ্যের (প্রায়শই ক্ষতি) গ্রেডিয়েন্ট গণনা করতে GradientTape.gradient(target, sources) ব্যবহার করুন:

# dy = 2x * dx
dy_dx = tape.gradient(y, x)
dy_dx.numpy()
6.0

উপরের উদাহরণটি স্কেলার ব্যবহার করে, কিন্তু tf.GradientTape যেকোন টেনসরে সহজে কাজ করে:

w = tf.Variable(tf.random.normal((3, 2)), name='w')
b = tf.Variable(tf.zeros(2, dtype=tf.float32), name='b')
x = [[1., 2., 3.]]

with tf.GradientTape(persistent=True) as tape:
  y = x @ w + b
  loss = tf.reduce_mean(y**2)

উভয় ভেরিয়েবলের ক্ষেত্রে loss গ্রেডিয়েন্ট পেতে, আপনি gradient পদ্ধতিতে উত্স হিসাবে উভয়কে পাস করতে পারেন। টেপটি কীভাবে উত্সগুলি পাস করা হয় সে সম্পর্কে নমনীয় এবং তালিকা বা অভিধানের যেকোনো নেস্টেড সমন্বয় গ্রহণ করবে এবং একইভাবে কাঠামোগত গ্রেডিয়েন্ট ফিরিয়ে দেবে ( tf.nest দেখুন)।

[dl_dw, dl_db] = tape.gradient(loss, [w, b])

প্রতিটি উৎসের ক্ষেত্রে গ্রেডিয়েন্টের উৎসের আকৃতি রয়েছে:

print(w.shape)
print(dl_dw.shape)
(3, 2)
(3, 2)

এখানে আবার গ্রেডিয়েন্ট গণনা করা হল, এবার ভেরিয়েবলের একটি অভিধান পাস করা হচ্ছে:

my_vars = {
    'w': w,
    'b': b
}

grad = tape.gradient(loss, my_vars)
grad['b']
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-1.6920902, -3.2363236], dtype=float32)>

একটি মডেলের সাপেক্ষে গ্রেডিয়েন্ট

চেকপয়েন্টিং এবং এক্সপোর্ট করার জন্য tf.Variables কে tf.Module বা এর একটি সাবক্লাসে ( layers.Layer , keras.Model ) সংগ্রহ করা সাধারণ।

বেশিরভাগ ক্ষেত্রে, আপনি একটি মডেলের প্রশিক্ষণযোগ্য ভেরিয়েবলের সাপেক্ষে গ্রেডিয়েন্ট গণনা করতে চাইবেন। যেহেতু tf.Module এর সমস্ত সাবক্লাস তাদের ভেরিয়েবলগুলিকে Module.trainable_variables প্রপার্টিতে একত্রিত করে, আপনি কোডের কয়েকটি লাইনে এই গ্রেডিয়েন্টগুলি গণনা করতে পারেন:

layer = tf.keras.layers.Dense(2, activation='relu')
x = tf.constant([[1., 2., 3.]])

with tf.GradientTape() as tape:
  # Forward pass
  y = layer(x)
  loss = tf.reduce_mean(y**2)

# Calculate gradients with respect to every trainable variable
grad = tape.gradient(loss, layer.trainable_variables)
for var, g in zip(layer.trainable_variables, grad):
  print(f'{var.name}, shape: {g.shape}')
dense/kernel:0, shape: (3, 2)
dense/bias:0, shape: (2,)

টেপ ঘড়ি কি নিয়ন্ত্রণ

ডিফল্ট আচরণ হল একটি প্রশিক্ষণযোগ্য tf.Variable অ্যাক্সেস করার পরে সমস্ত ক্রিয়াকলাপ রেকর্ড করা। এর কারণগুলি হল:

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

উদাহরণস্বরূপ, নিম্নলিখিতটি একটি গ্রেডিয়েন্ট গণনা করতে ব্যর্থ হয় কারণ tf.Tensor ডিফল্টরূপে "দেখা হয় না" এবং tf. tf.Variable প্রশিক্ষণযোগ্য নয়:

# A trainable variable
x0 = tf.Variable(3.0, name='x0')
# Not trainable
x1 = tf.Variable(3.0, name='x1', trainable=False)
# Not a Variable: A variable + tensor returns a tensor.
x2 = tf.Variable(2.0, name='x2') + 1.0
# Not a variable
x3 = tf.constant(3.0, name='x3')

with tf.GradientTape() as tape:
  y = (x0**2) + (x1**2) + (x2**2)

grad = tape.gradient(y, [x0, x1, x2, x3])

for g in grad:
  print(g)
tf.Tensor(6.0, shape=(), dtype=float32)
None
None
None

আপনি GradientTape.watched_variables পদ্ধতি ব্যবহার করে টেপ দ্বারা দেখা ভেরিয়েবল তালিকা করতে পারেন:

[var.name for var in tape.watched_variables()]
['x0:0']

tf.GradientTape হুক সরবরাহ করে যা ব্যবহারকারীকে কী দেখা হচ্ছে বা না দেখা হচ্ছে তার উপর নিয়ন্ত্রণ দেয়।

একটি tf.Tensor গ্রেডিয়েন্ট রেকর্ড করতে, আপনাকে GradientTape.watch(x) কল করতে হবে:

x = tf.constant(3.0)
with tf.GradientTape() as tape:
  tape.watch(x)
  y = x**2

# dy = 2x * dx
dy_dx = tape.gradient(y, x)
print(dy_dx.numpy())
6.0

বিপরীতভাবে, সমস্ত tf.Variables দেখার ডিফল্ট আচরণ নিষ্ক্রিয় করতে, গ্রেডিয়েন্ট টেপ তৈরি করার সময় watch_accessed_variables=False সেট করুন। এই গণনা দুটি ভেরিয়েবল ব্যবহার করে, কিন্তু শুধুমাত্র একটি ভেরিয়েবলের জন্য গ্রেডিয়েন্ট সংযোগ করে:

x0 = tf.Variable(0.0)
x1 = tf.Variable(10.0)

with tf.GradientTape(watch_accessed_variables=False) as tape:
  tape.watch(x1)
  y0 = tf.math.sin(x0)
  y1 = tf.nn.softplus(x1)
  y = y0 + y1
  ys = tf.reduce_sum(y)

যেহেতু GradientTape.watch x0 এ কল করা হয়নি, তাই এটির ক্ষেত্রে কোন গ্রেডিয়েন্ট গণনা করা হয় না:

# dys/dx1 = exp(x1) / (1 + exp(x1)) = sigmoid(x1)
grad = tape.gradient(ys, {'x0': x0, 'x1': x1})

print('dy/dx0:', grad['x0'])
print('dy/dx1:', grad['x1'].numpy())
dy/dx0: None
dy/dx1: 0.9999546

মধ্যবর্তী ফলাফল

আপনি tf.GradientTape প্রসঙ্গের মধ্যে গণনা করা মধ্যবর্তী মানের সাপেক্ষে আউটপুটের গ্রেডিয়েন্টের জন্য অনুরোধ করতে পারেন।

x = tf.constant(3.0)

with tf.GradientTape() as tape:
  tape.watch(x)
  y = x * x
  z = y * y

# Use the tape to compute the gradient of z with respect to the
# intermediate value y.
# dz_dy = 2 * y and y = x ** 2 = 9
print(tape.gradient(z, y).numpy())
18.0

ডিফল্টরূপে, GradientTape.gradient পদ্ধতি কল করার সাথে সাথে একটি GradientTape দ্বারা ধারণকৃত সংস্থানগুলি মুক্তি পায়। একই গণনার উপর একাধিক গ্রেডিয়েন্ট গণনা করতে, persistent=True সহ একটি গ্রেডিয়েন্ট টেপ তৈরি করুন। এটি gradient পদ্ধতিতে একাধিক কল করার অনুমতি দেয় কারণ টেপ অবজেক্টটি আবর্জনা সংগ্রহ করা হলে সংস্থানগুলি প্রকাশিত হয়। উদাহরণ স্বরূপ:

x = tf.constant([1, 3.0])
with tf.GradientTape(persistent=True) as tape:
  tape.watch(x)
  y = x * x
  z = y * y

print(tape.gradient(z, x).numpy())  # [4.0, 108.0] (4 * x**3 at x = [1.0, 3.0])
print(tape.gradient(y, x).numpy())  # [2.0, 6.0] (2 * x at x = [1.0, 3.0])
[  4. 108.]
[2. 6.]
del tape   # Drop the reference to the tape

কর্মক্ষমতা উপর নোট

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

  • গ্রেডিয়েন্ট টেপগুলি ব্যাকওয়ার্ড পাসের সময় ব্যবহারের জন্য ইনপুট এবং আউটপুট সহ মধ্যবর্তী ফলাফলগুলি সংরক্ষণ করতে মেমরি ব্যবহার করে।

    দক্ষতার জন্য, কিছু অপারেশনের (যেমন ReLU ) তাদের মধ্যবর্তী ফলাফল রাখতে হবে না এবং ফরোয়ার্ড পাসের সময় সেগুলি ছাঁটাই করা হয়। যাইহোক, যদি আপনি আপনার টেপে persistent=True ব্যবহার করেন, তাহলে কিছুই বাতিল করা হবে না এবং আপনার পিক মেমরির ব্যবহার বেশি হবে।

অ-স্কেলার লক্ষ্যগুলির গ্রেডিয়েন্ট

একটি গ্রেডিয়েন্ট মূলত একটি স্কেলারে একটি অপারেশন।

x = tf.Variable(2.0)
with tf.GradientTape(persistent=True) as tape:
  y0 = x**2
  y1 = 1 / x

print(tape.gradient(y0, x).numpy())
print(tape.gradient(y1, x).numpy())
4.0
-0.25

এইভাবে, আপনি যদি একাধিক লক্ষ্যের গ্রেডিয়েন্টের জন্য জিজ্ঞাসা করেন, প্রতিটি উত্সের ফলাফল হল:

  • লক্ষ্যের সমষ্টির গ্রেডিয়েন্ট বা সমতুল্য
  • প্রতিটি লক্ষ্যের গ্রেডিয়েন্টের যোগফল।
x = tf.Variable(2.0)
with tf.GradientTape() as tape:
  y0 = x**2
  y1 = 1 / x

print(tape.gradient({'y0': y0, 'y1': y1}, x).numpy())
3.75

একইভাবে, লক্ষ্য(গুলি) স্কেলার না হলে যোগফলের গ্রেডিয়েন্ট গণনা করা হয়:

x = tf.Variable(2.)

with tf.GradientTape() as tape:
  y = x * [3., 4.]

print(tape.gradient(y, x).numpy())
7.0

এটি ক্ষতির সংগ্রহের যোগফলের গ্রেডিয়েন্ট বা উপাদান-ভিত্তিক ক্ষতি গণনার যোগফলের গ্রেডিয়েন্ট নেওয়া সহজ করে তোলে।

আপনার যদি প্রতিটি আইটেমের জন্য একটি পৃথক গ্রেডিয়েন্টের প্রয়োজন হয়, Jacobians পড়ুন।

কিছু ক্ষেত্রে আপনি জ্যাকোবিয়ান এড়িয়ে যেতে পারেন। একটি উপাদান-ভিত্তিক গণনার জন্য, যোগফলের গ্রেডিয়েন্ট প্রতিটি উপাদানের ইনপুট-উপাদানের সাপেক্ষে ডেরিভেটিভ দেয়, যেহেতু প্রতিটি উপাদান স্বাধীন:

x = tf.linspace(-10.0, 10.0, 200+1)

with tf.GradientTape() as tape:
  tape.watch(x)
  y = tf.nn.sigmoid(x)

dy_dx = tape.gradient(y, x)
plt.plot(x, y, label='y')
plt.plot(x, dy_dx, label='dy/dx')
plt.legend()
_ = plt.xlabel('x')

png

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

যেহেতু একটি গ্রেডিয়েন্ট টেপ ক্রিয়াকলাপগুলি চালানোর সাথে সাথে রেকর্ড করে, পাইথন নিয়ন্ত্রণ প্রবাহ স্বাভাবিকভাবেই পরিচালনা করা হয় (উদাহরণস্বরূপ, if এবং while বিবৃতি)।

এখানে if এর প্রতিটি শাখায় একটি ভিন্ন পরিবর্তনশীল ব্যবহার করা হয়েছে। গ্রেডিয়েন্ট শুধুমাত্র ব্যবহৃত ভেরিয়েবলের সাথে সংযোগ করে:

x = tf.constant(1.0)

v0 = tf.Variable(2.0)
v1 = tf.Variable(2.0)

with tf.GradientTape(persistent=True) as tape:
  tape.watch(x)
  if x > 0.0:
    result = v0
  else:
    result = v1**2 

dv0, dv1 = tape.gradient(result, [v0, v1])

print(dv0)
print(dv1)
tf.Tensor(1.0, shape=(), dtype=float32)
None

শুধু মনে রাখবেন যে নিয়ন্ত্রণ বিবৃতিগুলি নিজেদের মধ্যে পার্থক্যযোগ্য নয়, তাই তারা গ্রেডিয়েন্ট-ভিত্তিক অপ্টিমাইজারদের কাছে অদৃশ্য।

উপরের উদাহরণে x এর মানের উপর নির্ভর করে, টেপটি result = v0 বা result = v1**2 রেকর্ড করে। x এর সাপেক্ষে গ্রেডিয়েন্ট সবসময় None হয়।

dx = tape.gradient(result, x)

print(dx)
None

কোনটির গ্রেডিয়েন্ট পাওয়া যাচ্ছে None

যখন একটি লক্ষ্য একটি উৎসের সাথে সংযুক্ত না থাকে তখন আপনি None এর একটি গ্রেডিয়েন্ট পাবেন।

x = tf.Variable(2.)
y = tf.Variable(3.)

with tf.GradientTape() as tape:
  z = y * y
print(tape.gradient(z, x))
None

এখানে z স্পষ্টতই x এর সাথে সংযুক্ত নয়, তবে গ্রেডিয়েন্ট সংযোগ বিচ্ছিন্ন করা যেতে পারে এমন বেশ কয়েকটি কম-স্পষ্ট উপায় রয়েছে।

1. একটি ভেরিয়েবলকে একটি টেনসর দিয়ে প্রতিস্থাপন করা হয়েছে

"টেপটি কী tf.Variable তা নিয়ন্ত্রণ করা" বিভাগে আপনি দেখেছেন যে টেপটি স্বয়ংক্রিয়ভাবে একটি tf. ভ্যারিয়েবল দেখবে তবে একটি tf.Tensor . টেনসর নয়।

একটি সাধারণ ত্রুটি হল tf.Variable আপডেট করার জন্য Variable.assign ব্যবহার করার পরিবর্তে একটি tf.Tensor কে tf.Variable দিয়ে প্রতিস্থাপন করা। এখানে একটি উদাহরণ:

x = tf.Variable(2.0)

for epoch in range(2):
  with tf.GradientTape() as tape:
    y = x+1

  print(type(x).__name__, ":", tape.gradient(y, x))
  x = x + 1   # This should be `x.assign_add(1)`
ResourceVariable : tf.Tensor(1.0, shape=(), dtype=float32)
EagerTensor : None

2. TensorFlow এর বাইরে গণনা করেছেন

টেপ গ্রেডিয়েন্ট পাথ রেকর্ড করতে পারে না যদি গণনা TensorFlow থেকে বেরিয়ে যায়। উদাহরণ স্বরূপ:

x = tf.Variable([[1.0, 2.0],
                 [3.0, 4.0]], dtype=tf.float32)

with tf.GradientTape() as tape:
  x2 = x**2

  # This step is calculated with NumPy
  y = np.mean(x2, axis=0)

  # Like most ops, reduce_mean will cast the NumPy array to a constant tensor
  # using `tf.convert_to_tensor`.
  y = tf.reduce_mean(y, axis=0)

print(tape.gradient(y, x))
None

3. একটি পূর্ণসংখ্যা বা স্ট্রিং এর মাধ্যমে গ্রেডিয়েন্ট নেওয়া হয়েছে

পূর্ণসংখ্যা এবং স্ট্রিং পার্থক্যযোগ্য নয়। যদি একটি গণনা পথ এই ডেটা প্রকারগুলি ব্যবহার করে তবে কোনও গ্রেডিয়েন্ট থাকবে না।

কেউ আশা করে না যে স্ট্রিংগুলি পার্থক্যযোগ্য হবে, তবে আপনি যদি dtype নির্দিষ্ট না করেন তবে ঘটনাক্রমে একটি int ধ্রুবক বা পরিবর্তনশীল তৈরি করা সহজ।

x = tf.constant(10)

with tf.GradientTape() as g:
  g.watch(x)
  y = x * x

print(g.gradient(y, x))
WARNING:tensorflow:The dtype of the watched tensor must be floating (e.g. tf.float32), got tf.int32
WARNING:tensorflow:The dtype of the target tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32
WARNING:tensorflow:The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32
None

TensorFlow স্বয়ংক্রিয়ভাবে প্রকারের মধ্যে কাস্ট করে না, তাই, অনুশীলনে, আপনি প্রায়ই অনুপস্থিত গ্রেডিয়েন্টের পরিবর্তে একটি টাইপ ত্রুটি পাবেন।

4. একটি রাষ্ট্রীয় বস্তুর মাধ্যমে গ্রেডিয়েন্ট গ্রহণ করা হয়েছে

স্টেট গ্রেডিয়েন্ট বন্ধ করে। আপনি যখন একটি রাষ্ট্রীয় বস্তু থেকে পড়েন, তখন টেপটি শুধুমাত্র বর্তমান অবস্থা পর্যবেক্ষণ করতে পারে, এটির দিকে নিয়ে যাওয়া ইতিহাস নয়।

একটি tf. tf.Tensor অপরিবর্তনীয়। একবার তৈরি হয়ে গেলে আপনি টেনসর পরিবর্তন করতে পারবেন না। এটির একটি মান আছে, কিন্তু কোনো রাষ্ট্র নেই। এখন পর্যন্ত আলোচিত সমস্ত ক্রিয়াকলাপও রাষ্ট্রহীন: একটি tf.matmul এর আউটপুট শুধুমাত্র এর ইনপুটগুলির উপর নির্ভর করে।

একটি tf.Variable . ভ্যারিয়েবলের অভ্যন্তরীণ অবস্থা রয়েছে—এর মান। আপনি যখন ভেরিয়েবল ব্যবহার করেন, তখন রাষ্ট্রটি পড়া হয়। একটি ভেরিয়েবলের সাপেক্ষে একটি গ্রেডিয়েন্ট গণনা করা স্বাভাবিক, তবে ভেরিয়েবলের অবস্থা গ্রেডিয়েন্ট গণনাকে আরও পিছনে যেতে বাধা দেয়। উদাহরণ স্বরূপ:

x0 = tf.Variable(3.0)
x1 = tf.Variable(0.0)

with tf.GradientTape() as tape:
  # Update x1 = x1 + x0.
  x1.assign_add(x0)
  # The tape starts recording from x1.
  y = x1**2   # y = (x1 + x0)**2

# This doesn't work.
print(tape.gradient(y, x0))   #dy/dx0 = 2*(x1 + x0)
None

একইভাবে, tf.data.Dataset এবং tf.queue s স্টেটফুল, এবং তাদের মধ্য দিয়ে যাওয়া টেনসরের সমস্ত গ্রেডিয়েন্ট বন্ধ করে দেবে।

কোনো গ্রেডিয়েন্ট নিবন্ধিত নেই

কিছু tf.Operation .অপারেশনগুলি অ-পার্থক্য হিসাবে নিবন্ধিত হয়েছে এবং None ফেরত দেবে না। অন্যদের কোনো গ্রেডিয়েন্ট নিবন্ধিত নেই

tf.raw_ops পৃষ্ঠা দেখায় কোন নিম্ন-স্তরের অপের গ্রেডিয়েন্ট নিবন্ধিত আছে।

যদি আপনি একটি ফ্লোট অপের মাধ্যমে একটি গ্রেডিয়েন্ট নেওয়ার চেষ্টা করেন যার কোনও গ্রেডিয়েন্ট নিবন্ধিত নেই তবে টেপটি নীরবে None ফেরত দেওয়ার পরিবর্তে একটি ত্রুটি নিক্ষেপ করবে। এইভাবে আপনি জানেন যে কিছু ভুল হয়েছে।

উদাহরণস্বরূপ, tf.image.adjust_contrast ফাংশন raw_ops.AdjustContrastv2 কে মোড়ানো হয়, যার একটি গ্রেডিয়েন্ট থাকতে পারে কিন্তু গ্রেডিয়েন্ট বাস্তবায়িত হয় না:

image = tf.Variable([[[0.5, 0.0, 0.0]]])
delta = tf.Variable(0.1)

with tf.GradientTape() as tape:
  new_image = tf.image.adjust_contrast(image, delta)

try:
  print(tape.gradient(new_image, [image, delta]))
  assert False   # This should not happen.
except LookupError as e:
  print(f'{type(e).__name__}: {e}')
LookupError: gradient registry has no entry for: AdjustContrastv2

আপনি যদি এই অপের মাধ্যমে পার্থক্য করতে চান, তাহলে আপনাকে হয় গ্রেডিয়েন্টটি বাস্তবায়ন করতে হবে এবং এটি নিবন্ধন করতে হবে ( tf.RegisterGradient ব্যবহার করে) অথবা অন্য অপ্স ব্যবহার করে ফাংশনটি পুনরায় প্রয়োগ করতে হবে।

None এর পরিবর্তে Zeros

কিছু ক্ষেত্রে সংযোগহীন গ্রেডিয়েন্টের জন্য None এর পরিবর্তে 0 পাওয়া সুবিধাজনক হবে। আপনি unconnected_gradients আর্গুমেন্ট ব্যবহার করে unconnected_gradients গ্রেডিয়েন্ট থাকলে কী ফেরত দেবেন তা নির্ধারণ করতে পারেন:

x = tf.Variable([2., 2.])
y = tf.Variable(3.)

with tf.GradientTape() as tape:
  z = y**2
print(tape.gradient(z, x, unconnected_gradients=tf.UnconnectedGradients.ZERO))
tf.Tensor([0. 0.], shape=(2,), dtype=float32)