[med-svn] [Git][med-team/python-hmmlearn][master] 3 commits: Replace my GIL hack with a proper patch from upstream.

Michael R. Crusoe (@crusoe) gitlab at salsa.debian.org
Mon Oct 7 09:46:13 BST 2024



Michael R. Crusoe pushed to branch master at Debian Med / python-hmmlearn


Commits:
1d47d537 by Michael R. Crusoe at 2024-10-07T10:00:30+02:00
Replace my GIL hack with a proper patch from upstream.

- - - - -
aae16302 by Michael R. Crusoe at 2024-10-07T10:39:28+02:00
d/control: removed duplicated word from the description

- - - - -
7fbe6a14 by Michael R. Crusoe at 2024-10-07T10:45:23+02:00
relase 0.3.2-2

- - - - -


3 changed files:

- debian/changelog
- debian/control
- debian/patches/gil_fix


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,11 @@
+python-hmmlearn (0.3.2-2) unstable; urgency=medium
+
+  * Team upload.
+  * Replace my GIL hack with a proper patch from upstream.
+  * d/control: removed duplicated word from the description
+
+ -- Michael R. Crusoe <crusoe at debian.org>  Mon, 07 Oct 2024 10:45:05 +0200
+
 python-hmmlearn (0.3.2-1) unstable; urgency=medium
 
   * Team upload.


=====================================
debian/control
=====================================
@@ -31,5 +31,5 @@ Recommends: ${python3:Recommends},
             python3-sklearn
 Description: unsupervised learning and inference of Hidden Markov Models
  Hmmlearn is a set of algorithms for unsupervised learning and inference
- of Hidden Markov Models. For supervised learning learning of HMMs and
+ of Hidden Markov Models. For supervised learning of HMMs and
  similar models see seqlearn.


=====================================
debian/patches/gil_fix
=====================================
@@ -1,25 +1,159 @@
-From: Michael R. Crusoe <crusoe at debian.org>
-Subject: hack for GIL bug
-Forwarded: https://github.com/hmmlearn/hmmlearn/pull/564
-
-Fixes the follow error and many similar to it
-
-    def _fit_scaling(self, X):
-        frameprob = self._compute_subnorm_likelihood(X)
->       logprob, fwdlattice, scaling_factors = _hmmc.forward_scaling(
-            self.startprob_subnorm_, self.transmat_subnorm_, frameprob)
-E       RuntimeError: pybind11::handle::inc_ref() PyGILState_Check() failure.
-
-hmmlearn/base.py:1103: RuntimeError
------------------------------ Captured stderr call -----------------------------
-pybind11::handle::inc_ref() is being called while the GIL is either not held or invalid. Please see https://pybind11.readthedocs.io/en/stable/advanced/misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.
-If you are convinced there is no bug in your code, you can #define PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF to disable this check. In that case you have to ensure this #define is consistently used for all translation units linked into a given pybind11 extension, otherwise there will be ODR violations. The failing pybind11::handle::inc_ref() call was triggered on a numpy.ndarray object.
+From 38b559464e5f8212225acc4c8aa213732ce8f6e8 Mon Sep 17 00:00:00 2001
+From: Antony Lee <anntzer.lee at 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
-@@ -1,3 +1,4 @@
-+#define PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF
- #include <pybind11/pybind11.h>
- #include <pybind11/numpy.h>
- #include <cfenv>
+@@ -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) {



View it on GitLab: https://salsa.debian.org/med-team/python-hmmlearn/-/compare/25a3b7382fefa24967c498427535b162121cd91a...7fbe6a149579bf7e8f3dd7370a6f363dda16dcee

-- 
View it on GitLab: https://salsa.debian.org/med-team/python-hmmlearn/-/compare/25a3b7382fefa24967c498427535b162121cd91a...7fbe6a149579bf7e8f3dd7370a6f363dda16dcee
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20241007/0e4214b3/attachment-0001.htm>


More information about the debian-med-commit mailing list