NumPy API บน TensorFlow

ดูบน 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 array

ตัวอย่างของ tf.experimental.numpy.ndarray ที่เรียกว่า ND Array แสดงถึงอาร์เรย์หนาแน่นหลายมิติของ 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 APIs มีความหมายที่ชัดเจนสำหรับการแปลงตัวอักษรเป็นอาร์เรย์ ND เช่นเดียวกับการดำเนินการส่งเสริมประเภทบนอินพุตอาร์เรย์ ND โปรดดู np.result_type สำหรับรายละเอียดเพิ่มเติม

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

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.int64 และ tnp.float64 ในทางตรงกันข้าม tf.convert_to_tensor ชอบประเภท tf.int32 และ tf.float32 สำหรับการแปลงค่าคงที่เป็น tf.Tensor TensorFlow NumPy APIs ยึดตามพฤติกรรม 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 ตามด้วยเส้นโครงเชิงเส้น ส่วนต่อมาจะแสดงวิธีคำนวณการไล่ระดับสีสำหรับโมเดลนี้โดยใช้ 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, มุมมองและ stride_tricks และ dtype บางส่วน (เช่น np.recarray และ np.object ) สำหรับรายละเอียดเพิ่มเติม โปรดดูเอกสารประกอบ TensorFlow NumPy API

การทำงานร่วมกันของ NumPy

อาร์เรย์ 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 จะตรวจสอบข้อกำหนดการจัดตำแหน่งและเรียกใช้สำเนาหากจำเป็น เมื่อส่งบัฟเฟอร์ CPU ND array ไปยัง NumPy โดยทั่วไปแล้วบัฟเฟอร์จะเป็นไปตามข้อกำหนดการจัดตำแหน่งและ NumPy จะไม่จำเป็นต้องสร้างสำเนา

อาร์เรย์ ND สามารถอ้างถึงบัฟเฟอร์ที่วางอยู่บนอุปกรณ์อื่นที่ไม่ใช่หน่วยความจำ CPU ในเครื่อง ในกรณีดังกล่าว การเรียกใช้ฟังก์ชัน NumPy จะทริกเกอร์การคัดลอกผ่านเครือข่ายหรืออุปกรณ์ตามความจำเป็น

จากสิ่งนี้ การผสมผสานกับการเรียก NumPy API ควรทำด้วยความระมัดระวัง และผู้ใช้ควรระวังโอเวอร์เฮดในการคัดลอกข้อมูล การโทรระหว่าง TensorFlow NumPy กับการโทร TensorFlow โดยทั่วไปจะปลอดภัยและหลีกเลี่ยงการคัดลอกข้อมูล ดูหัวข้อความสามารถในการทำงานร่วมกันของ TensorFlow สำหรับรายละเอียดเพิ่มเติม

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

TensorFlow NumPy กำหนด __array_priority__ ที่สูงกว่าของ NumPy ซึ่งหมายความว่าสำหรับโอเปอเรเตอร์ที่เกี่ยวข้องกับทั้ง ND array และ 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 array เป็นนามแฝงของ 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 สามารถส่งผ่านไปยัง TensorFlow API ได้ เนื่องจากอาร์เรย์ ND เป็นเพียงนามแฝงสำหรับ tf.Tensor ดังที่ได้กล่าวไว้ก่อนหน้านี้ การทำงานร่วมกันดังกล่าวจะไม่ทำสำเนาข้อมูล แม้แต่ข้อมูลที่วางอยู่บนคันเร่งหรืออุปกรณ์ระยะไกล

ในทางกลับกัน ออบเจ็กต์ tf.Tensor สามารถส่งผ่านไปยัง API tf.experimental.numpy ได้โดยไม่ต้องทำการคัดลอกข้อมูล

# 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

GradientTape ของ TensorFlow สามารถใช้สำหรับการขยายพันธุ์ย้อนหลังผ่านโค้ด 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

tf.function ของ 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 มีการสนับสนุนในตัวสำหรับการสร้างเวคเตอร์ลูปคู่ขนาน ซึ่งช่วยให้เร่งความเร็วได้ตั้งแต่หนึ่งถึงสองลำดับความสำคัญ การเร่งความเร็วเหล่านี้สามารถเข้าถึงได้ผ่านทาง 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
    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
ตัวยึดตำแหน่ง42

การคัดลอกอาร์เรย์ 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 ยังทำการเพิ่มประสิทธิภาพคอมไพเลอร์หลายอย่าง เช่น การผสานการทำงาน ซึ่งแปลเป็นการปรับปรุงประสิทธิภาพและหน่วยความจำ ดู การเพิ่มประสิทธิภาพกราฟ 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)
ตัวยึดตำแหน่ง46

png

อ่านเพิ่มเติม