Skip to content

Improve debug docs and function helpers #632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 99 additions & 109 deletions examples/howto/howto_debugging.ipynb
Original file line number Diff line number Diff line change
@@ -21,14 +21,22 @@
"## Introduction\n",
"There are various levels on which to debug a model. One of the simplest is to just print out the values that different variables are taking on.\n",
"\n",
"Because `PyMC` uses `PyTensor` expressions to build the model, and not functions, there is no way to place a `print` statement into a likelihood function. Instead, you can use the {class}`pytensor.printing.Print` class to print intermediate values."
"Because `PyMC` uses `PyTensor` expressions to build the model, and not functions, there is no way to place a `print` statement into a likelihood function. Instead, you can use the {class}`pytensor.printing.Print` class to print intermediate values. In PyMC we have `print_values` helper function to print intermediate values. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING (pytensor.tensor.blas): Using NumPy C-API based implementation for BLAS functions.\n"
]
}
],
"source": [
"import arviz as az\n",
"import matplotlib.pyplot as plt\n",
@@ -54,7 +62,7 @@
"metadata": {},
"source": [
"### How to print intermediate values of `PyTensor` functions\n",
"Since `PyTensor` functions are compiled to C, you have to use `pytensor.printing.Print` class to print intermediate values (imported below as `Print`). Python `print` function will not work. Below is a simple example of using `Print`. For more information, see {ref}`Debugging PyTensor <pytensor:debug_faq>`."
"Since `PyTensor` functions are compiled to C, you have to use `pymc.pytensorf.print_value` function to print intermediate values. Python `print` function will not work. Below is a simple example of using `print_value`. For more information, see {ref}`Debugging PyTensor <pytensor:debug_faq>`."
]
},
{
@@ -65,8 +73,8 @@
"source": [
"import pytensor.tensor as pt\n",
"\n",
"from pytensor import function\n",
"from pytensor.printing import Print"
"from pymc.pytensorf import print_value\n",
"from pytensor import function"
]
},
{
@@ -96,7 +104,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"To see what causes the `inf` value in the output, we can print intermediate values of $(x-y)$ using `Print`. `Print` class simply passes along its caller but prints out its value along a user-define message:"
"To see what causes the `inf` value in the output, we can print intermediate values of $(x-y)$ using `print_value`. `print_value` is based on the {class}`pytensor.prinitng.Print` class that simply passes along its caller but prints out its value along a user-define message:"
]
},
{
@@ -123,7 +131,7 @@
}
],
"source": [
"z_with_print = Print(\"x - y = \")(x - y)\n",
"z_with_print = print_value(x - y, \"x - y = \")\n",
"func_with_print = function([x, y], 1 / z_with_print)\n",
"func_with_print([1, 2, 3], [1, 0, -1])"
]
@@ -132,16 +140,16 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"`Print` reveals the root cause: $(x-y)$ takes a zero value when $x=1, y=1$, causing the `inf` output."
"`print_value` reveals the root cause: $(x-y)$ takes a zero value when $x=1, y=1$, causing the `inf` output."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### How to capture `Print` output for further analysis\n",
"### How to capture `print_values` output for further analysis\n",
"\n",
"When we expect many rows of output from `Print`, it can be desirable to redirect the output to a string buffer and access the values later on (thanks to **Lindley Lentati** for inspiring this example). Here is a toy example using Python `print` function:"
"When we expect many rows of output from `print_values`, it can be desirable to redirect the output to a string buffer and access the values later on (thanks to **Lindley Lentati** for inspiring this example). Here is a toy example using Python `print` function:"
]
},
{
@@ -203,8 +211,8 @@
" sd = pm.Normal(\"sd\", mu=0, sigma=1)\n",
"\n",
" # setting out printing for mu and sd\n",
" mu_print = Print(\"mu\")(mu)\n",
" sd_print = Print(\"sd\")(sd)\n",
" mu_print = print_value(mu)\n",
" sd_print = print_value(sd)\n",
"\n",
" # likelihood\n",
" obs = pm.Normal(\"obs\", mu=mu_print, sigma=sd_print, observed=x)"
@@ -218,57 +226,62 @@
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
"<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
" -->\r\n",
"<!-- Title: %3 Pages: 1 -->\r\n",
"<svg width=\"190pt\" height=\"233pt\"\r\n",
" viewBox=\"0.00 0.00 190.02 232.91\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 228.907)\">\r\n",
"<title>%3</title>\r\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-228.907 186.024,-228.907 186.024,4 -4,4\"/>\r\n",
"<g id=\"clust1\" class=\"cluster\"><title>cluster100</title>\r\n",
"<path fill=\"none\" stroke=\"black\" d=\"M54.0122,-8C54.0122,-8 128.012,-8 128.012,-8 134.012,-8 140.012,-14 140.012,-20 140.012,-20 140.012,-109.953 140.012,-109.953 140.012,-115.953 134.012,-121.953 128.012,-121.953 128.012,-121.953 54.0122,-121.953 54.0122,-121.953 48.0122,-121.953 42.0122,-115.953 42.0122,-109.953 42.0122,-109.953 42.0122,-20 42.0122,-20 42.0122,-14 48.0122,-8 54.0122,-8\"/>\r\n",
"<text text-anchor=\"middle\" x=\"121.512\" y=\"-15.8\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">100</text>\r\n",
"</g>\r\n",
"<!-- sd -->\r\n",
"<g id=\"node1\" class=\"node\"><title>sd</title>\r\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"41.0122\" cy=\"-187.43\" rx=\"41.0244\" ry=\"37.4533\"/>\r\n",
"<text text-anchor=\"middle\" x=\"41.0122\" y=\"-198.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">sd</text>\r\n",
"<text text-anchor=\"middle\" x=\"41.0122\" y=\"-183.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\r\n",
"<text text-anchor=\"middle\" x=\"41.0122\" y=\"-168.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\r\n",
"</g>\r\n",
"<!-- obs -->\r\n",
"<g id=\"node3\" class=\"node\"><title>obs</title>\r\n",
"<ellipse fill=\"lightgrey\" stroke=\"black\" cx=\"91.0122\" cy=\"-76.4767\" rx=\"41.0244\" ry=\"37.4533\"/>\r\n",
"<text text-anchor=\"middle\" x=\"91.0122\" y=\"-87.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">obs</text>\r\n",
"<text text-anchor=\"middle\" x=\"91.0122\" y=\"-72.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\r\n",
"<text text-anchor=\"middle\" x=\"91.0122\" y=\"-57.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\r\n",
"</g>\r\n",
"<!-- sd&#45;&gt;obs -->\r\n",
"<g id=\"edge1\" class=\"edge\"><title>sd&#45;&gt;obs</title>\r\n",
"<path fill=\"none\" stroke=\"black\" d=\"M56.5584,-152.554C61.2146,-142.408 66.3839,-131.143 71.2721,-120.492\"/>\r\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"74.4857,-121.88 75.4756,-111.332 68.1236,-118.961 74.4857,-121.88\"/>\r\n",
"</g>\r\n",
"<!-- mu -->\r\n",
"<g id=\"node2\" class=\"node\"><title>mu</title>\r\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141.012\" cy=\"-187.43\" rx=\"41.0244\" ry=\"37.4533\"/>\r\n",
"<text text-anchor=\"middle\" x=\"141.012\" y=\"-198.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">mu</text>\r\n",
"<text text-anchor=\"middle\" x=\"141.012\" y=\"-183.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\r\n",
"<text text-anchor=\"middle\" x=\"141.012\" y=\"-168.73\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\r\n",
"</g>\r\n",
"<!-- mu&#45;&gt;obs -->\r\n",
"<g id=\"edge2\" class=\"edge\"><title>mu&#45;&gt;obs</title>\r\n",
"<path fill=\"none\" stroke=\"black\" d=\"M125.466,-152.554C120.81,-142.408 115.641,-131.143 110.752,-120.492\"/>\r\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"113.901,-118.961 106.549,-111.332 107.539,-121.88 113.901,-118.961\"/>\r\n",
"</g>\r\n",
"</g>\r\n",
"</svg>\r\n"
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 9.0.0 (0)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"190pt\" height=\"247pt\"\n",
" viewBox=\"0.00 0.00 190.02 247.13\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 243.13)\">\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-243.13 186.02,-243.13 186.02,4 -4,4\"/>\n",
"<g id=\"clust1\" class=\"cluster\">\n",
"<title>cluster100</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M54.01,-8C54.01,-8 128.01,-8 128.01,-8 134.01,-8 140.01,-14 140.01,-20 140.01,-20 140.01,-117.82 140.01,-117.82 140.01,-123.82 134.01,-129.82 128.01,-129.82 128.01,-129.82 54.01,-129.82 54.01,-129.82 48.01,-129.82 42.01,-123.82 42.01,-117.82 42.01,-117.82 42.01,-20 42.01,-20 42.01,-14 48.01,-8 54.01,-8\"/>\n",
"<text text-anchor=\"middle\" x=\"121.89\" y=\"-15.2\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">100</text>\n",
"</g>\n",
"<!-- sd -->\n",
"<g id=\"node1\" class=\"node\">\n",
"<title>sd</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"41.01\" cy=\"-198.48\" rx=\"41.01\" ry=\"40.66\"/>\n",
"<text text-anchor=\"middle\" x=\"41.01\" y=\"-209.93\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">sd</text>\n",
"<text text-anchor=\"middle\" x=\"41.01\" y=\"-193.43\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\n",
"<text text-anchor=\"middle\" x=\"41.01\" y=\"-176.93\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\n",
"</g>\n",
"<!-- obs -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>obs</title>\n",
"<ellipse fill=\"lightgrey\" stroke=\"black\" cx=\"91.01\" cy=\"-81.16\" rx=\"41.01\" ry=\"40.66\"/>\n",
"<text text-anchor=\"middle\" x=\"91.01\" y=\"-92.61\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">obs</text>\n",
"<text text-anchor=\"middle\" x=\"91.01\" y=\"-76.11\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\n",
"<text text-anchor=\"middle\" x=\"91.01\" y=\"-59.61\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\n",
"</g>\n",
"<!-- sd&#45;&gt;obs -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>sd&#45;&gt;obs</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M56.97,-160.67C61.3,-150.69 66.05,-139.74 70.59,-129.26\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"73.67,-130.96 74.43,-120.4 67.24,-128.18 73.67,-130.96\"/>\n",
"</g>\n",
"<!-- mu -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>mu</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141.01\" cy=\"-198.48\" rx=\"41.01\" ry=\"40.66\"/>\n",
"<text text-anchor=\"middle\" x=\"141.01\" y=\"-209.93\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">mu</text>\n",
"<text text-anchor=\"middle\" x=\"141.01\" y=\"-193.43\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">~</text>\n",
"<text text-anchor=\"middle\" x=\"141.01\" y=\"-176.93\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Normal</text>\n",
"</g>\n",
"<!-- mu&#45;&gt;obs -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>mu&#45;&gt;obs</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M125.05,-160.67C120.72,-150.69 115.98,-139.74 111.44,-129.26\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"114.78,-128.18 107.59,-120.4 108.36,-130.96 114.78,-128.18\"/>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<graphviz.dot.Digraph at 0x1c8897bb7c0>"
"<graphviz.graphs.Digraph at 0x1cdb1e05b90>"
]
},
"execution_count": 8,
@@ -286,31 +299,14 @@
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Only 5 samples in chain.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"sd __str__ = 0.0\n",
"mu __str__ = 0.0\n"
]
},
{
"ename": "SamplingError",
"evalue": "Initial evaluation of model at starting point failed!\nStarting values:\n{'mu': array(0.), 'sd': array(0.)}\n\nInitial evaluation results:\n{'mu': -0.92, 'sd': -0.92, 'obs': -inf}",
"ename": "TypeError",
"evalue": "sample() takes from 0 to 1 positional arguments but 2 positional arguments (and 4 keyword-only arguments) were given",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mSamplingError\u001b[0m Traceback (most recent call last)",
"Input \u001b[1;32mIn [9]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m model:\n\u001b[0;32m 2\u001b[0m step \u001b[38;5;241m=\u001b[39m pm\u001b[38;5;241m.\u001b[39mMetropolis()\n\u001b[1;32m----> 3\u001b[0m trace \u001b[38;5;241m=\u001b[39m \u001b[43mpm\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msample\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtune\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mchains\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprogressbar\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrandom_seed\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mRANDOM_SEED\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[1;32mc:\\users\\igork\\pycharmprojects\\pymc\\pymc\\sampling.py:558\u001b[0m, in \u001b[0;36msample\u001b[1;34m(draws, step, init, n_init, initvals, trace, chain_idx, chains, cores, tune, progressbar, model, random_seed, discard_tuned_samples, compute_convergence_checks, callback, jitter_max_retries, return_inferencedata, idata_kwargs, mp_ctx, **kwargs)\u001b[0m\n\u001b[0;32m 556\u001b[0m \u001b[38;5;66;03m# One final check that shapes and logps at the starting points are okay.\u001b[39;00m\n\u001b[0;32m 557\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m ip \u001b[38;5;129;01min\u001b[39;00m initial_points:\n\u001b[1;32m--> 558\u001b[0m \u001b[43mmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_start_vals\u001b[49m\u001b[43m(\u001b[49m\u001b[43mip\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 559\u001b[0m _check_start_shape(model, ip)\n\u001b[0;32m 561\u001b[0m sample_args \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 562\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdraws\u001b[39m\u001b[38;5;124m\"\u001b[39m: draws,\n\u001b[0;32m 563\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstep\u001b[39m\u001b[38;5;124m\"\u001b[39m: step,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 573\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdiscard_tuned_samples\u001b[39m\u001b[38;5;124m\"\u001b[39m: discard_tuned_samples,\n\u001b[0;32m 574\u001b[0m }\n",
"File \u001b[1;32mc:\\users\\igork\\pycharmprojects\\pymc\\pymc\\model.py:1794\u001b[0m, in \u001b[0;36mModel.check_start_vals\u001b[1;34m(self, start)\u001b[0m\n\u001b[0;32m 1791\u001b[0m initial_eval \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpoint_logps(point\u001b[38;5;241m=\u001b[39melem)\n\u001b[0;32m 1793\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mall\u001b[39m(np\u001b[38;5;241m.\u001b[39misfinite(v) \u001b[38;5;28;01mfor\u001b[39;00m v \u001b[38;5;129;01min\u001b[39;00m initial_eval\u001b[38;5;241m.\u001b[39mvalues()):\n\u001b[1;32m-> 1794\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SamplingError(\n\u001b[0;32m 1795\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInitial evaluation of model at starting point failed!\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1796\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mStarting values:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00melem\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1797\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInitial evaluation results:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00minitial_eval\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1798\u001b[0m )\n",
"\u001b[1;31mSamplingError\u001b[0m: Initial evaluation of model at starting point failed!\nStarting values:\n{'mu': array(0.), 'sd': array(0.)}\n\nInitial evaluation results:\n{'mu': -0.92, 'sd': -0.92, 'obs': -inf}"
"\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[9], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m model:\n\u001b[0;32m 2\u001b[0m step \u001b[38;5;241m=\u001b[39m pm\u001b[38;5;241m.\u001b[39mMetropolis()\n\u001b[1;32m----> 3\u001b[0m trace \u001b[38;5;241m=\u001b[39m \u001b[43mpm\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msample\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtune\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mchains\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprogressbar\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrandom_seed\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mRANDOM_SEED\u001b[49m\u001b[43m)\u001b[49m\n",
"\u001b[1;31mTypeError\u001b[0m: sample() takes from 0 to 1 positional arguments but 2 positional arguments (and 4 keyword-only arguments) were given"
]
}
],
@@ -350,11 +346,8 @@
"Initializing NUTS using jitter+adapt_diag...\n",
"Sequential sampling (1 chains in 1 job)\n",
"NUTS: [mu, a, b]\n",
"Sampling 1 chain for 0 tune and 10 draw iterations (0 + 10 draws total) took 1 seconds.\n",
"The chain contains only diverging samples. The model is probably misspecified.\n",
"The acceptance probability does not match the target. It is 0, but should be close to 0.8. Try to increase the number of tuning steps.\n",
"C:\\Users\\igork\\AppData\\Local\\Temp\\ipykernel_14804\\1992602661.py:15: UserWarning: The number of samples is too small to check convergence reliably.\n",
" trace = pm.sample(draws=10, tune=0, chains=1, progressbar=False, random_seed=RANDOM_SEED)\n"
"Sampling 1 chain for 0 tune and 10 draw iterations (0 + 10 draws total) took 0 seconds.\n",
"The number of samples is too small to check convergence reliably.\n"
]
}
],
@@ -369,7 +362,7 @@
" mu = pm.Normal(\"mu\", mu=0, sigma=10)\n",
" a = pm.Normal(\"a\", mu=0, sigma=10, initval=0.1)\n",
" b = pm.Normal(\"b\", mu=0, sigma=10, initval=0.1)\n",
" sd_print = Print(\"Delta\")(a / b)\n",
" sd_print = print_value(a / b, name=\"Delta\")\n",
" obs = pm.Normal(\"obs\", mu=mu, sigma=sd_print, observed=y)\n",
"\n",
" # limiting number of samples and chains to simplify output\n",
@@ -389,7 +382,7 @@
{
"data": {
"text/plain": [
"'Delta __str__ = -85.74093608165128\\nDelta __str__ = -9.182002291671038\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315734173890055\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.312485782438435\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.314669656412736\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31581619157038\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315114719133609\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31511040479387\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.314077394936474\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.313673830463395\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31561025339713\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31526569370057\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\n'"
"'Delta __str__ = -85.74093608165128\\nDelta __str__ = -9.182002291671038\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315734173890057\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.312485782438435\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.314669656412734\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31581619157038\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.31511471913361\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315110404793872\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.314077394936474\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.313673830463394\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315610253397129\\nDelta __str__ = 0.10737295473067673\\nDelta __str__ = -9.315265693700571\\n'"
]
},
"execution_count": 11,
@@ -443,10 +436,7 @@
" 0.10737295, -9.31466966, 0.10737295, -9.31581619,\n",
" 0.10737295, -9.31511472, 0.10737295, -9.3151104 ,\n",
" 0.10737295, -9.31407739, 0.10737295, -9.31367383,\n",
" 0.10737295, -9.31561025, 0.10737295, -9.31526569,\n",
" 0.10737295, 0.10737295, 0.10737295, 0.10737295,\n",
" 0.10737295, 0.10737295, 0.10737295, 0.10737295,\n",
" 0.10737295, 0.10737295])"
" 0.10737295, -9.31561025, 0.10737295, -9.31526569])"
]
},
"execution_count": 13,
@@ -473,7 +463,7 @@
{
"data": {
"text/plain": [
"(34,)"
"(24,)"
]
},
"execution_count": 14,
@@ -511,25 +501,25 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Last updated: Tue Aug 02 2022\n",
"Last updated: Mon Feb 12 2024\n",
"\n",
"Python implementation: CPython\n",
"Python version : 3.10.5\n",
"IPython version : 8.4.0\n",
"Python version : 3.11.7\n",
"IPython version : 8.21.0\n",
"\n",
"pytensor: 2.7.5\n",
"xarray: 2022.3.0\n",
"pytensor: 2.18.6\n",
"xarray : 2024.1.1\n",
"\n",
"matplotlib: 3.5.2\n",
"pytensor : 2.7.5\n",
"numpy : 1.23.0\n",
"arviz : 0.12.1\n",
"sys : 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 06:57:19) [MSC v.1929 64 bit (AMD64)]\n",
"pandas : 2.2.0\n",
"re : 2.2.1\n",
"pandas : 1.4.3\n",
"pymc : 4.1.2\n",
"arviz : 0.17.0\n",
"sys : 3.11.7 | packaged by conda-forge | (main, Dec 23 2023, 14:27:59) [MSC v.1937 64 bit (AMD64)]\n",
"pymc : 0+untagged.9733.g94020c9.dirty\n",
"pytensor : 2.18.6\n",
"matplotlib: 3.8.2\n",
"numpy : 1.26.4\n",
"\n",
"Watermark: 2.3.1\n",
"Watermark: 2.4.3\n",
"\n"
]
}
@@ -564,7 +554,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
"version": "3.11.7"
}
},
"nbformat": 4,
22 changes: 11 additions & 11 deletions examples/howto/howto_debugging.myst.md
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ kernelspec:
## Introduction
There are various levels on which to debug a model. One of the simplest is to just print out the values that different variables are taking on.

