0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

TensorRT創(chuàng)建層時(shí)序緩存以保存層分析信息

星星科技指導(dǎo)員 ? 來源:NVIDIA ? 作者:Ken He ? 2022-05-13 16:14 ? 次閱讀

6.1. The Timing Cache

為了減少構(gòu)建器時(shí)間,TensorRT 創(chuàng)建了一個(gè)層時(shí)序緩存,以在構(gòu)建器階段保存層分析信息。它包含的信息特定于目標(biāo)構(gòu)建器設(shè)備、CUDA 和 TensorRT 版本,以及可以更改層實(shí)現(xiàn)的BuilderConfig參數(shù),例如BuilderFlag::kTF32或BuilderFlag::kREFIT。

如果有其他層具有相同的輸入/輸出張量配置和層參數(shù),則 TensorRT 構(gòu)建器會(huì)跳過分析并重用重復(fù)層的緩存結(jié)果。如果緩存中的計(jì)時(shí)查詢未命中,則構(gòu)建器會(huì)對(duì)該層計(jì)時(shí)并更新緩存。

時(shí)序緩存可以被序列化和反序列化。您可以通過IBuilderConfig::createTimingCache從緩沖區(qū)加載序列化緩存:

ITimingCache* cache = 
 config->createTimingCache(cacheFile.data(), cacheFile.size());

將緩沖區(qū)大小設(shè)置為0會(huì)創(chuàng)建一個(gè)新的空時(shí)序緩存。

然后,在構(gòu)建之前將緩存附加到構(gòu)建器配置。

config->setTimingCache(*cache, false);

在構(gòu)建期間,由于緩存未命中,時(shí)序緩存可以增加更多信息。在構(gòu)建之后,它可以被序列化以與另一個(gè)構(gòu)建器一起使用。

IHostMemory* serializedCache = cache->serialize();

如果構(gòu)建器沒有附加時(shí)間緩存,構(gòu)建器會(huì)創(chuàng)建自己的臨時(shí)本地緩存并在完成時(shí)將其銷毀。

緩存與算法選擇不兼容(請(qǐng)參閱算法選擇和可重現(xiàn)構(gòu)建部分)??梢酝ㄟ^設(shè)置BuilderFlag來禁用它。

6.2. Refitting An Engine

TensorRT 可以用新的權(quán)重改裝引擎而無需重建它,但是,在構(gòu)建時(shí)必須指定這樣做的選項(xiàng):

...
config->setFlag(BuilderFlag::kREFIT) 
builder->buildSerializedNetwork(network, config);

稍后,您可以創(chuàng)建一個(gè)Refitter對(duì)象:

ICudaEngine* engine = ...;
IRefitter* refitter = createInferRefitter(*engine,gLogger)

然后更新權(quán)重。例如,要更新名為“MyLayer”的卷積層的內(nèi)核權(quán)重:

Weights newWeights = ...;
refitter->setWeights("MyLayer",WeightsRole::kKERNEL,
                    newWeights);

新的權(quán)重應(yīng)該與用于構(gòu)建引擎的原始權(quán)重具有相同的計(jì)數(shù)。如果出現(xiàn)問題,例如錯(cuò)誤的層名稱或角色或權(quán)重計(jì)數(shù)發(fā)生變化,setWeights返回false。

由于引擎優(yōu)化的方式,如果您更改一些權(quán)重,您可能還必須提供一些其他權(quán)重。該界面可以告訴您需要提供哪些額外的權(quán)重。

您可以使用INetworkDefinition::setWeightsName()在構(gòu)建時(shí)命名權(quán)重 – ONNX 解析器使用此 API 將權(quán)重與 ONNX 模型中使用的名稱相關(guān)聯(lián)。然后,您可以使用setNamedWeights更新權(quán)重:

Weights newWeights = ...;
refitter->setNamedWeights("MyWeights", newWeights);

setNamedWeightssetWeights可以同時(shí)使用,即,您可以通過setNamedWeights更新具有名稱的權(quán)重,并通過setWeights更新那些未命名的權(quán)重。

這通常需要兩次調(diào)用IRefitter::getMissing,首先獲取必須提供的權(quán)重對(duì)象的數(shù)量,然后獲取它們的層和角色。

const int32_t n = refitter->getMissing(0, nullptr, nullptr);
std::vector layerNames(n);
std::vector weightsRoles(n);
refitter->getMissing(n, layerNames.data(), 
                        weightsRoles.data());

或者,要獲取所有缺失權(quán)重的名稱,請(qǐng)運(yùn)行:

const int32_t n = refitter->getMissingWeights(0, nullptr);
std::vector weightsNames(n);
refitter->getMissingWeights(n, weightsNames.data());

您可以按任何順序提供缺失的權(quán)重:

for (int32_t i = 0; i < n; ++i)
    refitter->setWeights(layerNames[i], weightsRoles[i],
                         Weights{...});

返回的缺失權(quán)重集是完整的,從某種意義上說,僅提供缺失的權(quán)重不會(huì)產(chǎn)生對(duì)任何更多權(quán)重的需求。

提供所有權(quán)重后,您可以更新引擎:

bool success = refitter->refitCudaEngine();
assert(success);

如果refit返回false,請(qǐng)檢查日志以獲取診斷信息,可能是關(guān)于仍然丟失的權(quán)重。 然后,您可以刪除refitter

delete refitter;

更新后的引擎的行為就像它是從使用新權(quán)重更新的網(wǎng)絡(luò)構(gòu)建的一樣。

要查看引擎中的所有可改裝權(quán)重,請(qǐng)使用refitter->getAll(...)refitter->getAllWeights(...);類似于上面使用getMissinggetMissingWeights的方式。

6.3. Algorithm Selection and Reproducible Builds

TensorRT 優(yōu)化器的默認(rèn)行為是選擇全局最小化引擎執(zhí)行時(shí)間的算法。它通過定時(shí)每個(gè)實(shí)現(xiàn)來做到這一點(diǎn),有時(shí),當(dāng)實(shí)現(xiàn)具有相似的時(shí)間時(shí),系統(tǒng)噪聲可能會(huì)決定在構(gòu)建器的任何特定運(yùn)行中將選擇哪個(gè)。不同的實(shí)現(xiàn)通常會(huì)使用不同的浮點(diǎn)值累加順序,兩種實(shí)現(xiàn)可能使用不同的算法,甚至以不同的精度運(yùn)行。因此,構(gòu)建器的不同調(diào)用通常不會(huì)導(dǎo)致引擎返回位相同的結(jié)果。

有時(shí),確定性構(gòu)建或重新創(chuàng)建早期構(gòu)建的算法選擇很重要。通過提供IAlgorithmSelector接口的實(shí)現(xiàn)并使用setAlgorithmSelector將其附加到構(gòu)建器配置,您可以手動(dòng)指導(dǎo)算法選擇。

方法IAlgorithmSelector::selectAlgorithms接收一個(gè)AlgorithmContext,其中包含有關(guān)層算法要求的信息,以及一組滿足這些要求的算法選擇。它返回 TensorRT 應(yīng)該為層考慮的算法集。

構(gòu)建器將從這些算法中選擇一種可以最小化網(wǎng)絡(luò)全局運(yùn)行時(shí)間的算法。如果未返回任何選項(xiàng)并且BuilderFlag::kREJECT_EMPTY_ALGORITHMS未設(shè)置,則 TensorRT 將其解釋為意味著任何算法都可以用于該層。要覆蓋此行為并在返回空列表時(shí)生成錯(cuò)誤,請(qǐng)?jiān)O(shè)置BuilderFlag::kREJECT_EMPTY_ALGORITHMSS標(biāo)志。

在 TensorRT 完成對(duì)給定配置文件的網(wǎng)絡(luò)優(yōu)化后,它會(huì)調(diào)用reportAlgorithms,它可用于記錄為每一層做出的最終選擇。

selectAlgorithms返回一個(gè)選項(xiàng)。要重播早期構(gòu)建中的選擇,請(qǐng)使用reportAlgorithms記錄該構(gòu)建中的選擇,并在selectAlgorithms中返回它們。

sampleAlgorithmSelector演示了如何使用算法選擇器在構(gòu)建器中實(shí)現(xiàn)確定性和可重復(fù)性。

注意:

  • 算法選擇中的“層”概念與INetworkDefinition中的ILayer不同。由于融合優(yōu)化,前者中的“層”可以等同于多個(gè)網(wǎng)絡(luò)層的集合。
  • selectAlgorithms中選擇最快的算法可能不會(huì)為整個(gè)網(wǎng)絡(luò)產(chǎn)生最佳性能,因?yàn)樗赡軙?huì)增加重新格式化的開銷。
  • 如果 TensorRT 發(fā)現(xiàn)該層是空操作,則IAlgorithm的時(shí)間在selectAlgorithms中為0 。
  • reportAlgorithms不提供提供給selectAlgorithmsIAlgorithm的時(shí)間和工作空間信息。

6.4. Creating A Network Definition From Scratch

除了使用解析器,您還可以通過網(wǎng)絡(luò)定義 API 將網(wǎng)絡(luò)直接定義到 TensorRT。此場(chǎng)景假設(shè)每層權(quán)重已在主機(jī)內(nèi)存中準(zhǔn)備好在網(wǎng)絡(luò)創(chuàng)建期間傳遞給 TensorRT。

以下示例創(chuàng)建了一個(gè)簡單的網(wǎng)絡(luò),其中包含InputConvolution、PoolingMatrixMultiply、Shuffle、ActivationSoftmax層。

6.4.1. C++

本節(jié)對(duì)應(yīng)的代碼可以在sampleMNISTAPI中找到。在此示例中,權(quán)重被加載到以下代碼中使用的weightMap數(shù)據(jù)結(jié)構(gòu)中。

首先創(chuàng)建構(gòu)建器和網(wǎng)絡(luò)對(duì)象。請(qǐng)注意,在以下示例中,記錄器通過所有 C++ 示例通用的logger.cpp文件進(jìn)行初始化。 C++ 示例幫助程序類和函數(shù)可以在common.h頭文件中找到。

    auto builder = SampleUniquePtr(nvinfer1::createInferBuilder(sample::gLogger.getTRTLogger()));
    const auto explicitBatchFlag = 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
    auto network = SampleUniquePtr(builder->createNetworkV2(explicitBatchFlag));

kEXPLICIT_BATCH標(biāo)志的更多信息,請(qǐng)參閱顯式與隱式批處理部分。

通過指定輸入張量的名稱、數(shù)據(jù)類型和完整維度,將輸入層添加到網(wǎng)絡(luò)。一個(gè)網(wǎng)絡(luò)可以有多個(gè)輸入,盡管在這個(gè)示例中只有一個(gè):

auto data = network->addInput(INPUT_BLOB_NAME, datatype, Dims4{1, 1, INPUT_H, INPUT_W});

添加帶有隱藏層輸入節(jié)點(diǎn)、步幅和權(quán)重的卷積層,用于過濾器和偏差。

auto conv1 = network->addConvolution(
*data->getOutput(0), 20, DimsHW{5, 5}, weightMap["conv1filter"], weightMap["conv1bias"]);
conv1->setStride(DimsHW{1, 1});

注意:傳遞給 TensorRT 層的權(quán)重在主機(jī)內(nèi)存中。

添加池化層;請(qǐng)注意,前一層的輸出作為輸入傳遞。

auto pool1 = network->addPooling(*conv1->getOutput(0), PoolingType::kMAX, DimsHW{2, 2});
pool1->setStride(DimsHW{2, 2});

添加一個(gè) Shuffle 層來重塑輸入,為矩陣乘法做準(zhǔn)備:

int32_t const batch = input->getDimensions().d[0];
int32_t const mmInputs = input.getDimensions().d[1] * input.getDimensions().d[2] * input.getDimensions().d[3]; 
auto inputReshape = network->addShuffle(*input);
inputReshape->setReshapeDimensions(Dims{2, {batch, mmInputs}});

現(xiàn)在,添加一個(gè)MatrixMultiply層。在這里,模型導(dǎo)出器提供了轉(zhuǎn)置權(quán)重,因此為這些權(quán)重指定了kTRANSPOSE選項(xiàng)。

IConstantLayer* filterConst = network->addConstant(Dims{2, {nbOutputs, mmInputs}}, mWeightMap["ip1filter"]);
auto mm = network->addMatrixMultiply(*inputReshape->getOutput(0), MatrixOperation::kNONE, *filterConst->getOutput(0), MatrixOperation::kTRANSPOSE);

添加偏差,它將在批次維度上廣播。

auto biasConst = network->addConstant(Dims{2, {1, nbOutputs}}, mWeightMap["ip1bias"]);
auto biasAdd = network->addElementWise(*mm->getOutput(0), *biasConst->getOutput(0), ElementWiseOperation::kSUM);

添加 ReLU 激活層:

auto relu1 = network->addActivation(*ip1->getOutput(0), ActivationType::kRELU);

添加 SoftMax 層以計(jì)算最終概率:

auto prob = network->addSoftMax(*relu1->getOutput(0));

為 SoftMax 層的輸出添加一個(gè)名稱,以便在推理時(shí)可以將張量綁定到內(nèi)存緩沖區(qū):

prob->getOutput(0)->setName(OUTPUT_BLOB_NAME);

將其標(biāo)記為整個(gè)網(wǎng)絡(luò)的輸出:

network->markOutput(*prob->getOutput(0));

代表 MNIST 模型的網(wǎng)絡(luò)現(xiàn)已完全構(gòu)建。請(qǐng)參閱構(gòu)建引擎反序列化文件部分,了解如何構(gòu)建引擎并使用此網(wǎng)絡(luò)運(yùn)行推理。

6.4.2. Python

此部分對(duì)應(yīng)的代碼可以在network_api_pytorch_mnist中找到。

這個(gè)例子使用一個(gè)幫助類來保存一些關(guān)于模型的元數(shù)據(jù):

class ModelData(object):
    INPUT_NAME = "data"
    INPUT_SHAPE = (1, 1, 28, 28)
    OUTPUT_NAME = "prob"
    OUTPUT_SIZE = 10
    DTYPE = trt.float32

在此示例中,權(quán)重是從 Pytorch MNIST 模型導(dǎo)入的。

weights = mnist_model.get_weights()

創(chuàng)建記錄器、構(gòu)建器和網(wǎng)絡(luò)類。

TRT_LOGGER = trt.Logger(trt.Logger.ERROR)
builder = trt.Builder(TRT_LOGGER)
EXPLICIT_BATCH = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
network = builder.create_network(common.EXPLICIT_BATCH)

kEXPLICIT_BATCH標(biāo)志的更多信息,請(qǐng)參閱顯式與隱式批處理部分。

接下來,為網(wǎng)絡(luò)創(chuàng)建輸入張量,指定張量的名稱、數(shù)據(jù)類型和形狀。

input_tensor = network.add_input(name=ModelData.INPUT_NAME, dtype=ModelData.DTYPE, shape=ModelData.INPUT_SHAPE)

添加一個(gè)卷積層,指定輸入、輸出圖的數(shù)量、內(nèi)核形狀、權(quán)重、偏差和步幅:

conv1_w = weights['conv1.weight'].numpy()
    conv1_b = weights['conv1.bias'].numpy()
    conv1 = network.add_convolution(input=input_tensor, num_output_maps=20, kernel_shape=(5, 5), kernel=conv1_w, bias=conv1_b)
    conv1.stride = (1, 1)

添加一個(gè)池化層,指定輸入(前一個(gè)卷積層的輸出)、池化類型、窗口大小和步幅:

pool1 = network.add_pooling(input=conv1.get_output(0), type=trt.PoolingType.MAX, window_size=(2, 2))
    pool1.stride = (2, 2)

添加下一對(duì)卷積和池化層:

    conv2_w = weights['conv2.weight'].numpy()
    conv2_b = weights['conv2.bias'].numpy()
    conv2 = network.add_convolution(pool1.get_output(0), 50, (5, 5), conv2_w, conv2_b)
    conv2.stride = (1, 1)

    pool2 = network.add_pooling(conv2.get_output(0), trt.PoolingType.MAX, (2, 2))
    pool2.stride = (2, 2)

添加一個(gè) Shuffle 層來重塑輸入,為矩陣乘法做準(zhǔn)備:

batch = input.shape[0]
mm_inputs = np.prod(input.shape[1:])
input_reshape = net.add_shuffle(input)
input_reshape.reshape_dims = trt.Dims2(batch, mm_inputs)

現(xiàn)在,添加一個(gè)MatrixMultiply層。在這里,模型導(dǎo)出器提供了轉(zhuǎn)置權(quán)重,因此為這些權(quán)重指定了kTRANSPOSE選項(xiàng)。

filter_const = net.add_constant(trt.Dims2(nbOutputs, k), weights["fc1.weight"].numpy())
mm = net.add_matrix_multiply(input_reshape.get_output(0), trt.MatrixOperation.NONE, filter_const.get_output(0), trt.MatrixOperation.TRANSPOSE);

添加將在批次維度廣播的偏差添加:

bias_const = net.add_constant(trt.Dims2(1, nbOutputs), weights["fc1.bias"].numpy())
bias_add = net.add_elementwise(mm.get_output(0), bias_const.get_output(0), trt.ElementWiseOperation.SUM)

添加 Relu 激活層:

    relu1 = network.add_activation(input=fc1.get_output(0), type=trt.ActivationType.RELU)

添加最后的全連接層,并將該層的輸出標(biāo)記為整個(gè)網(wǎng)絡(luò)的輸出:

    fc2_w = weights['fc2.weight'].numpy()
    fc2_b = weights['fc2.bias'].numpy()
    fc2 = network.add_fully_connected(relu1.get_output(0), ModelData.OUTPUT_SIZE, fc2_w, fc2_b)

    fc2.get_output(0).name = ModelData.OUTPUT_NAME
    network.mark_output(tensor=fc2.get_output(0))

代表 MNIST 模型的網(wǎng)絡(luò)現(xiàn)已完全構(gòu)建。請(qǐng)參閱構(gòu)建引擎執(zhí)行推理部分,了解如何構(gòu)建引擎并使用此網(wǎng)絡(luò)運(yùn)行推理。

6.5. Reduced Precision

6.5.1. Network-level Control of Precision

默認(rèn)情況下,TensorRT 以 32 位精度工作,但也可以使用 16 位浮點(diǎn)和 8 位量化浮點(diǎn)執(zhí)行操作。使用較低的精度需要更少的內(nèi)存并實(shí)現(xiàn)更快的計(jì)算。

降低精度支持取決于您的硬件(請(qǐng)參閱NVIDIA TensorRT 支持矩陣中的硬件和精度部分)。您可以查詢構(gòu)建器以檢查平臺(tái)上支持的精度支持:C++

if (builder->platformHasFastFp16()) { … };

Python

if builder.platform_has_fp16:

在構(gòu)建器配置中設(shè)置標(biāo)志會(huì)通知 TensorRT 它可能會(huì)選擇較低精度的實(shí)現(xiàn):C++

config->setFlag(BuilderFlag::kFP16);

Python

config.set_flag(trt.BuilderFlag.FP16)

共有三個(gè)精度標(biāo)志:FP16、INT8TF32,它們可以獨(dú)立啟用。請(qǐng)注意,如果 TensorRT 導(dǎo)致整體運(yùn)行時(shí)間較短,或者不存在低精度實(shí)現(xiàn),TensorRT 仍將選擇更高精度的內(nèi)核。

當(dāng) TensorRT 為層選擇精度時(shí),它會(huì)根據(jù)需要自動(dòng)轉(zhuǎn)換權(quán)重以運(yùn)行層。

sampleGoogleNetsampleMNIST提供了使用這些標(biāo)志的示例。

雖然使用FP16TF32精度相對(duì)簡單,但使用INT8時(shí)會(huì)有額外的復(fù)雜性。有關(guān)詳細(xì)信息,請(qǐng)參閱使用 INT8章節(jié)。

6.5.2. Layer-level Control of Precision

builder-flags提供了允許的、粗粒度的控制。然而,有時(shí)網(wǎng)絡(luò)的一部分需要更高的動(dòng)態(tài)范圍或?qū)?shù)值精度敏感。您可以限制每層的輸入和輸出類型:C++

layer->setPrecision(DataType::kFP16)

Python

layer.precision = trt.fp16

這為輸入和輸出提供了首選類型(此處為DataType::kFP16)。

您可以進(jìn)一步設(shè)置圖層輸出的首選類型:

C++

layer->setOutputType(out_tensor_index, DataType::kFLOAT)

Python

layer.set_output_type(out_tensor_index, trt.fp16)

計(jì)算將使用與輸入首選相同的浮點(diǎn)類型。大多數(shù) TensorRT 實(shí)現(xiàn)具有相同的輸入和輸出浮點(diǎn)類型;但是,Convolution、DeconvolutionFullyConnected可以支持量化的INT8輸入和未量化的FP16FP32輸出,因?yàn)橛袝r(shí)需要使用來自量化輸入的更高精度輸出來保持準(zhǔn)確性。

設(shè)置精度約束向 TensorRT 提示它應(yīng)該選擇一個(gè)輸入和輸出與首選類型匹配的層實(shí)現(xiàn),如果前一層的輸出和下一層的輸入與請(qǐng)求的類型不匹配,則插入重新格式化操作。請(qǐng)注意,只有通過構(gòu)建器配置中的標(biāo)志啟用了這些類型,TensorRT 才能選擇具有這些類型的實(shí)現(xiàn)。

默認(rèn)情況下,TensorRT 只有在產(chǎn)生更高性能的網(wǎng)絡(luò)時(shí)才會(huì)選擇這樣的實(shí)現(xiàn)。如果另一個(gè)實(shí)現(xiàn)更快,TensorRT 會(huì)使用它并發(fā)出警告。您可以通過首選構(gòu)建器配置中的類型約束來覆蓋此行為。

C++

config->setFlag(BuilderFlag::kPREFER_PRECISION_CONSTRAINTS)

Python

config.set_flag(trt.BuilderFlag.PREFER_PRECISION_CONSTRAINTS)

如果約束是首選的,TensorRT 會(huì)服從它們,除非沒有具有首選精度約束的實(shí)現(xiàn),在這種情況下,它會(huì)發(fā)出警告并使用最快的可用實(shí)現(xiàn)。

要將警告更改為錯(cuò)誤,請(qǐng)使用OBEY而不是PREFER

C++

config->setFlag(BuilderFlag::kOBEY_PRECISION_CONSTRAINTS);

Python

config.set_flag(trt.BuilderFlag.OBEY_PRECISION_CONSTRAINTS);

sampleINT8API說明了使用這些 API 降低精度。

精度約束是可選的 – 您可以查詢以確定是否已使用C++ 中的layer->precisionIsSet()或 Python 中的layer.precision_is_set設(shè)置了約束。如果沒有設(shè)置精度約束,那么從 C++ 中的layer->getPrecision()返回的結(jié)果,或者在 Python 中讀取精度屬性,是沒有意義的。輸出類型約束同樣是可選的。

layer->getOutput(i)->setType()layer->setOutputType()之間存在區(qū)別——前者是一種可選類型,它限制了 TensorRT 將為層選擇的實(shí)現(xiàn)。后者是強(qiáng)制性的(默認(rèn)為 FP32)并指定網(wǎng)絡(luò)輸出的類型。如果它們不同,TensorRT 將插入一個(gè)強(qiáng)制轉(zhuǎn)換以確保兩個(gè)規(guī)范都得到尊重。因此,如果您為產(chǎn)生網(wǎng)絡(luò)輸出的層調(diào)用setOutputType(),通常還應(yīng)該將相應(yīng)的網(wǎng)絡(luò)輸出配置為具有相同的類型。

6.5.3. Enabling TF32 Inference Using C++

TensorRT 默認(rèn)允許使用 TF32 Tensor Cores。在計(jì)算內(nèi)積時(shí),例如在卷積或矩陣乘法期間,TF32 執(zhí)行執(zhí)行以下操作:

  • 將 FP32 被乘數(shù)舍入到 FP16 精度,但保持 FP32 動(dòng)態(tài)范圍。
  • 計(jì)算四舍五入的被乘數(shù)的精確乘積。
  • 將乘積累加到 FP32 總和中。

TF32 Tensor Cores 可以使用 FP32 加速網(wǎng)絡(luò),通常不會(huì)損失準(zhǔn)確性。對(duì)于需要高動(dòng)態(tài)范圍的權(quán)重或激活的模型,它比 FP16 更強(qiáng)大。

不能保證 TF32 Tensor Cores 會(huì)被實(shí)際使用,也沒有辦法強(qiáng)制實(shí)現(xiàn)使用它們 – TensorRT 可以隨時(shí)回退到 FP32,如果平臺(tái)不支持 TF32,則總是回退。但是,您可以通過清除 TF32 builder 標(biāo)志來禁用它們。

C++

config->clearFlag(BuilderFlag::kTF32);

Python

config.clear_flag(trt.BuilderFlag.TF32)

盡管設(shè)置了BuilderFlag::kTF32,但在構(gòu)建引擎時(shí)設(shè)置環(huán)境變量NVIDIA_TF32_OVERRIDE=0會(huì)禁用TF32。此環(huán)境變量在設(shè)置為0時(shí)會(huì)覆蓋 NVIDIA 庫的任何默認(rèn)值或編程配置,因此它們永遠(yuǎn)不會(huì)使用TF32 Tensor Cores加速 FP32 計(jì)算。這只是一個(gè)調(diào)試工具,NVIDIA 庫之外的任何代碼都不應(yīng)更改基于此環(huán)境變量的行為。除0以外的任何其他設(shè)置都保留供將來使用。

警告:在引擎運(yùn)行時(shí)將環(huán)境變量NVIDIA_TF32_OVERRIDE設(shè)置為不同的值可能會(huì)導(dǎo)致無法預(yù)測(cè)的精度/性能影響。引擎運(yùn)轉(zhuǎn)時(shí)最好不要設(shè)置。

注意:除非您的應(yīng)用程序需要 TF32 提供的更高動(dòng)態(tài)范圍,否則FP16將是更好的解決方案,因?yàn)樗鼛缀蹩偰墚a(chǎn)生更快的性能。

6.6. I/O Formats

TensorRT 使用許多不同的數(shù)據(jù)格式優(yōu)化網(wǎng)絡(luò)。為了允許在 TensorRT 和客戶端應(yīng)用程序之間有效傳遞數(shù)據(jù),這些底層數(shù)據(jù)格式在網(wǎng)絡(luò) I/O 邊界處公開,即用于標(biāo)記為網(wǎng)絡(luò)輸入或輸出的張量,以及在將數(shù)據(jù)傳入和傳出插件時(shí)。對(duì)于其他張量,TensorRT 選擇導(dǎo)致最快整體執(zhí)行的格式,并可能插入重新格式化以提高性能。

您可以通過分析可用的 I/O 格式以及對(duì) TensorRT 之前和之后的操作最有效的格式來組裝最佳數(shù)據(jù)管道。

要指定 I/O 格式,請(qǐng)以位掩碼的形式指定一種或多種格式。 以下示例將輸入張量格式設(shè)置為TensorFormat::kHWC8。請(qǐng)注意,此格式僅適用于DataType::kHALF,因此必須相應(yīng)地設(shè)置數(shù)據(jù)類型。

C++

auto formats = 1U << TensorFormat::kHWC8;
network->getInput(0)->setAllowedFormats(formats);
network->getInput(0)->setType(DataType::kHALF);

Python

formats = 1 << int(tensorrt.TensorFormat.HWC8)
network.get_input(0).allowed_formats = formats
network.get_input(0).dtype = tensorrt.DataType.HALF

通過設(shè)置構(gòu)建器配置標(biāo)志DIRECT_IO,可以使 TensorRT 避免在網(wǎng)絡(luò)邊界插入重新格式化。這個(gè)標(biāo)志通常會(huì)適得其反,原因有兩個(gè):

  • 如果允許 TensorRT 插入重新格式化,則生成的引擎可能會(huì)更慢。重新格式化可能聽起來像是浪費(fèi)工作,但它可以允許最有效的內(nèi)核耦合。
  • 如果 TensorRT 在不引入此類重新格式化的情況下無法構(gòu)建引擎,則構(gòu)建將失敗。故障可能僅發(fā)生在某些目標(biāo)平臺(tái)上,因?yàn)檫@些平臺(tái)的內(nèi)核支持哪些格式。

該標(biāo)志的存在是為了希望完全控制重新格式化是否發(fā)生在 I/O 邊界的用戶,例如構(gòu)建僅在 DLA 上運(yùn)行而不回退到 GPU 進(jìn)行重新格式化的引擎。

sampleIOFormats說明了如何使用 C++ 指定 IO 格式。

下表顯示了支持的格式。Table 1. Supported I/O formats

請(qǐng)注意,對(duì)于矢量化格式,通道維度必須補(bǔ)零到矢量大小的倍數(shù)。例如,如果輸入綁定的維度為[16,3,224,224] 、kHALF數(shù)據(jù)類型和kHWC8格式,則綁定緩沖區(qū)的實(shí)際所需大小將為16* 8 *224*224*sizeof(half)字節(jié),甚至盡管engine->getBindingDimension()API 將張量維度返回為[16,3,224,224]。填充部分中的值(即本例中的C=3,4,…,7 )必須用零填充。

有關(guān)這些格式的數(shù)據(jù)在內(nèi)存中的實(shí)際布局方式,請(qǐng)參閱數(shù)據(jù)格式說明。

6.7.Compatibility of Serialized Engines

僅當(dāng)與用于序列化引擎的相同操作系統(tǒng)、CPU 架構(gòu)、GPU 模型和 TensorRT 版本一起使用時(shí),序列化引擎才能保證正常工作。

TensorRT 檢查引擎的以下屬性,如果它們與引擎被序列化的環(huán)境不匹配,將無法反序列化:

  • TensorRT 的主要、次要、補(bǔ)丁和構(gòu)建版本
  • 計(jì)算能力(主要和次要版本)

這確保了在構(gòu)建階段選擇的內(nèi)核存在并且可以運(yùn)行。此外,TensorRT 用于從 cuDNN 和 cuBLAS 中選擇和配置內(nèi)核的 API 不支持跨設(shè)備兼容性,因此在構(gòu)建器配置中禁用這些策略源的使用。 TensorRT 還會(huì)檢查以下屬性,如果它們不匹配,則會(huì)發(fā)出警告:

  • 全局內(nèi)存總線帶寬
  • 二級(jí)緩存大小
  • 每個(gè)塊和每個(gè)多處理器的最大共享內(nèi)存
  • 紋理對(duì)齊要求
  • 多處理器數(shù)量
  • GPU 設(shè)備是集成的還是分立的

如果引擎序列化和運(yùn)行時(shí)系統(tǒng)之間的 GPU 時(shí)鐘速度不同,則從序列化系統(tǒng)中選擇的策略對(duì)于運(yùn)行時(shí)系統(tǒng)可能不是最佳的,并且可能會(huì)導(dǎo)致一些性能下降。

如果反序列化過程中可用的設(shè)備內(nèi)存小于序列化過程中的數(shù)量,反序列化可能會(huì)由于內(nèi)存分配失敗而失敗。

在大型設(shè)備上構(gòu)建小型模型時(shí),TensorRT 可能會(huì)選擇效率較低但可在可用資源上更好地?cái)U(kuò)展的內(nèi)核。因此,如果優(yōu)化單個(gè)TensorRT 引擎以在同一架構(gòu)中的多個(gè)設(shè)備上使用,最好的方法是在最小的設(shè)備上運(yùn)行構(gòu)建器?;蛘?,您可以在計(jì)算資源有限的大型設(shè)備上構(gòu)建引擎(請(qǐng)參閱限制計(jì)算資源部分)。

6.8. Explicit vs Implicit Batch

TensorRT 支持兩種指定網(wǎng)絡(luò)的模式:顯式批處理和隱式批處理。

在隱式批處理模式下,每個(gè)張量都有一個(gè)隱式批處理維度,所有其他維度必須具有恒定長度。此模式由 TensoRT 的早期版本使用,現(xiàn)在已棄用,但繼續(xù)支持以實(shí)現(xiàn)向后兼容性。 在顯式批處理模式下,所有維度都是顯式的并且可以是動(dòng)態(tài)的,即它們的長度可以在執(zhí)行時(shí)改變。許多新功能(例如動(dòng)態(tài)形狀和循環(huán))僅在此模式下可用。 ONNX 解析器也需要它。

例如,考慮一個(gè)處理 NCHW 格式的具有 3 個(gè)通道的大小為 HxW 的 N 個(gè)圖像的網(wǎng)絡(luò)。在運(yùn)行時(shí),輸入張量的維度為 [N,3,H,W]。這兩種模式在INetworkDefinition指定張量維度的方式上有所不同:

  • 在顯式批處理模式下,網(wǎng)絡(luò)指定 [N,3,H,W]。
  • 在隱式批處理模式下,網(wǎng)絡(luò)僅指定 [3,H,W]。批次維度 N 是隱式的。

“跨批次對(duì)話”的操作無法在隱式批次模式下表達(dá),因?yàn)闊o法在網(wǎng)絡(luò)中指定批次維度。隱式批處理模式下無法表達(dá)的操作示例:

  • 減少整個(gè)批次維度
  • 重塑批次維度
  • 用另一個(gè)維度轉(zhuǎn)置批次維度

例外是張量可以在整個(gè)批次中廣播,通過方法ITensor::setBroadcastAcrossBatch用于網(wǎng)絡(luò)輸入,并通過隱式廣播用于其他張量。

顯式批處理模式消除了限制 – 批處理軸是軸 0。顯式批處理的更準(zhǔn)確術(shù)語是“batch oblivious”,因?yàn)樵谶@種模式下,TensorRT 對(duì)引導(dǎo)軸沒有特殊的語義含義,除非特定操作需要. 實(shí)際上,在顯式批處理模式下,甚至可能沒有批處理維度(例如僅處理單個(gè)圖像的網(wǎng)絡(luò)),或者可能存在多個(gè)長度不相關(guān)的批處理維度(例如比較從兩個(gè)批處理中提取的所有可能對(duì))。

INetworkDefinition時(shí),必須通過標(biāo)志指定顯式與隱式批處理的選擇。這是顯式批處理模式的 C++ 代碼:

IBuilder* builder = ...;
INetworkDefinition* network = builder->createNetworkV2(1U << static_cast(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH)));

對(duì)于隱式批處理,使用createNetwork或?qū)?0 傳遞給createNetworkV2

這是顯式批處理模式的 Python 代碼:

builder = trt.Builder(...)
builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)

對(duì)于隱式批處理,省略參數(shù)或傳遞 0。

6.9. Sparsity

NVIDIA 安培架構(gòu) GPU 支持結(jié)構(gòu)化稀疏性。為了利用該特性獲得更高的推理性能,卷積核權(quán)重和全連接權(quán)重必須滿足以下要求:

對(duì)于每個(gè)輸出通道和內(nèi)核權(quán)重中的每個(gè)空間像素,每 4 個(gè)輸入通道必須至少有 2 個(gè)零。換句話說,假設(shè)內(nèi)核權(quán)重的形狀為[K, C, R, S]和C % 4 == 0 ,那么要求是:

for k in K:
    for r in R:
        for s in S:
            for c_packed in range(0, C // 4):
                num_zeros(weights[k, c_packed*4:(c_packed+1)*4, r, s]) >= 2

要啟用稀疏特性,請(qǐng)?jiān)跇?gòu)建器配置中設(shè)置kSPARSE_WEIGHTS標(biāo)志,并確保啟用kFP16kINT8模式。例如

C++

config->setFlag(BuilderFlag::kSPARSE_WEIGHTS);

Python

config.set_flag(trt.BuilderFlag.SPARSE_WEIGHTS)

在構(gòu)建 TensorRT 引擎時(shí),在 TensorRT 日志的末尾,TensorRT 會(huì)報(bào)告哪些層包含滿足結(jié)構(gòu)稀疏性要求的權(quán)重,以及 TensorRT 在哪些層中選擇了利用結(jié)構(gòu)化稀疏性的策略。在某些情況下,具有結(jié)構(gòu)化稀疏性的策略可能比正常策略慢,TensorRT 在這些情況下會(huì)選擇正常策略。以下輸出顯示了一個(gè)顯示有關(guān)稀疏性信息的 TensorRT 日志示例:

[03/23/2021-00:14:05] [I] [TRT] (Sparsity) Layers eligible for sparse math: conv1, conv2, conv3
[03/23/2021-00:14:05] [I] [TRT] (Sparsity) TRT inference plan picked sparse implementation for layers: conv2, conv3

強(qiáng)制內(nèi)核權(quán)重具有結(jié)構(gòu)化的稀疏模式可能會(huì)導(dǎo)致準(zhǔn)確性損失。要通過進(jìn)一步微調(diào)恢復(fù)丟失的準(zhǔn)確性,請(qǐng)參閱PyTorch 中的 Automatic SParsity 工具。

要使用trtexec測(cè)量結(jié)構(gòu)化稀疏性的推理性能,請(qǐng)參閱trtexec部分。

6.10. Empty Tensors

TensorRT 支持空張量。如果張量具有一個(gè)或多個(gè)長度為零的維度,則它是一個(gè)空張量。零長度尺寸通常不會(huì)得到特殊處理。如果一條規(guī)則適用于長度為 L 的任意正值 L 的維度,它通常也適用于 L=0。

例如,當(dāng)沿最后一個(gè)軸連接兩個(gè)維度為[x,y,z][x,y,w]的張量時(shí),結(jié)果的維度為[x,y,z+w],無論x,y, z,或者w為零。

隱式廣播規(guī)則保持不變,因?yàn)橹挥袉挝婚L度維度對(duì)廣播是特殊的。例如,給定兩個(gè)維度為[1,y,z][x,1,z]的張量,它們由IElementWiseLayer計(jì)算的總和具有維度[x,y,z],無論x、y 或 z是否為零.

如果一個(gè)引擎綁定是一個(gè)空的張量,它仍然需要一個(gè)非空的內(nèi)存地址,并且不同的張量應(yīng)該有不同的地址。這與C++中每個(gè)對(duì)象都有唯一地址的規(guī)則是一致的,例如new float[0]返回一個(gè)非空指針。如果使用可能返回零字節(jié)空指針的內(nèi)存分配器,請(qǐng)改為請(qǐng)求至少一個(gè)字節(jié)。

有關(guān)空張量的任何每層特殊處理,請(qǐng)參閱TensorRT 層。

6.11. Reusing Input Buffers

TensorRT 還包括一個(gè)可選的 CUDA 事件作為enqueue方法的參數(shù),一旦輸入緩沖區(qū)可以重用,就會(huì)發(fā)出信號(hào)。這允許應(yīng)用程序在完成當(dāng)前推理的同時(shí)立即開始重新填充輸入緩沖區(qū)以進(jìn)行下一次推理。例如:

C++

context->enqueueV2(&buffers[0], stream, &inputReady);

Python

context.execute_async_v2(buffers, stream_ptr, inputReady)

6.12. Engine Inspector

TensorRT 提供IEngineInspectorAPI 來檢查 TensorRT 引擎內(nèi)部的信息。從反序列化的引擎中調(diào)用createEngineInspector()創(chuàng)建引擎inspector,然后調(diào)用getLayerInformation()getEngineInformation() inspectorAPI分別獲取引擎中特定層或整個(gè)引擎的信息??梢源蛴〕鼋o定引擎的第一層信息,以及引擎的整體信息,如下:

C++

auto inspector = std::unique_ptr(engine->createEngineInspector());
inspector->setExecutionContext(context); // OPTIONAL
std::cout << inspector->getLayerInformation(0, LayerInformationFormat::kJSON); // Print the information of the first layer in the engine.
std::cout << inspector->getEngineInformation(LayerInformationFormat::kJSON); // Print the information of the entire engine.

Python

inspector = engine.create_engine_inspector();
inspector.execution_context = context; # OPTIONAL
print(inspector.get_layer_information(0, LayerInformationFormat.JSON); # Print the information of the first layer in the engine.
print(inspector.get_engine_information(LayerInformationFormat.JSON); # Print the information of the entire engine.

請(qǐng)注意,引擎/層信息中的詳細(xì)程度取決于構(gòu)建引擎時(shí)的ProfilingVerbosity構(gòu)建器配置設(shè)置。默認(rèn)情況下,ProfilingVerbosity設(shè)置為kLAYER_NAMES_ONLY,因此只會(huì)打印層名稱。如果ProfilingVerbosity設(shè)置為kNONE,則不會(huì)打印任何信息;如果設(shè)置為kDETAILED,則會(huì)打印詳細(xì)信息。

getLayerInformation()API 根據(jù)ProfilingVerbosity設(shè)置打印的層信息的一些示例:

kLAYER_NAMES_ONLY

node_of_gpu_0/res4_0_branch2a_1 + node_of_gpu_0/res4_0_branch2a_bn_1 + node_of_gpu_0/res4_0_branch2a_bn_2

kDETAILED

{
  "Name": "node_of_gpu_0/res4_0_branch2a_1 + node_of_gpu_0/res4_0_branch2a_bn_1 + node_of_gpu_0/res4_0_branch2a_bn_2",
  "LayerType": "CaskConvolution",
  "Inputs": [
  {
    "Name": "gpu_0/res3_3_branch2c_bn_3",
    "Dimensions": [16,512,28,28],
    "Format/Datatype": "Thirty-two wide channel vectorized row major Int8 format."
  }],
  "Outputs": [
  {
    "Name": "gpu_0/res4_0_branch2a_bn_2",
    "Dimensions": [16,256,28,28],
    "Format/Datatype": "Thirty-two wide channel vectorized row major Int8 format."
  }],
  "ParameterType": "Convolution",
  "Kernel": [1,1],
  "PaddingMode": "kEXPLICIT_ROUND_DOWN",
  "PrePadding": [0,0],
  "PostPadding": [0,0],
  "Stride": [1,1],
  "Dilation": [1,1],
  "OutMaps": 256,
  "Groups": 1,
  "Weights": {"Type": "Int8", "Count": 131072},
  "Bias": {"Type": "Float", "Count": 256},
  "AllowSparse": 0,
  "Activation": "RELU",
  "HasBias": 1,
  "HasReLU": 1,
  "TacticName": "sm80_xmma_fprop_implicit_gemm_interleaved_i8i8_i8i32_f32_nchw_vect_c_32kcrs_vect_c_32_nchw_vect_c_32_tilesize256x128x64_stage4_warpsize4x2x1_g1_tensor16x8x32_simple_t1r1s1_epifadd",
  "TacticValue": "0x11bde0e1d9f2f35d"
}

另外,當(dāng)引擎使用動(dòng)態(tài)形狀構(gòu)建時(shí),引擎信息中的動(dòng)態(tài)維度將顯示為-1 ,并且不會(huì)顯示張量格式信息,因?yàn)檫@些字段取決于推理階段的實(shí)際形狀。要獲取特定推理形狀的引擎信息,請(qǐng)創(chuàng)建一個(gè)IExecutionContext,將所有輸入尺寸設(shè)置為所需的形狀,然后調(diào)用inspector->setExecutionContext(context)。設(shè)置上下文后,檢查器將打印上下文中設(shè)置的特定形狀的引擎信息。

trtexec工具提供了--profilingVerbosity、--dumpLayerInfo--exportLayerInfo標(biāo)志,可用于獲取給定引擎的引擎信息。有關(guān)詳細(xì)信息,請(qǐng)參閱trtexec部分。

目前,引擎信息中只包含綁定信息和層信息,包括中間張量的維度、精度、格式、策略指標(biāo)、層類型和層參數(shù)。在未來的 TensorRT 版本中,更多信息可能會(huì)作為輸出 JSON 對(duì)象中的新鍵添加到引擎檢查器輸出中。還將提供有關(guān)檢查器輸出中的鍵和字段的更多規(guī)范。

關(guān)于作者

Ken He 是 NVIDIA 企業(yè)級(jí)開發(fā)者社區(qū)經(jīng)理 & 高級(jí)講師,擁有多年的 GPU 和人工智能開發(fā)經(jīng)驗(yàn)。自 2017 年加入 NVIDIA 開發(fā)者社區(qū)以來,完成過上百場(chǎng)培訓(xùn),幫助上萬個(gè)開發(fā)者了解人工智能和 GPU 編程開發(fā)。在計(jì)算機(jī)視覺,高性能計(jì)算領(lǐng)域完成過多個(gè)獨(dú)立項(xiàng)目。并且,在機(jī)器人無人機(jī)領(lǐng)域,有過豐富的研發(fā)經(jīng)驗(yàn)。對(duì)于圖像識(shí)別,目標(biāo)的檢測(cè)與跟蹤完成過多種解決方案。曾經(jīng)參與 GPU 版氣象模式GRAPES,是其主要研發(fā)者。

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2090

    瀏覽量

    73420
  • CUDA
    +關(guān)注

    關(guān)注

    0

    文章

    121

    瀏覽量

    13574
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    金屬2工藝是什么

    金屬2(M2)工藝與金屬1工藝類似。金屬2工藝是指形成第二金屬互連線,金屬互連線的目的是實(shí)現(xiàn)把第一金屬或者第三
    的頭像 發(fā)表于 10-24 16:02 ?65次閱讀
    金屬<b class='flag-5'>層</b>2工藝是什么

    神經(jīng)網(wǎng)絡(luò)中的卷積、池化與全連接

    在深度學(xué)習(xí)中,卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network, CNN)是一種特別適用于處理圖像數(shù)據(jù)的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。它通過卷積、池化和全連接的組合,實(shí)現(xiàn)了對(duì)圖像特征的自動(dòng)提取和分類。本文將詳細(xì)探討卷
    的頭像 發(fā)表于 07-11 14:18 ?3592次閱讀

    反向傳播神經(jīng)網(wǎng)絡(luò)分為多少

    反向傳播神經(jīng)網(wǎng)絡(luò)(Backpropagation Neural Network,簡稱BP神經(jīng)網(wǎng)絡(luò))是一種多層前饋神經(jīng)網(wǎng)絡(luò),它通過反向傳播算法來調(diào)整網(wǎng)絡(luò)中的權(quán)重和偏置,最小化預(yù)測(cè)誤差。BP神經(jīng)網(wǎng)絡(luò)
    的頭像 發(fā)表于 07-03 11:02 ?337次閱讀

    PCB多層板為什么都是偶數(shù)?奇數(shù)不行嗎?

    因素: PCB疊設(shè)計(jì)為偶數(shù)的原因 1. 生產(chǎn)工藝: SMT貼片工廠通常使用雙面覆銅的核心板材,這意味著電路板的導(dǎo)電平面通常保存在雙面覆銅的芯上。由于雙面覆銅芯
    的頭像 發(fā)表于 07-03 09:36 ?402次閱讀

    什么是PCB疊?PCB疊設(shè)計(jì)原則

    對(duì)于信號(hào),通常每個(gè)信號(hào)都與內(nèi)電直接相鄰,與其他信號(hào)有有效的隔離,減小串?dāng)_。在設(shè)計(jì)過程中,可以考慮多層參考地平面,
    的頭像 發(fā)表于 04-10 16:02 ?2114次閱讀
    什么是PCB疊<b class='flag-5'>層</b>?PCB疊<b class='flag-5'>層</b>設(shè)計(jì)原則

    華為顯示面板專利公布,聚焦介質(zhì)、平坦化、像素界定及電路設(shè)計(jì)

    該專利主要內(nèi)容如下:顯示面板由間介質(zhì)、平坦化和像素界定有序堆疊而成;在顯示面板非像素區(qū)的第一功能內(nèi)置入內(nèi)切結(jié)構(gòu)和至少一個(gè)電極搭接結(jié)
    的頭像 發(fā)表于 02-21 09:40 ?526次閱讀
    華為顯示面板專利公布,聚焦介質(zhì)<b class='flag-5'>層</b>、平坦化<b class='flag-5'>層</b>、像素界定<b class='flag-5'>層</b>及電路設(shè)計(jì)

    4以上的PCB設(shè)計(jì),如何選取合適的疊方案?

    如果主元件面設(shè)計(jì)在BOTTOM或關(guān)鍵信號(hào)線在BOTTOM的話,則第三需排在一個(gè)完整地平面。在厚設(shè)置時(shí),地平面層和電源平面層之間的芯板厚度同樣不宜過厚。
    發(fā)表于 01-03 15:04 ?808次閱讀

    物聯(lián)網(wǎng)結(jié)構(gòu)之應(yīng)用

    物聯(lián)網(wǎng)應(yīng)用利用經(jīng)過分析處理的感知數(shù)據(jù),為用戶提供不同類型的特定服務(wù),其主要功能包括對(duì)采集數(shù)據(jù)的匯集、轉(zhuǎn)換、分析,以及用戶呈現(xiàn)的適配和事件觸發(fā)等。網(wǎng)絡(luò)
    的頭像 發(fā)表于 12-28 14:49 ?720次閱讀
    物聯(lián)網(wǎng)結(jié)構(gòu)之應(yīng)用<b class='flag-5'>層</b>

    板如何設(shè)置板層

    板是一種常用于電子產(chǎn)品中的印制電路板(PCB),具有四個(gè)層次或?qū)用?。在設(shè)計(jì)四板時(shí),需要合理設(shè)置板層,優(yōu)化電路性能和信號(hào)傳輸。本文將詳細(xì)介紹四板的板層設(shè)置方法。 四
    的頭像 發(fā)表于 12-21 11:26 ?1732次閱讀

    EDA頂層絲印怎么畫

    EDA(電子設(shè)計(jì)自動(dòng)化)頂層絲印是在PCB(Printed Circuit Board,印刷電路板)設(shè)計(jì)過程中起到標(biāo)記和輔助引導(dǎo)功能的一。它通常包含了元件名稱、位置、方向和標(biāo)志等信息,對(duì)于電路板
    的頭像 發(fā)表于 12-19 17:30 ?1779次閱讀

    電纜屏蔽的作用 電纜屏蔽的種類和使用場(chǎng)景

    電纜屏蔽的作用 電纜屏蔽的種類和使用場(chǎng)景 電纜屏蔽正確的接地做法 電纜屏蔽接地注意事項(xiàng) 電纜屏蔽是電纜結(jié)構(gòu)中的一部分,具有重要的作
    的頭像 發(fā)表于 12-11 15:05 ?1845次閱讀

    PCB中阻焊設(shè)計(jì)規(guī)則

    阻焊可以封住PCB,并在表面層的銅上提供一保護(hù)膜。阻焊需要從表面層的著陸焊盤拉回,這樣您可以有一個(gè)可供安裝和焊接元件的表面。從頂層焊盤上移除阻焊,應(yīng)該會(huì)圍繞焊盤邊緣延伸一定距離
    的頭像 發(fā)表于 12-08 09:40 ?2200次閱讀
    PCB中阻焊<b class='flag-5'>層</b>設(shè)計(jì)規(guī)則

    4板到12板層疊設(shè)計(jì)案例

    對(duì)于六板,優(yōu)先考慮方案三,優(yōu)先布線S1。增大S1和PWR1之間的間距,縮小PWR1和GND2之間的間距,減小電源平面的阻抗。
    發(fā)表于 11-27 15:25 ?418次閱讀

    柔性板能做四板嗎?

    絕緣性能:FPC柔性板的基材聚酰亞胺薄膜具有較好的絕緣性能,可以滿足四板的絕緣要求。但在制造過程中,需要注意導(dǎo)線之間的絕緣的設(shè)計(jì)和制造,確保四
    的頭像 發(fā)表于 11-09 16:12 ?1406次閱讀
    柔性板能做四<b class='flag-5'>層</b>板嗎?

    在TCP/IP5模型中,應(yīng)用是如何與傳輸連接的?

    TCP/IP5模型中,應(yīng)用是如何與傳輸連接的 “封裝”又是指什么?顯示全部
    發(fā)表于 10-28 06:53