ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

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 อาร์เรย์หมายถึงอาร์เรย์หลายมิติที่มีความหนาแน่นของการให้ 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 สำหรับรายละเอียดเพิ่มเติม

APIs TensorFlow ออก tf.Tensor ปัจจัยการผลิตไม่เปลี่ยนแปลงและไม่ได้ดำเนินการส่งเสริมการขายประเภทที่พวกเขาในขณะที่ APIs TensorFlow NumPy ส่งเสริมปัจจัยการผลิตทั้งหมดตามกฎ 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 ตามด้วยเส้นโครงเชิงเส้น ต่อมาส่วนจะแสดงวิธีการคำนวณการไล่ระดับสีสำหรับรุ่นนี้ใช้ 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 บูรณาการ Swig การสั่งซื้อการจัดเก็บ Fortran มุมมองและ stride_tricks และบาง dtype s (เช่น 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 และ 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 อาร์เรย์สามารถส่งผ่านไป TensorFlow APIs ตั้งแต่ ND อาร์เรย์เป็นเพียงนามแฝงไปยัง tf.Tensor ดังที่ได้กล่าวไว้ก่อนหน้านี้ การทำงานร่วมกันดังกล่าวจะไม่ทำสำเนาข้อมูล แม้แต่ข้อมูลที่วางอยู่บนคันเร่งหรืออุปกรณ์ระยะไกล

ตรงกันข้าม tf.Tensor วัตถุสามารถส่งผ่านไป tf.experimental.numpy APIs โดยไม่ต้องดำเนินการคัดลอกข้อมูล

# 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

ใช้รูปแบบที่สร้างขึ้นใน ตัวอย่างรุ่น ส่วนและคำนวณการไล่ระดับสีและ jacobians

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 APIs

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

คัดลอกอาร์เรย์ 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)

png

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