Because `PyMC` uses `PyTensor` expressions to build the model, and not functions, there is no way to place a `print` statement into a likelihood function. Instead, you can use the {class}`pytensor.printing.Print` class to print intermediate values.
Because `PyMC` uses `PyTensor` expressions to build the model, and not functions, there is no way to place a `print` statement into a likelihood function. Instead, you can use the {class}`pytensor.printing.Print` class to print intermediate values. In PyMC we have `print_values` helper function to print intermediate values.

```{code-cell} ipython3
import arviz as az
@@ -42,13 +42,13 @@ RANDOM_SEED = 8927
```

### How to print intermediate values of `PyTensor` functions
Since `PyTensor` functions are compiled to C, you have to use `pytensor.printing.Print` class to print intermediate values (imported below as `Print`). Python `print` function will not work. Below is a simple example of using `Print`. For more information, see {ref}`Debugging PyTensor <pytensor:debug_faq>`.
Since `PyTensor` functions are compiled to C, you have to use `pymc.pytensorf.print_value` function to print intermediate values. Python `print` function will not work. Below is a simple example of using `print_value`. For more information, see {ref}`Debugging PyTensor <pytensor:debug_faq>`.

```{code-cell} ipython3
import pytensor.tensor as pt
from pymc.pytensorf import print_value
from pytensor import function
from pytensor.printing import Print
```

