CSK与KCF算法推导(三)

  本文是CSK与KCF算法推导的第三篇,主要介绍算法的主体部分推导。

循环矩阵

  循环矩阵从CSK的文章里就提出了,概念也很容易理解。一个样本 x x x,可以通过循环移位生成不同的向量,组合成一个矩阵 C ( x ) C(x) C(x)。下面的图里分别列出了 x x x C ( x ) C(x) C(x) C ( x ) C(x) C(x)的转置。
在这里插入图片描述
  循环矩阵 C ( x ) C(x) C(x)和另一个列向量 z z z相乘,得到的结果就是 x x x z z z进行相关运算的结果。这个也很好理解,就是 x x x z z z上面滑动,然后进行乘加运算。同样可以写出循环卷积的矩阵表达式,循环卷积需要先将 x x x倒序,然后再滑动。对比循环卷积所用的矩阵和 ( C ( x ) ) T (C(x))^T (C(x))T的颜色,可以发现它们俩是一样的!
在这里插入图片描述
  循环矩阵 C ( x ) C(x) C(x)既然能和循环卷积联系起来了,那么自然可以想到把DFT矩阵也联系起来。这就能得出一个重要的结论:循环矩阵 C ( x ) C(x) C(x)能够用DFT矩阵对角化!
  下面是证明过程。先根据时域卷积等于频域乘积写出等式:
( C ( x ) ) T z = x ∗ z = F − 1 ( x ^ ⊙ z ^ ) {\left( {C(x)} \right)^T}z = x*z = {{\mathcal F}^{ - 1}}(\hat x \odot \hat z) (C(x))Tz=xz=F1(x^z^)
  其中“ ⊙ \odot ”是哈达玛积(Hadamard product),或者称为“element-wise product”,表示两个向量对应位置的分量直接相乘。 x ^ \hat x x^ z ^ \hat z z^分别表示 x x x z z zDFT变换之后的序列。
( C ( x ) ) T z = 1 s F H ( x ^ ⊙ F z ) = 1 s F H d i a g ( x ^ ) F z {\left( {C(x)} \right)^T}z = \frac{1}{s}{F^H}(\hat x \odot Fz) = \frac{1}{s}{F^H}diag(\hat x)Fz (C(x))Tz=s1FH(x^Fz)=s1FHdiag(x^)Fz
  两个列向量的哈达玛积可以转换成对角矩阵和列向量相乘。 d i a g ( x ^ ) diag(\hat x) diag(x^)表示把 x ^ \hat x x^放到对角线上形成对角矩阵。因为上式对所有的 z z z都成立,所以可以去掉 z z z,得到:
( C ( x ) ) T = 1 s F H d i a g ( x ^ ) F C ( x ) = ( 1 s F T ) d i a g ( x ^ ) ( 1 s F ∗ ) \begin{array}{l} {\left( {C(x)} \right)^T} = \frac{1}{s}{F^H}diag(\hat x)F\\ C(x) = \left( {\frac{1}{{\sqrt s }}{F^T}} \right)diag(\hat x)\left( {\frac{1}{{\sqrt s }}{F^*}} \right) \end{array} (C(x))T=s1FHdiag(x^)FC(x)=(s 1FT)diag(x^)(s 1F)
  又因为 F = F T F=F^T F=FT,且 U = 1 s F U={\frac{1}{{\sqrt s }}F} U=s 1F是酉矩阵。 C ( x ) C(x) C(x)可以进一步表示为:
C ( x ) = U d i a g ( x ^ ) U ∗ C(x) = Udiag(\hat x){U^*} C(x)=Udiag(x^)U
  这个结论就非常厉害了。所有循环矩阵都可以特征分解,特征值是原始序列的DFT;所有循环矩阵的特征向量都相同。这就为后面的运算带来了很大的便利。
  上面的推导是从循环卷积的角度出发的,而我在第一篇文章中还写了相关运算与DFT的关系。
在这里插入图片描述
  这里的相关运算相当于是 x x x相对于 z z z在向右滑动,所以 x x x的DFT结果需要取复共轭,可以这样表示结果:
C ( x ) z = x ⋆ z = F − 1 ( x ^ ∗ ⊙ z ^ ) {{C(x)z = x}} \star z = {{\mathcal F}^{ - 1}}({{\hat x}^*} \odot \hat z) C(x)z=xz=F1(x^z^)
  其中 ⋆ \star 表示相关运算,经过类似的推导之后可以得到:
C ( x ) = U ∗ d i a g ( x ^ ∗ ) U C(x) = U^*diag(\hat x^*){U} C(x)=Udiag(x^)U

循环移位的意义

  一方面原因已经在上面推导,循环矩阵能够用DFT对角化。另一方面要清楚输入样本 x x x并不都是我们关心的目标。我们关心的Target只有其中的一部分,就如下面的图所示。
在这里插入图片描述
  这么做就能够在训练的时候为我们关心的Target提供一些上下文(context)信息。 x x x在循环移位的过程中确实起到了“密集采样”的作用。

生成标签

  在生成标签的时候我们可以给原始样本 x x x一个较大的标签值,其他由循环移位产生的样本给较小的标签值,相对位移越大,标签值越小。
在这里插入图片描述
  因为是循环移位,所以移位越接近一个周期,这个样本越接近正样本。所以样本的标签值是一个峰值在两侧的高斯函数。

训练(不带核函数)

  样本训练还是用的岭回归。结合第二篇文章,虽然在引入核函数之后,我们就不关心 ω \omega ω是多少了,但在没有引入核函数的时候,能求出 ω \omega ω自然更好。
ω = ( X T X + λ I ) − 1 X T y \omega = {\left( {X^TX + \lambda I} \right)^{ - 1}}X^Ty ω=(XTX+λI)1XTy
  只需要将样本矩阵 X X X替换成 C ( x ) C(x) C(x)即可。上面的表达式里用的是转置而不是共轭转置,因为我们前面的推导是在实数的条件下得到的,因为这对于我们分析问题来说已经足够了。
  有人可能会担心, C ( x ) C(x) C(x)分解之后的三个矩阵都是复矩阵,这里是不是应该用共轭转置啊?要用共轭转置很简单,把前面岭回归的推导用共轭转置推导一遍就行,这里的转置是可以推广到共轭转置的。但其实也可以就只用转置,因为这里的 C ( x ) C(x) C(x)本质上还是实数矩阵,转置是能够成立的。我们已经在前面已经有两个关于 C ( x ) C(x) C(x)的分解了,可以都用来帮助化简。把 X = C ( x ) X=C(x) X=C(x)代入:
ω = ( U T d i a g ( x ^ ∗ ) U H U d i a g ( x ^ ) U ∗ + λ I ) − 1 U T d i a g ( x ^ ∗ ) U H y \omega = {\left( {{U^T}diag({{\hat x}^*}){U^H}Udiag(\hat x){U^*} + \lambda I} \right)^{ - 1}}{U^T}diag({{\hat x}^*}){U^H}y ω=(UTdiag(x^)UHUdiag(x^)U+λI)1UTdiag(x^)UHy
  把握几个关键点, U H U = U U H = U ∗ U = U U ∗ = I U^HU=UU^H=U^*U=UU^*=I UHU=UUH=UU=UU=I;对角矩阵相乘就是对角线上元素的对应相乘;对角矩阵转置就是对角线上元素求倒数; ( A B C ) − 1 = C − 1 B − 1 C − 1 (ABC)^{-1}=C^{-1}B^{-1}C^{-1} (ABC)1=C1B1C1 U x = x ^ / s Ux=\hat x/\sqrt s Ux=x^/s U ∗ x = x ^ ∗ / s U^*x=\hat x^*/\sqrt s Ux=x^/s
ω = ( U T d i a g ( x ^ ∗ ) U H U d i a g ( x ^ ) U ∗ + λ I ) − 1 U T d i a g ( x ^ ∗ ) U H y      = U d i a g ( 1 x ^ ∗ ⊙ x ^ + λ ) U ∗ U d i a g ( x ^ ∗ ) U ∗ y      = U d i a g ( x ^ ∗ x ^ ∗ ⊙ x ^ + λ ) U ∗ y \begin{array}{l} \omega = {\left( {{U^T}diag({{\hat x}^*}){U^H}Udiag(\hat x){U^*} + \lambda I} \right)^{ - 1}}{U^T}diag({{\hat x}^*}){U^H}y\\ \ \ \ \ = Udiag\left( {\frac{1}{{{{\hat x}^*} \odot \hat x + \lambda }}} \right){U^*}Udiag({{\hat x}^*}){U^*}y\\ \ \ \ \ = Udiag\left( {\frac{{{{\hat x}^*}}}{{{{\hat x}^*} \odot \hat x + \lambda }}} \right){U^*}y \end{array} ω=(UTdiag(x^)UHUdiag(x^)U+λI)1UTdiag(x^)UHy    =Udiag(x^x^+λ1)UUdiag(x^)Uy    =Udiag(x^x^+λx^)Uy
  这里 d i a g diag diag里面的计算都是element-wise的。
U ∗ ω = d i a g ( x ^ ∗ x ^ ∗ ⊙ x ^ + λ ) U ∗ y {U^*}\omega = diag\left( {\frac{{{{\hat x}^*}}}{{{{\hat x}^*} \odot \hat x + \lambda }}} \right){U^*}y Uω=diag(x^x^+λx^)Uy
ω ^ ∗ = x ^ ∗ ⊙ y ^ ∗ x ^ ∗ ⊙ x ^ + λ {{\hat \omega }^*} = \frac{{{{\hat x}^*} \odot {{\hat y}^*}}}{{{{\hat x}^*} \odot \hat x + \lambda }} ω^=x^x^+λx^y^
  最后的化简结果如下。相比于原先复杂的矩阵运算,现在只需要少量DFT、IDFT和element-wise的运算即可。
ω ^ = x ^ ⊙ y ^ x ^ ∗ ⊙ x ^ + λ \hat \omega = \frac{{\hat x \odot \hat y}}{{{{\hat x}^*} \odot \hat x + \lambda }} ω^=x^x^+λx^y^
  这个地方的推导也是知乎上有人提出推导有误的地方。原文中的结果里面分子的 x ^ \hat x x^多了复共轭,因为在原文的公式(55)处落下了一个复共轭。而这部分结果作者也没有用到具体算法中,所以对算法没有影响。

训练(带核函数)

  带核函数的情况下,我们就不用求 ω \omega ω了,只要求中间变量 α \alpha α就好了。
α = ( K + λ I ) − 1 y \alpha = {\left( {K + \lambda I} \right)^{ - 1}}y α=(K+λI)1y
  计算Gram矩阵
在这里插入图片描述

  逐行观察上面的矩阵乘法,就看前两行就行。可以发现这两行的结果也是一个相对移位的关系。所以当样本矩阵是循环矩阵的时候,这一组样本的Gram矩阵也会是循环矩阵。而循环的基向量就是Gram矩阵的第一行。 K K K是高维空间的Gram矩阵,这一结论自然也成立, K K K也是一个循环矩阵。
K = C ( k x x )          k x x = [ κ ( x , P 0 x ) κ ( x , P 1 x ) κ ( x , P 2 x ) ⋯ κ ( x , P n x ) ] K = C({k^{xx}})\;\;\;\;{k^{xx}} = \left[ {\begin{matrix} {\kappa (x,P^0x)}&{\kappa (x,P^1x)}&{\kappa (x,P^2x)}& \cdots &{\kappa (x,P^nx)} \end{matrix}} \right] K=C(kxx)kxx=[κ(x,P0x)κ(x,P1x)κ(x,P2x)κ(x,Pnx)]
  这里的 P P P矩阵的作用是让列向量 φ ( x ) \varphi(x) φ(x)循环移位。比如 P 0 P^0 P0是不移位, P 1 P^1 P1是循环移位1次, P 2 P^2 P2是循环移位2次,以此类推。
α = ( C ( k x x ) + λ I ) − 1 y = ( U d i a g ( k ^ x x ) U ∗ + λ I ) − 1 y \alpha = {\left( {C({k^{xx}}) + \lambda I} \right)^{ - 1}}y = {\left( {Udiag({{\hat k}^{xx}}){U^*} + \lambda I} \right)^{ - 1}}y α=(C(kxx)+λI)1y=(Udiag(k^xx)U+λI)1y
U ∗ α = d i a g ( 1 k ^ x x + λ ) U ∗ y {U^*}\alpha = diag\left( {\frac{1}{{{{\hat k}^{xx}} + \lambda }}} \right){U^*}y Uα=diag(k^xx+λ1)Uy
α ^ ∗ = y ^ ∗ k ^ x x + λ \hat \alpha^* = \frac{{\hat y^*}}{{{{\hat k}^{xx}} + \lambda }} α^=k^xx+λy^
  用循环矩阵的形式表示 K K K,然后特征分解,利用对角矩阵和酉矩阵的特性即可完成上面的化简。这时候计算量相对比较大的地方就是求 k x x k^{xx} kxx了,它是向量 x x x x x x的循环移位的向量在高维空间的内积构成的向量。
  然后对上面的等式两边取复共轭,就可以得到:
α ^ = y ^ k ^ x x ∗ + λ \hat \alpha = \frac{{\hat y}}{{{{{\hat k}^{xx}}^*} + \lambda }} α^=k^xx+λy^
  但这和论文里的结论不一样,论文里的结论,分母的 k ^ x x {\hat k }^{xx} k^xx没有取复共轭。但实际上这里取复共轭或者不取复共轭都行,因为 k ^ x x {\hat k }^{xx} k^xx是实数。
  什么样的实数序列做DFT之后还能是实数?观察旋转因子 W N k n W_N^{kn} WNkn,旋转因子在复平面上的分布就是有对称性的,当实数序列满足一定条件之后,虚部就能够抵消。
在这里插入图片描述
  观察可以发现,只要序列满足 x [ i ] = x [ N − i ]     i = 1 , 2 , . . . , N − 1 x[i] = x[N-i]\ \ \ i=1,2,...,N-1 x[i]=x[Ni]   i=1,2,...,N1这个条件,这些旋转因子的虚部就都能够被抵消。对于二维的图像来说,就是我们不关心它的第0行和第0列,第0行和第0列可以是任意实数,然后剩余的数据是中心对称的就可以。
  序列 x x x的自相关 k x x k^{xx} kxx自然就满足这一条件。所以更一般的结果还可以是:
α ^ = y ^ r e a l ( k ^ x x ) + λ \hat \alpha = \frac{{\hat y}}{{{real({{\hat k}^{xx}})} + \lambda }} α^=real(k^xx)+λy^
  我们还可以让结果更简单,就是如果 y y y给定的标签同样满足上面的条件,那么 y ^ \hat y y^就也是一个实数。这样整个 α ^ \hat \alpha α^也是实数了!!
α ^ = r e a l ( y ^ ) r e a l ( k ^ x x ) + λ \hat \alpha = \frac{real({\hat y})}{{{real({{\hat k}^{xx}})} + \lambda }} α^=real(k^xx)+λreal(y^)
  通过上面的计算,我们还可以想到一个结论, K = C ( k x x ) K = C({k^{xx}}) K=C(kxx)不光是一个循环矩阵,也还是一个对称矩阵, K = K T K=K^T K=KT。结合这一结论我们可以重新进行一次推导:
α = ( K T + λ I ) − 1 y \alpha = {\left( {{K^T} + \lambda I} \right)^{ - 1}}y α=(KT+λI)1y
α = ( C ( k x x ) T + λ I ) − 1 y = ( U ∗ d i a g ( k ^ x x ) U + λ I ) − 1 y \alpha = {\left( {C({k^{xx}})^T + \lambda I} \right)^{ - 1}}y = {\left( {U^*diag({{\hat k}^{xx}}){U} + \lambda I} \right)^{ - 1}}y α=(C(kxx)T+λI)1y=(Udiag(k^xx)U+λI)1y
U α = d i a g ( 1 k ^ x x + λ ) U y {U}\alpha = diag\left( {\frac{1}{{{{\hat k}^{xx}} + \lambda }}} \right){U}y Uα=diag(k^xx+λ1)Uy
α ^ = y ^ k ^ x x + λ \hat \alpha = \frac{{\hat y}}{{{{\hat k}^{xx}} + \lambda }} α^=k^xx+λy^
  这样就能直接得到论文中给出的结论。

带核函数的检测

  检测就是我们的训练完成之后送进一个新的样本 z z z来预测输出。不带核函数的情况下因为直接计算出了 ω \omega ω,所以只需要求 ω \omega ω z z z的内积就能得到结果。带核函数的情况在上一篇文章中介绍了,不需要显式地求出 ω \omega ω,只需要将输入样本 z z z和所有训练样本做内积,得到一个维度是样本个数的列向量,然后把这个列向量和 α \alpha α做内积即可得到一个预测结果。
  逐个样本 z z z进行检测太慢了,我们把 z z z也扩展成循环矩阵 C ( z ) C(z) C(z),然后就可以直接做一批样本的检测,这一批样本相互之间是空间上的位移关系,最后得到 f ( z ) f(z) f(z)是一个列向量,表示一批样本的检测结果。
在这里插入图片描述
  在没有引入核函数的情况下,上面的 C ( z ) C(z) C(z) ( C ( x ) ) T (C(x))^T (C(x))T相乘得到的也是一个循环矩阵。引入核函数之后,每个样本都经过 φ ( x ) \varphi(x) φ(x)映射到高维空间。我们把高维空间的 C ′ ( z ) C'(z) C(z) ( C ′ ( x ) ) T (C'(x))^T (C(x))T相乘的结果记作 K z K^z Kz
K z = C ( k z x )          k z x = [ κ ( z , P 0 x ) κ ( z , P 1 x ) κ ( z , P 2 x ) ⋯ κ ( z , P n x ) ] K^z = C({k^{zx}})\;\;\;\;{k^{zx}} = \left[ {\begin{matrix} {\kappa (z,P^0x)}&{\kappa (z,P^1x)}&{\kappa (z,P^2x)}& \cdots &{\kappa (z,P^nx)} \end{matrix}} \right] Kz=C(kzx)kzx=[κ(z,P0x)κ(z,P1x)κ(z,P2x)κ(z,Pnx)]
  把结果用循环矩阵化简:
f ( z ) = C ( z ) ( C ( x ) ) T α = K z α = C ( k z x ) α = U d i a g ( k ^ z x ) U ∗ α f(z) = C(z){\left( {C(x)} \right)^T}\alpha = {K^z}\alpha = C({k^{zx}})\alpha = Udiag({\hat k^{zx}}){U^*}\alpha f(z)=C(z)(C(x))Tα=Kzα=C(kzx)α=Udiag(k^zx)Uα
U ∗ f ( z ) = d i a g ( k ^ z x ) U ∗ α {U^*}f(z) = diag({{\hat k}^{zx}}){U^*}\alpha Uf(z)=diag(k^zx)Uα
f ^ ∗ ( z ) = k ^ z x ⊙ a ^ ∗ {{\hat f}^*}(z) = {{\hat k}^{zx}} \odot {{\hat a}^*} f^(z)=k^zxa^
  这里的结果和论文中的结果有点不一样,这是因为 K z K^z Kz的表示方式不太一样,原文中用的是 f ( z ) = ( K z ) T α f(z)=(K^z)^T\alpha f(z)=(Kz)Tα,所以 K z = C ( x ) ( C ( z ) ) T K^z=C(x)\left (C(z) \right)^T Kz=C(x)(C(z))T
在这里插入图片描述
K z = C ( k x z )          k x z = [ κ ( x , P 0 z ) κ ( x , P 1 z ) κ ( x , P 2 z ) ⋯ κ ( x , P n z ) ] K^z = C({k^{xz}})\;\;\;\;{k^{xz}} = \left[ {\begin{matrix} {\kappa (x,P^0z)}&{\kappa (x,P^1z)}&{\kappa (x,P^2z)}& \cdots &{\kappa (x,P^nz)} \end{matrix}} \right] Kz=C(kxz)kxz=[κ(x,P0z)κ(x,P1z)κ(x,P2z)κ(x,Pnz)]
  把结果用循环矩阵化简:
f ( z ) = ( K z ) T α = ( C ( k x z ) ) T α = U ∗ d i a g ( k ^ x z ) U α f(z) = ({K^z})^T\alpha = (C({k^{xz}}))^T\alpha = U^*diag({\hat k^{xz}}){U}\alpha f(z)=(Kz)Tα=(C(kxz))Tα=Udiag(k^xz)Uα
U f ( z ) = d i a g ( k ^ x z ) U α {U}f(z) = diag({{\hat k}^{xz}}){U}\alpha Uf(z)=diag(k^xz)Uα
f ^ ( z ) = k ^ x z ⊙ a ^ {{\hat f}}(z) = {{\hat k}^{xz}} \odot {{\hat a}} f^(z)=k^xza^
  这两个结论的区别在于求 x x x z z z的互相关时,两个序列的相对滑动方向不一样。结合我的第一篇文章中关于相关运算用DFT加速的内容:
k ^ z x = z ^ ⊙ x ^ ∗ {\hat k}^{zx} = \hat z \odot{\hat x}^* k^zx=z^x^
k ^ x z = x ^ ⊙ z ^ ∗ {\hat k}^{xz} = \hat x \odot{\hat z}^* k^xz=x^z^
  我更倾向于使用后者的结论,那样在没有引入核函数的情况下计算 f ( z ) f(z) f(z)可以表示为:
f ( z ) = F − 1 ( x ^ ⊙ z ^ ∗ ⊙ α ^ ) f(z)={\mathcal F}^{-1}(\hat x \odot{\hat z}^*\odot\hat \alpha) f(z)=F1(x^z^α^)

核函数计算

  有些核函数的计算也可以利用循环矩阵来加速。

多项式核

κ ( u , v ) = ( u T v + a ) b \kappa(u,v)=(u^Tv+a)^b κ(u,v)=(uTv+a)b
  在训练的时候计算 k x x k^{xx} kxx u u u v v v一个始终是原始样本 x x x,另一个是循环移位的样本。这就是自相关运算,所以可以用DFT来加速。
k i x x = κ ( x , P i x ) = ( x T P i x + a ) b = ( F − 1 ( x ^ ⊙ x ^ ∗ ) + a ) b k_i^{xx} = \kappa (x,{P^i}x) = {({x^T}{P^i}x + a)^b} = {\left( {{{\mathcal F}^{ - 1}}(\hat x \odot {{\hat x}^*}) + a} \right)^b} kixx=κ(x,Pix)=(xTPix+a)b=(F1(x^x^)+a)b
  在检测的时候计算 k x z k^{xz} kxz。这时候是互相关运算,互相关运算要注意它们相对滑动的方向,然后再确定哪个需要取复共轭。
k i x z = κ ( z , P i x ) = ( z T P i x + a ) b = ( F − 1 ( x ^ ⊙ z ^ ∗ ) + a ) b k_i^{xz} = \kappa (z,{P^i}x) = {({z^T}{P^i}x + a)^b} = {\left( {{{\mathcal F}^{ - 1}}(\hat x \odot {{\hat z}^*}) + a} \right)^b} kixz=κ(z,Pix)=(zTPix+a)b=(F1(x^z^)+a)b

高斯核

κ ( u , v ) = e x p ( − 1 σ 2 ∣ ∣ u − v ∣ ∣ 2 ) \kappa (u,v) = exp\left( { - \frac{1}{{{\sigma ^2}}}||u - v|{|^2}} \right) κ(u,v)=exp(σ21uv2)
  在训练的时候计算 k x x k^{xx} kxx
k i x x = κ ( x , P i x ) = e x p ( − 2 σ 2 ( ∣ ∣ x ∣ ∣ 2 − F − 1 ( x ^ ⊙ x ^ ∗ ) ) ) k_i^{xx} = \kappa (x,{P^i}x) = exp\left( { - \frac{2}{{{\sigma ^2}}}\left( {||x|{|^2} - {{\mathcal F}^{ - 1}}(\hat x \odot {{\hat x}^*})} \right)} \right) kixx=κ(x,Pix)=exp(σ22(x2F1(x^x^)))
  在检测的时候计算 k x z k^{xz} kxz
k i x z = κ ( x , P i x ) = e x p ( − 1 σ 2 ( ∣ ∣ x ∣ ∣ 2 + ∣ ∣ z ∣ ∣ 2 − 2 F − 1 ( x ^ ⊙ z ^ ∗ ) ) ) k_i^{xz} = \kappa (x,{P^i}x) = exp\left( { - \frac{1}{{{\sigma ^2}}}\left( {||x|{|^2} + ||z|{|^2} - 2{{\mathcal F}^{ - 1}}(\hat x \odot {{\hat z}^*})} \right)} \right) kixz=κ(x,Pix)=exp(σ21(x2+z22F1(x^z^)))

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值