مشاهده در TensorFlow.org | در Google Colab اجرا شود | مشاهده منبع در GitHub | دانلود دفترچه یادداشت |
بررسی اجمالی
TensorFlow زیرمجموعه ای از NumPy API را پیاده سازی می کند که به عنوان tf.experimental.numpy
موجود است. این اجازه می دهد تا کد NumPy را اجرا کنید که توسط TensorFlow تسریع می شود، در حالی که امکان دسترسی به تمام API های TensorFlow را نیز فراهم می کند.
برپایی
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
برای استفاده از tnp
به عنوان NumPy، رفتار NumPy را برای TensorFlow فعال کنید:
tnp.experimental_enable_numpy_behavior()
این فراخوانی ارتقای نوع را در TensorFlow فعال میکند و همچنین استنتاج نوع را در هنگام تبدیل حروف به تانسور تغییر میدهد تا با دقت بیشتری از استاندارد NumPy پیروی کند.
آرایه TensorFlow NumPy ND
نمونهای از tf.experimental.numpy.ndarray
، به نام آرایه ND ، یک آرایه متراکم چند بعدی از یک dtype
معین را نشان میدهد که روی یک دستگاه خاص قرار گرفته است. این نام مستعار tf.Tensor
است. کلاس آرایه ND را برای روش های مفیدی مانند 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,)
تبلیغ را تایپ کنید
API های TensorFlow NumPy دارای معنایی کاملاً تعریف شده برای تبدیل حرف به آرایه ND، و همچنین برای انجام ارتقای نوع در ورودی های آرایه ND هستند. لطفاً برای جزئیات بیشتر به np.result_type
مراجعه کنید.
APIهای tf.Tensor
ورودیهای tf.Tensor را بدون تغییر میگذارند و تبلیغات نوع را روی آنها انجام نمیدهند، در حالی که APIهای TensorFlow NumPy همه ورودیها را طبق قوانین تبلیغ نوع NumPy ارتقا میدهند. در مثال بعدی، ارتقای نوع را انجام خواهید داد. ابتدا جمع را روی ورودی های آرایه ND از انواع مختلف اجرا کنید و انواع خروجی را یادداشت کنید. هیچ یک از این نوع تبلیغات توسط API های TensorFlow مجاز نخواهد بود.
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
ها را به آرایه 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
هنگام تبدیل literals به آرایه ND، NumPy انواع گسترده مانند tnp.int64
و tnp.float64
را ترجیح می دهد. در مقابل، tf.convert_to_tensor
انواع tf.int32
و tf.float32
برای تبدیل ثابت ها به tf.Tensor
ترجیح می دهد. API های TensorFlow NumPy به رفتار NumPy برای اعداد صحیح پایبند هستند. در مورد float ها، آرگومان prefer_float32
experimental_enable_numpy_behavior
به شما امکان می دهد کنترل کنید که آیا tf.float32 را به tf.float32
ترجیح tf.float64
(پیش فرض به False
). مثلا:
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.
نمونه مدل
در مرحله بعد، می توانید نحوه ایجاد یک مدل و اجرای استنتاج بر روی آن را مشاهده کنید. این مدل ساده یک لایه relu و به دنبال آن یک طرح خطی اعمال می کند. بخشهای بعدی نحوه محاسبه گرادیانها را برای این مدل با استفاده از GradientTape
TensorFlow نشان میدهد.
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، ادغام Swig، ترتیب ذخیره سازی Fortran، views و 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 تبدیل می شوند.
تبدیل آرایه ND به و از 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)
کپی های بافر
اختلاط TensorFlow NumPy با کد NumPy ممکن است باعث ایجاد کپی های داده شود. این به این دلیل است که TensorFlow NumPy نسبت به NumPy الزامات سخت گیرانه تری در تراز حافظه دارد.
هنگامی که یک np.ndarray
به TensorFlow NumPy ارسال می شود، الزامات تراز را بررسی می کند و در صورت نیاز یک کپی را راه اندازی می کند. هنگام ارسال بافر CPU آرایه ND به NumPy، معمولاً بافر الزامات تراز را برآورده می کند و NumPy نیازی به ایجاد یک کپی ندارد.
آرایههای ND میتوانند به بافرهایی اشاره کنند که روی دستگاههایی غیر از حافظه محلی CPU قرار میگیرند. در چنین مواردی، فراخوانی یک تابع NumPy در صورت نیاز، کپیهایی را در سراسر شبکه یا دستگاه ایجاد میکند.
با توجه به این موضوع، اختلاط با فراخوانهای NumPy API معمولاً باید با احتیاط انجام شود و کاربر باید مراقب هزینههای کپی داده باشد. به هم پیوستن تماسهای TensorFlow NumPy با تماسهای TensorFlow عموماً ایمن است و از کپی کردن دادهها جلوگیری میکند. برای جزئیات بیشتر به بخش قابلیت همکاری 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'>
قابلیت همکاری تنسورفلو
یک آرایه ND را می توان به API های TensorFlow ارسال کرد، زیرا آرایه ND فقط نام مستعار 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)
Gradients و Jacobians: tf.GradientTape
GradientTape TensorFlow را می توان برای انتشار پس از طریق کد TensorFlow و TensorFlow NumPy استفاده کرد.
از مدل ایجاد شده در بخش Example Model استفاده کنید و گرادیان و ژاکوبین ها را محاسبه کنید.
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
tf.function
با "تریس کامپایل" کد و سپس بهینه سازی این ردیابی ها برای عملکرد بسیار سریعتر کار می کند. به مقدمه نمودارها و توابع مراجعه کنید.
tf.function
می توان برای بهینه سازی کد TensorFlow NumPy نیز استفاده کرد. در اینجا یک مثال ساده برای نشان دادن افزایش سرعت آورده شده است. توجه داشته باشید که متن کد tf.function
شامل تماسهایی با APIهای TensorFlow NumPy است.
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 میتواند عملیات را روی CPU، GPU، TPU و دستگاههای راه دور انجام دهد. از مکانیسم های استاندارد TensorFlow برای قرار دادن دستگاه استفاده می کند. در زیر یک مثال ساده نشان می دهد که چگونه می توان همه دستگاه ها را فهرست کرد و سپس مقداری محاسبات را روی یک دستگاه خاص قرار داد.
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 ها ارسال شوند. TensorFlow همچنین بسیاری از بهینه سازی های کامپایلر را انجام می دهد، مانند عملیات fusion، که به بهبود عملکرد و حافظه تبدیل می شود. برای کسب اطلاعات بیشتر به بهینه سازی نمودار TensorFlow با Grappler مراجعه کنید.
با این حال، TensorFlow در مقایسه با NumPy، هزینه های سربار بالاتری برای عملیات دیسپاچینگ دارد. برای بارهای کاری متشکل از عملیات کوچک (کمتر از حدود 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)