```{code-cell} ipython3
@@ -58,21 +58,21 @@ func = function([x, y], 1 / (x - y))
func([1, 2, 3], [1, 0, -1])
```

To see what causes the `inf` value in the output, we can print intermediate values of $(x-y)$ using `Print`. `Print` class simply passes along its caller but prints out its value along a user-define message:
To see what causes the `inf` value in the output, we can print intermediate values of $(x-y)$ using `print_value`. `print_value` is based on the {class}`pytensor.prinitng.Print` class that simply passes along its caller but prints out its value along a user-define message:

```{code-cell} ipython3
z_with_print = Print("x - y = ")(x - y)
z_with_print = print_value(x - y, "x - y = ")
func_with_print = function([x, y], 1 / z_with_print)
func_with_print([1, 2, 3], [1, 0, -1])
```

`Print` reveals the root cause: $(x-y)$ takes a zero value when $x=1, y=1$, causing the `inf` output.
`print_value` reveals the root cause: $(x-y)$ takes a zero value when $x=1, y=1$, causing the `inf` output.

+++

### How to capture `Print` output for further analysis
### How to capture `print_values` output for further analysis

When we expect many rows of output from `Print`, it can be desirable to redirect the output to a string buffer and access the values later on (thanks to **Lindley Lentati** for inspiring this example). Here is a toy example using Python `print` function:
When we expect many rows of output from `print_values`, it can be desirable to redirect the output to a string buffer and access the values later on (thanks to **Lindley Lentati** for inspiring this example). Here is a toy example using Python `print` function:

```{code-cell} ipython3
import sys
@@ -102,8 +102,8 @@ with pm.Model() as model:
sd = pm.Normal("sd", mu=0, sigma=1)
# setting out printing for mu and sd
mu_print = Print("mu")(mu)
sd_print = Print("sd")(sd)
mu_print = print_value(mu)
sd_print = print_value(sd)
# likelihood
obs = pm.Normal("obs", mu=mu_print, sigma=sd_print, observed=x)
@@ -136,7 +136,7 @@ with pm.Model() as model:
mu = pm.Normal("mu", mu=0, sigma=10)
a = pm.Normal("a", mu=0, sigma=10, initval=0.1)
b = pm.Normal("b", mu=0, sigma=10, initval=0.1)
sd_print = Print("Delta")(a / b)
sd_print = print_value(a / b, name="Delta")
obs = pm.Normal("obs", mu=mu, sigma=sd_print, observed=y)
# limiting number of samples and chains to simplify output