TensorFlow এ NumPy API

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

ওভারভিউ

TensorFlow NumPy API- এর একটি উপসেট প্রয়োগ করে, যা tf.experimental.numpy হিসাবে উপলব্ধ। এটি TensorFlow দ্বারা ত্বরান্বিত NumPy কোড চালানোর অনুমতি দেয়, পাশাপাশি TensorFlow-এর সমস্ত API-এ অ্যাক্সেসের অনুমতি দেয়।

সেটআপ

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow.experimental.numpy as tnp
import timeit

print("Using TensorFlow version %s" % tf.__version__)
Using TensorFlow version 2.6.0

NumPy আচরণ সক্ষম করা হচ্ছে

NumPy হিসাবে tnp ব্যবহার করার জন্য, TensorFlow-এর জন্য NumPy আচরণ সক্ষম করুন:

tnp.experimental_enable_numpy_behavior()

এই কল TensorFlow-এ টাইপ প্রচার সক্ষম করে এবং টাইপ ইনফারেন্স পরিবর্তন করে, যখন লিটারেলকে টেনসরে রূপান্তর করে, আরও কঠোরভাবে NumPy মান অনুসরণ করতে।

TensorFlow NumPy ND অ্যারে

tf.experimental.numpy.ndarray এর একটি উদাহরণ, যাকে ND অ্যারে বলা হয়, একটি নির্দিষ্ট ডিভাইসে স্থাপিত একটি প্রদত্ত dtype একটি বহুমাত্রিক ঘন বিন্যাসের প্রতিনিধিত্ব করে। এটি tf.Tensor এর একটি উপনাম। ndarray.T , ndarray.reshape , ndarray.ravel এবং অন্যান্যের মতো দরকারী পদ্ধতির জন্য ND অ্যারে ক্লাসটি দেখুন।

প্রথমে একটি এনডি অ্যারে অবজেক্ট তৈরি করুন এবং তারপরে বিভিন্ন পদ্ধতি চালু করুন।

# Create an ND array and check out different attributes.
ones = tnp.ones([5, 3], dtype=tnp.float32)
print("Created ND array with shape = %s, rank = %s, "
      "dtype = %s on device = %s\n" % (
          ones.shape, ones.ndim, ones.dtype, ones.device))

# `ndarray` is just an alias to `tf.Tensor`.
print("Is `ones` an instance of tf.Tensor: %s\n" % isinstance(ones, tf.Tensor))

# Try commonly used member functions.
print("ndarray.T has shape %s" % str(ones.T.shape))
print("narray.reshape(-1) has shape %s" % ones.reshape(-1).shape)
Created ND array with shape = (5, 3), rank = 2, dtype = <dtype: 'float32'> on device = /job:localhost/replica:0/task:0/device:GPU:0

Is `ones` an instance of tf.Tensor: True

ndarray.T has shape (3, 5)
narray.reshape(-1) has shape (15,)

টাইপ প্রচার

TensorFlow NumPy API-এ লিটারেলগুলিকে ND অ্যারেতে রূপান্তর করার জন্য, সেইসাথে ND অ্যারে ইনপুটগুলিতে টাইপ প্রচার করার জন্য ভালভাবে সংজ্ঞায়িত শব্দার্থ আছে। আরো বিস্তারিত জানার জন্য অনুগ্রহ করে np.result_type দেখুন।

TensorFlow APIs tf.Tensor ইনপুটগুলিকে অপরিবর্তিত রাখে এবং সেগুলিতে টাইপ প্রচার করে না, যখন TensorFlow NumPy APIগুলি NumPy প্রকার প্রচারের নিয়ম অনুসারে সমস্ত ইনপুট প্রচার করে। পরবর্তী উদাহরণে, আপনি টাইপ প্রচার সম্পাদন করবেন। প্রথমে, বিভিন্ন ধরণের ND অ্যারে ইনপুটগুলিতে যোগ চালান এবং আউটপুট প্রকারগুলি নোট করুন। TensorFlow API-এর দ্বারা এই ধরনের প্রচারের কোনোটিই অনুমোদিত হবে না।

print("Type promotion for operations")
values = [tnp.asarray(1, dtype=d) for d in
          (tnp.int32, tnp.int64, tnp.float32, tnp.float64)]
