![]() | ![]() | ![]() | ![]() |
Gambaran
TensorFlow mengimplementasikan subset NumPy API , tersedia sebagai tf.experimental.numpy
. Hal ini memungkinkan menjalankan kode NumPy, yang dipercepat oleh TensorFlow, sekaligus mengizinkan akses ke semua API TensorFlow.
Mempersiapkan
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.4.0
Array TensorFlow NumPy ND
Sebuah contoh dari tf.experimental.numpy.ndarray
, disebut ND Array, merupakan array padat multidimensi diberikan dtype
ditempatkan pada perangkat tertentu. Masing-masing dari objek ini secara internal membungkus tf.Tensor
. Lihat kelas array ND untuk metode yang berguna seperti ndarray.T
, ndarray.reshape
, ndarray.ravel
, dan lainnya.
Pertama buat objek array ND, lalu panggil metode yang berbeda.
# 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.data.device))
# Check out the internally wrapped `tf.Tensor` object.
print("The ND array wraps a tf.Tensor: %s\n" % ones.data)
# 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 = float32 on device = /job:localhost/replica:0/task:0/device:GPU:0 The ND array wraps a tf.Tensor: tf.Tensor( [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.] [1. 1. 1.] [1. 1. 1.]], shape=(5, 3), dtype=float32) ndarray.T has shape (3, 5) narray.reshape(-1) has shape 15
Jenis promosi
TensorFlow NumPy API memiliki semantik yang terdefinisi dengan baik untuk mengonversi literal menjadi array ND, serta untuk melakukan promosi jenis pada input array ND. Silakan lihat np.result_type
untuk lebih jelasnya. Saat mengonversi literal ke array ND, NumPy lebih memilih tipe lebar seperti tnp.int64
dan tnp.float64
.
Sebaliknya, tf.convert_to_tensor
lebih suka tf.int32
dan tf.float32
jenis untuk mengkonversi konstanta untuk tf.Tensor
. API TensorFlow membiarkan input tf.Tensor
tidak berubah dan tidak melakukan promosi jenis padanya.
Pada contoh berikutnya, Anda akan melakukan promosi tipe. Pertama, jalankan penambahan pada input larik ND dari berbagai jenis dan catat jenis keluarannya. Tidak satu pun dari jenis promosi ini akan diizinkan pada objek tf.Tensor
lurus. Terakhir, konversikan literal ke array ND menggunakan ndarray.asarray
dan catat jenis yang dihasilkan.
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, v2.dtype, (v1 + v2).dtype))
print("Type inference during array creation")
print("tnp.asarray(1).dtype == tnp.%s" % tnp.asarray(1).dtype)
print("tnp.asarray(1.).dtype == tnp.%s\n" % tnp.asarray(1.).dtype)
Type promotion for operations int32 + int64 => int64 int32 + float32 => float64 int32 + float64 => float64 int64 + float32 => float64 int64 + float64 => float64 float32 + float64 => float64 Type inference during array creation tnp.asarray(1).dtype == tnp.int64 tnp.asarray(1.).dtype == tnp.float64
Penyiaran
Mirip dengan TensorFlow, NumPy mendefinisikan semantik kaya untuk nilai "penyiaran". Anda dapat melihat panduan penyiaran NumPy untuk informasi lebih lanjut dan membandingkannya dengan semantik penyiaran 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)
Pengindeksan
NumPy mendefinisikan aturan pengindeksan yang sangat canggih. Lihat panduan Pengindeksan NumPy . Perhatikan penggunaan array ND sebagai indeks di bawah ini.
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 ndarray<tf.Tensor( [[[16 17 18 19] [20 21 22 23]]], shape=(1, 2, 4), dtype=int64)> Boolean indexing ndarray<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 ndarray<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.
Contoh Model
Selanjutnya, Anda dapat melihat cara membuat model dan menjalankan inferensi di atasnya. Model sederhana ini menerapkan lapisan relu diikuti dengan proyeksi linier. Bagian selanjutnya akan menunjukkan cara menghitung gradien untuk model ini menggunakan 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)))
ndarray<tf.Tensor( [[-0.89206064 -0.18108469] [-0.89206064 -0.18108469]], shape=(2, 2), dtype=float32)>
TensorFlow NumPy dan NumPy
TensorFlow NumPy mengimplementasikan subset dari spesifikasi NumPy lengkap. Sementara lebih banyak simbol akan ditambahkan seiring waktu, ada fitur sistematis yang tidak akan didukung dalam waktu dekat. Ini termasuk dukungan NumPy C API, integrasi Swig, urutan penyimpanan Fortran, tampilan dan stride_tricks
, dan beberapa dtype
s (seperti np.recarray
dan np.object
). Untuk detail selengkapnya, lihat Dokumentasi API NumPy TensorFlow .
Interoperabilitas NumPy
Array TensorFlow ND dapat beroperasi dengan fungsi NumPy. Objek ini mengimplementasikan antarmuka __array__
. NumPy menggunakan antarmuka ini untuk mengubah argumen fungsi menjadi nilai np.ndarray
sebelum memprosesnya.
Demikian pula, fungsi TensorFlow NumPy dapat menerima input dari berbagai jenis termasuk tf.Tensor
dan np.ndarray
. Input ini diubah ke array ND dengan memanggil ndarray.asarray
padanya.
Konversi array ND ke dan dari np.ndarray
dapat memicu penyalinan data aktual. Silakan lihat bagian salinan buffer untuk lebih jelasnya.
# 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.ops.numpy_ops.np_arrays.ndarray'>
# It is easy to plot ND arrays, given the __array__ interface.
labels = 15 + 2 * tnp.random.randn(1000)
_ = plt.hist(labels)
Salinan penyangga
Memadukan TensorFlow NumPy dengan kode NumPy dapat memicu penyalinan data. Ini karena TensorFlow NumPy memiliki persyaratan yang lebih ketat pada penyelarasan memori dibandingkan dengan NumPy.
Saat np.ndarray
diteruskan ke TensorFlow NumPy, ini akan memeriksa persyaratan penyelarasan dan memicu salinan jika diperlukan. Saat meneruskan buffer CPU array ND ke NumPy, biasanya buffer tersebut akan memenuhi persyaratan penyelarasan dan NumPy tidak perlu membuat salinan.
Array ND dapat merujuk ke buffer yang ditempatkan pada perangkat selain memori CPU lokal. Dalam kasus seperti itu, menjalankan fungsi NumPy akan memicu salinan di seluruh jaringan atau perangkat sesuai kebutuhan.
Mengingat hal ini, pencampuran dengan panggilan NumPy API umumnya harus dilakukan dengan hati-hati dan pengguna harus berhati-hati terhadap overhead penyalinan data. Menyisipkan panggilan TensorFlow NumPy dengan panggilan TensorFlow umumnya aman dan menghindari penyalinan data. Lihat bagian tentang interoperabilitas TensorFlow untuk mengetahui detail selengkapnya.
Prioritas operator
TensorFlow NumPy mendefinisikan __array_priority__
lebih tinggi dari NumPy. Artinya, untuk operator yang melibatkan array ND dan np.ndarray
, yang pertama akan diutamakan, yaitu masukan np.ndarray
akan diubah menjadi array ND dan implementasi TensorFlow NumPy pada operator akan dipanggil.
x = tnp.ones([2]) + np.ones([2])
print("x = %s\nclass = %s" % (x, x.__class__))
x = ndarray<tf.Tensor([2. 2.], shape=(2,), dtype=float64)> class = <class 'tensorflow.python.ops.numpy_ops.np_arrays.ndarray'>
TF NumPy dan TensorFlow
TensorFlow NumPy dibuat di atas TensorFlow dan karenanya beroperasi secara mulus dengan TensorFlow.
tf.Tensor
dan array ND
Array ND adalah pembungkus tipis pada tf.Tensor
. Jenis ini dapat dikonversi dengan murah satu sama lain tanpa memicu salinan data yang sebenarnya.
x = tf.constant([1, 2])
# Convert `tf.Tensor` to `ndarray`.
tnp_x = tnp.asarray(x)
print(tnp_x)
# Convert `ndarray` to `tf.Tensor` can be done in following ways.
print(tnp_x.data)
print(tf.convert_to_tensor(tnp_x))
# Note that tf.Tensor.numpy() will continue to return `np.ndarray`.
print(x.numpy(), x.numpy().__class__)
ndarray<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'>
Interoperabilitas TensorFlow
Array ND bisa diteruskan ke TensorFlow API. Panggilan ini secara internal mengonversi input array ND ke tf.Tensor
. Seperti yang disebutkan sebelumnya, konversi semacam itu tidak benar-benar melakukan salinan data, bahkan untuk data yang ditempatkan pada akselerator atau perangkat jarak jauh.
Sebaliknya, objek tf.Tensor
dapat diteruskan ke API tf.experimental.numpy
. Input ini secara internal akan diubah ke array ND tanpa melakukan salinan data.
# ND array passed into TensorFlow function.
# This returns a `tf.Tensor`.
tf_sum = tf.reduce_sum(tnp.ones([2, 3], tnp.float32))
print("Output = %s" % tf_sum)
# `tf.Tensor` passed into TensorFlow NumPy function.
# This returns an ND array.
tnp_sum = tnp.sum(tf.ones([2, 3]))
print("Output = %s" % tnp_sum)
Output = tf.Tensor(6.0, shape=(), dtype=float32) Output = ndarray<tf.Tensor(6.0, shape=(), dtype=float32)>
Prioritas operator
Jika array ND dan objek tf.Tensor
digabungkan menggunakan operator, aturan prioritas digunakan untuk menentukan objek mana yang mengeksekusi operator. Ini dikontrol oleh nilai __array_priority__
ditentukan oleh kelas-kelas ini.
tf.Tensor
mendefinisikan __array_priority__
lebih tinggi dari array ND. Artinya, input array ND akan diubah menjadi tf.Tensor
dan versi operator tf.Tensor
akan dipanggil.
Kode di bawah ini menunjukkan bagaimana hal itu mempengaruhi tipe keluaran.
x = tnp.ones([2, 2]) + tf.ones([2, 1])
print("x = %s\nClass = %s" % (x, x.__class__))
x = tf.Tensor( [[2. 2.] [2. 2.]], shape=(2, 2), dtype=float32) Class = <class 'tensorflow.python.framework.ops.EagerTensor'>
Gradien dan Jacobian: tf. GradientTape
GradientTape TensorFlow dapat digunakan untuk propagasi mundur melalui kode TensorFlow dan TensorFlow NumPy. GradientTape API juga dapat mengembalikan keluaran array ND.
Gunakan model yang dibuat di bagian Model Contoh , dan hitung gradien dan jacobian.
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: [(32, 64), (64,), (64, 2)] Gradient shapes: [(32, 64), (64,), (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)
Kompilasi jejak: tf.function
TensorFlow's tf.function
bekerja dengan "melacak kompilasi" kode dan kemudian mengoptimalkan jejak ini untuk performa yang jauh lebih cepat. Lihat Pengantar Grafik dan Fungsi .
tf.function
juga dapat digunakan untuk mengoptimalkan kode TensorFlow NumPy. Berikut adalah contoh sederhana untuk mendemonstrasikan speedups. Perhatikan bahwa tf.function
kode tf.function
menyertakan panggilan ke TensorFlow NumPy API, dan input serta outputnya adalah array ND.
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.3229853999973784 ms tf.function compiled performance 0.4066010000087772 ms
Vektorisasi: tf.vectorized_map
TensorFlow memiliki dukungan bawaan untuk melakukan vektorisasi loop paralel, yang memungkinkan percepatan satu hingga dua kali lipat. Speedup ini dapat diakses melalui tf.vectorized_map
API dan juga berlaku untuk kode TensorFlow NumPy.
Terkadang berguna untuk menghitung gradien dari setiap keluaran dalam sebuah batch dengan elemen batch masukan yang sesuai. Perhitungan seperti itu dapat dilakukan secara efisien menggunakan tf.vectorized_map
seperti yang ditunjukkan di bawah ini.
@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.3884524000000056 ms Running unvectorized computation 38.94797479999852 ms
Penempatan perangkat
TensorFlow NumPy dapat melakukan operasi pada CPU, GPU, TPU, dan perangkat jarak jauh. Ini menggunakan mekanisme TensorFlow standar untuk penempatan perangkat. Di bawah ini contoh sederhana menunjukkan bagaimana membuat daftar semua perangkat dan kemudian menempatkan beberapa perhitungan pada perangkat tertentu.
TensorFlow juga memiliki API untuk mereplikasi komputasi di seluruh perangkat dan melakukan pengurangan kolektif yang tidak akan dibahas di sini.
Daftar perangkat
tf.config.list_logical_devices
dan tf.config.list_physical_devices
dapat digunakan untuk menemukan perangkat apa yang akan digunakan.
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')]
Menempatkan operasi: tf.device
Operasi dapat ditempatkan pada perangkat dengan memanggilnya dalam lingkup 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.data.device)
Using device: LogicalDevice(name='/device:GPU:0', device_type='GPU') prediction is placed on /job:localhost/replica:0/task:0/device:GPU:0
Menyalin array ND di seluruh perangkat: tnp.copy
Panggilan ke tnp.copy
, ditempatkan di lingkup perangkat tertentu, akan menyalin data ke perangkat itu, kecuali data sudah ada di perangkat itu.
with tf.device("/device:CPU:0"):
prediction_cpu = tnp.copy(prediction)
print(prediction.data.device)
print(prediction_cpu.data.device)
/job:localhost/replica:0/task:0/device:GPU:0 /job:localhost/replica:0/task:0/device:CPU:0
Perbandingan kinerja
TensorFlow NumPy menggunakan kernel TensorFlow yang sangat dioptimalkan yang dapat dikirim pada CPU, GPU, dan TPU. TensorFlow juga melakukan banyak pengoptimalan compiler, seperti fusi operasi, yang menghasilkan peningkatan performa dan memori. Lihat pengoptimalan grafik TensorFlow dengan Grappler untuk mempelajari lebih lanjut.
Namun TensorFlow memiliki overhead yang lebih tinggi untuk operasi pengiriman dibandingkan dengan NumPy. Untuk beban kerja yang terdiri dari operasi kecil (kurang dari sekitar 10 mikrodetik), overhead ini dapat mendominasi waktu proses dan NumPy dapat memberikan kinerja yang lebih baik. Untuk kasus lain, TensorFlow biasanya memberikan performa yang lebih baik.
Jalankan tolok ukur di bawah untuk membandingkan performa NumPy dan TensorFlow NumPy untuk berbagai ukuran input.
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)