hmm.html 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>Hidden Markov Models &#8212; State Space Models: A Modern Approach</title>
  7. <link href="../../_static/css/theme.css" rel="stylesheet">
  8. <link href="../../_static/css/index.ff1ffe594081f20da1ef19478df9384b.css" rel="stylesheet">
  9. <link rel="stylesheet"
  10. href="../../_static/vendor/fontawesome/5.13.0/css/all.min.css">
  11. <link rel="preload" as="font" type="font/woff2" crossorigin
  12. href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-solid-900.woff2">
  13. <link rel="preload" as="font" type="font/woff2" crossorigin
  14. href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-brands-400.woff2">
  15. <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
  16. <link rel="stylesheet" type="text/css" href="../../_static/sphinx-book-theme.css?digest=c3fdc42140077d1ad13ad2f1588a4309" />
  17. <link rel="stylesheet" type="text/css" href="../../_static/togglebutton.css" />
  18. <link rel="stylesheet" type="text/css" href="../../_static/copybutton.css" />
  19. <link rel="stylesheet" type="text/css" href="../../_static/mystnb.css" />
  20. <link rel="stylesheet" type="text/css" href="../../_static/sphinx-thebe.css" />
  21. <link rel="stylesheet" type="text/css" href="../../_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css" />
  22. <link rel="stylesheet" type="text/css" href="../../_static/panels-variables.06eb56fa6e07937060861dad626602ad.css" />
  23. <link rel="preload" as="script" href="../../_static/js/index.be7d3bbb2ef33a8344ce.js">
  24. <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
  25. <script src="../../_static/jquery.js"></script>
  26. <script src="../../_static/underscore.js"></script>
  27. <script src="../../_static/doctools.js"></script>
  28. <script src="../../_static/clipboard.min.js"></script>
  29. <script src="../../_static/copybutton.js"></script>
  30. <script>let toggleHintShow = 'Click to show';</script>
  31. <script>let toggleHintHide = 'Click to hide';</script>
  32. <script>let toggleOpenOnPrint = 'true';</script>
  33. <script src="../../_static/togglebutton.js"></script>
  34. <script>var togglebuttonSelector = '.toggle, .admonition.dropdown, .tag_hide_input div.cell_input, .tag_hide-input div.cell_input, .tag_hide_output div.cell_output, .tag_hide-output div.cell_output, .tag_hide_cell.cell, .tag_hide-cell.cell';</script>
  35. <script src="../../_static/sphinx-book-theme.d59cb220de22ca1c485ebbdc042f0030.js"></script>
  36. <script>const THEBE_JS_URL = "https://unpkg.com/thebe@0.8.2/lib/index.js"
  37. const thebe_selector = ".thebe,.cell"
  38. const thebe_selector_input = "pre"
  39. const thebe_selector_output = ".output, .cell_output"
  40. </script>
  41. <script async="async" src="../../_static/sphinx-thebe.js"></script>
  42. <link rel="index" title="Index" href="../../genindex.html" />
  43. <link rel="search" title="Search" href="../../search.html" />
  44. <link rel="next" title="Hidden Semi-Markov Models" href="hsmm.html" />
  45. <link rel="prev" title="Introduction" href="ssm_index.html" />
  46. <meta name="viewport" content="width=device-width, initial-scale=1" />
  47. <meta name="docsearch:language" content="None">
  48. <!-- Google Analytics -->
  49. </head>
  50. <body data-spy="scroll" data-target="#bd-toc-nav" data-offset="80">
  51. <div class="container-fluid" id="banner"></div>
  52. <div class="container-xl">
  53. <div class="row">
  54. <div class="col-12 col-md-3 bd-sidebar site-navigation show" id="site-navigation">
  55. <div class="navbar-brand-box">
  56. <a class="navbar-brand text-wrap" href="../../index.html">
  57. <h1 class="site-logo" id="site-title">State Space Models: A Modern Approach</h1>
  58. </a>
  59. </div><form class="bd-search d-flex align-items-center" action="../../search.html" method="get">
  60. <i class="icon fas fa-search"></i>
  61. <input type="search" class="form-control" name="q" id="search-input" placeholder="Search this book..." aria-label="Search this book..." autocomplete="off" >
  62. </form><nav class="bd-links" id="bd-docs-nav" aria-label="Main">
  63. <div class="bd-toc-item active">
  64. <ul class="nav bd-sidenav">
  65. <li class="toctree-l1">
  66. <a class="reference internal" href="../../root.html">
  67. State Space Models: A Modern Approach
  68. </a>
  69. </li>
  70. </ul>
  71. <ul class="current nav bd-sidenav">
  72. <li class="toctree-l1">
  73. <a class="reference internal" href="../scratch.html">
  74. Scratchpad
  75. </a>
  76. </li>
  77. <li class="toctree-l1 current active has-children">
  78. <a class="reference internal" href="ssm_index.html">
  79. Introduction
  80. </a>
  81. <input checked="" class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" type="checkbox"/>
  82. <label for="toctree-checkbox-1">
  83. <i class="fas fa-chevron-down">
  84. </i>
  85. </label>
  86. <ul class="current">
  87. <li class="toctree-l2 current active">
  88. <a class="current reference internal" href="#">
  89. Hidden Markov Models
  90. </a>
  91. </li>
  92. <li class="toctree-l2">
  93. <a class="reference internal" href="hsmm.html">
  94. Hidden Semi-Markov Models
  95. </a>
  96. </li>
  97. <li class="toctree-l2">
  98. <a class="reference internal" href="lgssm.html">
  99. Linear Gaussian SSMs
  100. </a>
  101. </li>
  102. <li class="toctree-l2">
  103. <a class="reference internal" href="nonlin.html">
  104. Non-Linear Gaussian SSMs
  105. </a>
  106. </li>
  107. <li class="toctree-l2">
  108. <a class="reference internal" href="nongauss.html">
  109. Non-Gaussian SSMs
  110. </a>
  111. </li>
  112. <li class="toctree-l2">
  113. <a class="reference internal" href="switching.html">
  114. Switching SSMs
  115. </a>
  116. </li>
  117. <li class="toctree-l2">
  118. <a class="reference internal" href="deep.html">
  119. Deep SSMs
  120. </a>
  121. </li>
  122. <li class="toctree-l2">
  123. <a class="reference internal" href="rnn.html">
  124. Recurrent Neural Networks
  125. </a>
  126. </li>
  127. </ul>
  128. </li>
  129. <li class="toctree-l1 has-children">
  130. <a class="reference internal" href="../hmm/hmm_index.html">
  131. Inference in discrete SSMs
  132. </a>
  133. <input class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" type="checkbox"/>
  134. <label for="toctree-checkbox-2">
  135. <i class="fas fa-chevron-down">
  136. </i>
  137. </label>
  138. <ul>
  139. <li class="toctree-l2">
  140. <a class="reference internal" href="../hmm/hmm_filter.html">
  141. HMM filtering (forwards algorithm)
  142. </a>
  143. </li>
  144. <li class="toctree-l2">
  145. <a class="reference internal" href="../hmm/hmm_smoother.html">
  146. HMM smoothing (forwards-backwards algorithm)
  147. </a>
  148. </li>
  149. <li class="toctree-l2">
  150. <a class="reference internal" href="../hmm/hmm_viterbi.html">
  151. Viterbi algorithm
  152. </a>
  153. </li>
  154. <li class="toctree-l2">
  155. <a class="reference internal" href="../hmm/hmm_parallel.html">
  156. Parallel HMM smoothing
  157. </a>
  158. </li>
  159. <li class="toctree-l2">
  160. <a class="reference internal" href="../hmm/hmm_sampling.html">
  161. Forwards-filtering backwards-sampling algorithm
  162. </a>
  163. </li>
  164. </ul>
  165. </li>
  166. <li class="toctree-l1 has-children">
  167. <a class="reference internal" href="../lgssm/lgssm_index.html">
  168. Inference in linear-Gaussian SSMs
  169. </a>
  170. <input class="toctree-checkbox" id="toctree-checkbox-3" name="toctree-checkbox-3" type="checkbox"/>
  171. <label for="toctree-checkbox-3">
  172. <i class="fas fa-chevron-down">
  173. </i>
  174. </label>
  175. <ul>
  176. <li class="toctree-l2">
  177. <a class="reference internal" href="../lgssm/kalman_filter.html">
  178. Kalman filtering
  179. </a>
  180. </li>
  181. <li class="toctree-l2">
  182. <a class="reference internal" href="../lgssm/kalman_smoother.html">
  183. Kalman (RTS) smoother
  184. </a>
  185. </li>
  186. <li class="toctree-l2">
  187. <a class="reference internal" href="../lgssm/kalman_parallel.html">
  188. Parallel Kalman Smoother
  189. </a>
  190. </li>
  191. <li class="toctree-l2">
  192. <a class="reference internal" href="../lgssm/kalman_sampling.html">
  193. Forwards-filtering backwards sampling
  194. </a>
  195. </li>
  196. </ul>
  197. </li>
  198. <li class="toctree-l1 has-children">
  199. <a class="reference internal" href="../extended/extended_index.html">
  200. Extended (linearized) methods
  201. </a>
  202. <input class="toctree-checkbox" id="toctree-checkbox-4" name="toctree-checkbox-4" type="checkbox"/>
  203. <label for="toctree-checkbox-4">
  204. <i class="fas fa-chevron-down">
  205. </i>
  206. </label>
  207. <ul>
  208. <li class="toctree-l2">
  209. <a class="reference internal" href="../extended/extended_filter.html">
  210. Extended Kalman filtering
  211. </a>
  212. </li>
  213. <li class="toctree-l2">
  214. <a class="reference internal" href="../extended/extended_smoother.html">
  215. Extended Kalman smoother
  216. </a>
  217. </li>
  218. <li class="toctree-l2">
  219. <a class="reference internal" href="../extended/extended_parallel.html">
  220. Parallel extended Kalman smoothing
  221. </a>
  222. </li>
  223. </ul>
  224. </li>
  225. <li class="toctree-l1 has-children">
  226. <a class="reference internal" href="../unscented/unscented_index.html">
  227. Unscented methods
  228. </a>
  229. <input class="toctree-checkbox" id="toctree-checkbox-5" name="toctree-checkbox-5" type="checkbox"/>
  230. <label for="toctree-checkbox-5">
  231. <i class="fas fa-chevron-down">
  232. </i>
  233. </label>
  234. <ul>
  235. <li class="toctree-l2">
  236. <a class="reference internal" href="../unscented/unscented_filter.html">
  237. Unscented filtering
  238. </a>
  239. </li>
  240. <li class="toctree-l2">
  241. <a class="reference internal" href="../unscented/unscented_smoother.html">
  242. Unscented smoothing
  243. </a>
  244. </li>
  245. </ul>
  246. </li>
  247. <li class="toctree-l1">
  248. <a class="reference internal" href="../quadrature/quadrature_index.html">
  249. Quadrature and cubature methods
  250. </a>
  251. </li>
  252. <li class="toctree-l1">
  253. <a class="reference internal" href="../postlin/postlin_index.html">
  254. Posterior linearization
  255. </a>
  256. </li>
  257. <li class="toctree-l1">
  258. <a class="reference internal" href="../adf/adf_index.html">
  259. Assumed Density Filtering
  260. </a>
  261. </li>
  262. <li class="toctree-l1">
  263. <a class="reference internal" href="../vi/vi_index.html">
  264. Variational inference
  265. </a>
  266. </li>
  267. <li class="toctree-l1">
  268. <a class="reference internal" href="../pf/pf_index.html">
  269. Particle filtering
  270. </a>
  271. </li>
  272. <li class="toctree-l1">
  273. <a class="reference internal" href="../smc/smc_index.html">
  274. Sequential Monte Carlo
  275. </a>
  276. </li>
  277. <li class="toctree-l1 has-children">
  278. <a class="reference internal" href="../learning/learning_index.html">
  279. Offline parameter estimation (learning)
  280. </a>
  281. <input class="toctree-checkbox" id="toctree-checkbox-6" name="toctree-checkbox-6" type="checkbox"/>
  282. <label for="toctree-checkbox-6">
  283. <i class="fas fa-chevron-down">
  284. </i>
  285. </label>
  286. <ul>
  287. <li class="toctree-l2">
  288. <a class="reference internal" href="../learning/em.html">
  289. Expectation Maximization (EM)
  290. </a>
  291. </li>
  292. <li class="toctree-l2">
  293. <a class="reference internal" href="../learning/sgd.html">
  294. Stochastic Gradient Descent (SGD)
  295. </a>
  296. </li>
  297. <li class="toctree-l2">
  298. <a class="reference internal" href="../learning/vb.html">
  299. Variational Bayes (VB)
  300. </a>
  301. </li>
  302. <li class="toctree-l2">
  303. <a class="reference internal" href="../learning/mcmc.html">
  304. Markov Chain Monte Carlo (MCMC)
  305. </a>
  306. </li>
  307. </ul>
  308. </li>
  309. <li class="toctree-l1">
  310. <a class="reference internal" href="../tracking/tracking_index.html">
  311. Multi-target tracking
  312. </a>
  313. </li>
  314. <li class="toctree-l1">
  315. <a class="reference internal" href="../ensemble/ensemble_index.html">
  316. Data assimilation using Ensemble Kalman filter
  317. </a>
  318. </li>
  319. <li class="toctree-l1">
  320. <a class="reference internal" href="../bnp/bnp_index.html">
  321. Bayesian non-parametric SSMs
  322. </a>
  323. </li>
  324. <li class="toctree-l1">
  325. <a class="reference internal" href="../changepoint/changepoint_index.html">
  326. Changepoint detection
  327. </a>
  328. </li>
  329. <li class="toctree-l1">
  330. <a class="reference internal" href="../timeseries/timeseries_index.html">
  331. Timeseries forecasting
  332. </a>
  333. </li>
  334. <li class="toctree-l1">
  335. <a class="reference internal" href="../gp/gp_index.html">
  336. Markovian Gaussian processes
  337. </a>
  338. </li>
  339. <li class="toctree-l1">
  340. <a class="reference internal" href="../ode/ode_index.html">
  341. Differential equations and SSMs
  342. </a>
  343. </li>
  344. <li class="toctree-l1">
  345. <a class="reference internal" href="../control/control_index.html">
  346. Optimal control
  347. </a>
  348. </li>
  349. <li class="toctree-l1">
  350. <a class="reference internal" href="../../bib.html">
  351. Bibliography
  352. </a>
  353. </li>
  354. </ul>
  355. </div>
  356. </nav> <!-- To handle the deprecated key -->
  357. <div class="navbar_extra_footer">
  358. Powered by <a href="https://jupyterbook.org">Jupyter Book</a>
  359. </div>
  360. </div>
  361. <main class="col py-md-3 pl-md-4 bd-content overflow-auto" role="main">
  362. <div class="topbar container-xl fixed-top">
  363. <div class="topbar-contents row">
  364. <div class="col-12 col-md-3 bd-topbar-whitespace site-navigation show"></div>
  365. <div class="col pl-md-4 topbar-main">
  366. <button id="navbar-toggler" class="navbar-toggler ml-0" type="button" data-toggle="collapse"
  367. data-toggle="tooltip" data-placement="bottom" data-target=".site-navigation" aria-controls="navbar-menu"
  368. aria-expanded="true" aria-label="Toggle navigation" aria-controls="site-navigation"
  369. title="Toggle navigation" data-toggle="tooltip" data-placement="left">
  370. <i class="fas fa-bars"></i>
  371. <i class="fas fa-arrow-left"></i>
  372. <i class="fas fa-arrow-up"></i>
  373. </button>
  374. <div class="dropdown-buttons-trigger">
  375. <button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn" aria-label="Download this page"><i
  376. class="fas fa-download"></i></button>
  377. <div class="dropdown-buttons">
  378. <!-- ipynb file if we had a myst markdown file -->
  379. <!-- Download raw file -->
  380. <a class="dropdown-buttons" href="../../_sources/chapters/ssm/hmm.ipynb"><button type="button"
  381. class="btn btn-secondary topbarbtn" title="Download source file" data-toggle="tooltip"
  382. data-placement="left">.ipynb</button></a>
  383. <!-- Download PDF via print -->
  384. <button type="button" id="download-print" class="btn btn-secondary topbarbtn" title="Print to PDF"
  385. onclick="printPdf(this)" data-toggle="tooltip" data-placement="left">.pdf</button>
  386. </div>
  387. </div>
  388. <!-- Source interaction buttons -->
  389. <div class="dropdown-buttons-trigger">
  390. <button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn"
  391. aria-label="Connect with source repository"><i class="fab fa-github"></i></button>
  392. <div class="dropdown-buttons sourcebuttons">
  393. <a class="repository-button"
  394. href="https://github.com/ssm-jax/ssm-book"><button type="button" class="btn btn-secondary topbarbtn"
  395. data-toggle="tooltip" data-placement="left" title="Source repository"><i
  396. class="fab fa-github"></i>repository</button></a>
  397. <a class="issues-button"
  398. href="https://github.com/ssm-jax/ssm-book/issues/new?title=Issue%20on%20page%20%2Fchapters/ssm/hmm.html&body=Your%20issue%20content%20here."><button
  399. type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip" data-placement="left"
  400. title="Open an issue"><i class="fas fa-lightbulb"></i>open issue</button></a>
  401. </div>
  402. </div>
  403. <!-- Full screen (wrap in <a> to have style consistency -->
  404. <a class="full-screen-button"><button type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip"
  405. data-placement="bottom" onclick="toggleFullScreen()" aria-label="Fullscreen mode"
  406. title="Fullscreen mode"><i
  407. class="fas fa-expand"></i></button></a>
  408. <!-- Launch buttons -->
  409. <div class="dropdown-buttons-trigger">
  410. <button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn"
  411. aria-label="Launch interactive content"><i class="fas fa-rocket"></i></button>
  412. <div class="dropdown-buttons">
  413. <a class="binder-button" href="https://mybinder.org/v2/gh/ssm-jax/ssm-book/main?urlpath=tree/chapters/ssm/hmm.ipynb"><button type="button"
  414. class="btn btn-secondary topbarbtn" title="Launch Binder" data-toggle="tooltip"
  415. data-placement="left"><img class="binder-button-logo"
  416. src="../../_static/images/logo_binder.svg"
  417. alt="Interact on binder">Binder</button></a>
  418. <a class="colab-button" href="https://colab.research.google.com/github/ssm-jax/ssm-book/blob/main/chapters/ssm/hmm.ipynb"><button type="button" class="btn btn-secondary topbarbtn"
  419. title="Launch Colab" data-toggle="tooltip" data-placement="left"><img class="colab-button-logo"
  420. src="../../_static/images/logo_colab.png"
  421. alt="Interact on Colab">Colab</button></a>
  422. </div>
  423. </div>
  424. </div>
  425. <!-- Table of contents -->
  426. <div class="d-none d-md-block col-md-2 bd-toc show noprint">
  427. <div class="tocsection onthispage pt-5 pb-3">
  428. <i class="fas fa-list"></i> Contents
  429. </div>
  430. <nav id="bd-toc-nav" aria-label="Page">
  431. <ul class="visible nav section-nav flex-column">
  432. <li class="toc-h2 nav-item toc-entry">
  433. <a class="reference internal nav-link" href="#boilerplate">
  434. Boilerplate
  435. </a>
  436. </li>
  437. <li class="toc-h2 nav-item toc-entry">
  438. <a class="reference internal nav-link" href="#utility-code">
  439. Utility code
  440. </a>
  441. </li>
  442. <li class="toc-h2 nav-item toc-entry">
  443. <a class="reference internal nav-link" href="#example-casino-hmm">
  444. Example: Casino HMM
  445. </a>
  446. </li>
  447. <li class="toc-h2 nav-item toc-entry">
  448. <a class="reference internal nav-link" href="#sampling-from-the-joint">
  449. Sampling from the joint
  450. </a>
  451. <ul class="nav section-nav flex-column">
  452. <li class="toc-h3 nav-item toc-entry">
  453. <a class="reference internal nav-link" href="#numpy-version">
  454. Numpy version
  455. </a>
  456. </li>
  457. <li class="toc-h3 nav-item toc-entry">
  458. <a class="reference internal nav-link" href="#jax-version">
  459. JAX version
  460. </a>
  461. </li>
  462. <li class="toc-h3 nav-item toc-entry">
  463. <a class="reference internal nav-link" href="#check-correctness-by-computing-empirical-pairwise-statistics">
  464. Check correctness by computing empirical pairwise statistics
  465. </a>
  466. </li>
  467. </ul>
  468. </li>
  469. </ul>
  470. </nav>
  471. </div>
  472. </div>
  473. </div>
  474. <div id="main-content" class="row">
  475. <div class="col-12 col-md-9 pl-md-3 pr-md-0">
  476. <!-- Table of contents that is only displayed when printing the page -->
  477. <div id="jb-print-docs-body" class="onlyprint">
  478. <h1>Hidden Markov Models</h1>
  479. <!-- Table of contents -->
  480. <div id="print-main-content">
  481. <div id="jb-print-toc">
  482. <div>
  483. <h2> Contents </h2>
  484. </div>
  485. <nav aria-label="Page">
  486. <ul class="visible nav section-nav flex-column">
  487. <li class="toc-h2 nav-item toc-entry">
  488. <a class="reference internal nav-link" href="#boilerplate">
  489. Boilerplate
  490. </a>
  491. </li>
  492. <li class="toc-h2 nav-item toc-entry">
  493. <a class="reference internal nav-link" href="#utility-code">
  494. Utility code
  495. </a>
  496. </li>
  497. <li class="toc-h2 nav-item toc-entry">
  498. <a class="reference internal nav-link" href="#example-casino-hmm">
  499. Example: Casino HMM
  500. </a>
  501. </li>
  502. <li class="toc-h2 nav-item toc-entry">
  503. <a class="reference internal nav-link" href="#sampling-from-the-joint">
  504. Sampling from the joint
  505. </a>
  506. <ul class="nav section-nav flex-column">
  507. <li class="toc-h3 nav-item toc-entry">
  508. <a class="reference internal nav-link" href="#numpy-version">
  509. Numpy version
  510. </a>
  511. </li>
  512. <li class="toc-h3 nav-item toc-entry">
  513. <a class="reference internal nav-link" href="#jax-version">
  514. JAX version
  515. </a>
  516. </li>
  517. <li class="toc-h3 nav-item toc-entry">
  518. <a class="reference internal nav-link" href="#check-correctness-by-computing-empirical-pairwise-statistics">
  519. Check correctness by computing empirical pairwise statistics
  520. </a>
  521. </li>
  522. </ul>
  523. </li>
  524. </ul>
  525. </nav>
  526. </div>
  527. </div>
  528. </div>
  529. <div>
  530. <div class="tex2jax_ignore mathjax_ignore section" id="hidden-markov-models">
  531. <span id="sec-hmm-ex"></span><h1>Hidden Markov Models<a class="headerlink" href="#hidden-markov-models" title="Permalink to this headline">¶</a></h1>
  532. <p>In this section, we introduce Hidden Markov Models (HMMs).</p>
  533. <div class="section" id="boilerplate">
  534. <h2>Boilerplate<a class="headerlink" href="#boilerplate" title="Permalink to this headline">¶</a></h2>
  535. <div class="cell docutils container">
  536. <div class="cell_input docutils container">
  537. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install necessary libraries</span>
  538. <span class="k">try</span><span class="p">:</span>
  539. <span class="kn">import</span> <span class="nn">jax</span>
  540. <span class="k">except</span><span class="p">:</span>
  541. <span class="c1"># For cuda version, see https://github.com/google/jax#installation</span>
  542. <span class="o">%</span><span class="k">pip</span> install --upgrade &quot;jax[cpu]&quot;
  543. <span class="kn">import</span> <span class="nn">jax</span>
  544. <span class="k">try</span><span class="p">:</span>
  545. <span class="kn">import</span> <span class="nn">jsl</span>
  546. <span class="k">except</span><span class="p">:</span>
  547. <span class="o">%</span><span class="k">pip</span> install git+https://github.com/probml/jsl
  548. <span class="kn">import</span> <span class="nn">jsl</span>
  549. <span class="k">try</span><span class="p">:</span>
  550. <span class="kn">import</span> <span class="nn">rich</span>
  551. <span class="k">except</span><span class="p">:</span>
  552. <span class="o">%</span><span class="k">pip</span> install rich
  553. <span class="kn">import</span> <span class="nn">rich</span>
  554. </pre></div>
  555. </div>
  556. </div>
  557. </div>
  558. <div class="cell docutils container">
  559. <div class="cell_input docutils container">
  560. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Import standard libraries</span>
  561. <span class="kn">import</span> <span class="nn">abc</span>
  562. <span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
  563. <span class="kn">import</span> <span class="nn">functools</span>
  564. <span class="kn">import</span> <span class="nn">itertools</span>
  565. <span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">NamedTuple</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Union</span><span class="p">,</span> <span class="n">Tuple</span>
  566. <span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
  567. <span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
  568. <span class="kn">import</span> <span class="nn">jax</span>
  569. <span class="kn">import</span> <span class="nn">jax.numpy</span> <span class="k">as</span> <span class="nn">jnp</span>
  570. <span class="kn">from</span> <span class="nn">jax</span> <span class="kn">import</span> <span class="n">lax</span><span class="p">,</span> <span class="n">vmap</span><span class="p">,</span> <span class="n">jit</span><span class="p">,</span> <span class="n">grad</span>
  571. <span class="kn">from</span> <span class="nn">jax.scipy.special</span> <span class="kn">import</span> <span class="n">logit</span>
  572. <span class="kn">from</span> <span class="nn">jax.nn</span> <span class="kn">import</span> <span class="n">softmax</span>
  573. <span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">partial</span>
  574. <span class="kn">from</span> <span class="nn">jax.random</span> <span class="kn">import</span> <span class="n">PRNGKey</span><span class="p">,</span> <span class="n">split</span>
  575. <span class="kn">import</span> <span class="nn">inspect</span>
  576. <span class="kn">import</span> <span class="nn">inspect</span> <span class="k">as</span> <span class="nn">py_inspect</span>
  577. <span class="kn">from</span> <span class="nn">rich</span> <span class="kn">import</span> <span class="n">inspect</span> <span class="k">as</span> <span class="n">r_inspect</span>
  578. <span class="kn">from</span> <span class="nn">rich</span> <span class="kn">import</span> <span class="nb">print</span> <span class="k">as</span> <span class="n">r_print</span>
  579. <span class="k">def</span> <span class="nf">print_source</span><span class="p">(</span><span class="n">fname</span><span class="p">):</span>
  580. <span class="n">r_print</span><span class="p">(</span><span class="n">py_inspect</span><span class="o">.</span><span class="n">getsource</span><span class="p">(</span><span class="n">fname</span><span class="p">))</span>
  581. </pre></div>
  582. </div>
  583. </div>
  584. </div>
  585. </div>
  586. <div class="section" id="utility-code">
  587. <h2>Utility code<a class="headerlink" href="#utility-code" title="Permalink to this headline">¶</a></h2>
  588. <div class="cell docutils container">
  589. <div class="cell_input docutils container">
  590. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">normalize</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">eps</span><span class="o">=</span><span class="mf">1e-15</span><span class="p">):</span>
  591. <span class="sd">&#39;&#39;&#39;</span>
  592. <span class="sd"> Normalizes the values within the axis in a way that they sum up to 1.</span>
  593. <span class="sd"> Parameters</span>
  594. <span class="sd"> ----------</span>
  595. <span class="sd"> u : array</span>
  596. <span class="sd"> axis : int</span>
  597. <span class="sd"> eps : float</span>
  598. <span class="sd"> Threshold for the alpha values</span>
  599. <span class="sd"> Returns</span>
  600. <span class="sd"> -------</span>
  601. <span class="sd"> * array</span>
  602. <span class="sd"> Normalized version of the given matrix</span>
  603. <span class="sd"> * array(seq_len, n_hidden) :</span>
  604. <span class="sd"> The values of the normalizer</span>
  605. <span class="sd"> &#39;&#39;&#39;</span>
  606. <span class="n">u</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">u</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">jnp</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">u</span> <span class="o">&lt;</span> <span class="n">eps</span><span class="p">,</span> <span class="n">eps</span><span class="p">,</span> <span class="n">u</span><span class="p">))</span>
  607. <span class="n">c</span> <span class="o">=</span> <span class="n">u</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="n">axis</span><span class="p">)</span>
  608. <span class="n">c</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">c</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span>
  609. <span class="k">return</span> <span class="n">u</span> <span class="o">/</span> <span class="n">c</span><span class="p">,</span> <span class="n">c</span>
  610. </pre></div>
  611. </div>
  612. </div>
  613. </div>
  614. </div>
  615. <div class="section" id="example-casino-hmm">
  616. <span id="sec-casino-ex"></span><h2>Example: Casino HMM<a class="headerlink" href="#example-casino-hmm" title="Permalink to this headline">¶</a></h2>
  617. <p>We first create the “Ocassionally dishonest casino” model from <span id="id1">[<a class="reference internal" href="../../bib.html#id3" title="R. Durbin, S. Eddy, A. Krogh, and G. Mitchison. Biological Sequence Analysis: Probabilistic Models of Proteins and Nucleic Acids. Cambridge University Press, 1998.">DEKM98</a>]</span>.</p>
  618. <div class="figure align-default" id="casino-fig">
  619. <a class="reference internal image-reference" href="../../_images/casino.png"><img alt="../../_images/casino.png" src="../../_images/casino.png" style="width: 208.5px; height: 142.5px;" /></a>
  620. <p class="caption"><span class="caption-number">Fig. 3 </span><span class="caption-text">Illustration of the casino HMM.</span><a class="headerlink" href="#casino-fig" title="Permalink to this image">¶</a></p>
  621. </div>
  622. <p>There are 2 hidden states, each of which emit 6 possible observations.</p>
  623. <div class="cell docutils container">
  624. <div class="cell_input docutils container">
  625. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># state transition matrix</span>
  626. <span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span>
  627. <span class="p">[</span><span class="mf">0.95</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">],</span>
  628. <span class="p">[</span><span class="mf">0.10</span><span class="p">,</span> <span class="mf">0.90</span><span class="p">]</span>
  629. <span class="p">])</span>
  630. <span class="c1"># observation matrix</span>
  631. <span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span>
  632. <span class="p">[</span><span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">],</span> <span class="c1"># fair die</span>
  633. <span class="p">[</span><span class="mi">1</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="o">/</span><span class="mi">10</span><span class="p">]</span> <span class="c1"># loaded die</span>
  634. <span class="p">])</span>
  635. <span class="n">pi</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">normalize</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]))</span>
  636. <span class="n">pi</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">pi</span><span class="p">)</span>
  637. <span class="p">(</span><span class="n">nstates</span><span class="p">,</span> <span class="n">nobs</span><span class="p">)</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">shape</span><span class="p">(</span><span class="n">B</span><span class="p">)</span>
  638. </pre></div>
  639. </div>
  640. </div>
  641. <div class="cell_output docutils container">
  642. <div class="output stderr highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
  643. </pre></div>
  644. </div>
  645. </div>
  646. </div>
  647. <p>Let’s make a little data structure to store all the parameters.
  648. We use NamedTuple rather than dataclass, since we assume these are immutable.
  649. (Also, standard python dataclass does not work well with JAX, which requires parameters to be
  650. pytrees, as discussed in <a class="reference external" href="https://github.com/google/jax/issues/2371">https://github.com/google/jax/issues/2371</a>).</p>
  651. <div class="cell docutils container">
  652. <div class="cell_input docutils container">
  653. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">Array</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">,</span> <span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">]</span>
  654. <span class="k">class</span> <span class="nc">HMM</span><span class="p">(</span><span class="n">NamedTuple</span><span class="p">):</span>
  655. <span class="n">trans_mat</span><span class="p">:</span> <span class="n">Array</span> <span class="c1"># A : (n_states, n_states)</span>
  656. <span class="n">obs_mat</span><span class="p">:</span> <span class="n">Array</span> <span class="c1"># B : (n_states, n_obs)</span>
  657. <span class="n">init_dist</span><span class="p">:</span> <span class="n">Array</span> <span class="c1"># pi : (n_states)</span>
  658. <span class="n">params_np</span> <span class="o">=</span> <span class="n">HMM</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">pi</span><span class="p">)</span>
  659. <span class="nb">print</span><span class="p">(</span><span class="n">params_np</span><span class="p">)</span>
  660. <span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">params_np</span><span class="o">.</span><span class="n">trans_mat</span><span class="p">))</span>
  661. <span class="n">params</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">tree_map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">params_np</span><span class="p">)</span>
  662. <span class="nb">print</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
  663. <span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">trans_mat</span><span class="p">))</span>
  664. </pre></div>
  665. </div>
  666. </div>
  667. <div class="cell_output docutils container">
  668. <div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>HMM(trans_mat=array([[0.95, 0.05],
  669. [0.1 , 0.9 ]]), obs_mat=array([[0.16666667, 0.16666667, 0.16666667, 0.16666667, 0.16666667,
  670. 0.16666667],
  671. [0.1 , 0.1 , 0.1 , 0.1 , 0.1 ,
  672. 0.5 ]]), init_dist=array([0.5, 0.5], dtype=float32))
  673. &lt;class &#39;numpy.ndarray&#39;&gt;
  674. HMM(trans_mat=DeviceArray([[0.95, 0.05],
  675. [0.1 , 0.9 ]], dtype=float32), obs_mat=DeviceArray([[0.16666667, 0.16666667, 0.16666667, 0.16666667, 0.16666667,
  676. 0.16666667],
  677. [0.1 , 0.1 , 0.1 , 0.1 , 0.1 ,
  678. 0.5 ]], dtype=float32), init_dist=DeviceArray([0.5, 0.5], dtype=float32))
  679. &lt;class &#39;jaxlib.xla_extension.DeviceArray&#39;&gt;
  680. </pre></div>
  681. </div>
  682. </div>
  683. </div>
  684. </div>
  685. <div class="section" id="sampling-from-the-joint">
  686. <h2>Sampling from the joint<a class="headerlink" href="#sampling-from-the-joint" title="Permalink to this headline">¶</a></h2>
  687. <p>Let’s write code to sample from this model.</p>
  688. <div class="section" id="numpy-version">
  689. <h3>Numpy version<a class="headerlink" href="#numpy-version" title="Permalink to this headline">¶</a></h3>
  690. <p>First we code it in numpy using a for loop.</p>
  691. <div class="cell docutils container">
  692. <div class="cell_input docutils container">
  693. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hmm_sample_np</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
  694. <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="n">random_state</span><span class="p">)</span>
  695. <span class="n">trans_mat</span><span class="p">,</span> <span class="n">obs_mat</span><span class="p">,</span> <span class="n">init_dist</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">trans_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">obs_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">init_dist</span>
  696. <span class="n">n_states</span><span class="p">,</span> <span class="n">n_obs</span> <span class="o">=</span> <span class="n">obs_mat</span><span class="o">.</span><span class="n">shape</span>
  697. <span class="n">state_seq</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">seq_len</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
  698. <span class="n">obs_seq</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">seq_len</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
  699. <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">seq_len</span><span class="p">):</span>
  700. <span class="k">if</span> <span class="n">t</span><span class="o">==</span><span class="mi">0</span><span class="p">:</span>
  701. <span class="n">zt</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">init_dist</span><span class="p">)</span>
  702. <span class="k">else</span><span class="p">:</span>
  703. <span class="n">zt</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">trans_mat</span><span class="p">[</span><span class="n">zt</span><span class="p">])</span>
  704. <span class="n">yt</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">n_obs</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">obs_mat</span><span class="p">[</span><span class="n">zt</span><span class="p">])</span>
  705. <span class="n">state_seq</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">zt</span>
  706. <span class="n">obs_seq</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">yt</span>
  707. <span class="k">return</span> <span class="n">state_seq</span><span class="p">,</span> <span class="n">obs_seq</span>
  708. </pre></div>
  709. </div>
  710. </div>
  711. </div>
  712. <div class="cell docutils container">
  713. <div class="cell_input docutils container">
  714. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">seq_len</span> <span class="o">=</span> <span class="mi">100</span>
  715. <span class="n">state_seq</span><span class="p">,</span> <span class="n">obs_seq</span> <span class="o">=</span> <span class="n">hmm_sample_np</span><span class="p">(</span><span class="n">params_np</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
  716. <span class="nb">print</span><span class="p">(</span><span class="n">state_seq</span><span class="p">)</span>
  717. <span class="nb">print</span><span class="p">(</span><span class="n">obs_seq</span><span class="p">)</span>
  718. </pre></div>
  719. </div>
  720. </div>
  721. <div class="cell_output docutils container">
  722. <div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
  723. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  724. 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
  725. [4 1 0 2 3 4 5 4 3 1 5 4 5 0 5 2 5 3 5 4 5 5 4 2 1 4 1 0 0 4 2 2 3 3 3 0 4
  726. 0 2 4 3 2 5 5 3 5 3 1 3 3 3 2 3 5 5 0 4 4 5 0 0 1 3 5 1 5 0 1 2 4 0 0 0 4
  727. 0 5 1 4 3 5 4 5 0 2 3 5 2 4 1 2 1 0 4 3 5 0 4 5 1 5]
  728. </pre></div>
  729. </div>
  730. </div>
  731. </div>
  732. </div>
  733. <div class="section" id="jax-version">
  734. <h3>JAX version<a class="headerlink" href="#jax-version" title="Permalink to this headline">¶</a></h3>
  735. <p>Now let’s write a JAX version using jax.lax.scan (for the inter-dependent states) and vmap (for the observations).
  736. This is harder to read than the numpy version, but faster.</p>
  737. <div class="cell docutils container">
  738. <div class="cell_input docutils container">
  739. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#@partial(jit, static_argnums=(1,))</span>
  740. <span class="k">def</span> <span class="nf">markov_chain_sample</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">init_dist</span><span class="p">,</span> <span class="n">trans_mat</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">):</span>
  741. <span class="n">n_states</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">init_dist</span><span class="p">)</span>
  742. <span class="k">def</span> <span class="nf">draw_state</span><span class="p">(</span><span class="n">prev_state</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
  743. <span class="n">state</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">trans_mat</span><span class="p">[</span><span class="n">prev_state</span><span class="p">])</span>
  744. <span class="k">return</span> <span class="n">state</span><span class="p">,</span> <span class="n">state</span>
  745. <span class="n">rng_key</span><span class="p">,</span> <span class="n">rng_state</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
  746. <span class="n">keys</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_state</span><span class="p">,</span> <span class="n">seq_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
  747. <span class="n">initial_state</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">init_dist</span><span class="p">)</span>
  748. <span class="n">final_state</span><span class="p">,</span> <span class="n">states</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">lax</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="n">initial_state</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
  749. <span class="n">state_seq</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">initial_state</span><span class="p">]),</span> <span class="n">states</span><span class="p">)</span>
  750. <span class="k">return</span> <span class="n">state_seq</span>
  751. </pre></div>
  752. </div>
  753. </div>
  754. </div>
  755. <div class="cell docutils container">
  756. <div class="cell_input docutils container">
  757. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#@partial(jit, static_argnums=(1,))</span>
  758. <span class="k">def</span> <span class="nf">hmm_sample</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">):</span>
  759. <span class="n">trans_mat</span><span class="p">,</span> <span class="n">obs_mat</span><span class="p">,</span> <span class="n">init_dist</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">trans_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">obs_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">init_dist</span>
  760. <span class="n">n_states</span><span class="p">,</span> <span class="n">n_obs</span> <span class="o">=</span> <span class="n">obs_mat</span><span class="o">.</span><span class="n">shape</span>
  761. <span class="n">rng_key</span><span class="p">,</span> <span class="n">rng_obs</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
  762. <span class="n">state_seq</span> <span class="o">=</span> <span class="n">markov_chain_sample</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">init_dist</span><span class="p">,</span> <span class="n">trans_mat</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">)</span>
  763. <span class="k">def</span> <span class="nf">draw_obs</span><span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
  764. <span class="n">obs</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">n_obs</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">obs_mat</span><span class="p">[</span><span class="n">z</span><span class="p">])</span>
  765. <span class="k">return</span> <span class="n">obs</span>
  766. <span class="n">keys</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_obs</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">)</span>
  767. <span class="n">obs_seq</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">vmap</span><span class="p">(</span><span class="n">draw_obs</span><span class="p">,</span> <span class="n">in_axes</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))(</span><span class="n">state_seq</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
  768. <span class="k">return</span> <span class="n">state_seq</span><span class="p">,</span> <span class="n">obs_seq</span>
  769. </pre></div>
  770. </div>
  771. </div>
  772. </div>
  773. <div class="cell docutils container">
  774. <div class="cell_input docutils container">
  775. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#@partial(jit, static_argnums=(1,))</span>
  776. <span class="k">def</span> <span class="nf">hmm_sample2</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">):</span>
  777. <span class="n">trans_mat</span><span class="p">,</span> <span class="n">obs_mat</span><span class="p">,</span> <span class="n">init_dist</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">trans_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">obs_mat</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">init_dist</span>
  778. <span class="n">n_states</span><span class="p">,</span> <span class="n">n_obs</span> <span class="o">=</span> <span class="n">obs_mat</span><span class="o">.</span><span class="n">shape</span>
  779. <span class="k">def</span> <span class="nf">draw_state</span><span class="p">(</span><span class="n">prev_state</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
  780. <span class="n">state</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">trans_mat</span><span class="p">[</span><span class="n">prev_state</span><span class="p">])</span>
  781. <span class="k">return</span> <span class="n">state</span><span class="p">,</span> <span class="n">state</span>
  782. <span class="n">rng_key</span><span class="p">,</span> <span class="n">rng_state</span><span class="p">,</span> <span class="n">rng_obs</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
  783. <span class="n">keys</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_state</span><span class="p">,</span> <span class="n">seq_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
  784. <span class="n">initial_state</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">n_states</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">init_dist</span><span class="p">)</span>
  785. <span class="n">final_state</span><span class="p">,</span> <span class="n">states</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">lax</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="n">initial_state</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
  786. <span class="n">state_seq</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">initial_state</span><span class="p">]),</span> <span class="n">states</span><span class="p">)</span>
  787. <span class="k">def</span> <span class="nf">draw_obs</span><span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
  788. <span class="n">obs</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">n_obs</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">obs_mat</span><span class="p">[</span><span class="n">z</span><span class="p">])</span>
  789. <span class="k">return</span> <span class="n">obs</span>
  790. <span class="n">keys</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">rng_obs</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">)</span>
  791. <span class="n">obs_seq</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">vmap</span><span class="p">(</span><span class="n">draw_obs</span><span class="p">,</span> <span class="n">in_axes</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))(</span><span class="n">state_seq</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
  792. <span class="k">return</span> <span class="n">state_seq</span><span class="p">,</span> <span class="n">obs_seq</span>
  793. </pre></div>
  794. </div>
  795. </div>
  796. </div>
  797. <div class="cell docutils container">
  798. <div class="cell_input docutils container">
  799. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">key</span> <span class="o">=</span> <span class="n">PRNGKey</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  800. <span class="n">seq_len</span> <span class="o">=</span> <span class="mi">100</span>
  801. <span class="n">state_seq</span><span class="p">,</span> <span class="n">obs_seq</span> <span class="o">=</span> <span class="n">hmm_sample</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">)</span>
  802. <span class="nb">print</span><span class="p">(</span><span class="n">state_seq</span><span class="p">)</span>
  803. <span class="nb">print</span><span class="p">(</span><span class="n">obs_seq</span><span class="p">)</span>
  804. </pre></div>
  805. </div>
  806. </div>
  807. <div class="cell_output docutils container">
  808. <div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  809. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
  810. 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
  811. [5 5 2 2 0 0 0 1 3 3 2 2 5 1 5 1 0 2 2 4 2 5 1 5 5 0 0 4 2 4 3 2 3 4 1 0 5
  812. 2 2 2 1 4 3 2 2 2 4 1 0 3 5 2 5 1 4 2 5 2 5 0 5 4 4 4 2 2 0 4 5 2 2 0 1 5
  813. 1 3 4 5 1 5 0 5 1 5 1 2 4 5 3 4 5 4 0 4 0 2 4 5 3 3]
  814. </pre></div>
  815. </div>
  816. </div>
  817. </div>
  818. </div>
  819. <div class="section" id="check-correctness-by-computing-empirical-pairwise-statistics">
  820. <h3>Check correctness by computing empirical pairwise statistics<a class="headerlink" href="#check-correctness-by-computing-empirical-pairwise-statistics" title="Permalink to this headline">¶</a></h3>
  821. <p>We will compute the number of i-&gt;j transitions, and check that it is close to the true
  822. A[i,j] transition probabilites.</p>
  823. <div class="cell docutils container">
  824. <div class="cell_input docutils container">
  825. <div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">collections</span>
  826. <span class="k">def</span> <span class="nf">compute_counts</span><span class="p">(</span><span class="n">state_seq</span><span class="p">,</span> <span class="n">nstates</span><span class="p">):</span>
  827. <span class="n">wseq</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">state_seq</span><span class="p">)</span>
  828. <span class="n">word_pairs</span> <span class="o">=</span> <span class="p">[</span><span class="n">pair</span> <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">wseq</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">wseq</span><span class="p">[</span><span class="mi">1</span><span class="p">:])]</span>
  829. <span class="n">counter_pairs</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">Counter</span><span class="p">(</span><span class="n">word_pairs</span><span class="p">)</span>
  830. <span class="n">counts</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">nstates</span><span class="p">,</span> <span class="n">nstates</span><span class="p">))</span>
  831. <span class="k">for</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span><span class="n">v</span><span class="p">)</span> <span class="ow">in</span> <span class="n">counter_pairs</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
  832. <span class="n">counts</span><span class="p">[</span><span class="n">k</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">k</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="n">v</span>
  833. <span class="k">return</span> <span class="n">counts</span>
  834. <span class="k">def</span> <span class="nf">normalize_counts</span><span class="p">(</span><span class="n">counts</span><span class="p">):</span>
  835. <span class="n">ncounts</span> <span class="o">=</span> <span class="n">vmap</span><span class="p">(</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">normalize</span><span class="p">(</span><span class="n">v</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span> <span class="n">in_axes</span><span class="o">=</span><span class="mi">0</span><span class="p">)(</span><span class="n">counts</span><span class="p">)</span>
  836. <span class="k">return</span> <span class="n">ncounts</span>
  837. <span class="n">init_dist</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">])</span>
  838. <span class="n">trans_mat</span> <span class="o">=</span> <span class="n">jnp</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">0.7</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">]])</span>
  839. <span class="n">rng_key</span> <span class="o">=</span> <span class="n">jax</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">PRNGKey</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
  840. <span class="n">seq_len</span> <span class="o">=</span> <span class="mi">500</span>
  841. <span class="n">state_seq</span> <span class="o">=</span> <span class="n">markov_chain_sample</span><span class="p">(</span><span class="n">rng_key</span><span class="p">,</span> <span class="n">init_dist</span><span class="p">,</span> <span class="n">trans_mat</span><span class="p">,</span> <span class="n">seq_len</span><span class="p">)</span>
  842. <span class="nb">print</span><span class="p">(</span><span class="n">state_seq</span><span class="p">)</span>
  843. <span class="n">counts</span> <span class="o">=</span> <span class="n">compute_counts</span><span class="p">(</span><span class="n">state_seq</span><span class="p">,</span> <span class="n">nstates</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
  844. <span class="nb">print</span><span class="p">(</span><span class="n">counts</span><span class="p">)</span>
  845. <span class="n">trans_mat_empirical</span> <span class="o">=</span> <span class="n">normalize_counts</span><span class="p">(</span><span class="n">counts</span><span class="p">)</span>
  846. <span class="nb">print</span><span class="p">(</span><span class="n">trans_mat_empirical</span><span class="p">)</span>
  847. <span class="k">assert</span> <span class="n">jnp</span><span class="o">.</span><span class="n">allclose</span><span class="p">(</span><span class="n">trans_mat</span><span class="p">,</span> <span class="n">trans_mat_empirical</span><span class="p">,</span> <span class="n">atol</span><span class="o">=</span><span class="mf">1e-1</span><span class="p">)</span>
  848. </pre></div>
  849. </div>
  850. </div>
  851. <div class="cell_output docutils container">
  852. <div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>[0 0 1 1 1 1 0 0 1 1 1 0 1 0 0 1 1 1 1 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1
  853. 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 1 1 0 1 1 0 1 1 0 1 1 1 0 0 1 1 0 1 0 0 1 0
  854. 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0
  855. 0 0 1 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 0
  856. 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 1 0 0 0 0
  857. 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 1 1 0 0 0 1 1 0 0 0
  858. 0 0 0 1 1 1 0 0 0 0 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 1 1 0 1 0 0 1 0 0
  859. 0 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 1 1 1 1
  860. 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1
  861. 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 1 1 0 1 0 0 0
  862. 0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 0 1 1 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 1 0
  863. 1 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
  864. 0 0 0 0 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 1 0 0 1 1 0 0 1
  865. 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 1 1]
  866. [[244. 93.]
  867. [ 92. 70.]]
  868. [[0.7240356 0.27596438]
  869. [0.56790125 0.43209878]]
  870. </pre></div>
  871. </div>
  872. </div>
  873. </div>
  874. </div>
  875. </div>
  876. </div>
  877. <script type="text/x-thebe-config">
  878. {
  879. requestKernel: true,
  880. binderOptions: {
  881. repo: "binder-examples/jupyter-stacks-datascience",
  882. ref: "master",
  883. },
  884. codeMirrorConfig: {
  885. theme: "abcdef",
  886. mode: "python"
  887. },
  888. kernelOptions: {
  889. kernelName: "python3",
  890. path: "./chapters/ssm"
  891. },
  892. predefinedOutput: true
  893. }
  894. </script>
  895. <script>kernelName = 'python3'</script>
  896. </div>
  897. <!-- Previous / next buttons -->
  898. <div class='prev-next-area'>
  899. <a class='left-prev' id="prev-link" href="ssm_index.html" title="previous page">
  900. <i class="fas fa-angle-left"></i>
  901. <div class="prev-next-info">
  902. <p class="prev-next-subtitle">previous</p>
  903. <p class="prev-next-title">Introduction</p>
  904. </div>
  905. </a>
  906. <a class='right-next' id="next-link" href="hsmm.html" title="next page">
  907. <div class="prev-next-info">
  908. <p class="prev-next-subtitle">next</p>
  909. <p class="prev-next-title">Hidden Semi-Markov Models</p>
  910. </div>
  911. <i class="fas fa-angle-right"></i>
  912. </a>
  913. </div>
  914. </div>
  915. </div>
  916. <footer class="footer">
  917. <p>
  918. By Kevin Murphy, Scott Linderman, et al.<br/>
  919. &copy; Copyright 2021.<br/>
  920. </p>
  921. </footer>
  922. </main>
  923. </div>
  924. </div>
  925. <script src="../../_static/js/index.be7d3bbb2ef33a8344ce.js"></script>
  926. </body>
  927. </html>