for i, v1 in enumerate(values):
  for v2 in values[i + 1:]:
    print("%s + %s => %s" % 
          (v1.dtype.name, v2.dtype.name, (v1 + v2).dtype.name))
Type promotion for operations
int32 + int64 => int64
int32 + float32 => float64
int32 + float64 => float64
int64 + float32 => float64
int64 + float64 => float64
float32 + float64 => float64

অবশেষে, ndarray.asarray ব্যবহার করে ndarray.asarray ND অ্যারেতে রূপান্তর করুন এবং ফলাফলের ধরনটি নোট করুন।

print("Type inference during array creation")
print("tnp.asarray(1).dtype == tnp.%s" % tnp.asarray(1).dtype.name)
print("tnp.asarray(1.).dtype == tnp.%s\n" % tnp.asarray(1.).dtype.name)
Type inference during array creation
tnp.asarray(1).dtype == tnp.int64
tnp.asarray(1.).dtype == tnp.float64

লিটারেলগুলিকে ND অ্যারেতে রূপান্তর করার সময়, NumPy tnp.int64 এবং tnp.float64 এর মতো বিস্তৃত প্রকার পছন্দ করে। বিপরীতে, tf.convert_to_tensor ধ্রুবককে tf.Tensor এ রূপান্তর করার জন্য tf.int32 এবং tf.float32 প্রকার পছন্দ করে। TensorFlow NumPy APIগুলি পূর্ণসংখ্যার জন্য NumPy আচরণ মেনে চলে। floats-এর ক্ষেত্রে, experimental_enable_numpy_behavior এর prefer_float32 যুক্তি আপনাকে tf.float64 (ডিফল্ট থেকে False ) এর চেয়ে tf.float32 পছন্দ করবে কিনা তা নিয়ন্ত্রণ করতে দেয়। উদাহরণ স্বরূপ:

tnp.experimental_enable_numpy_behavior(prefer_float32=True)
print("When prefer_float32 is True:")
print("tnp.asarray(1.).dtype == tnp.%s" % tnp.asarray(1.).dtype.name)
print("tnp.add(1., 2.).dtype == tnp.%s" % tnp.add(1., 2.).dtype.name)

tnp.experimental_enable_numpy_behavior(prefer_float32=False)
print("When prefer_float32 is False:")
print("tnp.asarray(1.).dtype == tnp.%s" % tnp.asarray(1.).dtype.name)
print("tnp.add(1., 2.).dtype == tnp.%s" % tnp.add(1., 2.).dtype.name)
When prefer_float32 is True:
tnp.asarray(1.).dtype == tnp.float32
tnp.add(1., 2.).dtype == tnp.float32
When prefer_float32 is False:
tnp.asarray(1.).dtype == tnp.float64
tnp.add(1., 2.).dtype == tnp.float64

সম্প্রচার

TensorFlow এর মতো, NumPy "সম্প্রচার" মানগুলির জন্য সমৃদ্ধ শব্দার্থবিদ্যাকে সংজ্ঞায়িত করে। আপনি আরও তথ্যের জন্য NumPy সম্প্রচার নির্দেশিকাটি দেখতে পারেন এবং TensorFlow সম্প্রচার শব্দার্থবিদ্যার সাথে এটি তুলনা করতে পারেন।

x = tnp.ones([2, 3])
y = tnp.ones([3])
z = tnp.ones([1, 2, 1])
print("Broadcasting shapes %s, %s and %s gives shape %s" % (
    x.shape, y.shape, z.shape, (x + y + z).shape))
Broadcasting shapes (2, 3), (3,) and (1, 2, 1) gives shape (1, 2, 3)

ইনডেক্সিং

NumPy খুব পরিশীলিত ইনডেক্সিং নিয়ম সংজ্ঞায়িত করে। NumPy ইন্ডেক্সিং গাইড দেখুন। নীচের সূচক হিসাবে ND অ্যারেগুলির ব্যবহার লক্ষ্য করুন।

x = tnp.arange(24).reshape(2, 3, 4)

print("Basic indexing")
print(x[1, tnp.newaxis, 1:3, ...], "\n")

print("Boolean indexing")
print(x[:, (True, False, True)], "\n")

