NumPy API di TensorFlow

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Ringkasan

TensorFlow mengimplementasikan subset dari NumPy API , tersedia sebagai tf.experimental.numpy . Hal ini memungkinkan menjalankan kode NumPy, yang dipercepat oleh TensorFlow, sekaligus memungkinkan 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.6.0

Mengaktifkan perilaku NumPy

Untuk menggunakan tnp sebagai NumPy, aktifkan perilaku NumPy untuk TensorFlow:

tnp.experimental_enable_numpy_behavior()

Panggilan ini mengaktifkan promosi jenis di TensorFlow dan juga mengubah inferensi jenis, saat mengonversi literal ke tensor, untuk mengikuti standar NumPy dengan lebih ketat.

TensorFlow NumPy ND array

Sebuah instance dari tf.experimental.numpy.ndarray , yang disebut ND Array , mewakili array padat multidimensi dari tipe- dtype tertentu yang ditempatkan pada perangkat tertentu. Ini adalah alias untuk tf.Tensor . Lihat kelas array ND untuk metode yang berguna seperti ndarray.T , ndarray.reshape , ndarray.ravel dan lainnya.

Pertama, buat objek larik 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.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,)

Jenis promosi

TensorFlow NumPy API memiliki semantik yang terdefinisi dengan baik untuk mengonversi literal ke array ND, serta untuk melakukan promosi jenis pada input array ND. Silakan lihat np.result_type untuk lebih jelasnya.

API TensorFlow membiarkan input tf.Tensor tidak berubah dan tidak melakukan promosi jenis pada input tersebut, sementara TensorFlow NumPy API mempromosikan semua input sesuai dengan aturan promosi jenis NumPy. Pada contoh berikutnya, Anda akan melakukan promosi jenis. Pertama, jalankan penambahan pada input array ND dari tipe yang berbeda dan perhatikan tipe outputnya. Tidak satu pun dari jenis promosi ini akan diizinkan oleh 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

Terakhir, konversi literal ke array ND menggunakan ndarray.asarray dan catat jenis yang dihasilkan.

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

Saat mengonversi literal ke array ND, NumPy lebih menyukai tipe lebar seperti tnp.int64 dan tnp.float64 . Sebaliknya, tf.convert_to_tensor lebih memilih tipe tf.int32 dan tf.float32 untuk mengonversi konstanta ke tf.Tensor . TensorFlow NumPy API mematuhi perilaku NumPy untuk bilangan bulat. Untuk float, argumen prefer_float32 dari experimental_enable_numpy_behavior memungkinkan Anda mengontrol apakah akan memilih tf.float32 daripada tf.float64 (default ke False ). Sebagai contoh:

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

Penyiaran

Mirip dengan TensorFlow, NumPy mendefinisikan semantik yang 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
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.

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)))
tf.Tensor(
[[-1.7706785  1.1137733]
 [-1.7706785  1.1137733]], shape=(2, 2), dtype=float32)

TensorFlow NumPy dan NumPy

TensorFlow NumPy mengimplementasikan subset dari spesifikasi NumPy lengkap. Sementara lebih banyak simbol akan ditambahkan dari waktu ke waktu, ada fitur sistematis yang tidak akan didukung dalam waktu dekat. Ini termasuk dukungan NumPy C API, integrasi Swig, urutan penyimpanan Fortran, views dan stride_tricks , dan beberapa dtype s (seperti np.recarray dan np.object ). Untuk detail selengkapnya, lihat Dokumentasi TensorFlow NumPy API .

Interoperabilitas NumPy

Array TensorFlow ND dapat beroperasi dengan fungsi NumPy. Objek-objek ini mengimplementasikan antarmuka __array__ . NumPy menggunakan antarmuka ini untuk mengonversi argumen fungsi ke nilai np.ndarray sebelum memprosesnya.

Demikian pula, fungsi TensorFlow NumPy dapat menerima input dari berbagai jenis termasuk np.ndarray . Input ini dikonversi ke array ND dengan memanggil ndarray.asarray pada input tersebut.

