Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来

server/2025/2/26 14:06:12/

Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来

深度学习的优化中,自然梯度下降(Natural Gradient Descent)是一个强大的工具,它利用Fisher信息矩阵(FIM)调整梯度方向,让参数更新更高效。然而,Fisher信息矩阵的计算复杂度是个大难题——对于参数量巨大的神经网络,直接计算和求逆几乎是不可能的。这时,Kronecker分解(Kronecker-Factored Approximate Curvature,简称K-FAC)登场了。它通过巧妙的近似,让自然梯度在深度学习中变得实用。今天,我们就来聊聊K-FAC的原理、优势,以及参数正交性如何给它加分。


Fisher信息矩阵的挑战

Fisher信息矩阵 ( I ( θ ) I(\theta) I(θ) ) 衡量了模型输出对参数 ( θ \theta θ ) 的敏感度,在自然梯度下降中的更新公式是:

θ t + 1 = θ t − η I ( θ ) − 1 ∂ L ∂ θ \theta_{t+1} = \theta_t - \eta I(\theta)^{-1} \frac{\partial L}{\partial \theta} θt+1=θtηI(θ)1θL

这里,( I ( θ ) − 1 I(\theta)^{-1} I(θ)1 ) 是Fisher信息矩阵的逆,起到“校正”梯度的作用。但问题来了:

  • 存储复杂度:如果模型有 ( n n n ) 个参数,( I ( θ ) I(\theta) I(θ) ) 是一个 ( n × n n \times n n×n ) 的矩阵,需要 ( O ( n 2 ) O(n^2) O(n2) ) 的存储空间。
  • 计算复杂度:求逆需要 ( O ( n 3 ) O(n^3) O(n3)) 的时间复杂度。

对于一个有百万参数的神经网络,( n 2 n^2 n2 ) 和 ( n 3 n^3 n3 ) 是天文数字,直接计算完全不现实。K-FAC的出现,就是要解决这个“卡脖子”的问题。


什么是Kronecker分解(K-FAC)?

K-FAC是一种近似方法,全称是“Kronecker-Factored Approximate Curvature”。它的核心思想是利用神经网络的层级结构,将Fisher信息矩阵分解成小块矩阵,然后用Kronecker乘积(一种特殊的矩阵乘法)来近似表示。这样,既降低了计算成本,又保留了自然梯度的大部分优势。

通俗比喻

想象你在整理一个巨大的仓库(Fisher信息矩阵),里面堆满了杂乱的货物(参数间的关系)。直接搬运整个仓库太费力,而K-FAC就像把仓库分成几个小隔间(每一层网络一个),每个隔间用两个简单清单(小矩阵)描述货物分布。这样,你不用搬整个仓库,只需处理小隔间,就能大致知道货物的布局。


K-FAC的原理

1. 分层近似

神经网络通常是分层的,每一层有自己的权重(例如 ( W l W_l Wl ))。K-FAC假设Fisher信息矩阵 ( I ( θ ) I(\theta) I(θ) ) 对不同层之间的参数交叉项近似为零,只关注每层内部的参数关系。这样,( I ( θ ) I(\theta) I(θ) ) 变成一个块对角矩阵(block-diagonal matrix),每个块对应一层:

I ( θ ) ≈ diag ( I 1 , I 2 , … , I L ) I(\theta) \approx \text{diag}(I_1, I_2, \dots, I_L) I(θ)diag(I1,I2,,IL)

其中 ( I l I_l Il ) 是第 ( l l l ) 层的Fisher信息矩阵。

2. Kronecker分解

对于每一层 ( l l l ),权重 ( W l W_l Wl ) 是一个矩阵(比如 ( m × n m \times n m×n ))。对应的Fisher信息矩阵 ( I l I_l Il ) 本来是一个 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 的大矩阵,直接计算很麻烦。K-FAC观察到,神经网络的梯度可以分解为输入和输出的贡献,于是近似为:

I l ≈ A l ⊗ G l I_l \approx A_l \otimes G_l IlAlGl

  • ( A l A_l Al ):输入激活的协方差矩阵(大小 ( m × m m \times m m×m )),表示前一层输出的统计特性。
  • ( G l G_l Gl ):梯度相对于输出的协方差矩阵(大小 ( n × n n \times n n×n )),表示当前层输出的统计特性。
  • ( ⊗ \otimes ):Kronecker乘积,将两个小矩阵“组合”成一个大矩阵。后文有解释。

3. 高效求逆

Kronecker乘积有个妙处:如果 ( I l = A l ⊗ G l I_l = A_l \otimes G_l Il=AlGl ),其逆可以通过小矩阵的逆计算:

I l − 1 = A l − 1 ⊗ G l − 1 I_l^{-1} = A_l^{-1} \otimes G_l^{-1} Il1=Al1Gl1

  • ( A l A_l Al ) 是 ( m × m m \times m m×m ),求逆是 ( O ( m 3 ) O(m^3) O(m3) )。
  • ( G l G_l Gl ) 是 ( n × n n \times n n×n ),求逆是 ( O ( n 3 ) O(n^3) O(n3) )。

相比直接求 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 矩阵的 ( O ( ( m n ) 3 ) O((mn)^3) O((mn)3) ),K-FAC把复杂度降到了 ( O ( m 3 + n 3 ) O(m^3 + n^3) O(m3+n3) ),通常 ( m m m ) 和 ( n n n ) 远小于 ( m ⋅ n m \cdot n mn ),节省巨大。


K-FAC的数学细节

假设第 ( l l l ) 层的输出为 ( a l = W l h l − 1 a_l = W_l h_{l-1} al=Wlhl1 )(( h l − 1 h_{l-1} hl1 ) 是前一层激活),损失为 ( L L L )。Fisher信息矩阵的精确定义是:

I l = E [ vec ( ∂ L ∂ a l h l − 1 T ) vec ( ∂ L ∂ a l h l − 1 T ) T ] I_l = E\left[ \text{vec}\left( \frac{\partial L}{\partial a_l} h_{l-1}^T \right) \text{vec}\left( \frac{\partial L}{\partial a_l} h_{l-1}^T \right)^T \right] Il=E[vec(alLhl1T)vec(alLhl1T)T]

K-FAC近似为:

I l ≈ E [ h l − 1 h l − 1 T ] ⊗ E [ ∂ L ∂ a l ∂ L ∂ a l T ] = A l ⊗ G l I_l \approx E\left[ h_{l-1} h_{l-1}^T \right] \otimes E\left[ \frac{\partial L}{\partial a_l} \frac{\partial L}{\partial a_l}^T \right] = A_l \otimes G_l IlE[hl1hl1T]E[alLalLT]=AlGl

  • ( A l = E [ h l − 1 h l − 1 T ] A_l = E[h_{l-1} h_{l-1}^T] Al=E[hl1hl1T] ):输入协方差。
  • ( G l = E [ ∂ L ∂ a l ∂ L ∂ a l T ] G_l = E\left[ \frac{\partial L}{\partial a_l} \frac{\partial L}{\partial a_l}^T \right] Gl=E[alLalLT] ):输出梯度协方差。

自然梯度更新变成:

vec ( Δ W l ) = ( A l − 1 ⊗ G l − 1 ) vec ( ∂ L ∂ W l ) \text{vec}(\Delta W_l) = (A_l^{-1} \otimes G_l^{-1}) \text{vec}\left( \frac{\partial L}{\partial W_l} \right) vec(ΔWl)=(Al1Gl1)vec(WlL)

实际中,( A l A_l Al ) 和 ( G l G_l Gl ) 通过小批量数据的平均值估计,动态更新。


K-FAC的优势

1. 计算效率

从 ( O ( n 3 ) O(n^3) O(n3) ) 降到 ( O ( m 3 + n 3 ) O(m^3 + n^3) O(m3+n3) ),K-FAC让自然梯度在大型网络中可行。例如,一个隐藏层有 1000 个神经元,普通方法需要处理百万级矩阵,而K-FAC只需处理千级矩阵。

2. 保留曲率信息

虽然是近似,K-FAC依然捕捉了每层参数的局部曲率,帮助模型更快收敛,尤其在损失函数表面复杂时。

3. 并行性

每一层的 ( A l A_l Al ) 和 ( G l G_l Gl ) 可以独立计算,非常适合GPU并行加速。


参数正交性如何助力K-FAC?

参数正交性是指Fisher信息矩阵的非对角元素 ( I i j = 0 I_{ij} = 0 Iij=0 )(( i ≠ j i \neq j i=j )),意味着参数间信息独立。K-FAC天然假设层间正交(块对角结构),但层内参数的正交性也能进一步简化计算。

1. 更接近对角形式

如果模型设计时让权重尽量正交(比如通过正交初始化,( W l W l T = I W_l W_l^T = I WlWlT=I )),( A l A_l Al ) 和 ( G l G_l Gl ) 的非对角元素会减小,( I l I_l Il ) 更接近对角矩阵。求逆时计算量进一步降低,甚至可以用简单的逐元素除法近似。

2. 提高稳定性

正交参数减少梯度方向的耦合,自然梯度更新更稳定,避免震荡。例如,卷积网络中正交卷积核可以增强K-FAC的效果。

3. 实际应用

在RNN或Transformer中,正交初始化(如Hennig的正交矩阵)结合K-FAC,能显著提升训练速度和性能。


K-FAC的应用场景

  • 深度神经网络:K-FAC在DNN优化中加速收敛,常用于图像分类任务。
  • 强化学习:如ACKTR算法,结合K-FAC改进策略优化。
  • 生成模型:变分自编码器(VAE)中,K-FAC优化变分参数。

总结

Kronecker分解(K-FAC)通过分层和Kronecker乘积,将Fisher信息矩阵的计算复杂度从“天文数字”降到可接受范围,让自然梯度下降在深度学习中大放异彩。它不仅高效,还保留了曲率信息,适合现代大规模模型。参数正交性则是它的好帮手,通过减少参数间干扰,让K-FAC更简单、更稳定。下次训练网络时,不妨试试K-FAC,也许会带来惊喜!

补充:解释Kronecker乘积

详细解释Kronecker乘积(Kronecker Product)的含义,以及为什么K-FAC观察到神经网络的梯度可以分解为输入和输出的贡献,从而将其近似为 ( I l ≈ A l ⊗ G l I_l \approx A_l \otimes G_l IlAlGl )。


什么是Kronecker乘积?

Kronecker乘积是一种特殊的矩阵运算,用符号 ( ⊗ \otimes ) 表示。它可以将两个较小的矩阵“组合”成一个更大的矩阵。具体来说,假设有两个矩阵:

  • ( A A A ) 是 ( m × m m \times m m×m ) 的矩阵。
  • ( G G G ) 是 ( n × n n \times n n×n ) 的矩阵。

它们的Kronecker乘积 ( A ⊗ G A \otimes G AG ) 是一个 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 的矩阵,定义为:

A ⊗ G = [ a 11 G a 12 G ⋯ a 1 m G a 21 G a 22 G ⋯ a 2 m G ⋮ ⋮ ⋱ ⋮ a m 1 G a m 2 G ⋯ a m m G ] A \otimes G = \begin{bmatrix} a_{11} G & a_{12} G & \cdots & a_{1m} G \\ a_{21} G & a_{22} G & \cdots & a_{2m} G \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} G & a_{m2} G & \cdots & a_{mm} G \end{bmatrix} AG= a11Ga21Gam1Ga12Ga22Gam2Ga1mGa2mGammG

其中,( a i j a_{ij} aij ) 是 ( A A A ) 的第 ( i i i ) 行第 ( j j j ) 列元素,( G G G ) 是整个 ( n × n n \times n n×n ) 矩阵。也就是说,( A A A ) 的每个元素 ( a i j a_{ij} aij ) 都被放大为一个 ( n × n n \times n n×n ) 的块矩阵 ( a i j G a_{ij} G aijG )。

通俗解释

想象你在做一个拼图,( A A A ) 是一个 ( m × m m \times m m×m ) 的模板,告诉你每个位置的重要性(比如协方差);( G G G ) 是一个 ( n × n n \times n n×n ) 的小图案。Kronecker乘积就像把 ( G G G ) 这个图案按照 ( A A A ) 的模板放大排列,形成一个更大的拼图,最终大小是 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) )。

例子

假设 ( A = [ 1 2 3 4 ] A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} A=[1324] )(2×2),( G = [ 0 1 1 0 ] G = \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} G=[0110] )(2×2),则:

A ⊗ G = [ 1 ⋅ [ 0 1 1 0 ] 2 ⋅ [ 0 1 1 0 ] 3 ⋅ [ 0 1 1 0 ] 4 ⋅ [ 0 1 1 0 ] ] A \otimes G = \begin{bmatrix} 1 \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} & 2 \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} \\ 3 \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} & 4 \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} \end{bmatrix} AG= 1[0110]3[0110]2[0110]4[0110]

= [ 0 1 0 2 1 0 2 0 0 3 0 4 3 0 4 0 ] = \begin{bmatrix} 0 & 1 & 0 & 2 \\ 1 & 0 & 2 & 0 \\ 0 & 3 & 0 & 4 \\ 3 & 0 & 4 & 0 \end{bmatrix} = 0103103002042040

结果是一个 4×4 矩阵(( 2 ⋅ 2 × 2 ⋅ 2 2 \cdot 2 \times 2 \cdot 2 22×22 ))。


K-FAC为何用Kronecker乘积近似?

现在我们来看K-FAC为什么观察到神经网络的梯度可以分解为输入和输出的贡献,并用 ( I l ≈ A l ⊗ G l I_l \approx A_l \otimes G_l IlAlGl ) 来近似Fisher信息矩阵。

背景:Fisher信息矩阵的定义

对于第 ( l l l ) 层的权重 ( W l W_l Wl )(一个 ( m × n m \times n m×n ) 矩阵),Fisher信息矩阵 ( I l I_l Il ) 是关于 ( W l W_l Wl ) 的二阶统计量。假设输出为 ( a l = W l h l − 1 a_l = W_l h_{l-1} al=Wlhl1 )(( h l − 1 h_{l-1} hl1 ) 是前一层激活),损失为 ( L L L ),精确的Fisher信息矩阵是:

I l = E [ vec ( ∂ L ∂ a l h l − 1 T ) vec ( ∂ L ∂ a l h l − 1 T ) T ] I_l = E\left[ \text{vec}\left( \frac{\partial L}{\partial a_l} h_{l-1}^T \right) \text{vec}\left( \frac{\partial L}{\partial a_l} h_{l-1}^T \right)^T \right] Il=E[vec(alLhl1T)vec(alLhl1T)T]

这里:

  • ( ∂ L ∂ a l \frac{\partial L}{\partial a_l} alL ) 是损失对输出的梯度(大小为 ( n × 1 n \times 1 n×1 ))。
  • ( h l − 1 h_{l-1} hl1 ) 是输入激活(大小为 ( m × 1 m \times 1 m×1 ))。
  • ( ∂ L ∂ a l h l − 1 T \frac{\partial L}{\partial a_l} h_{l-1}^T alLhl1T ) 是 ( W l W_l Wl ) 的梯度(( m × n m \times n m×n ) 矩阵)。
  • ( vec ( ⋅ ) \text{vec}(\cdot) vec() ) 将矩阵拉成向量,( I l I_l Il ) 是 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 的。

直接计算这个期望需要存储和操作一个巨大矩阵,复杂度为 ( O ( ( m n ) 2 ) O((mn)^2) O((mn)2) )。

K-FAC的观察:梯度分解

K-FAC注意到,神经网络的梯度 ( ∂ L ∂ W l = ∂ L ∂ a l h l − 1 T \frac{\partial L}{\partial W_l} = \frac{\partial L}{\partial a_l} h_{l-1}^T WlL=alLhl1T ) 天然具有“输入”和“输出”的分离结构:

  • 输入贡献:( h l − 1 h_{l-1} hl1 ) 是前一层的激活,决定了梯度的“空间结构”。
  • 输出贡献:( ∂ L ∂ a l \frac{\partial L}{\partial a_l} alL ) 是当前层的输出梯度,决定了梯度的“强度”。

这两个部分是外积(outer product)的形式,提示我们可以分别统计它们的特性,而不是直接算整个大矩阵的协方差。

分解为输入和输出的协方差

K-FAC假设梯度的期望可以近似分解为输入和输出的独立统计量:

I l ≈ E [ h l − 1 h l − 1 T ] ⊗ E [ ∂ L ∂ a l ∂ L ∂ a l T ] I_l \approx E\left[ h_{l-1} h_{l-1}^T \right] \otimes E\left[ \frac{\partial L}{\partial a_l} \frac{\partial L}{\partial a_l}^T \right] IlE[hl1hl1T]E[alLalLT]

  • ( A l = E [ h l − 1 h l − 1 T ] A_l = E[h_{l-1} h_{l-1}^T] Al=E[hl1hl1T] ):输入激活的协方差矩阵(( m × m m \times m m×m )),捕捉了 ( h l − 1 h_{l-1} hl1 ) 的统计特性。
  • ( G l = E [ ∂ L ∂ a l ∂ L ∂ a l T ] G_l = E\left[ \frac{\partial L}{\partial a_l} \frac{\partial L}{\partial a_l}^T \right] Gl=E[alLalLT] ):输出梯度的协方差矩阵(( n × n n \times n n×n )),捕捉了后续层反馈的统计特性。

为什么用Kronecker乘积 ( ⊗ \otimes )?因为梯度 ( ∂ L ∂ W l \frac{\partial L}{\partial W_l} WlL ) 是一个矩阵,其向量化形式 ( vec ( ∂ L ∂ W l ) \text{vec}(\frac{\partial L}{\partial W_l}) vec(WlL) ) 的协方差天然可以用输入和输出的外积结构表示。Kronecker乘积正好能将 ( A l A_l Al ) 和 ( G l G_l Gl ) “组合”成一个 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 的矩阵,与 ( I l I_l Il ) 的维度一致。

为什么这个近似合理?
  1. 结构假设

    • 神经网络的分层设计让输入 ( h l − 1 h_{l-1} hl1 ) 和输出梯度 ( ∂ L ∂ a l \frac{\partial L}{\partial a_l} alL ) 在统计上相对独立。
    • 这种分解假设 ( h l − 1 h_{l-1} hl1 ) 和 ( ∂ L ∂ a l \frac{\partial L}{\partial a_l} alL ) 的相关性主要通过外积体现,忽略了更高阶的交叉项。
  2. 维度匹配

    • ( A l ⊗ G l A_l \otimes G_l AlGl ) 生成一个 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 矩阵,与 ( I l I_l Il ) 的维度一致。
    • 它保留了输入和输出的主要统计信息,同时简化了计算。
  3. 经验验证

    • 实验表明,这种近似在实践中效果很好,尤其在全连接层和卷积层中,能捕捉梯度曲率的主要特征。

为什么分解为输入和输出的贡献?

回到K-FAC的观察:神经网络的梯度 ( ∂ L ∂ W l = ∂ L ∂ a l h l − 1 T \frac{\partial L}{\partial W_l} = \frac{\partial L}{\partial a_l} h_{l-1}^T WlL=alLhl1T ) 是一个外积形式,这种结构启发我们分开考虑:

  • 输入端(( h l − 1 h_{l-1} hl1 )):它来自前一层,反映了数据的空间分布(如激活的协方差)。
  • 输出端(( ∂ L ∂ a l \frac{\partial L}{\partial a_l} alL )):它来自后续层,反映了损失对当前输出的敏感度。

在神经网络中,梯度本质上是“输入”和“输出”交互的结果。K-FAC利用这一点,将Fisher信息矩阵分解为两部分的乘积,而不是直接处理整个权重矩阵的复杂关系。这种分解不仅符合直觉(网络是层层传递的),也大大降低了计算负担。


总结

Kronecker乘积 ( ⊗ \otimes ) 是K-FAC的核心工具,它将输入协方差 ( A l A_l Al ) 和输出梯度协方差 ( G l G_l Gl ) 组合成一个大矩阵,近似表示Fisher信息矩阵 ( I l I_l Il )。这种近似的依据是神经网络梯度的外积结构——输入和输出的贡献可以分开统计。K-FAC通过这种方式,把原本难以计算的 ( ( m ⋅ n ) × ( m ⋅ n ) (m \cdot n) \times (m \cdot n) (mn)×(mn) ) 矩阵问题,简化成了两个小矩阵的操作,既高效又实用。

后记

2025年2月24日22点48分于上海,在Grok3大模型辅助下完成。


http://www.ppmy.cn/server/170762.html

相关文章

《2025国内免费DeepSeek-R1自部署平台实测指南:三大运营商/腾讯/华为哪家强?附避坑清单》

更新日期:2025年2月24日 | 实测时效性声明:部分服务可能因政策调整限流或下线,建议结合最新信息参考。 一、前言:为什么关注DeepSeek-R1自部署? DeepSeek-R1-671B作为国内首个千亿级开源模型,其“满血版”…

ResNet 改进:添加LSKBlock动态调整其大空间感受场

目录 1. LSKBlock模块 2. 改进位置 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. LSKBlock模块 LSKBlock模块是一种用于深度学习模型的模块,尤其在计算机视觉任务中表现出色。它结合了局部特征、语义特征和全局特征,以…

Rk3568驱动开发_完善字符驱动_4

1.代码 驱动代码&#xff1a; #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/io.h>#define CHREDE…

反向代理模块kfj

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…

N皇后问题(位运算版本)

问题描述 在一个 的国际象棋棋盘上放置 个皇后&#xff0c;使得任意两个皇后都不能处于同一行、同一列或同一斜线上。目标是找出所有满足该条件的皇后放置方案。 时间复杂度是O(n!),对于n 乘 n的格子&#xff0c;每行都有n种选择&#xff0c;选择可能依次递减。同时要便随着…

【HDLbits--Comb组合逻辑】

HDLbits--Comb组合逻辑 1.5 组合逻辑1.5 Demo 在 Verilog 中&#xff0c;组合逻辑&#xff08;Combinational Logic&#xff09;是指输出仅依赖于当前输入的逻辑电路&#xff0c;没有记忆功能&#xff08;即没有状态存储&#xff09;。组合逻辑的特点是&#xff1a; 无时钟信号…

2025-02-25 学习记录--C/C++-用C语言实现删除字符串中的子串

用C语言实现删除字符串中的子串 在C语言中&#xff0c;你可以使用strstr函数来查找子串&#xff0c;然后用memmove或strcpy来覆盖或删除找到的子串。 一、举例 &#x1f430; #include <stdio.h> // 包含标准输入输出库&#xff0c;用于使用 printf 函数 #include <s…

【算法】793. 高精度乘法

题目 793. 高精度乘法 思路 把b当作一个整体进行乘法&#xff0c;用A的每一位和b相乘&#xff0c;还要加上判断001的情况&#xff0c;把前面的0删掉。 代码 #include<iostream> #include<vector> using namespace std; vector<int>mul(vector<int>…