print("Advanced indexing")
print(x[1, (0, 0, 1), tnp.asarray([0, 1, 1])])
Basic indexing
tf.Tensor(
[[[16 17 18 19]
  [20 21 22 23]]], shape=(1, 2, 4), dtype=int64) 

Boolean indexing
tf.Tensor(
[[[ 0  1  2  3]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [20 21 22 23]]], shape=(2, 2, 4), dtype=int64) 

Advanced indexing
tf.Tensor([12 13 17], shape=(3,), dtype=int64)
# Mutation is currently not supported
try:
  tnp.arange(6)[1] = -1
except TypeError:
  print("Currently, TensorFlow NumPy does not support mutation.")
Currently, TensorFlow NumPy does not support mutation.

উদাহরণ মডেল

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

class Model(object):
  """Model with a dense and a linear layer."""

  def __init__(self):
    self.weights = None

  def predict(self, inputs):
    if self.weights is None:
      size = inputs.shape[1]
      # Note that type `tnp.float32` is used for performance.
      stddev = tnp.sqrt(size).astype(tnp.float32)
      w1 = tnp.random.randn(size, 64).astype(tnp.float32) / stddev
      bias = tnp.random.randn(64).astype(tnp.float32)
      w2 = tnp.random.randn(64, 2).astype(tnp.float32) / 8
      self.weights = (w1, bias, w2)
    else:
      w1, bias, w2 = self.weights
    y = tnp.matmul(inputs, w1) + bias
    y = tnp.maximum(y, 0)  # Relu
    return tnp.matmul(y, w2)  # Linear projection

model = Model()
# Create input data and compute predictions.
print(model.predict(tnp.ones([2, 32], dtype=tnp.float32)))
tf.Tensor(
[[-1.7706785  1.1137733]
 [-1.7706785  1.1137733]], shape=(2, 2), dtype=float32)

TensorFlow NumPy এবং NumPy

TensorFlow NumPy সম্পূর্ণ NumPy স্পেকের একটি উপসেট প্রয়োগ করে। যদিও সময়ের সাথে সাথে আরো চিহ্ন যোগ করা হবে, সেখানে পদ্ধতিগত বৈশিষ্ট্য রয়েছে যা অদূর ভবিষ্যতে সমর্থিত হবে না। এর মধ্যে রয়েছে NumPy C API সমর্থন, সুইগ ইন্টিগ্রেশন, Fortran স্টোরেজ অর্ডার, ভিউ এবং stride_tricks এবং কিছু dtype s (যেমন np.recarray এবং np.object )। আরও বিশদ বিবরণের জন্য, অনুগ্রহ করে TensorFlow NumPy API ডকুমেন্টেশন দেখুন।

NumPy ইন্টারঅপারেবিলিটি

TensorFlow ND অ্যারে NumPy ফাংশনগুলির সাথে ইন্টারঅপারেট করতে পারে। এই বস্তুগুলি __array__ ইন্টারফেস বাস্তবায়ন করে। NumPy এই ইন্টারফেসটি ব্যবহার করে ফাংশন আর্গুমেন্টগুলিকে প্রক্রিয়া করার আগে np.ndarray মানগুলিতে রূপান্তর করতে।

একইভাবে, TensorFlow NumPy ফাংশন np.ndarray সহ বিভিন্ন ধরনের ইনপুট গ্রহণ করতে পারে। এই ইনপুটগুলিকে ndarray.asarray কল করে একটি ND অ্যারেতে রূপান্তরিত করা হয়।

np.ndarray থেকে এনডি অ্যারের রূপান্তর প্রকৃত ডেটা np.ndarray ট্রিগার করতে পারে। আরও বিশদ বিবরণের জন্য অনুগ্রহ করে বাফার কপিগুলির বিভাগটি দেখুন।

# ND array passed into NumPy function.
np_sum = np.sum(tnp.ones([2, 3]))
print("sum = %s. Class: %s" % (float(np_sum), np_sum.__class__))

# `np.ndarray` passed into TensorFlow NumPy function.
tnp_sum = tnp.sum(np.ones([2, 3]))
print("sum = %s. Class: %s" % (float(tnp_sum), tnp_sum.__class__))
sum = 6.0. Class: <class 'numpy.float64'>
sum = 6.0. Class: <class 'tensorflow.python.framework.ops.EagerTensor'>
# It is easy to plot ND arrays, given the __array__ interface.
labels = 15 + 2 * tnp.random.randn(1, 1000)
_ = plt.hist(labels)

