国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

佛山營(yíng)銷網(wǎng)站建設(shè)seo快速工具

佛山營(yíng)銷網(wǎng)站建設(shè),seo快速工具,臨海市城鄉(xiāng)建設(shè)規(guī)劃局網(wǎng)站,大學(xué)網(wǎng)站 作風(fēng)建設(shè)專題Contents混合精度訓(xùn)練 (Mixed Precision Training)單精度浮點(diǎn)數(shù) (FP32) 和半精度浮點(diǎn)數(shù) (FP16)為什么要用 FP16為什么只用 FP16 會(huì)有問題解決方案損失縮放 (Loss Scaling)FP32 權(quán)重備份黑名單Tensor CoreNVIDIA apex 庫代碼解讀opt-level (o1, o2, o3, o4)apex 的 o1 實(shí)現(xiàn)apex …

Contents

  • 混合精度訓(xùn)練 (Mixed Precision Training)
    • 單精度浮點(diǎn)數(shù) (FP32) 和半精度浮點(diǎn)數(shù) (FP16)
    • 為什么要用 FP16
    • 為什么只用 FP16 會(huì)有問題
    • 解決方案
      • 損失縮放 (Loss Scaling)
      • FP32 權(quán)重備份
      • 黑名單
      • Tensor Core
    • NVIDIA apex 庫代碼解讀
      • opt-level (o1, o2, o3, o4)
      • apex 的 o1 實(shí)現(xiàn)
      • apex 的 o2 實(shí)現(xiàn)
  • 在 PyTorch 中使用混合精度訓(xùn)練
    • Automatic Mixed Precision (AMP)
      • Typical Mixed Precision Training
      • Saving/Resuming
      • Working with Unscaled Gradients (Gradient Clipping)
      • Working with Scaled Gradients
        • Gradient accumulation
        • Gradient penalty
      • Working with Multiple GPUs
  • 其他注意事項(xiàng)
  • References

PyTorch 1.6 之前,大家都是用 NVIDIA 的 apex 庫來實(shí)現(xiàn) AMP 訓(xùn)練。1.6 版本之后,PyTorch 出廠自帶 AMP,僅需幾行代碼,就能讓顯存占用減半,訓(xùn)練速度加倍

混合精度訓(xùn)練 (Mixed Precision Training)

單精度浮點(diǎn)數(shù) (FP32) 和半精度浮點(diǎn)數(shù) (FP16)

  • PyTorch 默認(rèn)使用單精度浮點(diǎn)數(shù) (FP32) 來進(jìn)行網(wǎng)絡(luò)模型的計(jì)算和權(quán)重存儲(chǔ),表示范圍為 [?3e38,?1e?38]∪[1e?38,3e38]\left[-3 e^{38},-1 e^{-38}\right] \cup\left[1 e^{-38}, 3 e^{38}\right][?3e38,?1e?38][1e?38,3e38]. 而半精度浮點(diǎn)數(shù) (FP16) 表示范圍只有 [?6.5e4,?5.9e?8]∪[5.9e?8,6.5e4]\left[-6.5 e^{4},-5.9 e^{-8}\right] \cup\left[5.9 e^{-8}, 6.5 e^{4}\right][?6.5e4,?5.9e?8][5.9e?8,6.5e4],可以看到 FP32 能夠表示的范圍要比 FP16 大的多得多
    在這里插入圖片描述其中sign 位表示正負(fù),exponent 位表示指數(shù),fraction 位表示分?jǐn)?shù)
  • 此外浮點(diǎn)數(shù)還存在舍入誤差當(dāng)兩個(gè)數(shù)字相差太大時(shí),相加是無效的。例如 2?3+2?142^{-3}+2^{-14}2?3+2?14 在 FP32 中就不會(huì)有問題,但在 FP16 中,由于 FP16 表示的固定間隔為 2?132^{-13}2?13,因此 2?142^{-14}2?14 加了跟沒加一樣
# FP32
>>> torch.tensor(2**-3) + torch.tensor(2**-14)
tensor(0.1251)# FP16
>>> torch.tensor(2**-3).half() + torch.tensor(2**-14).half()
tensor(0.1250, dtype=torch.float16)

在這里插入圖片描述


對(duì)于 float16

  • 如果 Exponent 位全部為 0:
    • 如果 fraction 位全部為 0,則表示數(shù)字 0
    • 如果 fraction 位不為 0,則表示一個(gè)非常小的數(shù)字 (subnormal numbers),其計(jì)算方式為 (?1)signbit×2?14×(0+fraction1024)(-1)^{signbit}\times2^{-14}\times(0+\frac{fraction}{1024})(?1)signbit×2?14×(0+1024fraction?)
  • 如果 Exponent 位全部為 1:
    • 如果 fraction 位全部為 0,則表示 ±inf±inf±inf
    • 如果 fraction 位不為0,則表示 NAN
  • Exponent 位的其他情況:(?1)signbit×(exponent×2?15)×(1+fraction1024)(-1)^{signbit}\times(exponent\times2^{-15})\times(1+\frac{fraction}{1024})(?1)signbit×(exponent×2?15)×(1+1024fraction?)

在這里插入圖片描述

為什么要用 FP16

  • 如果我們?cè)谟?xùn)練過程中將 FP32 替代為 FP16,有以下兩個(gè)好處:(1) 減少顯存占用: FP16 的顯存占用只有 FP32 的一半,這使得我們可以用更大的 batch size;(2) 加速訓(xùn)練: 使用 FP16,模型的訓(xùn)練速度幾乎可以提升 1 倍

為什么只用 FP16 會(huì)有問題

如果我們簡(jiǎn)單地把模型權(quán)重和輸入從 FP32 轉(zhuǎn)化成 FP16,雖然速度可以翻倍,但是模型的精度會(huì)被嚴(yán)重影響。原因如下:

  • 上/下溢出: FP16 的表示范圍不大,超過 6.5e46.5 e^{4}6.5e4 的數(shù)字會(huì)上溢出變成 inf,小于
    5.9e?85.9 e^{-8}5.9e?8 的數(shù)字會(huì)下溢出變成 0。下溢出更加常見,因?yàn)?strong>在網(wǎng)絡(luò)訓(xùn)練的后期,模型的梯度往往很小,甚至?xí)∮?FP16 的下限,此時(shí)梯度值就會(huì)變成 0,模型參數(shù)無法更新。下圖為 SSD 網(wǎng)絡(luò)在訓(xùn)練過程中的梯度統(tǒng)計(jì),有 67% 的值下溢出變成 0
    在這里插入圖片描述
  • 舍入誤差: 就算梯度不會(huì)上/下溢出,如果梯度值和模型的參數(shù)值相差太遠(yuǎn),也會(huì)發(fā)生舍入誤差的問題。假設(shè)模型參數(shù) w=2?3w=2^{-3}w=2?3,學(xué)習(xí)率 η=2?2\eta=2^{-2}η=2?2,梯度 g=2?12g=2^{-12}g=2?12,則 w′=w+η×g=2?3+2?2×2?12=2?3w'=w+\eta\times g=2^{-3}+2^{-2}\times 2^{-12}=2^{-3}w=w+η×g=2?3+2?2×2?12=2?3

解決方案

損失縮放 (Loss Scaling)

  • 為了解決下溢出的問題,論文中對(duì)計(jì)算出來的 loss 值進(jìn)行縮放 (scale),由于鏈?zhǔn)椒▌t的存在,對(duì) loss 的縮放會(huì)作用在每個(gè)梯度上。縮放后的梯度,就會(huì)平移到 FP16 的有效范圍內(nèi)。這樣就可以用 FP16 存儲(chǔ)梯度而又不會(huì)溢出了。此外,在進(jìn)行更新之前,需要先將縮放后的梯度轉(zhuǎn)化為 FP32,再將梯度反縮放 (unscale) 回去以便進(jìn)行參數(shù)的梯度下降 (注意這里一定要先轉(zhuǎn)成 FP32,不然 unscale 的時(shí)候還是會(huì)下溢出)
  • 縮放因子 (loss_scale) 一般都是框架自動(dòng)確定的,只要沒有發(fā)生 inf 或者 nan,loss_scale 越大越好。因?yàn)殡S著訓(xùn)練的進(jìn)行,網(wǎng)絡(luò)的梯度會(huì)越來越小,更大的 loss_scale 可以更加充分地利用 FP16 的表示范圍

FP32 權(quán)重備份

  • 為了實(shí)現(xiàn) FP16 的訓(xùn)練,我們需要把模型權(quán)重和輸入數(shù)據(jù)都轉(zhuǎn)成 FP16,反向傳播的時(shí)候就會(huì)得到 FP16 的梯度。如果此時(shí)直接進(jìn)行更新,因?yàn)樘荻?×\times× 學(xué)習(xí)率的值往往較小,和模型權(quán)重的差距會(huì)很大,可能會(huì)出現(xiàn)舍入誤差的問題
  • 解決思路是: 將模型權(quán)重、激活值、梯度等數(shù)據(jù)用 FP16 來存儲(chǔ),同時(shí)維護(hù)一份 FP32 的模型權(quán)重副本用于更新。在反向傳播得到 FP16 的梯度以后,將其轉(zhuǎn)化成 FP32 并 unscale,最后更新 FP32 的模型權(quán)重。因?yàn)檎麄€(gè)更新過程是在 FP32 的環(huán)境中進(jìn)行的,所以不會(huì)出現(xiàn)舍入誤差

黑名單

  • 對(duì)于那些在 FP16 環(huán)境中運(yùn)行不穩(wěn)定的模塊,我們會(huì)將其添加到黑名單中,強(qiáng)制它在 FP32 的精度下運(yùn)行。比如需要計(jì)算 batch 均值的 BN 層就應(yīng)該在 FP32 下運(yùn)行,否則會(huì)發(fā)生舍入誤差。還有一些函數(shù)對(duì)于算法精度要求很高,比如 torch.acos(),也應(yīng)該在 FP32 下運(yùn)行
  • 如何保證黑名單模塊在 FP32 環(huán)境中運(yùn)行: 以 BN 層為例,將其權(quán)重轉(zhuǎn)為 FP32,并且將輸入從 FP16 轉(zhuǎn)成 FP32,這樣就可以保證整個(gè)模塊是在 FP32 下運(yùn)行的

Tensor Core

  • Tensor Core 可以讓 FP16 做矩陣相乘,然后把結(jié)果累加到 FP32 的矩陣中。這樣既可以享受 FP16 高速的矩陣乘法,又可以利用 FP32 來消除舍入誤差
    在這里插入圖片描述

NVIDIA apex 庫代碼解讀

opt-level (o1, o2, o3, o4)

在這里插入圖片描述

  • 首先介紹下 apex 提供的幾種 opt-level: o1, o2, o3, o4
  • o0純 FP32,用來當(dāng)精度的基準(zhǔn)o3純 FP16,用來當(dāng)速度的基準(zhǔn)
  • 重點(diǎn)講 o1 和 o2 。我們之前講的 AMP 策略其實(shí)就是 o2: 除了 BN 層的權(quán)重和輸入使用 FP32,模型的其余權(quán)重和輸入都會(huì)轉(zhuǎn)化為 FP16。此外還會(huì)創(chuàng)建一個(gè) FP32 的權(quán)重副本來執(zhí)行更新操作
  • 和 o2 不同, o1 不再需要 FP32 權(quán)重備份,因?yàn)?o1 的模型一直都是 FP32。 可能有些讀者會(huì)好奇,既然模型參數(shù)是 FP32,那怎么在訓(xùn)練過程中使用 FP16 呢?答案是 o1 建立了一個(gè) PyTorch 函數(shù)的黑白名單,對(duì)于白名單上的函數(shù),強(qiáng)制要求其用 FP16,即會(huì)將函數(shù)的參數(shù)先轉(zhuǎn)化為 FP16,再執(zhí)行函數(shù)本身。黑名單則強(qiáng)制要求 FP32。以 nn.Linear 為例, 這個(gè)模塊有兩個(gè)權(quán)重參數(shù) weight 和 bias,輸入為 input,前向傳播就是調(diào)用了 torch.nn.functional.linear(input, weight, bias)。 o1 模式會(huì)將 input、weight、bias 先轉(zhuǎn)化為 FP16 格式 input_fp16、weight_fp16、bias_fp16,再調(diào)用函數(shù) torch.nn.functional.linear(input_fp16, weight_fp16, bias_fp16)。這樣一來就實(shí)現(xiàn)了模型參數(shù)是 FP32,但是仍然可以使用 FP16 來加速訓(xùn)練。o1 還有一個(gè)細(xì)節(jié): 雖然白名單上的 PyTorch 函數(shù)是以 FP16 運(yùn)行的,但是產(chǎn)生的梯度是 FP32,所以不需要手動(dòng)將其轉(zhuǎn)成 FP32 再 unscale,直接 unscale 即可。通常來說 o1 比 o2 更穩(wěn),一般先選擇 o1,再嘗試 o2 看是否掉點(diǎn),如果不掉點(diǎn)就用 o2

apex 的 o1 實(shí)現(xiàn)

  • (1) 根據(jù)黑白名單對(duì) PyTorch 內(nèi)置的函數(shù)進(jìn)行包裝。白名單函數(shù)強(qiáng)制 FP16,黑名單函數(shù)強(qiáng)制 FP32。其余函數(shù)則根據(jù)參數(shù)類型自動(dòng)判斷,如果參數(shù)都是 FP16,則以 FP16 運(yùn)行,如果有一個(gè)參數(shù)為 FP32,則以 FP32 運(yùn)行
  • (2) 將 loss_scale 初始化為一個(gè)很大的值
  • (3) 對(duì)于每次迭代
    • (a). 前向傳播: 模型權(quán)重是 FP32,按照黑白名單自動(dòng)選擇算子精度
    • (b). 將 loss 乘以 loss_scale
    • (ccc). 反向傳播: 因?yàn)槟P蜋?quán)重是 FP32,所以即使函數(shù)以 FP16 運(yùn)行,也會(huì)得到 FP32 的梯度
    • (d). 將梯度 unscale,即除以 loss_scale
    • (e). 如果檢測(cè)到 inf 或 nan.
      • i. loss_scale /= 2
      • ii. 跳過此次更新
    • (f). optimizer.step(),執(zhí)行此次更新
    • (g). 如果連續(xù) 2000 次迭代都沒有出現(xiàn) inf 或 nan,則 loss_scale *= 2

apex 的 o2 實(shí)現(xiàn)

  • (1) 將除了 BN 層以外的模型權(quán)重轉(zhuǎn)化為 FP16,并且包裝了 forward 函數(shù),將其參數(shù)也轉(zhuǎn)化為 FP16
  • (2) 維護(hù)一個(gè) FP32 的模型權(quán)重副本用于更新
  • (3) 將 loss_scale 初始化為一個(gè)很大的值
  • (4) 對(duì)于每次迭代
    • (a). 前向傳播: 除了 BN 層是 FP32,模型其它部分都是 FP16
    • (b). 將 loss 乘以 loss_scale
    • (ccc). 反向傳播,得到 FP16 的梯度
    • (d). 將 FP16 梯度轉(zhuǎn)化為 FP32,并 unscale
    • (e). 如果檢測(cè)到 inf 或 nan
      • i. loss_scale /= 2
      • ii. 跳過此次更新
    • (f). optimizer.step(),執(zhí)行此次更新
    • (g). 如果連續(xù) 2000 次迭代都沒有出現(xiàn) inf 或 nan,則 loss_scale *= 2

在 PyTorch 中使用混合精度訓(xùn)練

Automatic Mixed Precision (AMP)

from torch.cuda.amp import autocast, GradScaler
  • 通常 AMP 需要同時(shí)使用 autocast 和 GradScaler,其中 autocast 的實(shí)例對(duì)象是作為上下文管理器 (context manger) 或裝飾器 (decorator) 來允許用戶代碼的某些區(qū)域在混合精度下運(yùn)行,自動(dòng)為 CUDA 算子選擇(單/半)精度來提升性能并保持精度 (See the Autocast Op Reference for details on what precision autocast chooses for each op, and under what circumstances.),并且 autocast 區(qū)域是可以嵌套的,這可以強(qiáng)制讓 FP16 下可能溢出的模型部分以 FP32 運(yùn)行;而 GradScaler 則是用來進(jìn)行 loss scale
  • autocast 應(yīng)該只封裝網(wǎng)絡(luò)的前向傳播 (forward pass(es)),以及損失計(jì)算 (loss computation(s))。反向傳播不推薦在 autocast 區(qū)域內(nèi)執(zhí)行,反向傳播的操作會(huì)自動(dòng)以對(duì)應(yīng)的前向傳播的操作的數(shù)據(jù)類型運(yùn)行

Typical Mixed Precision Training

# Creates model and optimizer in default precision
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)# Creates a GradScaler once at the beginning of training.
scaler = GradScaler(enabled=True)for epoch in epochs:for input, target in data:optimizer.zero_grad()# Runs the forward pass with autocasting.with autocast(enabled=True, dtype=torch.float16):output = model(input)loss = loss_fn(output, target)# Scales loss.  Calls backward() on scaled loss to create scaled gradients.scaler.scale(loss).backward()# scaler.step() first unscales the gradients of the optimizer's assigned params.# If these gradients do not contain infs or NaNs, optimizer.step() is then called,# otherwise, optimizer.step() is skipped.scaler.step(optimizer)# Updates the loss scale value for next iteration.scaler.update()

Saving/Resuming

checkpoint = {"model": net.state_dict(),"optimizer": opt.state_dict(),"scaler": scaler.state_dict()}
net.load_state_dict(checkpoint["model"])
opt.load_state_dict(checkpoint["optimizer"])
scaler.load_state_dict(checkpoint["scaler"])

Working with Unscaled Gradients (Gradient Clipping)

  • 經(jīng)過 scaler.scale(loss).backward() 得到的梯度是 scaled gradient,如果想要在 scaler.step(optimizer) 前進(jìn)行梯度裁剪等操作,就必須先用 scaler.unscale_(optimizer) 得到 unscaled gradient
scaler = GradScaler()for epoch in epochs:for input, target in data:optimizer.zero_grad()with autocast(dtype=torch.float16):output = model(input)loss = loss_fn(output, target)scaler.scale(loss).backward()# Unscales the gradients of optimizer's assigned params in-placescaler.unscale_(optimizer)# Since the gradients of optimizer's assigned params are unscaled, clips as usual:torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)# optimizer's gradients are already unscaled, so scaler.step does not unscale them,# although it still skips optimizer.step() if the gradients contain infs or NaNs.scaler.step(optimizer)# Updates the scale for next iteration.scaler.update()

Working with Scaled Gradients

Gradient accumulation

  • Gradient accumulation 基于 effective batch of size batch_per_iter * iters_to_accumulate (* num_procs if distributed) 進(jìn)行梯度累加,因此屬于同一個(gè) effective batch 的多個(gè)迭代 batch 內(nèi),scale factor 應(yīng)該保持不變 (scale updates should occur at effective-batch granularity),并且累加的梯度應(yīng)該是 Scaled Gradients。因?yàn)槿绻谔荻壤奂咏Y(jié)束前的某一個(gè)迭代中 unscale gradient (或改變 scale factor),那么下一個(gè)迭代的梯度回傳就會(huì)把 scaled grads 加到 unscaled grads (或乘上了不同 scale factor 的 scaled grads) 上,這會(huì)使得在最后進(jìn)行梯度更新時(shí),我們無法恢復(fù)出 accumulated unscaled grads. 如果想要 unscaled grads,應(yīng)該在梯度累加結(jié)束后調(diào)用 scaler.unscale_(optimizer)
scaler = GradScaler()for epoch in epochs:for i, (input, target) in enumerate(data):with autocast(dtype=torch.float16):output = model(input)loss = loss_fn(output, target)loss = loss / iters_to_accumulate# Accumulates scaled gradients.scaler.scale(loss).backward()if (i + 1) % iters_to_accumulate == 0:# may unscale_ here if desired (e.g., to allow clipping unscaled gradients)scaler.step(optimizer)scaler.update()optimizer.zero_grad()

Gradient penalty

  • https://pytorch.org/docs/stable/notes/amp_examples.html#gradient-penalty

Working with Multiple GPUs

  • 目前的版本中 (v1.13),不管是 DP (one GPU per thread) (多線程) 還是 DDP (one GPU per process) (多進(jìn)程),上述代碼都無需改動(dòng)。只有當(dāng)使用 DDP (multiple GPUs per process) 時(shí),才需要給 model 的 forwad 方法添加 autocast 裝飾器或上下文管理器
  • 當(dāng)然,如果使用老版本的 pytorch,是否需要改動(dòng)代碼請(qǐng)參考官方文檔

