หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

NumPy API บน TensorFlow

ดูใน TensorFlow.org เรียกใช้ใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดสมุดบันทึก

ภาพรวม

TensorFlow ใช้ชุดย่อยของ NumPy API ซึ่งมีอยู่ใน tf.experimental.numpy สิ่งนี้ช่วยให้สามารถรันโค้ด NumPy เร่งโดย TensorFlow ในขณะเดียวกันก็อนุญาตให้เข้าถึง API ทั้งหมดของ TensorFlow

ติดตั้ง

pip install --quiet --upgrade tf-nightly
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

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

อาร์เรย์ ND TensorFlow NumPy

อินสแตนซ์ของ tf.experimental.numpy.ndarray เรียกว่า ND Array แสดงถึงอาร์เรย์หนาแน่นหลายมิติของ dtype กำหนด 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.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:CPU: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

ประเภทการส่งเสริมการขาย

TensorFlow NumPy APIs มีความหมายที่กำหนดไว้อย่างดีสำหรับการแปลงตัวอักษรเป็นอาร์เรย์ ND เช่นเดียวกับการดำเนินการส่งเสริมประเภทบนอินพุตอาร์เรย์ ND โปรดดู np.result_type สำหรับรายละเอียดเพิ่มเติม . เมื่อแปลง tnp.int64 อาร์เรย์ ND NumPy ชอบประเภทกว้างเช่น tnp.int64 และ tnp.float64

ในทางตรงกันข้าม tf.convert_to_tensor ชอบ tf.int32 และ tf.float32 ประเภทสำหรับการแปลงค่าคงที่จะ tf.Tensor TensorFlow APIs ปล่อยให้ tf.Tensor อินพุตของ tf.Tensor ไม่เปลี่ยนแปลงและไม่ดำเนินการส่งเสริมประเภทกับพวกเขา

ในตัวอย่างถัดไปคุณจะทำการโปรโมตประเภท ขั้นแรกให้รันการเพิ่มอินพุตอาร์เรย์ ND ประเภทต่างๆและจดบันทึกประเภทเอาต์พุต ไม่อนุญาตให้มีการโปรโมตประเภทนี้ในวัตถุ tf.Tensor ตรง สุดท้ายแปลงตัวอักษรเป็นอาร์เรย์ ND โดยใช้ ndarray.asarrray และจดประเภทผลลัพธ์

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


การแพร่ภาพ

เช่นเดียวกับ 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
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.

โมเดลตัวอย่าง

จากนั้นคุณสามารถดูวิธีสร้างแบบจำลองและเรียกใช้การอนุมานได้ โมเดลอย่างง่ายนี้ใช้เลเยอร์ 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)))
ndarray<tf.Tensor(
[[-1.9939271  0.5987421]
 [-1.9939271  0.5987421]], shape=(2, 2), dtype=float32)>

TensorFlow NumPy และ NumPy

TensorFlow NumPy ใช้ชุดย่อยของข้อมูลจำเพาะ NumPy แบบเต็ม แม้ว่าจะมีการเพิ่มสัญลักษณ์เพิ่มเติมเมื่อเวลาผ่านไป แต่ก็มีคุณลักษณะที่เป็นระบบซึ่งจะไม่ได้รับการสนับสนุนในอนาคตอันใกล้นี้ ซึ่งรวมถึงการสนับสนุน NumPy C API, การรวม Swig, ลำดับพื้นที่จัดเก็บ Fortran, มุมมองและ stride_tricks และ stride_tricks บาง dtype (เช่น np.recarray และ np.object ) สำหรับรายละเอียดเพิ่มเติมโปรดดูเอกสาร TensorFlow NumPy API

ความสามารถในการทำงานร่วมกันของ NumPy

อาร์เรย์ ND TensorFlow สามารถทำงานร่วมกับฟังก์ชัน NumPy วัตถุเหล่านี้ใช้อินเทอร์เฟซ __array__ NumPy ใช้อินเทอร์เฟซนี้เพื่อแปลงอาร์กิวเมนต์ของฟังก์ชันเป็นค่า np.ndarray ก่อนประมวลผล

ในทำนองเดียวกันฟังก์ชัน TensorFlow NumPy สามารถรับอินพุตประเภทต่างๆรวมถึง tf.Tensor และ 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.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)

png

สำเนาบัฟเฟอร์

การผสม TensorFlow NumPy กับโค้ด NumPy อาจทำให้เกิดการคัดลอกข้อมูล เนื่องจาก TensorFlow NumPy มีข้อกำหนดที่เข้มงวดกว่าในการจัดตำแหน่งหน่วยความจำมากกว่า NumPy

เมื่อ np.ndarray ถูกส่งผ่านไปยัง TensorFlow Numpy ระบบจะตรวจสอบข้อกำหนดในการจัดตำแหน่งและเรียกใช้สำเนาหากจำเป็น เมื่อส่งผ่านบัฟเฟอร์ซีพียูอาร์เรย์ ND ไปยัง NumPy โดยทั่วไปบัฟเฟอร์จะตอบสนองความต้องการในการจัดตำแหน่งและ 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 = ndarray<tf.Tensor([2. 2.], shape=(2,), dtype=float64)>
class = <class 'tensorflow.python.ops.numpy_ops.np_arrays.ndarray'>

TF NumPy และ TensorFlow

TensorFlow NumPy ถูกสร้างขึ้นบน TensorFlow และด้วยเหตุนี้จึงทำงานร่วมกับ TensorFlow ได้อย่างราบรื่น

tf.Tensor และอาร์เรย์ ND

อาร์เรย์ ND เป็นกระดาษห่อบาง ๆ บน tf.Tensor ประเภทเหล่านี้สามารถแปลงได้ในราคาถูกโดยไม่ต้องเรียกสำเนาข้อมูลจริง

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