png

বাফার কপি

NumPy কোডের সাথে TensorFlow NumPy মিশ্রিত করা ডেটা কপি ট্রিগার করতে পারে। এর কারণ হল TensorFlow NumPy-এর মেমরি সারিবদ্ধকরণের জন্য NumPy-এর তুলনায় কঠোর প্রয়োজনীয়তা রয়েছে।

যখন একটি np.ndarray এ পাস করা হয়, তখন এটি সারিবদ্ধকরণের প্রয়োজনীয়তা পরীক্ষা করবে এবং প্রয়োজন হলে একটি অনুলিপি ট্রিগার করবে। NumPy-এ একটি ND অ্যারে CPU বাফার পাস করার সময়, সাধারণত বাফারটি সারিবদ্ধকরণের প্রয়োজনীয়তাগুলি পূরণ করবে এবং NumPy-কে একটি অনুলিপি তৈরি করতে হবে না।

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

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

অপারেটরের অগ্রাধিকার

TensorFlow NumPy একটি __array_priority__ NumPy এর চেয়ে বেশি সংজ্ঞায়িত করে। এর মানে হল যে ND অ্যারে এবং np.ndarray উভয়ের সাথে জড়িত অপারেটরদের জন্য, পূর্বেরটি অগ্রাধিকার পাবে, অর্থাৎ, np.ndarray ইনপুট একটি ND অ্যারেতে রূপান্তরিত হবে এবং অপারেটরের TensorFlow NumPy বাস্তবায়ন শুরু হবে।

x = tnp.ones([2]) + np.ones([2])
print("x = %s\nclass = %s" % (x, x.__class__))
x = tf.Tensor([2. 2.], shape=(2,), dtype=float64)
class = <class 'tensorflow.python.framework.ops.EagerTensor'>

TF NumPy এবং TensorFlow

TensorFlow NumPy TensorFlow এর উপরে তৈরি করা হয়েছে এবং তাই TensorFlow এর সাথে নির্বিঘ্নে ইন্টারঅপারেটিং করে।

tf.Tensor এবং ND অ্যারে

ND অ্যারে হল tf.Tensor এর একটি উপনাম, তাই স্পষ্টতই প্রকৃত ডেটা কপি ট্রিগার না করেই এগুলিকে মিশ্রিত করা যেতে পারে।

x = tf.constant([1, 2])
print(x)

# `asarray` and `convert_to_tensor` here are no-ops.
tnp_x = tnp.asarray(x)
print(tnp_x)
print(tf.convert_to_tensor(tnp_x))

# Note that tf.Tensor.numpy() will continue to return `np.ndarray`.
print(x.numpy(), x.numpy().__class__)
tf.Tensor([1 2], shape=(2,), dtype=int32)
tf.Tensor([1 2], shape=(2,), dtype=int32)
tf.Tensor([1 2], shape=(2,), dtype=int32)
[1 2] <class 'numpy.ndarray'>

টেনসরফ্লো ইন্টারঅপারেবিলিটি

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

বিপরীতভাবে, tf.Tensor অবজেক্টগুলি tf.experimental.numpy API-এ পাঠানো যেতে পারে, ডাটা কপি না করেই।

# ND array passed into TensorFlow function.
tf_sum = tf.reduce_sum(tnp.ones([2, 3], tnp.float32))
print("Output = %s" % tf_sum)

# `tf.Tensor` passed into TensorFlow NumPy function.
tnp_sum = tnp.sum(tf.ones([2, 3]))
print("Output = %s" % tnp_sum)
Output = tf.Tensor(6.0, shape=(), dtype=float32)
Output = tf.Tensor(6.0, shape=(), dtype=float32)

গ্রেডিয়েন্ট এবং জ্যাকোবিয়ান: tf.GradientTape

TensorFlow এর GradientTape TensorFlow এবং TensorFlow NumPy কোডের মাধ্যমে ব্যাকপ্রপাগেশনের জন্য ব্যবহার করা যেতে পারে।

উদাহরণ মডেল বিভাগে তৈরি মডেল ব্যবহার করুন, এবং গ্রেডিয়েন্ট এবং জ্যাকোবিয়ান গণনা করুন।

def create_batch(batch_size=32):
  """Creates a batch of input and labels."""
  return (tnp.random.randn(batch_size, 32).astype(tnp.float32),
          tnp.random.randn(batch_size, 2).astype(tnp.float32))

def compute_gradients(model, inputs, labels):
  """Computes gradients of squared loss between model prediction and labels."""
  with tf.GradientTape() as tape:
    assert model.weights is not None
    # Note that `model.weights` need to be explicitly watched since they
    # are not tf.Variables.
    tape.watch(model.weights)
    # Compute prediction and loss
    prediction = model.predict(inputs)
    loss = tnp.sum(tnp.square(prediction - labels))
  # This call computes the gradient through the computation above.
  return tape.gradient(loss, model.weights)

inputs, labels = create_batch()
gradients = compute_gradients(model, inputs, labels)

# Inspect the shapes of returned gradients to verify they match the
# parameter shapes.
print("Parameter shapes:", [w.shape for w in model.weights])
print("Gradient shapes:", [g.shape for g in gradients])
# Verify that gradients are of type ND array.
assert isinstance(gradients[0], tnp.ndarray)
Parameter shapes: [TensorShape([32, 64]), TensorShape([64]), TensorShape([64, 2])]
Gradient shapes: [TensorShape([32, 64]), TensorShape([64]), TensorShape([64, 2])]
# Computes a batch of jacobians. Each row is the jacobian of an element in the
# batch of outputs w.r.t. the corresponding input batch element.
def prediction_batch_jacobian(inputs):
  with tf.GradientTape() as tape:
    tape.watch(inputs)
    prediction = model.predict(inputs)
  return prediction, tape.batch_jacobian(prediction, inputs)

inp_batch = tnp.ones([16, 32], tnp.float32)
output, batch_jacobian = prediction_batch_jacobian(inp_batch)
# Note how the batch jacobian shape relates to the input and output shapes.
print("Output shape: %s, input shape: %s" % (output.shape, inp_batch.shape))
print("Batch jacobian shape:", batch_jacobian.shape)
Output shape: (16, 2), input shape: (16, 32)
Batch jacobian shape: (16, 2, 32)

ট্রেস সংকলন: tf.function

TensorFlow-এর tf.function "ট্রেস কম্পাইল" করে এবং তারপরে এই ট্রেসগুলিকে আরও দ্রুত কর্মক্ষমতার জন্য অপ্টিমাইজ করে কাজ করে। গ্রাফ এবং ফাংশনের ভূমিকা দেখুন।

tf.function NumPy কোডটিও অপ্টিমাইজ করতে ব্যবহার করা যেতে পারে। স্পিডআপগুলি প্রদর্শন করার জন্য এখানে একটি সহজ উদাহরণ। মনে রাখবেন যে tf.function কোডের বডিতে TensorFlow NumPy API-তে কল করা আছে।

inputs, labels = create_batch(512)
print("Eager performance")
compute_gradients(model, inputs, labels)
print(timeit.timeit(lambda: compute_gradients(model, inputs, labels),
                    number=10) * 100, "ms")

print("\ntf.function compiled performance")
compiled_compute_gradients = tf.function(compute_gradients)
compiled_compute_gradients(model, inputs, labels)  # warmup
print(timeit.timeit(lambda: compiled_compute_gradients(model, inputs, labels),
                    number=10) * 100, "ms")
Eager performance
1.291419400013183 ms

tf.function compiled performance
0.5561202000080812 ms

ভেক্টরাইজেশন: tf.vectorized_map

TensorFlow-এ সমান্তরাল লুপগুলিকে ভেক্টরাইজ করার জন্য অন্তর্নির্মিত সমর্থন রয়েছে, যা এক থেকে দুই ক্রম মাত্রার গতি বৃদ্ধি করতে দেয়। এই স্পিডআপগুলি tf.vectorized_map API-এর মাধ্যমে অ্যাক্সেসযোগ্য এবং TensorFlow NumPy কোডেও প্রযোজ্য।

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

