使用ctcloss训练矩阵生成目标字符串

首先我们需要明确 c t c l o s s ctcloss ctcloss是用来做什么的。比如说我们要生成的目标字符串长度为 l l l,而这个字符串包含 s s s个字符,字符串允许的最大长度为 L L L,这里我们认为一个位置是一个时间步,就是一拍,记为 T T T
对于这个允许最大长度,需要做出一些解释,我们需要定义一个生成字符串的规则,因为训练的时候,这个标签的长度是不一样的,所以我们需要引入空格来生成字符串,那么相应的,关于空格定义以下两条规则:

  1. 空格与空格之间的字符串是可以去掉重复字母的
  2. 使用空格间隔的两个部分串不能去重,比如说这个串长成:cc cc,在运用上述两条规则之后应该变成c c

举例来说,对于目标生成串如果是 C A T CAT CAT的话,那么在时间拍为 5 5 5拍的情况下,他有这以下 28 28 28条路径可以生成 C A T CAT CAT
在这里插入图片描述
注:上述图片引自这里,博主对这篇文章加以致谢,还好有这个文章让我对 c t c l o s s ctcloss ctcloss有了初步的认识。

因此我们首先拿在手里的是一个随机矩阵为 y y y,这个矩阵的形状是 [ k , T ] [k,T] [k,T],其中 y [ i , j ] y[i,j] y[i,j]表示的是在第 j j j个时间步,该字符为 i i i的概率,而我们需要做的是训练这个 y y y矩阵,让他最终产生指定字符串的概率 p p p最大,所以我们设置 − l n ( p ) -ln(p) ln(p)为损失函数,目标就是让这个损失函数最小。
那么我们应该怎么做呢?你可以枚举出这全部 28 28 28条路径的概率, l i k e   t h i s like\space this like this,然后把他们相加之后求损失和。

在这里插入图片描述
但是我知道你一定不想这么做。所以呢,我们需要使用一种更加简洁的方法来求这个概率,咋做呢?这里就要放上这张过程图了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/b8d163baf95f40ea8f4ad8cd78c383fd.png

首先对字符串进行了插入空格的操作,我一开始的时候不给他插入空格不行,必须得考虑每一步能不能取到空格,并且状态转移的时候,还要考虑从第几个空格转移过来,非常麻烦,不如直接插入空格。接下来使用动态规划的方法来代替暴力搜索,分析 t t t时刻由 t − 1 t-1 t1时刻字符的状态转移方程:

  1. t t t时刻,能取到 s s s字符,那么这个字符可以由 t − 1 t-1 t1时刻的 s s s字符转移过来,两个一样的字符消去就行了呗。
  2. s − 1 s-1 s1字符转移过来 , , 就是 _ C _ A _ T _ \_C\_A\_T\_ _C_A_T_ T T T接在 _ \_ _后面的情况。
  3. 从第 s − 2 s-2 s2个字符转移过来,这个时候第 s s s个字符和第 s − 2 s-2 s2个字符必须不能相同,否则的话就是 _ C _ A _ A _ T _ \_C\_A\_A\_T\_ _C_A_A_T_的两个 A A A越过中间的空格连在一起,这不铁定消去了。

所以状态转移使用如下的方法实现:

alpha[s, t] = alpha[s, t - 1]
if s - 1 >= 0:
   alpha[s, t] += alpha[s - 1, t - 1]
if s - 2 >= 0 and blank_label[s] != '0' and blank_label[s] != blank_label[s - 2]:
   alpha[s, t] += alpha[s - 2, t - 1]
alpha[s, t] *= y[map_dict[blank_label[s]], t]

但是你一定会问弄这个动态规划矩阵有个锤子用,我们来看看:
对于 a l p h a alpha alpha矩阵当中的任意一个元素来说,我们可以得到以下的表达式,其中 l l l是任意一个可能产生字符串的路径, π \pi π是全部路径, l t l_t lt代表这个路径上在第 t t t拍上的字符, P P P为概率。
a l p h a [ i , t ] = P ( l t ) ∑ l ∈ π ∏ t ′ = 1 t − 1 P ( l t ′ ) alpha[i,t] = P(l_t)\sum_{l\in \pi} \prod_{t'=1}^{t-1} P(l_{t'}) alpha[i,t]=P(lt)lπt=1t1P(lt)
那么如果求出后向传播的矩阵 b e t a beta beta
b e t a [ i , t ] = P ( l t ) ∑ l ∈ π ∏ t ′ = t + 1 T P ( l t ′ ) beta[i,t] = P(l_t)\sum_{l\in \pi} \prod_{t'=t+1}^{T} P(l_{t'}) beta[i,t]=P(lt)lπt=t+1TP(lt)
就能得到矩阵:
a l p h a [ i , t ] ∗ b e t a [ i , t ] = P ( l t ) ∑ l ∈ π ∏ t ′ = 1 T P ( l t ′ ) alpha[i,t]*beta[i,t] = P(l_t)\sum_{l\in \pi} \prod_{t'=1}^{T} P(l_{t'}) alpha[i,t]beta[i,t]=P(lt)lπt=1TP(lt)
所以我们非常想求的总概率 p = ∑ l ∈ π ∏ t ′ = 1 T P ( l t ′ ) p=\sum_{l\in \pi} \prod_{t'=1}^{T} P(l_{t'}) p=lπt=1TP(lt)就可以使用 a l p h a [ i , t ] ∗ b e t a [ i , t ] P ( l t ) \frac{alpha[i,t]*beta[i,t]}{P(l_t)} P(lt)alpha[i,t]beta[i,t]来表示。
公式推导鸣谢:这里
注:这只是我大概的理解,不能十分完备的使用原文章中的符号
接下来就到了非常鸡冻人心的训练过程,差点没给我训练死了。因为改了一天这个梯度公式,并且我体会了什么是梯度消失, s o f t m a x softmax softmax的作用,接下来将详细记录我训练的这个过程,应该只是我记得的了,其中非常感谢这几篇文章的帮助,尤其是在晚上八点还是没有结果的时候看到的这篇文章,但是当时通过死亡调试梯度矩阵已经反应过来是梯度问题了hh。首先先声明一下:我不能完全保证我的梯度求解没有问题,但是的确训练出了结果,并且参考多篇博客,梯度的结果全都不一样,因此我只能找到一个我认为最合理的梯度来进行梯度下降。
那么我们再来捋一下思路:首先要最小化 − l n ( p ) -ln(p) ln(p),而前面已经求出 p = a l p h a [ i , t ] ∗ b e t a [ i , t ] P ( l t ) p=\frac{alpha[i,t]*beta[i,t]}{P(l_t)} p=P(lt)alpha[i,t]beta[i,t],这里将 P ( l t ) P(l_t) P(lt)换成 y k t y_{k}^{t} ykt来表示,就是在 t t t时刻的第 k k k个字符的概率。我们想对 y y y求偏导,但有一个 b u g bug bug就是 y y y他不一定每一列的和都是 1 1 1,所以需要对他进行 s o f t m a x softmax softmax操作,因此,我们用 x k t x_{k}^{t} xkt代表经过 s o f t m a x softmax softmax之后的 y k t y_{k}^{t} ykt。分析一下 y y y经过所有变换得到 p p p的过程: y ∼ s o f t m a x ∼ a l p h a + b e t a ∼ p y\sim softmax \sim alpha+beta \sim p ysoftmaxalpha+betap。需要求的梯度经过以上分析可以表示成为:
∂ ( − l n p ) ∂ y k t = − 1 p ∂ p ∂ x k t ∂ x k t ∂ y k t \begin{align} \frac{\partial (-lnp)}{\partial y_{k}^{t}} =-\frac{1}{p}\frac{\partial p}{\partial x_{k}^{t}}\frac{\partial x_{k}^{t}}{\partial y_{k}^{t}} \end{align} ykt(lnp)=p1xktpyktxkt
前面已经知道: p = a l p h a [ i , t ] ∗ b e t a [ i , t ] x k t p=\frac{alpha[i,t]*beta[i,t]}{x_{k}^{t}} p=xktalpha[i,t]beta[i,t],在这个公式当中 a l p h a 、 b e t a alpha、beta alphabeta x k t x_{k}^{t} xkt并不是完全没有关系的,他们可以表示成 c o n s 1 ∗ x k t cons1*x_{k}^{t} cons1xkt的形式,其中 c o n s 1 cons1 cons1是到达 x k t x_{k}^{t} xkt字符之前的所有可能字符概率乘积的和, c o n s 2 cons2 cons2同理,值得注意的是,我们的假定是字符的概率是可以相乘的,也就是完全独立的,因此 c o n s 1 cons1 cons1 c o n s 2 cons2 cons2对于 x k t x_k^t xkt来说是常数。所以 p p p应该化简为 c o n s 1 ∗ c o n s 2 ∗ x k t cons1*cons2*x_{k}^{t} cons1cons2xkt,其中 c o n s 1 = a l p h a x k t , c o n s 2 = b e t a x k t cons1=\frac{alpha}{x_{k}^{t}},cons2 =\frac{beta}{x_{k}^{t}} cons1=xktalpha,cons2=xktbeta,所以
∂ p ∂ x k t = a l p h a x k t b e t a x k t \begin{align} \frac{\partial p}{\partial x_{k}^{t}}=\frac{alpha}{x_{k}^{t}}\frac{beta}{x_{k}^{t}} \end{align} xktp=xktalphaxktbeta
由于 x k t = s o f t m a x ( y k t ) x_{k}^{t}=softmax(y_{k}^{t}) xkt=softmax(ykt),即 x k t = e y k t ∑ j = 1 s e y j t x_{k}^{t}=\frac{e^{y_{k}^{t}}}{\sum_{j=1}^{s}e^{y_{j}^{t}}} xkt=j=1seyjteykt,所以有
∂ x k t ∂ y k t = e y k t ∗ ∑ j = 1 s e y j t − ( e y k t ) 2 ( ∑ j = 1 s e y j t ) 2 = x k t − ( x k t ) 2 \begin{align} \frac{\partial x_{k}^{t}}{\partial y_{k}^{t}} = \frac{e^{y_{k}^{t}}*\sum_{j=1}^{s}e^{y_{j}^{t}}-(e^{y_{k}^{t}})^2}{(\sum_{j=1}^{s}e^{y_{j}^{t}})^2} =x_{k}^{t}-(x_{k}^{t})^2 \end{align} yktxkt=(j=1seyjt)2eyktj=1seyjt(eykt)2=xkt(xkt)2
( 2 ) (2) (2)式和 ( 3 ) (3) (3)代入 ( 1 ) (1) (1)中得到:
∂ ( − l n p ) ∂ y k t = − 1 p a l p h a ∗ b e t a x k t ( 1 − x k t ) = a l p h a ∗ b e t a p − a l p h a ∗ b e t a p ∗ x k t \begin{align} \frac{\partial (-lnp)}{\partial y_{k}^{t}}&=-\frac{1}{p}\frac{alpha*beta}{x_{k}^{t}}(1-x_k^t)\\ &=\frac{alpha*beta}{p}-\frac{alpha*beta}{p*x_k^t}\notag \end{align} ykt(lnp)=p1xktalphabeta(1xkt)=palphabetapxktalphabeta
那么到这里我们整个梯度就全部推导完成了,接下来我们根据这个图来研究一下梯度的结构:
![在这里插入图片描述](https://img-blog.csdnimg.cn/b8d163baf95f40ea8f4ad8cd78c383fd.png
我们在做动态规划的时候,并不是每一个节点都被规划了。我们设定目标产生的字符串为 a b d d c e abddce abddce,一共有 8 8 8拍,也就是 a l p h a alpha alpha长成这样:
在这里插入图片描述
然后我们在看看 y y y,注意这里面的 y y y包含空格,且与这个表在这里插入图片描述
相对应:
在这里插入图片描述
我们发现第一拍里面只有空格和字母 a a a是允许有值的,也就是其余位置的 a l p h a alpha alpha b e t a beta beta都是 0 0 0,这很容易理解,在某一个拍某个字母完全没有可能取到的话,在前向更新的概率 p p p中也不会被计算。因此我们来看一下梯度 a l p h a ∗ b e t a p − a l p h a ∗ b e t a p ∗ x k t \frac{alpha*beta}{p}-\frac{alpha*beta}{p*x_k^t} palphabetapxktalphabeta,按照这个概率计算的话,所有不可能取到的点的梯度都是 0 0 0,但是这些字母对应的 y y y值是需要用梯度更新为 0 0 0的,所以这就是昨天我训练了一大天都没啥用的原因,当然还要包括推公式、初始化、没有归一化、梯度消失的错误。。。
所以最合理的办法就是分类讨论,但是我们重新观察一下这个梯度公式 a l p h a ∗ b e t a p − a l p h a ∗ b e t a p ∗ x k t \frac{alpha*beta}{p}-\frac{alpha*beta}{p*x_k^t} palphabetapxktalphabeta,发现 a l p h a ∗ b e t a p \frac{alpha*beta}{p} palphabeta,在被更新到的节点位置,这个值的取值应该是 x k t x_k^t xkt,如果将梯度写成 x k t − a l p h a ∗ b e t a p ∗ x k t x_k^t-\frac{alpha*beta}{p*x_k^t} xktpxktalphabeta的话,那么在没有更新到的节点位置,其 a l p h a alpha alpha b e t a beta beta应该是 0 0 0,虽然这个是归一化之后的 y y y,但是起码梯度位置有值了,因此我们实际的计算梯度为:
∂ ( − l n p ) ∂ y k t = x k t − a l p h a ∗ b e t a p ∗ x k t \frac{\partial (-lnp)}{\partial y_{k}^{t}}=x_k^t-\frac{alpha*beta}{p*x_k^t} ykt(lnp)=xktpxktalphabeta
最终训练结果:

['e', 'd', '0', 'd', 'd', 'e', 'd', 'd', '0']
['e', 'd', '0', 'd', 'd', 'e', 'd', 'd', '0']
['e', 'd', '0', 'd', 'd', 'e', 'd', 'd', '0']
['e', 'a', '0', 'd', 'd', 'e', 'd', 'c', '0']
['e', 'a', '0', 'd', 'd', 'e', 'd', 'c', '0']
['e', 'a', '0', 'd', 'd', 'd', 'd', 'c', '0']
['e', 'a', '0', 'd', 'd', 'd', 'd', 'c', 'e']
['e', 'a', '0', 'd', 'd', 'd', 'd', 'c', 'e']
['e', 'a', '0', 'd', 'd', 'd', 'd', 'c', 'e']
['e', 'a', '0', 'd', 'd', 'd', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['e', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']
['0', 'a', 'b', 'd', 'd', '0', 'd', 'c', 'e']

整个过程代码:

import numpy as np
import math


def insert_blank(labels):
    l_ = []
    l_.append('0')
    for i in range(len(labels)):
        l_.append(labels[i])
        l_.append('0')
    return l_

def std_matrix(alpha):
    alpha = math.e ** alpha
    b = alpha.sum(axis=0)
    return alpha / b

def check():
    print(math.e ** alpha[-1][-1] + math.e ** alpha[-2][-1] - math.e ** beta[0][1] - math.e ** beta[1][1])
    for i in range(alpha.shape[0]):
        for j in range(alpha.shape[1]):
            alpha[i, j] = alpha[i, j] + beta[i, j]
    print(alpha)

def decode_fn(y, chars):
    res = []
    for j in range(y.shape[1]):
        t = -1
        max_ = -1
        for i in range(y.shape[0]):
            if (y[i, j] > max_):
                max_ = y[i, j]
                t = i
        res.append(chars[t])
    return res

'''
the init process
'''
T = 8
labels = ['a', 'b', 'd', 'd', 'c', 'e']
chars = ['0', 'a', 'b', 'c', 'd', 'e']
y = np.random.rand(len(chars), T + 1)  # 这个还得包含空格,4个字符,5拍
x = std_matrix(y)
map_dict = {'0': 0, 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 4, 'f': 5}
alk = 0.09
blank_label = insert_blank(labels)
length = len(labels)
length_ = len(blank_label)
epoch = 80
'''
train process
'''
for m in range(epoch):
    alpha = np.zeros((len(blank_label), T + 1))  # 这个一共是5拍
    for i in range(alpha.shape[0]):
        for j in range(alpha.shape[1]):
            alpha[i, j] = -math.inf
    alpha[0][1] = np.log(x[0][1])  # 这个是在第一个时刻,选空格
    alpha[1][1] = np.log(x[1][1])  # 这个是在第一个时刻,选第一个字符
    beta = np.ones((len(blank_label), T + 1))
    for i in range(beta.shape[0]):
        for j in range(beta.shape[1]):
            beta[i, j] = -math.inf
    beta[-1][-1] = np.log(x[-1][-1])
    beta[-2][-1] = np.log(x[-2][-1])
    '''
    forward
    '''
    for t in range(2, T + 1):
        lim_down = max(2 * (length - (T - t + 1)) + 1, 0)
        lim_up = min(2 * t - 1, length_ - 1)
        for s in range(lim_down, lim_up + 1, 1):
            alpha[s, t] = math.e ** alpha[s, t - 1]
            if s - 1 >= 0:
                alpha[s, t] += math.e ** alpha[s - 1, t - 1]
            if s - 2 >= 0 and blank_label[s] != '0' and blank_label[s] != blank_label[s - 2]:
                alpha[s, t] += math.e ** alpha[s - 2, t - 1]
            alpha[s, t] = np.log(alpha[s, t])
            alpha[s, t] += np.log(x[map_dict[blank_label[s]], t])
    # print(alpha)

    '''
    backward
    '''

    for t in range(T - 1, 0, -1):
        lim_down = max(2 * (length - (T - t + 1)) + 1, 0)
        lim_up = min(2 * t - 1, length_ - 1)
        for s in range(lim_up, lim_down - 1, -1):
            beta[s, t] = math.e ** beta[s, t + 1]
            if s + 1 < length_:
                beta[s, t] += math.e ** beta[s + 1, t + 1]
            if s + 2 < length_ and blank_label[s] != '0' and blank_label[s] != blank_label[s + 2]:
                beta[s, t] += math.e ** beta[s + 2, t + 1]
            beta[s, t] = np.log(beta[s, t])
            beta[s, t] += np.log(x[map_dict[blank_label[s]]][t])
    check = np.zeros((len(chars), T + 1))
    p = math.e ** alpha[-1][-1] + math.e ** alpha[-2][-1]
    # p = math.e ** p
    grad = np.zeros((len(chars), T + 1))
    for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            ab = 0
            for k in range(alpha.shape[0]):
                if alpha[k][j] == -np.inf or beta[k][j] == -np.inf:
                    continue
                if blank_label[k] == chars[i]:
                    ab += (math.e ** alpha[k][j]) * (math.e ** beta[k][j])
            check[i, j] = ab / x[i, j]
            # if(x[i][j] == 0):
            # print(x,y)
            # ab_x2 = ab / (x[i, j] ** 2)
            grad[i, j] = x[i, j] - ab/ (p*x[i,j])
    # print(y)
    y = y - grad * alk
    y = np.where(y > 0, y, 0)
    x = std_matrix(y)
    print(decode_fn(x, chars))

若您对我的文章有任何疑问都欢迎指出
参考文章:

  1. 文章1
  2. 文章2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/90176.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【云原生】Docker的数据管理(数据卷、容器互联)

目录 一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 二、数据卷容器&#xff08;容器与容器之间数据共享&#xff09; 三、 容器互联&#xff08;使用centos镜像&#xff09; 总结 用户在使用Docker的过程中&#xff0c;往往需要能查看容器内应用产生的数据…

数学建模(四)整数规划—匈牙利算法

目录 一、0-1型整数规划问题 1.1 案例 1.2 指派问题的标准形式 2.2 非标准形式的指派问题 二、指派问题的匈牙利解法 2.1 匈牙利解法的一般步骤 2.2 匈牙利解法的实例 2.3 代码实现 一、0-1型整数规划问题 1.1 案例 投资问题&#xff1a; 有600万元投资5个项目&…

Hbase分布式安装

一、环境准备 启动zookeeper 启动hdfs 二、安装 上传安装包 1、解压 tar -zxf hbase-2.2.2-bin.tar.gz -C /opt/installs/2、更名 mv hbase-2.2.2/ hbase3、配置环境变量 [roothadoop11 conf]# vim /etc/profile export HBASE_HOME/opt/installs/hbase export PATH$PATH:$…

构建高性能云原生大数据处理平台:融合人工智能优化数据分析流程

文章目录 架构要点优势与应用案例研究&#xff1a;基于云原生大数据平台的智能营销分析未来展望&#xff1a;大数据与人工智能的融合结论 &#x1f388;个人主页&#xff1a;程序员 小侯 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏…

某网站DES加密逆向分析实战

文章目录 一、抓包分析二、加密分析一、重写加密 一、抓包分析 分析站点&#xff1a; aHR0cDovL2VpcC5jaGFuZmluZS5jb20v 首先我们提交一下登陆信息&#xff1a; 搜索j_password查看加密函数: 把上图搜索到的encryptPassword函数拿出来分析一下&#xff1a; function encryptP…

免费的png打包plist工具CppTextu,一款把若干资源图片拼接为一张大图的免费工具

经常做游戏打包贴图的都知道&#xff0c;要把图片打包为一张或多张大图&#xff0c;要使用打包工具TexturePacker。 TexturePacker官方版可以直接导入PSD、SWF、PNG、BMP等常见的图片格式&#xff0c;主要用于网页、游戏和动画的制作&#xff0c;它可以将多个小图片汇聚成一个…

springboot服务注册到Eureka,端口总是默认8080,自己配置端口不生效

这段时间接手了一个公司的老项目&#xff0c;用的是SpringCloud&#xff0c;在我用的时候突然发现有一个服务&#xff0c;注册到Eureka后&#xff0c;界面显示的端口和实际Ribbon调用的实例端口是不一致的&#xff0c;后来我自己写了个端口获取了一下所有的实例信息&#xff0c…

C语言 数字在升序数组中出现的次数

目录 1.题目描述 2.题目分析 2.1遍历数组方法 2.2二分查找方法 2.3代码示例 数字在升序数组中出现的次数 这道题可以用遍历数组和二分查找来处理 1.题目描述 2.题目分析 题目中有一个关键信息&#xff0c;非降序数组&#xff0c;我们可以使用if语句来处理这个问题 if(…

C#矩阵XY排序

矩阵XY快速排序 using MyVision.Script.Method;public class MyScript : ScriptMethods {//struct MOTIONPOSXY_S{public double Pos_x;public double Pos_y;};//脚本执行该方法public bool Process(){//try{//脚本代码写在下方 List<double> PointX GetDoubleList(&qu…

二分查找逻辑

目录 二分查找 查找逻辑 题目练习 题目描述 代码示例 总结 二分查找 二分查找是我们经常使用的一种算法&#xff0c;他的逻辑是 在升序或者降序且无重复元素的数组中&#xff0c;比较目标值和数组中间值的方法&#xff0c;每次缩小一半的搜索范围&#xff0c;相比遍历可…

ssm+vue农家乐信息平台源码和论文

ssmvue农家乐信息平台源码和论文066 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 1、研究现状 国外&#xff0c;农家乐都被作为潜在的发展农村经济&#xff0c;增加农民收入的重要手段&#xff0c;让农户广…

Unity Alembic闪烁问题

最近在做项目时&#xff0c;发现Clo3D导出的服装abc动画&#xff0c;导入到Unity中后(已提前导入Alembic插件)&#xff0c;运行时屏幕会闪烁(变黑)。 经过几轮测试&#xff0c;发现是切线的问题。解决办法很简单。将abc文件上的Tangents属性值改为None即可。

matlab-对数据集加噪声并实现tsne可视化

matlab-对数据集加噪声并实现tsne可视化 最近才知道&#xff0c;原来可以不用模型&#xff0c;也能实现对数据集数据的可视化。 **一、**以COIL-100数据集为例子。 问题&#xff1a; 前提&#xff1a;首先对COIL-100数据集根据角度0-175和180-255&#xff0c;分别划分成C1,C…

时序分解 | MATLAB实现基于SVD奇异值分解的信号分解分量可视化

时序分解 | MATLAB实现基于SVD奇异值分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SVD奇异值分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SVD分解重构算法&#xff0c;MATLAB程序&#xff0c;奇异值分解 (Singular Value Decompo…

c语言调用mciSendString播放音乐

如下所示&#xff0c;这是一个使用c语言调用系统方法mciSendString()&#xff0c;让系统播放音乐的示例&#xff1a; baihuaxiang 代码&#xff1a; #include <graphics.h> #include <Windows.h> #include <mmsystem.h>#pragma comment(lib,"WINMM.LIB…

数据结构——线性数据结构(数组,链表,栈,队列)

文章目录 1. 数组2. 链表2.1. 链表简介2.2. 链表分类2.2.1. 单链表2.2.2. 循环链表2.2.3. 双向链表2.2.4. 双向循环链表 2.3. 应用场景2.4. 数组 vs 链表 3. 栈3.1. 栈简介3.2. 栈的常见应用常见应用场景3.2.1. 实现浏览器的回退和前进功能3.2.2. 检查符号是否成对出现3.2.3. 反…

3D模型转换工具HOOPS Exchange助力打造虚拟现实应用程序

挑战&#xff1a; 支持使用各种 CAD 系统和 CAD 文件格式的客户群向可视化硬件提供快速、准确的数据加载提供对详细模型信息的访问&#xff0c;同时确保高帧率性能 解决方案&#xff1a; HOOPS Exchange领先的CAD数据转换工具包 结果&#xff1a; 确保支持来自领先工程软件…

边缘计算网关是如何提高物联网的效率的?

随着物联网的持续发展&#xff0c;物联网应用的丰富和规模的扩大&#xff0c;带来了海量的数据处理、传输和计算需求。 传统的“数据中央处理”模式越来越难以适应物联网的扩展速度&#xff0c;在这一趋势下&#xff0c;边缘计算在物联网系统的部署运营中就发挥出了显著的增效…

docker在阿里云上的镜像仓库管理

目录 一.登录进入阿里云网站&#xff0c;点击个人实例进行创建 二.创建仓库&#xff0c;填写相关信息 三.在访问凭证中设置固定密码用于登录&#xff0c;登录时用户名是使用你注册阿里云的账号名称&#xff0c;密码使用设置的固定密码 四.为镜像打标签并推送到仓库 五.拉取…

什么是Sui Kiosk,它可以做什么,如何赋能创作者?

创作者和IP持有者需要一些工具帮助他们在区块链上实现其商业模式。Sui Kiosk作为Sui上的一种原语可以满足这种需求&#xff0c;为创作者提供动态选项&#xff0c;使他们能够在任何交易场景中设置完成交易的条件。 本文将向您介绍为什么要在SuiFrens中使用Sui Kiosk&#xff0c…