도움말 Kaggle에 TensorFlow과 그레이트 배리어 리프 (Great Barrier Reef)를 보호하기 도전에 참여

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 동작 활성화

사용하기 위해서는 tnp NumPy와 같은 TensorFlow에 대한 NumPy와 동작을 수 있습니다 :

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

유형 프로모션

TensorFlow NumPy API에는 리터럴을 ND 배열로 변환하고 ND 배열 입력에서 유형 승격을 수행하기 위한 잘 정의된 의미 체계가 있습니다. 참조하시기 바랍니다 np.result_type 자세한 내용은.

TensorFlow API를 떠나 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

마지막으로, ND 배열로 변환 리터럴은 사용 ndarray.asarray 및 결과 유형을 확인합니다.

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.int64tnp.float64 . 반대로 tf.convert_to_tensor 선호 tf.int32tf.float32 로 정수 변환 유형 tf.Tensor . TensorFlow NumPy API는 정수에 대한 NumPy 동작을 따릅니다. 수레에 관해서는, prefer_float32 의 인수 experimental_enable_numpy_behavior 당신이 선호할지 여부를 제어 할 수 있습니다 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 레이어를 적용한 다음 선형 투영을 적용합니다. 나중에 섹션 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 지원, 꿀꺽 꿀꺽 통합, 포트란 저장하기 위해, 뷰 및 포함 stride_tricks , 일부 dtype 의 (같은 np.recarraynp.object ). 자세한 내용은 참조하십시오 TensorFlow NumPy와의 API 문서를 .

넘파이 상호 운용성

TensorFlow ND 어레이는 NumPy 함수와 상호 운용할 수 있습니다. 이러한 개체는 구현 __array__ 인터페이스를. NumPy와는 기능면 인수 변환이 인터페이스를 사용 np.ndarray 을 처리하기 전에 값을.

마찬가지로, TensorFlow NumPy와 기능을 포함하여 다양한 종류의 입력을 받아 들일 수 np.ndarray . 이 입력은 호출하여 ND 배열로 변환됩니다 ndarray.asarray 그들.

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

png

버퍼 복사본

TensorFlow NumPy를 NumPy 코드와 혼합하면 데이터 복사가 트리거될 수 있습니다. TensorFlow NumPy는 NumPy보다 메모리 정렬에 대한 요구 사항이 더 엄격하기 때문입니다.

np.ndarray TensorFlow NumPy와 전달, 그것은 정렬 요구 사항을 확인하고 필요한 경우 사본을 트리거합니다. NumPy에 ND 어레이 CPU 버퍼를 전달할 때 일반적으로 버퍼는 정렬 요구 사항을 충족하고 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'>

TensorFlow 상호 운용성

ND 배열이 단지 별칭 년부터 ND 배열은, TensorFlow API에 전달 될 수 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 아니라 TensorFlow 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에는 병렬 루프 벡터화에 대한 지원이 내장되어 있어 10~200배의 속도 향상이 가능합니다. 이러한 속도 향상은 통해 액세스 할 수 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_devicestf.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는 CPU, GPU 및 TPU에서 디스패치할 수 있는 고도로 최적화된 TensorFlow 커널을 사용합니다. TensorFlow는 또한 성능 및 메모리 개선으로 변환되는 연산 융합과 같은 많은 컴파일러 최적화를 수행합니다. 참조 그래플러와 TensorFlow 그래프 최적화는 더 배울 수 있습니다.

그러나 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)

png

추가 읽기