Konversi larik ND ke dan dari np.ndarray dapat memicu salinan data aktual. Silakan lihat bagian tentang 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.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

Salinan penyangga

Mencampur TensorFlow NumPy dengan kode NumPy dapat memicu salinan data. Ini karena TensorFlow NumPy memiliki persyaratan yang lebih ketat pada penyelarasan memori daripada NumPy.

Saat np.ndarray diteruskan ke TensorFlow NumPy, np.ndarray akan memeriksa persyaratan penyelarasan dan memicu salinan jika diperlukan. Saat meneruskan buffer CPU array ND ke NumPy, umumnya buffer 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 API NumPy umumnya harus dilakukan dengan hati-hati dan pengguna harus berhati-hati terhadap overhead penyalinan data. Menyela panggilan TensorFlow NumPy dengan panggilan TensorFlow umumnya aman dan menghindari penyalinan data. Lihat bagian tentang interoperabilitas TensorFlow untuk detail selengkapnya.

Prioritas operator

TensorFlow NumPy mendefinisikan __array_priority__ lebih tinggi dari NumPy. Ini berarti bahwa untuk operator yang melibatkan larik ND dan np.ndarray , yang pertama akan diutamakan, yaitu, input np.ndarray akan dikonversi ke larik ND dan implementasi TensorFlow NumPy dari operator akan dipanggil.

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 dan TensorFlow

TensorFlow NumPy dibangun di atas TensorFlow dan karenanya beroperasi secara lancar dengan TensorFlow.

tf.Tensor dan larik ND

Array ND adalah alias untuk tf.Tensor , jadi jelas mereka dapat dicampur tanpa memicu salinan data yang sebenarnya.

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'>

Interoperabilitas TensorFlow

Array ND dapat diteruskan ke API TensorFlow, karena array ND hanyalah alias untuk tf.Tensor . Seperti disebutkan sebelumnya, interoperasi tersebut tidak melakukan salinan data, bahkan untuk data yang ditempatkan pada akselerator atau perangkat jarak jauh.

Sebaliknya, objek tf.Tensor dapat diteruskan ke tf.experimental.numpy API, tanpa melakukan penyalinan data.

# 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)

Gradien dan Jacobian: tf.GradientTape

GradientTape TensorFlow dapat digunakan untuk backpropagation melalui kode TensorFlow dan TensorFlow NumPy.

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: [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)

Kompilasi jejak: tf.function

tf.function tf.function bekerja dengan "mengkompilasi jejak" kode dan kemudian mengoptimalkan jejak ini untuk kinerja 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 isi kode tf.function menyertakan panggilan ke 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

Vektorisasi: tf.vectorized_map

TensorFlow memiliki dukungan bawaan untuk membuat vektor loop paralel, yang memungkinkan percepatan satu hingga dua kali lipat. Percepatan ini dapat diakses melalui tf.vectorized_map API dan juga berlaku untuk kode TensorFlow NumPy.

Kadang-kadang berguna untuk menghitung gradien setiap output dalam satu batch dengan elemen batch input yang sesuai. Perhitungan tersebut 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.5265710999992734 ms

Running unvectorized computation
40.35122630002661 ms

Penempatan perangkat

TensorFlow NumPy dapat menempatkan operasi pada CPU, GPU, TPU, dan perangkat jarak jauh. Ini menggunakan mekanisme TensorFlow standar untuk penempatan perangkat. Di bawah 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 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.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.device)
print(prediction_cpu.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 kompiler, seperti penggabungan operasi, yang menghasilkan peningkatan kinerja 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 runtime dan NumPy dapat memberikan kinerja yang lebih baik. Untuk kasus lain, TensorFlow umumnya harus memberikan kinerja yang lebih baik.

Jalankan tolok ukur di bawah ini untuk membandingkan kinerja NumPy dan TensorFlow NumPy untuk ukuran input yang berbeda.

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

Bacaan lebih lanjut