@tf.function
def vectorized_per_example_gradients(inputs, labels):
  def single_example_gradient(arg):
    inp, label = arg
    return compute_gradients(model,
                             tnp.expand_dims(inp, 0),
                             tnp.expand_dims(label, 0))
  # Note that a call to `tf.vectorized_map` semantically maps
  # `single_example_gradient` over each row of `inputs` and `labels`.
  # The interface is similar to `tf.map_fn`.
  # The underlying machinery vectorizes away this map loop which gives
  # nice speedups.
  return tf.vectorized_map(single_example_gradient, (inputs, labels))

batch_size = 128
inputs, labels = create_batch(batch_size)

per_example_gradients = vectorized_per_example_gradients(inputs, labels)
for w, p in zip(model.weights, per_example_gradients):
  print("Weight shape: %s, batch size: %s, per example gradient shape: %s " % (
      w.shape, batch_size, p.shape))
Weight shape: (32, 64), batch size: 128, per example gradient shape: (128, 32, 64) 
Weight shape: (64,), batch size: 128, per example gradient shape: (128, 64) 
Weight shape: (64, 2), batch size: 128, per example gradient shape: (128, 64, 2)
# Benchmark the vectorized computation above and compare with
# unvectorized sequential computation using `tf.map_fn`.
@tf.function
def unvectorized_per_example_gradients(inputs, labels):
  def single_example_gradient(arg):
    inp, label = arg
    return compute_gradients(model,
                             tnp.expand_dims(inp, 0),
                             tnp.expand_dims(label, 0))

  return tf.map_fn(single_example_gradient, (inputs, labels),
                   fn_output_signature=(tf.float32, tf.float32, tf.float32))

print("Running vectorized computation")
print(timeit.timeit(lambda: vectorized_per_example_gradients(inputs, labels),
                    number=10) * 100, "ms")

print("\nRunning unvectorized computation")
per_example_gradients = unvectorized_per_example_gradients(inputs, labels)
print(timeit.timeit(lambda: unvectorized_per_example_gradients(inputs, labels),
                    number=10) * 100, "ms")
Running vectorized computation
0.5265710999992734 ms

Running unvectorized computation
40.35122630002661 ms

ডিভাইস বসানো

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

TensorFlow-এ এছাড়াও ডিভাইস জুড়ে গণনার প্রতিলিপি এবং যৌথ হ্রাস সম্পাদনের জন্য API রয়েছে যা এখানে কভার করা হবে না।

ডিভাইসের তালিকা করুন

tf.config.list_logical_devices এবং tf.config.list_physical_devices ব্যবহার করা যেতে পারে কোন ডিভাইস ব্যবহার করতে হবে তা খুঁজে বের করতে।

print("All logical devices:", tf.config.list_logical_devices())
print("All physical devices:", tf.config.list_physical_devices())

# Try to get the GPU device. If unavailable, fallback to CPU.
try:
  device = tf.config.list_logical_devices(device_type="GPU")[0]
except IndexError:
  device = "/device:CPU:0"