其他注意事項(xiàng)

  • 常數(shù)的范圍:為了保證計(jì)算不溢出,首先要保證人為設(shè)定的常數(shù)不溢出,如各種 epsilon,INF (改成 -float('inf') 就可以啦)

References

  • paper: Micikevicius, Paulius, et al. “Mixed precision training.” (ICLR, 2018).
  • AUTOMATIC MIXED PRECISION PACKAGE - TORCH.AMP
  • CUDA AUTOMATIC MIXED PRECISION EXAMPLES
  • Automatic Mixed Precision Recipe
  • 由淺入深的混合精度訓(xùn)練教程
  • 【PyTorch】唯快不破:基于 Apex 的混合精度加速
  • 淺談混合精度訓(xùn)練
  • 【Trick2】torch.cuda.amp自動(dòng)混合精度訓(xùn)練 —— 節(jié)省顯存并加快推理速度
  • 自動(dòng)混合精度訓(xùn)練 (AMP) – PyTorch
http://aloenet.com.cn/news/44964.html

相關(guān)文章:

  • 長(zhǎng)春網(wǎng)站建設(shè)58同城想在百度做推廣怎么做
  • 國(guó)外做家譜的網(wǎng)站開發(fā)小程序
  • 網(wǎng)站建設(shè)要學(xué)會(huì)編程嗎網(wǎng)站的營(yíng)銷推廣方案
  • 國(guó)外網(wǎng)站設(shè)計(jì)網(wǎng)站昆明百度推廣開戶
  • wordpress 網(wǎng)頁目錄下湖南專業(yè)seo公司
  • 小貸網(wǎng)站需要多少錢可以做seo快速排名優(yōu)化方法
  • 做導(dǎo)航網(wǎng)站犯法嗎web網(wǎng)頁制作教程
  • 教師可以做網(wǎng)站嗎最近熱點(diǎn)新聞事件
  • 寧國(guó)做網(wǎng)站優(yōu)化營(yíng)商環(huán)境的措施建議
  • 網(wǎng)站的域名可以修改嗎做營(yíng)銷策劃的公司
  • 網(wǎng)站如何做口碑營(yíng)銷大數(shù)據(jù)
  • 專門做水果的網(wǎng)站重慶seo優(yōu)化效果好
  • wordpress底部插件超級(jí)seo助手
  • 可以免費(fèi)看日本黃片的app做網(wǎng)站上海單個(gè)關(guān)鍵詞優(yōu)化
  • 單頁面網(wǎng)站推廣重慶seo推廣運(yùn)營(yíng)
  • 優(yōu)化網(wǎng)站排名方法教程怎樣自己做網(wǎng)站
  • 武漢++外貿(mào)網(wǎng)站建設(shè)千瓜數(shù)據(jù)
  • 星空無限傳媒官網(wǎng)免費(fèi)下載seo服務(wù)收費(fèi)
  • 化妝品網(wǎng)站系統(tǒng)規(guī)劃58同城安居客
  • 南昌市有幫做網(wǎng)站的嗎作品提示優(yōu)化要?jiǎng)h嗎
  • 江蘇專業(yè)網(wǎng)站建設(shè)網(wǎng)絡(luò)營(yíng)銷站點(diǎn)推廣的方法
  • 門戶網(wǎng)站建設(shè)管理總則關(guān)鍵詞優(yōu)化排名查詢
  • 合肥做網(wǎng)站優(yōu)化哪家好建立網(wǎng)站需要什么條件
  • pc網(wǎng)站建設(shè)方案有哪些seo綜合排名優(yōu)化
  • 許昌做網(wǎng)站漢獅網(wǎng)絡(luò)網(wǎng)站片區(qū)
  • 公司網(wǎng)站開發(fā)建設(shè)什么會(huì)計(jì)科目今日財(cái)經(jīng)最新消息
  • 手機(jī)網(wǎng)站建設(shè)價(jià)格低正規(guī)百度推廣
  • 深圳做網(wǎng)站推廣品牌推廣計(jì)劃書怎么寫
  • 綿陽市建設(shè)局官方網(wǎng)站軍事新聞俄烏最新消息
  • 網(wǎng)站建設(shè)費(fèi)科目外貿(mào)推廣具體是做什么