计算机视觉中的十万个[为]什么(1)

什么是CUDA?

释义

CUDA是NVIDIA的一个框架,用于使用gpu(图形处理单元)进行通用操作。通常,这些都是我们在3D图形中使用的线性代数运算,但你也可以将它们用于机器学习等事情。所以你把这些gpu——传统上是用于游戏的——用于高性能计算。
在这里插入图片描述

在使用CUDA时,你遇到过什么痛点吗?

是的,这是一个非常新的领域,它发展得非常迅速,有一大堆不同的CUDA版本,它们不一定能很好地相互兼容。所以你需要注意模型所使用的CUDA版本。也许你可以创建一个像Docker这样的东西,把所有东西都预先打包好。当你使用这些不同的机器学习框架时,ONNX是用来转换你的模型的一个很好的中介。

什么是cuDNN?

NVIDIA CUDA Deep Neural Network (cuDNN)是一个使用CUDA构建的深度神经网络库。它为深度神经网络的常见操作提供GPU加速功能。你可以自己直接使用它,但是像TensorFlow这样的库已经在cuDNN的支持下构建了抽象。

什么是ONNX?

释义

ONNX是一个中间机器学习框架,用于不同机器学习框架之间的转换。假设你想将TensorFlow训练的模型转换到TensorRT,或者你想将PyTorch训练的模型得到TFLite,或者其他机器学习框架。

在使用ONNX时,你遇到过什么陷阱吗?

是的。当使用ONNX(一个开源工具)构建时,他们正在构建新的功能。他们试图追踪机器学习领域的所有新研究,但这些版本可能会落后。有一个版本的TensorFlow与ONNX的一个版本不兼容,你必须升级和降级这些版本才可能成功。

什么是OpenVINO?

释义

OpenVINO是Intel发布的一个机器学习框架,允许你在他们的硬件上运行机器学习模型。Intel最流行的硬件部署选项之一是VPU,即视觉处理单元,您需要能够将您的模型转换为OpenVINO,以便利用(由VPU提供的)优化处理。

是否有一种简单的方法将模型导入OpenVINO?

当然可以。Luxonis OpenCV AI Kit (OAK)就是Intel本地硬件部署选项中的一个例子。

什么是CoreML?

CoreML是苹果用于设备推理的机器学习框架。当您进行设备推理时,您需要特别考虑创建一个小的、低延迟的、低功耗的模型。CoreML允许您轻松地将一个模型文件——在苹果生态系统中称为.mlmodel文件——部署到iphone和苹果设备上。模型格式经过苹果的神经网络引擎优化,使模型运行更快,功耗更低。
你可以使用CreateML之类的工具创建一个CoreML模型。你也可以从TensorFlow导入.h5文件,或者从Python导入.pt文件。基本上,CoreML是一种在苹果的设备运行机器学习模型的简单方法。

什么是Tensorflow?

TensorFlow 是一个Google开源的端到端机器学习平台。它拥有一个全面而灵活的生态系统,其中包含各种工具、库和社区资源,可助力研究人员推动先进机器学习技术的发展,并使开发者能够轻松地构建和部署由机器学习提供支持的应用。

什么是Tensorflow Lite?

释义

TensorFlow Lite 是一组工具,可帮助开发者在移动设备、嵌入式设备和 IoT 设备上运行 TensorFlow 模型。它支持设备端机器学习推断,延迟较低,并且二进制文件很小。
TensorFlow Lite 包括两个主要组件:

  • TensorFlow Lite 解释器,它可在手机、嵌入式 Linux 设备和微控制器等很多不同类型的硬件上运行经过专门优化的模型。
  • TensorFlow Lite 转换器,它可将 TensorFlow 模型转换为方便解释器使用的格式,并可引入优化以减小二进制文件的大小和提高性能。

开发工作流程

使用 TensorFlow Lite 的工作流包括如下步骤:

  • 选择模型
    您可以使用自己的 TensorFlow 模型、在线查找模型,或者从我们的预训练模型中选择一个模型直接使用或重新训练。

  • 转换模型
    如果您使用的是自定义模型,请使用 TensorFlow Lite 转换器将模型转换为 TensorFlow Lite 格式,只需几行 Python 代码就能搞定。

  • 部署到您的设备
    请使用 TensorFlow Lite 解释器(提供多种语言的 API)在设备端运行您的模型。

  • 优化您的模型
    请使用我们的模型优化工具包缩减模型的大小并提高其效率,同时最大限度地降低对准确率的影响。

