Skip to content

Instantly share code, notes, and snippets.

@Sinusoidal36
Created November 26, 2020 21:49
Show Gist options
  • Save Sinusoidal36/393b0aa6d73dfbd907933e750476e1b7 to your computer and use it in GitHub Desktop.
Save Sinusoidal36/393b0aa6d73dfbd907933e750476e1b7 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"import plotly.express as px\n",
"import pandas as pd\n",
"import timeit\n",
"from IPython.display import Image\n",
"\n",
"DATASKETCH_PKG_PATH = '/home/sinusoidal/projects/datasketch/'"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"old_setup = '''\n",
"from datasketch import minhash\n",
"from xxhash import xxh3_64_intdigest as hashfunc\n",
"import random\n",
"\n",
"'''\n",
"\n",
"new_setup = f'''\n",
"import importlib.util\n",
"import random\n",
"from xxhash import xxh3_64_intdigest as hashfunc\n",
"DATASKETCH_PKG_PATH = \"{DATASKETCH_PKG_PATH}\"\n",
"\n",
"spec = importlib.util.spec_from_file_location(\"minhash\", DATASKETCH_PKG_PATH + \"datasketch/minhash.py\")\n",
"minhash = importlib.util.module_from_spec(spec)\n",
"spec.loader.exec_module(minhash)\n",
"\n",
"spec = importlib.util.spec_from_file_location(\"bulk\", DATASKETCH_PKG_PATH + \"datasketch/bulk.py\")\n",
"bulk = importlib.util.module_from_spec(spec)\n",
"spec.loader.exec_module(bulk)\n",
"\n",
"'''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Updates\n",
"\n",
"Here it is shown that the new update implementation is substantially faster when providing a list of tokens instead of performing updates iteratively. \n",
"\n",
"Comparative performance scales with the number of updates."
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {},
"outputs": [],
"source": [
"iterations = 100\n",
"repeats = 10\n",
"\n",
"update_setup = '''\n",
"byte_data = [str(random.randint(0, 1000000)).encode(\"utf8\") for n in range({})]\n",
"'''\n",
"iterative_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"for b in byte_data:\n",
" m.update(b)\n",
"'''\n",
"list_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"m.update(byte_data)\n",
"'''\n",
"\n",
"data = []\n",
"for token_count in [10, 100, 1000, 10000]:\n",
" _update_setup = update_setup.format(token_count)\n",
" old = timeit.repeat(iterative_statement, setup=old_setup + _update_setup, number=iterations, repeat=repeats)\n",
" new = timeit.repeat(list_statement, setup=new_setup + _update_setup, number=iterations, repeat=repeats)\n",
" data += [{'version':'old', 'tokens':token_count, 't':t} for t in old]\n",
" data += [{'version':'new', 'tokens':token_count, 't':t} for t in new]"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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gAACCCBQagECb6nby+EQQAABBBBAAAEECLzMAAIIIIAAAggggECpBQi8pW4vh0MAAQQQQAABBBAg8DIDCCCAAAIIIIAAAqUWIPCWur0cDgEEEEAAAQQQQIDAywwggAACCCCAAAIIlFqAwFvq9nI4BBBAAAEEEEAAAQIvM4AAAggggAACCCBQagECb6nby+EQQAABBBBAAAEECLzMAAIIIIAAAggggECpBQi8pW4vh0MAAQQQQAABBBAg8DIDCCCAAAIIIIAAAqUWIPCWur0cDgEEEEAAAQQQQIDAywwggAACCCCAAAIIlFqAwFvq9nI4BBBAAAEEEEAAAQIvM4AAAggggAACCCBQagECb6nby+EQQAABBBBAAAEECLzMAAIIIIAAAggggECpBQi8pW4vh0MAAQQQQAABBBAg8DIDCCCAAAIIIIAAAqUWIPCWur0cDgEEEEAAAQQQQIDAywwggAACCCCAAAIIlFqAwFvq9nI4BBBAAAEEEEAAAQIvM4AAAggggAACCCBQagECb6nby+EQQAABBBBAAAEECLzMAAIIIIAAAggggECpBQi8pW4vh0MAAQQQQAABBBAg8DIDCCCAAAIIIIAAAqUWIPCWur0cDgEEEEAAAQQQQIDAywwggAACCCCAAAIIlFqAwFvq9nI4BBBAAAEEEEAAAQIvM4AAAggggAACCCBQagECb6nby+EQQAABBBBAAAEECLzMAAIIIIAAAggggECpBf4Pa2J7m4d/d1AAAAAASUVORK5CYII=\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.DataFrame(data)\n",
"df['millis'] = (df['t'] * 1000) / iterations\n",
"reference = df.groupby(['version','tokens'])['millis'].median().old\n",
"df = df.loc[df['version'] == 'new'].groupby(['version','tokens'])['millis'].median() / reference\n",
"df = df.reset_index()\n",
"df['ratio'] = 1 / df['millis']\n",
"\n",
"fig = px.bar(\n",
" df,\n",
" y='ratio',\n",
" x='tokens'\n",
")\n",
"fig.update_layout(barmode='group')\n",
"fig.update_xaxes(type='category')\n",
"Image(fig.to_image(format=\"png\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bulk\n",
"\n",
"Here it is shown that we can avoid a significant amount of overhead when computing minhashes using the bulk method. \n",
"\n",
"This yields anywhere from 5-25X performance gains when combined with the new update method."
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [],
"source": [
"iterations = 3\n",
"repeats = 2\n",
"\n",
"bulk_setup = '''\n",
"minhash_data = [[str(random.randint(0, 1000000)).encode(\"utf8\") for n in range({})] for m in range({})]\n",
"'''\n",
"old_statement = '''\n",
"for byte_data in minhash_data:\n",
" m = minhash.MinHash(hashfunc=hashfunc)\n",
" for b in byte_data:\n",
" m.update(b)\n",
"'''\n",
"new_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"bulk.compute_minhashes(minhash_data, m)\n",
"'''\n",
"\n",
"data = []\n",
"for minhash_count in [10, 100, 1000]:\n",
" for token_count in [10, 50, 100, 1000]:\n",
" _bulk_setup = bulk_setup.format(token_count, minhash_count)\n",
" old = timeit.repeat(old_statement, setup=old_setup + _bulk_setup, number=iterations, repeat=repeats)\n",
" new = timeit.repeat(new_statement, setup=new_setup + _bulk_setup, number=iterations, repeat=repeats)\n",
" data += [{'version':'old', 'tokens':token_count, 'minhashes':minhash_count, 't':t} for t in old]\n",
" data += [{'version':'new', 'tokens':token_count, 'minhashes':minhash_count, 't':t} for t in new]"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.DataFrame(data)\n",
"df['millis'] = (df['t'] * 1000) / iterations\n",
"reference = df.groupby(['version','minhashes','tokens'])['millis'].median().old\n",
"df = df.loc[df['version'] == 'new'].groupby(['version','minhashes','tokens'])['millis'].median() / reference\n",
"df = df.reset_index()\n",
"df['tokens'] = df['tokens'].astype(str)\n",
"df['ratio'] = 1 / df['millis']\n",
"\n",
"fig = px.bar(\n",
" df,\n",
" y='ratio',\n",
" x='minhashes',\n",
" color='tokens'\n",
")\n",
"fig.update_layout(barmode='group')\n",
"fig.update_xaxes(type='category')\n",
"Image(fig.to_image(format=\"png\"))"
]
}
],
"metadata": {
"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.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment