Skip to content

Instantly share code, notes, and snippets.

@cako
Created December 16, 2021 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cako/27315a40d70805afa4ec6541b59a8401 to your computer and use it in GitHub Desktop.
Save cako/27315a40d70805afa4ec6541b59a8401 to your computer and use it in GitHub Desktop.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "destroyed-operations",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import timeit\n",
"\n",
"from tqdm.notebook import tqdm"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "authorized-israeli",
"metadata": {},
"outputs": [],
"source": [
"def test1(x, dim):\n",
" s = (slice(None),) * dim + (slice(1, -1),) + (slice(None),) * (x.ndim - dim - 1)\n",
" x[s] *= 2\n",
" return x\n",
"\n",
"def test2(x, dim):\n",
" y = np.swapaxes(x, dim, -1)\n",
" y[..., 1:-1] *= 2\n",
" y = np.swapaxes(y, dim, -1)\n",
" return y\n",
"\n",
"def test3(x, dim):\n",
" y = np.moveaxis(x, dim, -1)\n",
" y[..., 1:-1] *= 2\n",
" y = np.moveaxis(y, -1, dim)\n",
" return y\n",
"\n",
"def test4(x, dim):\n",
" y = np.ascontiguousarray(np.swapaxes(x, dim, -1))\n",
" y[..., 1:-1] *= 2\n",
" y = np.swapaxes(y, dim, -1)\n",
" return y\n",
"\n",
"\n",
"def check():\n",
" a = np.random.rand(100, 100, 100)\n",
" b = a.copy()\n",
" b1 = test1(b, 1)\n",
" b = a.copy()\n",
" b2 = test2(b, 1)\n",
" b = a.copy()\n",
" b3 = test3(b, 1)\n",
"\n",
" assert np.allclose(b1, b2)\n",
" assert np.allclose(b2, b3)\n",
"\n",
"check()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "forced-wagon",
"metadata": {},
"outputs": [],
"source": [
"def setup_arrays(size):\n",
" return f\"\"\"\n",
"import numpy as np\n",
"np.random.seed(42)\n",
"shape = ({size},) * 3\n",
"x = np.random.rand(*shape)\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "controlling-vermont",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2d746b9a5ee04709bf68a2ff95343f19",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/10 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"sizes = np.arange(50, 550, 50)\n",
"benchmark = {\"slice\": [], \"swapaxis\": [], \"moveaxis\": [], \"contiguous\": []}\n",
"for s in tqdm(sizes):\n",
" benchmark[\"slice\"].append(\n",
" timeit.timeit('test1(x, 1)', setup=\"from __main__ import test1;\" + setup_arrays(s), number=100))\n",
" benchmark[\"swapaxis\"].append(\n",
" timeit.timeit('test2(x, 1)', setup=\"from __main__ import test2;\" + setup_arrays(s), number=100))\n",
" benchmark[\"moveaxis\"].append(\n",
" timeit.timeit('test3(x, 1)', setup=\"from __main__ import test3;\" + setup_arrays(s), number=100))\n",
" benchmark[\"contiguous\"].append(\n",
" timeit.timeit('test4(x, 1)', setup=\"from __main__ import test4;\" + setup_arrays(s), number=100)) "
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "underlying-aaron",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots()\n",
"for title, times in benchmark.items():\n",
" ax.plot(sizes, 1e3 * np.array(times) / 100, label=title)\n",
"ax.set(xlabel=\"Dimension of one axis\", ylabel=\"Runtime [ms]\")\n",
"ax.legend()\n",
"fig.tight_layout()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "radio-ridge",
"metadata": {},
"outputs": [],
"source": [
"def test1_fft(x, dim):\n",
" s = (slice(None),) * dim + (slice(1, -1),) + (slice(None),) * (x.ndim - dim - 1)\n",
" x[s] = np.abs(np.fft.fft(x[s], axis=dim))\n",
" return x\n",
"\n",
"def test2_fft(x, dim):\n",
" y = np.swapaxes(x, dim, -1)\n",
" y[..., 1:-1] = np.abs(np.fft.fft(y[..., 1:-1], axis=-1))\n",
" y = np.swapaxes(y, dim, -1)\n",
" return y\n",
"\n",
"def test3_fft(x, dim):\n",
" y = np.moveaxis(x, dim, -1)\n",
" y[..., 1:-1] = np.abs(np.fft.fft(y[..., 1:-1], axis=-1))\n",
" y = np.moveaxis(y, -1, dim)\n",
" return y\n",
"\n",
"def test4_fft(x, dim):\n",
" y = np.ascontiguousarray(np.swapaxes(x, dim, -1))\n",
" y[..., 1:-1] = np.abs(np.fft.fft(y[..., 1:-1], axis=-1))\n",
" y = np.swapaxes(y, dim, -1)\n",
" return y\n",
"\n",
"\n",
"def check():\n",
" a = np.random.rand(100, 100, 100)\n",
" b = a.copy()\n",
" b1 = test1_fft(b, 1)\n",
" b = a.copy()\n",
" b2 = test2_fft(b, 1)\n",
" b = a.copy()\n",
" b3 = test3_fft(b, 1)\n",
"\n",
" assert np.allclose(b1, b2)\n",
" assert np.allclose(b2, b3)\n",
"\n",
"check()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "lasting-blocking",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3320444fba6b4e69bf2c15c5a5c96b73",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/10 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"sizes = np.arange(20, 220, 20)\n",
"benchmark_fft = {\"slice\": [], \"swapaxis\": [], \"moveaxis\": [], \"contiguous\": []}\n",
"for s in tqdm(sizes):\n",
" benchmark_fft[\"slice\"].append(\n",
" timeit.timeit('test1_fft(x, 1)', setup=\"from __main__ import test1_fft;\" + setup_arrays(s), number=100))\n",
" benchmark_fft[\"swapaxis\"].append(\n",
" timeit.timeit('test2_fft(x, 1)', setup=\"from __main__ import test2_fft;\" + setup_arrays(s), number=100))\n",
" benchmark_fft[\"moveaxis\"].append(\n",
" timeit.timeit('test3_fft(x, 1)', setup=\"from __main__ import test3_fft;\" + setup_arrays(s), number=100))\n",
" benchmark_fft[\"contiguous\"].append(\n",
" timeit.timeit('test4_fft(x, 1)', setup=\"from __main__ import test4_fft;\" + setup_arrays(s), number=100)) "
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "iraqi-pittsburgh",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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ya29bz2ma4zuOppSZykL2vahvWSRtX4pBaXH1repxsy7ixYd07H+pgkqSO3cuZN333236vWqVauYMGFCACNSStWXMzubok8/JW7kyFqbcH+3PY+u6TOIoZQ1aSP4JuMbbup9E3Fhccd0nbTkNLrGd2Vm2Q7ctnAuZzGzfzz2Bg/B2nlXE1SQOjRB9e/fn4kTJwYwIqVUfRW89x64XCSMHXPYNmMMr37+M7fZF+DqeB4v7PqEZhHNuL779cd8HRFhdLfRbCncxi9dh3OZ/Xtmf7/1mB/VBWvnXU1QfvLWW2/Rp08f0tLSGDNmDDt37mT48OH06dOHc845h/T0dADGjx/PhAkTOP300+nQoUPVkEQPPfQQS5cupW/fvrzwwgssXryYSy+9FICcnBzOO+88evbsyS233ELbtm3Jzc1l586d9OrVqyqGZ599lieeeALwDo102mmn0adPH0aOHElBgffL1GHDhnGgs3Nubi7t2rUDYP369QwcOJC+ffvSp08ftm7d2hC3TalGz1NRQeGMmUSdfTYhbdsetv3bbXl0z3yfOEpY3PNc1uas5Y6+dxBuCz+u613S/hIi7ZHMiAoj0pTRueAbvttx7DMVBePMu34bLDYY7H36aSo3ntzpNkK7d6P5X/5S5z7r16/n73//O8uXLycpKYn8/HzGjRtXtbz55ptMmDCBjz76CIA9e/awbNkyNm3axIgRI7jqqqv45z//ybPPPssnn3wCeMfrO+DJJ59k+PDhPPzww3z22We88cYbtURR09ixY3n55ZcZOnQojz32GE8++SQvvvjiEfefPHkyd999N9dffz0Oh0NHO1eqnormzcNdUFDrjLnGGF5e+DOT7J9S2X4YL+2aT4fYDozoOOK4rxdhj2BExxF8sOUD/hzXhmsLlzB9xVWc3jHpmM5zoPPur1dcSe7k10h54P7jjulk0RqUH3z11VeMGjWKpCTvByQhIYHvvvuO667zjsM1ZswYli1bVrX/5ZdfjsVioUePHuzbt++o51+2bBnXXHMNABdeeCHx8fF17l9UVERhYSFDhw4FYNy4cSxZsqTOYwYPHszTTz/NM888w65duwgPP76/7pT6LTHGkP/WW4R2707EwAGHbV+8OYeeWXNIoIi5XQazs3gn95xyDzbLidUVRncdjdPjZG77vpzGOtauX0fu/spjPk9V5923g6Pz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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots()\n",
"for title, times in benchmark_fft.items():\n",
" ax.plot(sizes, 1e3 * np.array(times) / 100, label=title)\n",
"ax.set(xlabel=\"Dimension of one axis\", ylabel=\"Runtime [ms]\")\n",
"ax.legend()\n",
"fig.tight_layout()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "falling-height",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "surgical-marathon",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment