File: gil_fix

package info (click to toggle)
python-hmmlearn 0.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 588 kB
  • sloc: python: 4,797; cpp: 321; makefile: 13
file content (159 lines) | stat: -rw-r--r-- 6,080 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
From 38b559464e5f8212225acc4c8aa213732ce8f6e8 Mon Sep 17 00:00:00 2001
From: Antony Lee <anntzer.lee@gmail.com>
Date: Sun, 6 Oct 2024 22:47:34 +0200
Subject: [PATCH] Reacquire GIL before constructing tuples containing numpy
 arrays.

... as explicitly required by pybind11.  Compile with `#define
PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF` to observe GIL assertion
failures in absence of this patch.
---
 src/_hmmc.cpp | 111 ++++++++++++++++++++++++++------------------------
 1 file changed, 58 insertions(+), 53 deletions(-)

--- python-hmmlearn.orig/src/_hmmc.cpp
+++ python-hmmlearn/src/_hmmc.cpp
@@ -63,37 +63,39 @@
   auto scaling_ = py::array_t<double>{{ns}};
   auto scaling = scaling_.mutable_unchecked<1>();
   auto log_prob = 0.;
-  py::gil_scoped_release nogil;
-  std::fill_n(fwd.mutable_data(0, 0), fwd.size(), 0);
-  for (auto i = 0; i < nc; ++i) {
-    fwd(0, i) = startprob(i) * frameprob(0, i);
-  }
-  auto sum = std::accumulate(&fwd(0, 0), &fwd(0, nc), 0.);
-  if (sum < min_sum) {
-    throw std::range_error{"forward pass failed with underflow; "
-                           "consider using implementation='log' instead"};
-  }
-  auto scale = scaling(0) = 1. / sum;
-  log_prob -= std::log(scale);
-  for (auto i = 0; i < nc; ++i) {
-    fwd(0, i) *= scale;
-  }
-  for (auto t = 1; t < ns; ++t) {
-    for (auto j = 0; j < nc; ++j) {
-      for (auto i = 0; i < nc; ++i) {
-        fwd(t, j) += fwd(t - 1, i) * transmat(i, j);
-      }
-      fwd(t, j) *= frameprob(t, j);
+  {
+    py::gil_scoped_release nogil;
+    std::fill_n(fwd.mutable_data(0, 0), fwd.size(), 0);
+    for (auto i = 0; i < nc; ++i) {
+      fwd(0, i) = startprob(i) * frameprob(0, i);
     }
-    auto sum = std::accumulate(&fwd(t, 0), &fwd(t, nc), 0.);
+    auto sum = std::accumulate(&fwd(0, 0), &fwd(0, nc), 0.);
     if (sum < min_sum) {
       throw std::range_error{"forward pass failed with underflow; "
                              "consider using implementation='log' instead"};
     }
-    auto scale = scaling(t) = 1. / sum;
+    auto scale = scaling(0) = 1. / sum;
     log_prob -= std::log(scale);
-    for (auto j = 0; j < nc; ++j) {
-      fwd(t, j) *= scale;
+    for (auto i = 0; i < nc; ++i) {
+      fwd(0, i) *= scale;
+    }
+    for (auto t = 1; t < ns; ++t) {
+      for (auto j = 0; j < nc; ++j) {
+        for (auto i = 0; i < nc; ++i) {
+          fwd(t, j) += fwd(t - 1, i) * transmat(i, j);
+        }
+        fwd(t, j) *= frameprob(t, j);
+      }
+      auto sum = std::accumulate(&fwd(t, 0), &fwd(t, nc), 0.);
+      if (sum < min_sum) {
+        throw std::range_error{"forward pass failed with underflow; "
+                               "consider using implementation='log' instead"};
+      }
+      auto scale = scaling(t) = 1. / sum;
+      log_prob -= std::log(scale);
+      for (auto j = 0; j < nc; ++j) {
+        fwd(t, j) *= scale;
+      }
     }
   }
   return {log_prob, fwdlattice_, scaling_};
@@ -117,16 +119,18 @@
   auto buf = std::vector<double>(nc);
   auto fwdlattice_ = py::array_t<double>{{ns, nc}};
   auto fwd = fwdlattice_.mutable_unchecked<2>();
-  py::gil_scoped_release nogil;
-  for (auto i = 0; i < nc; ++i) {
-    fwd(0, i) = log_startprob(i) + log_frameprob(0, i);
-  }
-  for (auto t = 1; t < ns; ++t) {
-    for (auto j = 0; j < nc; ++j) {
-      for (auto i = 0; i < nc; ++i) {
-        buf[i] = fwd(t - 1, i) + log_transmat(i, j);
+  {
+    py::gil_scoped_release nogil;
+    for (auto i = 0; i < nc; ++i) {
+      fwd(0, i) = log_startprob(i) + log_frameprob(0, i);
+    }
+    for (auto t = 1; t < ns; ++t) {
+      for (auto j = 0; j < nc; ++j) {
+        for (auto i = 0; i < nc; ++i) {
+          buf[i] = fwd(t - 1, i) + log_transmat(i, j);
+        }
+        fwd(t, j) = logsumexp(buf.data(), nc) + log_frameprob(t, j);
       }
-      fwd(t, j) = logsumexp(buf.data(), nc) + log_frameprob(t, j);
     }
   }
   auto log_prob = logsumexp(&fwd(ns - 1, 0), nc);
@@ -290,30 +294,31 @@
   auto viterbi_lattice_ = py::array_t<double>{{ns, nc}};
   auto state_sequence = state_sequence_.mutable_unchecked<1>();
   auto viterbi_lattice = viterbi_lattice_.mutable_unchecked<2>();
-  py::gil_scoped_release nogil;
-  for (auto i = 0; i < nc; ++i) {
-    viterbi_lattice(0, i) = log_startprob(i) + log_frameprob(0, i);
-  }
-  for (auto t = 1; t < ns; ++t) {
+  {
+    py::gil_scoped_release nogil;
     for (auto i = 0; i < nc; ++i) {
-      auto max = -std::numeric_limits<double>::infinity();
-      for (auto j = 0; j < nc; ++j) {
-        max = std::max(max, viterbi_lattice(t - 1, j) + log_transmat(j, i));
+      viterbi_lattice(0, i) = log_startprob(i) + log_frameprob(0, i);
+    }
+    for (auto t = 1; t < ns; ++t) {
+      for (auto i = 0; i < nc; ++i) {
+        auto max = -std::numeric_limits<double>::infinity();
+        for (auto j = 0; j < nc; ++j) {
+          max = std::max(max, viterbi_lattice(t - 1, j) + log_transmat(j, i));
+        }
+        viterbi_lattice(t, i) = max + log_frameprob(t, i);
       }
-      viterbi_lattice(t, i) = max + log_frameprob(t, i);
     }
-  }
-  auto row = &viterbi_lattice(ns - 1, 0);
-  auto prev = state_sequence(ns - 1) = std::max_element(row, row + nc) - row;
-  auto log_prob = row[prev];
-  for (auto t = ns - 2; t >= 0; --t) {
-    auto max = std::make_pair(-std::numeric_limits<double>::infinity(), 0);
-    for (auto i = 0; i < nc; ++i) {
-      max = std::max(max, {viterbi_lattice(t, i) + log_transmat(i, prev), i});
+    auto row = &viterbi_lattice(ns - 1, 0);
+    auto prev = state_sequence(ns - 1) = std::max_element(row, row + nc) - row;
+    for (auto t = ns - 2; t >= 0; --t) {
+      auto max = std::make_pair(-std::numeric_limits<double>::infinity(), 0);
+      for (auto i = 0; i < nc; ++i) {
+        max = std::max(max, {viterbi_lattice(t, i) + log_transmat(i, prev), i});
+      }
+      state_sequence(t) = prev = max.second;
     }
-    state_sequence(t) = prev = max.second;
   }
-  return {log_prob, state_sequence_};
+  return {viterbi_lattice(ns - 1, state_sequence(ns - 1)), state_sequence_};
 }
 
 PYBIND11_MODULE(_hmmc, m) {