什么是JAX深度学习框架?

您可能听说过TensorFlow和PyTorch,甚至可能听说过MXNet——但在机器学习框架领域出现了一个新成员——谷歌的JAX。
在过去的两年中,JAX一直在深入学习研究,促进谷歌的Vision Transformer (ViT)的实现,并为DeepMind的研究提供动力。

释义

简而言之,JAX是在python的numpy基础上添加自动差分以及在GPU上优化运行等功能。编写numpy和编写JAX之间的无缝转换使得JAX在机器学习从业者中流行起来。
JAX提供了四种主要的函数转换,使其在执行深度学习工作时能够高效使用。

JAX四种主要的函数转换

  • grad : 自动差分,你可以取任意阶导数。
from jax import grad
import jax.numpy as jnp

def tanh(x):  # Define a function
  y = jnp.exp(-2.0 * x)
  return (1.0 - y) / (1.0 + y)

grad_tanh = grad(tanh)  # Obtain its gradient function
print(grad_tanh(1.0))   # Evaluate it at x = 1.0
# prints 0.4199743
  • jit : 自动优化您的函数,以高效的运行他们的操作。也可以用作函数装饰器。
import jax.numpy as jnp
from jax import jit

def slow_f(x):
  # Element-wise ops see a large benefit from fusion
  return x * x + x * 2.0

x = jnp.ones((5000, 5000))
fast_f = jit(slow_f)
%timeit -n10 -r3 fast_f(x)  # ~ 4.5 ms / loop on Titan X
%timeit -n10 -r3 slow_f(x)  # ~ 14.5 ms / loop (also on GPU via JAX)
  • vmap:跨维度映射函数。例如,这意味着在传递批处理时,您不必像以前那样仔细地跟踪维度。
predictions = vmap(predict, in_axes=(None, 0))(params, input_batch)
  • pmap:多GPU处理
from jax import random, pmap
import jax.numpy as jnp

# Create 8 random 5000 x 6000 matrices, one per GPU
keys = random.split(random.PRNGKey(0), 8)
mats = pmap(lambda key: random.normal(key, (5000, 6000)))(keys)

# Run a local matmul on each device in parallel (no data transfer)
result = pmap(lambda x: jnp.dot(x, x.T))(mats)  # result.shape is (8, 5000, 5000)

# Compute the mean on each device in parallel and print the result
print(pmap(jnp.mean)(result))
# prints [1.1566595 1.1805978 ... 1.2321935 1.2015157]

JAX与常用深度学习框架比较

  • JAX vs PyTorch
    与JAX最近的机器学习框架是PyTorch。这是因为它们都有一个共同的根源,那就是努力尽可能地变得很"numpy"。
    JAX的功能和较底层的函数定义使得它更适合于某些研究任务。
    也就是说,PyTorch提供了更广泛的库和实用程序、预先训练和预先编写的网络定义、数据加载器以及到部署端的可移植性。
  • JAX vs TensorFlow
    JAX和TensorFlow都是谷歌编写的。从实践中来看,JAX似乎更容易开发,而且更直观。
    也就是说,JAX缺乏TensorFlow多年来构建的广泛基础设施——无论是开源项目、预先训练的模型、教程、更高级别的抽象(通过Keras),还是到部署端的可移植性。

JAX的缺点

  • 一个数据加载器——你需要实现你自己的数据加载器或使用TensorFlow或PyTorch的数据加载器
  • 更高级别的模型抽象
  • 部署的可移植性

什么时候应该使用JAX

JAX是一种新的机器学习框架,在机器学习研究中越来越受欢迎。如果您是在研究领域进行操作,那么JAX是您的项目的一个很好的选择。
如果您正在开发应用程序,PyTorch和TensorFlow框架将以更快的速度推动您的计划。

什么是PyTorch

PyTorch是一个开源的机器学习库,专门用于张量计算、自动差分和GPU加速。基于这些原因,PyTorch是最受欢迎的深度学习库之一,与Keras和TensorFlow竞争“最常用”的深度学习软件包。
PyTorch由于其pythonic特性和易于扩展(例如,实现自定义层类型、网络架构等),在研究界尤其受欢迎。

PyTorch比TensorFlow和Keras更好吗?

这是一个错误的问题,特别是如果你是深度学习的新手。没有谁比谁好。Keras和TensorFlow有特定的用途,就像PyTorch一样。