All logical devices: [LogicalDevice(name='/device:CPU:0', device_type='CPU'), LogicalDevice(name='/device:GPU:0', device_type='GPU')]
All physical devices: [PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU'), PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

স্থাপন অপারেশন: tf.device

একটি tf.device স্কোপে কল করে একটি ডিভাইসে অপারেশন স্থাপন করা যেতে পারে।

print("Using device: %s" % str(device))
# Run operations in the `tf.device` scope.
# If a GPU is available, these operations execute on the GPU and outputs are
# placed on the GPU memory.
with tf.device(device):
  prediction = model.predict(create_batch(5)[0])

print("prediction is placed on %s" % prediction.device)
Using device: LogicalDevice(name='/device:GPU:0', device_type='GPU')
prediction is placed on /job:localhost/replica:0/task:0/device:GPU:0

ডিভাইস জুড়ে ND অ্যারে অনুলিপি করা হচ্ছে: tnp.copy

tnp.copy এ একটি কল, একটি নির্দিষ্ট ডিভাইস স্কোপে রাখা, সেই ডিভাইসে ডেটা কপি করবে, যদি না ডেটা ইতিমধ্যেই সেই ডিভাইসে থাকে।

with tf.device("/device:CPU:0"):
  prediction_cpu = tnp.copy(prediction)
print(prediction.device)
print(prediction_cpu.device)
/job:localhost/replica:0/task:0/device:GPU:0
/job:localhost/replica:0/task:0/device:CPU:0

কর্মক্ষমতা তুলনা

TensorFlow NumPy অত্যন্ত অপ্টিমাইজ করা TensorFlow কার্নেল ব্যবহার করে যা CPU, GPU এবং TPU-তে পাঠানো যেতে পারে। টেনসরফ্লো অনেক কম্পাইলার অপ্টিমাইজেশনও করে, যেমন অপারেশন ফিউশন, যা পারফরম্যান্স এবং মেমরির উন্নতিতে অনুবাদ করে। আরও জানতে Grappler-এর সাথে TensorFlow গ্রাফ অপ্টিমাইজেশন দেখুন।

যদিও NumPy-এর তুলনায় TensorFlow-এর ক্রিয়াকলাপ প্রেরণের জন্য উচ্চ ওভারহেড রয়েছে। ছোট ক্রিয়াকলাপ (প্রায় 10 মাইক্রোসেকেন্ডের কম) দ্বারা গঠিত কাজের চাপের জন্য, এই ওভারহেডগুলি রানটাইমে আধিপত্য বিস্তার করতে পারে এবং NumPy আরও ভাল পারফরম্যান্স প্রদান করতে পারে। অন্যান্য ক্ষেত্রে, TensorFlow সাধারণত ভাল পারফরম্যান্স প্রদান করা উচিত।

বিভিন্ন ইনপুট আকারের জন্য NumPy এবং TensorFlow NumPy কর্মক্ষমতা তুলনা করতে নীচের বেঞ্চমার্কটি চালান।

def benchmark(f, inputs, number=30, force_gpu_sync=False):
  """Utility to benchmark `f` on each value in `inputs`."""
  times = []
  for inp in inputs:
    def _g():
      if force_gpu_sync:
        one = tnp.asarray(1)
      f(inp)
      if force_gpu_sync:
        with tf.device("CPU:0"):
          tnp.copy(one)  # Force a sync for GPU case

    _g()  # warmup
    t = timeit.timeit(_g, number=number)
    times.append(t * 1000. / number)
  return times


def plot(np_times, tnp_times, compiled_tnp_times, has_gpu, tnp_times_gpu):
  """Plot the different runtimes."""
  plt.xlabel("size")
  plt.ylabel("time (ms)")
  plt.title("Sigmoid benchmark: TF NumPy vs NumPy")
  plt.plot(sizes, np_times, label="NumPy")
  plt.plot(sizes, tnp_times, label="TF NumPy (CPU)")
  plt.plot(sizes, compiled_tnp_times, label="Compiled TF NumPy (CPU)")
  if has_gpu:
    plt.plot(sizes, tnp_times_gpu, label="TF NumPy (GPU)")
  plt.legend()
# Define a simple implementation of `sigmoid`, and benchmark it using
# NumPy and TensorFlow NumPy for different input sizes.

def np_sigmoid(y):
  return 1. / (1. + np.exp(-y))

def tnp_sigmoid(y):
  return 1. / (1. + tnp.exp(-y))

@tf.function
def compiled_tnp_sigmoid(y):
  return tnp_sigmoid(y)

sizes = (2 ** 0, 2 ** 5, 2 ** 10, 2 ** 15, 2 ** 20)
np_inputs = [np.random.randn(size).astype(np.float32) for size in sizes]
np_times = benchmark(np_sigmoid, np_inputs)

with tf.device("/device:CPU:0"):
  tnp_inputs = [tnp.random.randn(size).astype(np.float32) for size in sizes]
  tnp_times = benchmark(tnp_sigmoid, tnp_inputs)
  compiled_tnp_times = benchmark(compiled_tnp_sigmoid, tnp_inputs)

has_gpu = len(tf.config.list_logical_devices("GPU"))
if has_gpu:
  with tf.device("/device:GPU:0"):
    tnp_inputs = [tnp.random.randn(size).astype(np.float32) for size in sizes]
    tnp_times_gpu = benchmark(compiled_tnp_sigmoid, tnp_inputs, 100, True)
else:
  tnp_times_gpu = None
plot(np_times, tnp_times, compiled_tnp_times, has_gpu, tnp_times_gpu)

png

আরও পড়া