ความสามารถในการทำงานร่วมกันของ TensorFlow

อาร์เรย์ ND สามารถส่งผ่านไปยัง TensorFlow API ได้ การเรียกเหล่านี้จะแปลงอินพุตอาร์เรย์ ND ภายในเป็น tf.Tensor ดังที่ได้กล่าวไว้ก่อนหน้านี้การแปลงดังกล่าวไม่ได้ทำสำเนาข้อมูลแม้กระทั่งสำหรับข้อมูลที่วางไว้บนตัวเร่งความเร็วหรืออุปกรณ์ระยะไกล

ในทางกลับกันออบเจ็กต์ tf.Tensor สามารถส่งผ่านไปยัง tf.experimental.numpy API ได้ อินพุตเหล่านี้จะถูกแปลงเป็นอาร์เรย์ ND ภายในโดยไม่ต้องทำสำเนาข้อมูล

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

ลำดับความสำคัญของตัวดำเนินการ

เมื่ออาร์เรย์ ND และวัตถุ tf.Tensor รวมกันโดยใช้ตัวดำเนินการกฎลำดับความสำคัญจะถูกใช้เพื่อกำหนดว่าวัตถุใดเรียกใช้ตัวดำเนินการ สิ่งนี้ถูกควบคุมโดยค่า __array_priority__ กำหนดโดยคลาสเหล่านี้

tf.Tensor กำหนด __array_priority__ สูงกว่าอาร์เรย์ ND ซึ่งหมายความว่าอินพุตอาร์เรย์ ND จะถูกแปลงเป็น tf.Tensor และตัว tf.Tensor รุ่น tf.Tensor

โค้ดด้านล่างแสดงให้เห็นว่ามีผลต่อประเภทเอาต์พุตอย่างไร

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

การไล่ระดับสีและจาโคเบียน: tf.GradientTape

GradientTape ของ TensorFlow สามารถใช้สำหรับ backpropagation ผ่านรหัส TensorFlow และ TensorFlow NumPy GradientTape API ยังสามารถส่งคืนเอาต์พุตอาร์เรย์ ND

ใช้โมเดลที่สร้างในส่วน โมเดลตัวอย่าง และคำนวณการไล่ระดับสีและจาโคเบียน

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)

การรวบรวมการติดตาม: tf.function

ฟังก์ชัน tf. ของ tf.function ทำงานโดย "การรวบรวมการติดตาม" โค้ดจากนั้นปรับแต่งการติดตามเหล่านี้เพื่อประสิทธิภาพที่เร็วขึ้นมาก ดูข้อมูล เบื้องต้นเกี่ยวกับกราฟและฟังก์ชัน

tf.function สามารถใช้เพื่อเพิ่มประสิทธิภาพโค้ด TensorFlow NumPy ได้เช่นกัน นี่คือตัวอย่างง่ายๆในการสาธิตการเร่งความเร็ว โปรดสังเกตว่าเนื้อความของโค้ด tf.function ประกอบด้วยการเรียกไปยัง TensorFlow NumPy APIs และอินพุตและเอาต์พุตเป็นอาร์เรย์ 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.330081999998356 ms

tf.function compiled performance
0.6170850999978938 ms

Vectorization: tf.vectorized_map

TensorFlow มีการสนับสนุนในตัวสำหรับ vectorizing ลูปคู่ขนานซึ่งช่วยให้เพิ่มความเร็วได้ตั้งแต่หนึ่งถึงสองคำสั่งขนาด การ tf.vectorized_map ความเร็วเหล่านี้สามารถเข้าถึงได้ผ่าน tf.vectorized_map API และนำไปใช้กับรหัส TensorFlow NumPy ด้วย

บางครั้งก็มีประโยชน์ในการคำนวณการไล่ระดับสีของแต่ละเอาต์พุตในแบตช์ wrt องค์ประกอบแบตช์อินพุตที่เกี่ยวข้อง การคำนวณดังกล่าวสามารถทำได้อย่างมีประสิทธิภาพโดยใช้ 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
    output = compute_gradients(model,
                               tnp.expand_dims(inp, 0),
                               tnp.expand_dims(label, 0))
    return output

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

print("Running vectorized computaton")
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=5) * 200, "ms")
Running vectorized computaton
0.629824799995049 ms

Running unvectorized computation
6.98705439999685 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')]
All physical devices: [PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU')]

การวางการดำเนินการ: 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.data.device)
Using device: /device:CPU:0
prediction is placed on /job:localhost/replica:0/task:0/device:CPU:0

การคัดลอกอาร์เรย์ ND ข้ามอุปกรณ์: tnp.copy

การโทรไปที่ tnp.copy ซึ่งอยู่ในขอบเขตอุปกรณ์บางอย่างจะคัดลอกข้อมูลไปยังอุปกรณ์นั้นเว้นแต่ข้อมูลจะอยู่ในอุปกรณ์นั้นแล้ว

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:CPU:0
/job:localhost/replica:0/task:0/device:CPU:0

การเปรียบเทียบประสิทธิภาพ

TensorFlow NumPy ใช้เคอร์เนล TensorFlow ที่ได้รับการปรับปรุงประสิทธิภาพสูงซึ่งสามารถจัดส่งบน CPU, GPU และ TPU ได้ TensorFlow ยังดำเนินการเพิ่มประสิทธิภาพคอมไพเลอร์หลายอย่างเช่นการดำเนินการฟิวชั่นซึ่งแปลเป็นการปรับปรุงประสิทธิภาพและหน่วยความจำ ดู การเพิ่มประสิทธิภาพกราฟ 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)

png