例如,您不能笼统地说Java肯定比Python更好。当使用机器学习和数据科学时,Python比Java更有说服力。但是,如果您打算开发在多个高可靠性体系结构上运行的企业应用程序,那么Java可能是更好的选择。

一般遵循以下规律:

  • 如果你正在做研究,你绝对应该使用PyTorch
  • 如果你是初学者,你应该使用Keras
  • 如果您正在开发一个行业应用程序,请使用TensorFlow和Keras

什么是TensorRT?

TensorRT是用于生产部署的高性能神经网络推理优化器和运行时引擎。TensorRT通过组合层和优化内核选择来优化网络,以提高延迟、吞吐量、功率效率和内存消耗。

TensorRT是由NVIDIA开发的一个库,用于在NVIDIA图形处理单元(gpu)上进行更快的推理。TensorRT基于NVIDIA的并行编程模型CUDA。对于许多实时服务和嵌入式应用程序,它可以提供大约4到5倍的推理速度。然而,根据文档,它确实提供了比CPU快40倍的推理速度。

在本文中,我们将研究两件事。首先,TRT如何对深度学习模型进行优化?其次,如何使用TensorFlow-TensorRT模块优化深度学习模型。

TensorRT如何进行优化?

TensorRT执行五种类型的优化,以增加深度学习模型的吞吐量。在本文中,我们将讨论所有五种类型的优化。
TensorRT为优化模型而执行的优化类型。
(1)权重和激活精度校准
不同精度的动态范围
在训练过程中,参数和激活均为FP32(float32)精度。将它们转换成FP16或INT8精度。这种优化不仅减少了延迟,而且大大减少了模型大小,因为FP32的精度会被转换成FP16或INT8。

现在,在转换到FP16(精度较低)时,由于FP16的动态范围低于FP32,我们的一些权值会因为溢出而缩小。但从实验上看,这并不会显著影响精度。

但是,我们如何证明这一点呢?我们知道FP32是高精度的。一般来说,权值和激活值对噪声具有弹性。在训练时,模型试图保留推理所需的特征。所以,扔掉不必要的东西是一种内在的过程。因此,当我们在低精度转换模型时,我们假设模型排除了噪声。

这种裁剪溢出权重的技术在转换为INT8精度时不起作用。因为INT8的值很小,从[-127到+127],我们的大部分权重会在较低的精度下被修改和溢出,导致我们的模型的精度显著下降。所以我们要做的是,我们在INT8精度中使用缩放和偏差项映射这些权重。

a) 如何找到一个缩放因子和偏差项?
偏差项不会增加价值,所以我们将关注缩放因子。为了得到缩放因子,我们直接将FP32值中的-|max|和|max|映射到INT8 -127和127值。其他值根据线性比例相应地分配。如图3的左图所示。
INT8校准
这也会导致准确度的显著下降。现在,不是从|max|值。我们所做的是,我们将阈值范围映射到-127或127,而阈值的所有其他异常值映射到极值范围,即-127或127。如图3的右图所示。

b) 如何得到阈值的最优值?
因此,为了在INT8中表示FP32分布,TensorRT使用KL-divergence来度量差异并使之最小化。TensorRT使用迭代搜索代替基于梯度下降的优化来寻找阈值。KL-divergence的伪代码步骤如下。你可以在这里详细阅读。

1) 在校准数据集上运行FP32推理。
2) For 每层:
    ~ 收集激活直方图
    ~ 生成许多不同饱和阈值的量化分布。
    ~选择最小化KL_divergence的阈值。

c) 校准数据
校准数据是一组有代表性的数据集,它给出激活值的直方图,用于寻找最小kl-divergence的阈值。这个过程称为校准,数据集称为校准数据集。
(2)层和张量融合
当使用任何深度学习框架执行一个图时,都需要例行地执行类似的计算。因此,为了克服这个问题,TensorRT使用层和张量融合来优化GPU内存和带宽,通过垂直或水平(或两者都)融合内核中的节点,这减少了开销和读写每一层张量数据的成本。下面是一个简单的类比,我们不是在三次旅行中从市场购买三种物品,而是在一次旅行中购买所有三种物品。
在这里插入图片描述
TensorRT在GoogLeNet Inception模块图上的垂直和水平层融合,减少了计算和内存开销。

如上所示,TensorRT识别出所有输入和filter大小相似但权重不同的层,并将它们组合成单个1x1 CBR层,如图4右侧所示。

(3)Kernel auto-tuning
在优化模型的过程中,可以执行一些特定于内核的优化。它根据目标GPU平台选择最佳层、算法和最佳批处理大小。例如,执行卷积运算的方法有多种,但在选定的平台上,TRT会自动选择哪一种方法是最优的。

