Python numpy正在表演

2024-06-16 13:15:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用python实现隐马尔可夫模型训练,结果numpy代码看起来非常慢。训练一个模特需要30分钟。下面是我的代码,我同意这是非常低效的。我试着学习numpy向量化和高级索引方法,但无法理解如何在代码中使用它们。我可以确定大部分的执行是集中的,reestimate()函数占用了超过99%的执行时间,尤其是打印CHK5和CHK6的部分。在

    def reestimate(self):
        newTransition = numpy.zeros(shape=(int(self.num_states),int(self.num_states)))
        newOutput = numpy.zeros(shape=(int(self.num_states),int(self.num_symbols)))
        numerator = numpy.zeros(shape=(int(self.num_obSeq),))
        denominator = numpy.zeros(shape=(int(self.num_obSeq),))
        sumP = 0
        i = 0
        print "CHK1"
        while i < self.num_states:
            j=0
            while j < self.num_states:
                if j < i or j > i + self.delta:
                    newTransition[i][j] = 0
                else:
                    k=0
                    print "CHK2"
                    while k < self.num_obSeq:
                        numerator[k] = denominator[k] = 0
                        self.setObSeq(self.obSeq[k])

                        sumP += self.computeAlpha()
                        self.computeBeta()
                        t=0
                        while t < self.len_obSeq - 1:
                            numerator[k] += self.alpha[t][i] * self.transition[i][j] * self.output[j][self.currentSeq[t + 1]] * self.beta[t + 1][j]
                            denominator[k] += self.alpha[t][i] * self.beta[t][i]
                            t += 1
                        k += 1
                    denom=0
                    k=0
                    print "CHK3"
                    while k < self.num_obSeq:
                        newTransition[i,j] += (1 / sumP) * numerator[k]
                        denom += (1 / sumP) * denominator[k]
                        k += 1
                    newTransition[i,j] /= denom
                    newTransition[i,j] += self.MIN_PROBABILITY
                j += 1
            i += 1
        sumP = 0
        i = 0
        print "CHK4"
        while i < self.num_states:
            j=0
            while j < self.num_symbols:
                k=0
                while k < self.num_obSeq:
                    numerator[k] = denominator[k] = 0
                    self.setObSeq(self.obSeq[k])
                    # print self.obSeq[k]
                    sumP += self.computeAlpha()
                    self.computeBeta()
                    t=0
                    print "CHK5"
                    while t < self.len_obSeq - 1:
                        if self.currentSeq[t] == j:
                            numerator[k] += self.alpha[t,i] * self.beta[t,i]
                        denominator[k] += self.alpha[t,i] * self.beta[t,i]
                        t += 1
                    k += 1
                denom=0
                k=0
                print "CHK6"
                while k < self.num_obSeq:
                    newOutput[i,j] += (1 / sumP) * numerator[k]
                    denom += (1 / sumP) * denominator[k]
                    k += 1
                newOutput[i,j] /= denom
                newOutput[i,j] += self.MIN_PROBABILITY,
                j += 1
            i += 1
        self.transition = newTransition
        self.output = newOutput

    def train(self):
        i = 0
        while i < 20:
            self.reestimate()
            print "reestimating....." ,i
            i += 1

Tags: selfnumpyzerosnumintprintstateswhile
1条回答
网友
1楼 · 发布于 2024-06-16 13:15:43

将内部循环矢量化很简单。下面是代码第二部分的示例(当然未经测试):

print "CHK4"
for i in xrange(self.num_states):
    for j in xrange(self.num_symbols):
        for k in xrange(self.num_obSeq):
            self.setObSeq(self.obSeq[k])
            # print self.obSeq[k]
            sumP += self.computeAlpha()
            self.computeBeta()
            alpha_times_beta = self.alpha[:,i] * self.beta[:,i]
            numerator[k] = numpy.sum(alpha_times_beta[self.currentSeq == j])
            denominator[k] = numpy.sum(alpha_times_beta)
        denom = numpy.sum(denominator)
        newOutput[i,j] = numpy.sum(numerator) / (sumP * denom) + self.MIN_PROBABILITY
self.transition = newTransition
self.output = newOutput

也可以将外环矢量化,但到目前为止,最大的增益通常只通过聚焦于内环获得。一些评论:

  • 似乎大多数while循环都可以变成for循环。尽管这对速度没有太大的影响,但是如果在循环之前知道迭代次数,这是首选方法。

  • 惯例是使用import numpy as np,并在其余代码中使用np.function

  • 只计算求和(accum = 0; for item in vector: accum += item)的简单循环应该像accum = np.sum(vector)一样向量化。

  • 循环中的条件求和可以通过布尔索引转换为矢量化和,因此accum = 0; for i in range(n): if cond[i]: accum += vector[i]可以替换为accum = np.sum(vector[cond])

我很想知道在这些修改之后,代码的速度有多快,我想您可以轻松地获得超过10的因子。在

相关问题 更多 >