(4)动态张量内存
TensorRT通过只在张量使用期间将内存分配给它来提高内存重用。它有助于减少内存占用,避免分配开销,以便快速有效地执行。
(5)Multiple Stream Execution
TensorRT被设计用于并行处理多个输入流。这基本上是英伟达的CUDA流。

使用Tensorflow-TensorRT (TF-TRT) API

现在我们已经看到了这个过程,TRT如何优化模型以更快的推断和更低的延迟。接下来,我们将研究Tensorflow-TRT API,以优化我们的深度学习模型,以更快地进行推理。
(1)安装TensorRT环境
在终端上执行下面的命令,在64位Ubuntu 18.04和TensorFlow≥2.0上安装TensorRT。当我们想使用NVIDIA GPU优化时候, 我们需要安装NVIDIA机器学习包,libnvinfer5和TensorFlow-GPU。

pip install tensorflow-gpu==2.0.0
wget https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb
dpkg -i nvidia-machine-learning-repo-*.deb
apt-get update
sudo apt-get install libnvinfer5

如果你不确定你的系统上是否存在Tensor-core GPU。您可以使用以下命令检查它。

from tensorflow.python.client import device_lib

def check_tensor_core_gpu_present():
    local_device_protos = device_lib.list_local_devices()
    for line in local_device_protos:
        if "compute capability" in str(line):
            compute_capability = float(line.physical_device_desc.split("compute capability: ")[-1])
            if compute_capability>=7.0:
                return True
    
print("Tensor Core GPU Present:", check_tensor_core_gpu_present())
tensor_core_gpu = check_tensor_core_gpu_present()

首先,我们导入trt_converter和一个预训练resnet50模型,需要在这个模型上执行优化。如果我们想要我们的模型在FP16或FP32精度中得到优化,那么我们可以在转换参数中更改precision_mode参数。此外,我们可以设置max_workspace_size_bytes参数,该参数表示系统上的最大RAM容量。

from tensorflow.python.compiler.tensorrt import trt_convert as trt
from tensorflow.keras.applications.resnet50 import ResNet50

model = ResNet50(weights='imagenet')

print('Converting to TF-TRT FP32...')
conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace(precision_mode=trt.TrtPrecisionMode.FP32, max_workspace_size_bytes=8000000000)

converter = trt.TrtGraphConverterV2(input_saved_model_dir='resnet50_saved_model',
                                    conversion_params=conversion_params)
converter.convert()
converter.save(output_saved_model_dir='resnet50_saved_model_TFTRT_FP32')
print('Done Converting to TF-TRT FP32')

但是,将精度转换为INT8,我们还需要校准数据,就像在文章开头中描述的那样,我们可以在调用转换函数时传递这个校准输入数据。代码片段如下所示。

batch_size = 8
batched_input = np.zeros((batch_size, 224, 224, 3), dtype=np.float32)

for i in range(batch_size):
  img_path = './data/img%d.JPG' % (i % 4)
  img = image.load_img(img_path, target_size=(224, 224))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)
  x = preprocess_input(x)
  batched_input[i, :] = x
batched_input = tf.constant(batched_input)
print('batched_input shape: ', batched_input.shape)

print('Converting to TF-TRT INT8...')
conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace(
    precision_mode=trt.TrtPrecisionMode.INT8, 
    max_workspace_size_bytes=8000000000, 
    use_calibration=True)
converter = trt.TrtGraphConverterV2(
    input_saved_model_dir='resnet50_saved_model', 
    conversion_params=conversion_params)

def calibration_input_fn():
    yield (batched_input, )
converter.convert(calibration_input_fn=calibration_input_fn)

converter.save(output_saved_model_dir='resnet50_saved_model_TFTRT_INT8')
print('Done Converting to TF-TRT INT8')

以上实现是针对TensorFlow版本≥2.0完成的。而如果你想在TensorFlow1.x上执行优化,你可以使用TrtGraphConverterV1而不是TrtGraphConverterV2。

结束语

本文的所有内容,包括图片都摘自NVIDIA TensorRT的官方文档和网站。

什么是PaddlePaddle?

PaddlePaddle (PArallel Distributed Deep LEarning)是一个易于使用、高效、灵活、可扩展的深度学习平台,最初由百度的科学家和工程师开发,专注于大规模生产部署。PaddlePaddle社区规模相对较小。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值