Committing module

This commit is contained in:
Jamie Hardt
2025-08-03 15:03:54 -07:00
commit 6c424099fd
9 changed files with 787 additions and 0 deletions

162
notebooks/00_Infer.ipynb Normal file
View File

@@ -0,0 +1,162 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "1a3ea8e9-175b-4592-9341-cdba151c6fc2",
"metadata": {},
"outputs": [],
"source": [
"categories = [\n",
" {\n",
" \"name\": \"Automobile\",\n",
" \"description\": \"Topics related to vehicles such as cars, trucks, and their brands.\",\n",
" \"keywords\": [\"Mazda\", \"Toyota\", \"SUV\", \"sedan\", \"pickup\"]\n",
" },\n",
" {\n",
" \"name\": \"Firearms\",\n",
" \"description\": \"Topics related to guns, rifles, pistols, ammunition, and other weapons.\",\n",
" \"keywords\": [\"Winchester\", \"Glock\", \"rifle\", \"bullet\", \"shotgun\"]\n",
" },\n",
" {\n",
" \"name\": \"Computers\",\n",
" \"description\": \"Topics involving computer hardware and software, such as hard drives, CPUs, and laptops.\",\n",
" \"keywords\": [\"Winchester\", \"CPU\", \"hard drive\", \"RAM\", \"SSD\", \"motherboard\"]\n",
" },\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d181860c-dd33-4327-b9d9-29297170558d",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/j/Library/Caches/pypoetry/virtualenvs/ucsinfer2-yBtBMMP2-py3.13/lib/python3.13/site-packages/torch/nn/modules/module.py:1762: FutureWarning: `encoder_attention_mask` is deprecated and will be removed in version 4.55.0 for `BertSdpaSelfAttention.forward`.\n",
" return forward_call(*args, **kwargs)\n"
]
}
],
"source": [
"from sentence_transformers import SentenceTransformer\n",
"import numpy as np\n",
"from numpy.linalg import norm\n",
"\n",
"model = SentenceTransformer(\"all-MiniLM-L6-v2\")\n",
"\n",
"def build_category_embedding(cat_info):\n",
" components = [cat_info[\"name\"], cat_info[\"description\"]] + cat_info.get('keywords', [])\n",
" composite_text = \". \".join(components)\n",
" return model.encode(composite_text, convert_to_numpy=True)\n",
"\n",
"# Embed all categories\n",
"\n",
"for info in categories:\n",
" info['embedding'] = build_category_embedding(info)\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "00842b35-04b3-42db-b352-b78154b65818",
"metadata": {},
"outputs": [],
"source": [
"# def cosine_similarity(a, b):\n",
"# return np.dot(a, b) / (norm(a) * norm(b))\n",
"\n",
"def classify_text(text, categories):\n",
" text_embedding = model.encode(text, convert_to_numpy=True)\n",
"\n",
" print(f\"Text: {text}\")\n",
" sim = model.similarity(text_embedding, [info['embedding'] for info in categories])\n",
" print(sim)\n",
" maxind = np.argmax(sim)\n",
" print(f\" -> Category: {categories[maxind]['name']}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "deb8cd47-b09b-445c-a688-a7e0bf0d7f2e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Text: I took my Winchester to the shooting range yesterday.\n",
"tensor([[-0.0456, 0.3874, 0.0935]])\n",
" -> Category: Firearms\n",
"Text: I bought a new Mazda with an automatic transmission.\n",
"tensor([[0.3483, 0.0454, 0.0285]])\n",
" -> Category: Automobile\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/j/Library/Caches/pypoetry/virtualenvs/ucsinfer2-yBtBMMP2-py3.13/lib/python3.13/site-packages/sentence_transformers/util.py:55: UserWarning: Creating a tensor from a list of numpy.ndarrays is extremely slow. Please consider converting the list to a single numpy.ndarray with numpy.array() before converting to a tensor. (Triggered internally at /Users/runner/work/pytorch/pytorch/pytorch/torch/csrc/utils/tensor_new.cpp:257.)\n",
" a = torch.tensor(a)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Text: My old Winchester hard drive finally failed.\n",
"tensor([[-0.0305, 0.2024, 0.3047]])\n",
" -> Category: Computers\n",
"Text: Keys clicking, typing\n",
"tensor([[0.0957, 0.1107, 0.1531]])\n",
" -> Category: Computers\n"
]
}
],
"source": [
"text1 = \"I took my Winchester to the shooting range yesterday.\"\n",
"text2 = \"I bought a new Mazda with an automatic transmission.\"\n",
"text3 = \"My old Winchester hard drive finally failed.\"\n",
"text4 = \"Keys clicking, typing\"\n",
"\n",
"\n",
"for text in [text1, text2, text3, text4]:\n",
" classify_text(text, categories)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1831d482-2596-439c-9641-eb91fcae73c6",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,225 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "eb04426a-cfb8-4f6f-9348-4308438fb9a5",
"metadata": {},
"source": [
"# Finding UCS categories with sentence embedding\n",
"\n",
"In this brief example we use sentence embedding to decide the UCS category for a sound, based on a text description.\n",
"\n",
"## Step 1: Creating embeddings for UCS categories\n",
"\n",
"We first select a SentenceTransformer model and establish a method for generating embeddings that correspond with each category by using the _Explanations_, _Category_, _SubCategory_, and _Synonyms_ from the UCS spreadsheet.\n",
"\n",
"`model.encode` is a slow process so we can write this as an async function so the client can parallelize it if it wants to."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "ef63fc07-c0d7-4616-9be1-1f0c2f275a69",
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import os.path\n",
"\n",
"from sentence_transformers import SentenceTransformer\n",
"import numpy as np\n",
"from numpy.linalg import norm\n",
"\n",
"MODEL_NAME = \"paraphrase-multilingual-mpnet-base-v2\"\n",
"\n",
"model = SentenceTransformer(MODEL_NAME)\n",
"\n",
"def build_category_embedding(cat_info: list[dict] ):\n",
" # print(f\"Building embedding for {cat_info['CatID']}...\")\n",
" components = [cat_info[\"Explanations\"], cat_info[\"Category\"], cat_info[\"SubCategory\"]] + cat_info.get('Synonyms', [])\n",
" composite_text = \". \".join(components)\n",
" return model.encode(composite_text, convert_to_numpy=True)"
]
},
{
"cell_type": "markdown",
"id": "da2820ad-851b-4cb7-a496-b124275eef58",
"metadata": {},
"source": [
"We now generate an embeddings for each category using the `ucs-community` repository, which conveniently has JSON versions of all of the UCS category descriptions and languages.\n",
"\n",
"We cache the categories in a file named `EMBEDDING_NAME.cache` so multiple runs don't have to recalculate the entire emebddings table. If this file doesn't exist we create it by creating the embeddings and pickling the result, and if it does we read it."
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "d4c1bc74-5c5d-4714-b671-c75c45b82490",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cached embeddings unavailable, recalculating...\n",
"Loaded 752 categories...\n",
"Writing embeddings to file...\n",
"Loaded 752 category embeddings...\n"
]
}
],
"source": [
"import pickle\n",
"\n",
"def create_embeddings(ucs: list) -> list:\n",
" embeddings_list = []\n",
" for info in ucs:\n",
" embeddings_list += [{'CatID': info['CatID'], \n",
" 'Embedding': build_category_embedding(info)\n",
" }]\n",
"\n",
" return embeddings_list\n",
"\n",
"EMBEDDING_CACHE_NAME = MODEL_NAME + \".cache\"\n",
"\n",
"if not os.path.exists(EMBEDDING_CACHE_NAME):\n",
" print(\"Cached embeddings unavailable, recalculating...\")\n",
"\n",
" # for lang in ['en']:\n",
" with open(\"ucs-community/json/en.json\") as f:\n",
" ucs = json.load(f)\n",
" \n",
" print(f\"Loaded {len(ucs)} categories...\")\n",
" \n",
" embeddings_list = create_embeddings(ucs)\n",
"\n",
" with open(EMBEDDING_CACHE_NAME, \"wb\") as g:\n",
" print(\"Writing embeddings to file...\")\n",
" pickle.dump(embeddings_list, g)\n",
"\n",
"else:\n",
" print(f\"Loading cached category emebddings...\")\n",
" with open(EMBEDDING_CACHE_NAME, \"rb\") as g:\n",
" embeddings_list = pickle.load(g)\n",
"\n",
"\n",
"print(f\"Loaded {len(embeddings_list)} category embeddings...\")"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "c98d1af1-b4c5-478c-b051-0f8f33399dfd",
"metadata": {},
"outputs": [],
"source": [
"def classify_text(text):\n",
" text_embedding = model.encode(text, convert_to_numpy=True)\n",
" sim = model.similarity(text_embedding, [info['Embedding'] for info in embeddings_list])\n",
" maxind = np.argmax(sim)\n",
" print(f\" ⇒ Category: {embeddings_list[maxind]['CatID']}\")\n",
"\n",
"\n",
"def classify_text_ranked(text):\n",
" text_embedding = model.encode(text, convert_to_numpy=True)\n",
" embeddings = np.array([info['Embedding'] for info in embeddings_list])\n",
" sim = model.similarity(text_embedding, embeddings)[0]\n",
" maxinds = np.argsort(sim)[-5:]\n",
" # print(maxinds)\n",
" print(\" ⇒ Top 5: \" + \", \".join([embeddings_list[x]['CatID'] for x in reversed(maxinds)]))\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "21768c01-d75f-49be-9f47-686332ba7921",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Text: Black powder explosion with loud report\n",
" ⇒ Top 5: EXPLMisc, AIRBrst, METLCrsh, EXPLReal, FIREBrst\n",
"\n",
"Text: Steam enging chuff\n",
" ⇒ Top 5: TRNSteam, FIRESizz, FIREGas, WATRFizz, GEOFuma\n",
"\n",
"Text: Playing card flick onto table\n",
" ⇒ Top 5: GAMEMisc, GAMEBoard, GAMECas, PAPRFltr, GAMEArcd\n",
"\n",
"Text: BMW 228 out fast\n",
" ⇒ Top 5: MOTRMisc, AIRHiss, VEHTire, VEHMoto, VEHAntq\n",
"\n",
"Text: City night skyline atmosphere\n",
" ⇒ Top 5: AMBUrbn, AMBTraf, AMBCele, AMBAir, AMBTran\n",
"\n",
"Text: Civil war 12-pound gun cannon\n",
" ⇒ Top 5: GUNCano, GUNArtl, GUNRif, BLLTMisc, WEAPMisc\n",
"\n",
"Text: Domestic combination boiler - pump switches off & cooling\n",
" ⇒ Top 5: MACHHvac, MACHFan, MACHPump, MOTRTurb, MECHRelay\n",
"\n",
"Text: Cello bow on cactus, animal screech\n",
" ⇒ Top 5: MUSCStr, CERMTonl, MUSCShake, MUSCPluck, MUSCWind\n",
"\n",
"Text: Electricity Generator And Arc Machine Start Up\n",
" ⇒ Top 5: ELECArc, MOTRElec, ELECSprk, BOATElec, TOOLPowr\n",
"\n",
"Text: Horse, canter One Horse: Canter Up, Stop\n",
" ⇒ Top 5: VOXScrm, WEAPWhip, FEETHors, MOVEAnml, VEHWagn\n",
"\n"
]
}
],
"source": [
"texts = [\n",
" \"Black powder explosion with loud report\",\n",
" \"Steam enging chuff\",\n",
" \"Playing card flick onto table\",\n",
" \"BMW 228 out fast\",\n",
" \"City night skyline atmosphere\",\n",
" \"Civil war 12-pound gun cannon\",\n",
" \"Domestic combination boiler - pump switches off & cooling\",\n",
" \"Cello bow on cactus, animal screech\",\n",
" \"Electricity Generator And Arc Machine Start Up\",\n",
" \"Horse, canter One Horse: Canter Up, Stop\"\n",
"]\n",
"\n",
"for text in texts:\n",
" print(f\"Text: {text}\")\n",
" classify_text_ranked(text)\n",
" print(\"\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36b7a30e-8bd1-486d-bc50-ce77704df64f",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,146 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "24915fba-1f44-46af-9233-66b896d7fa41",
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"with open(\"ucs-community/json/en.json\") as f:\n",
" ucs = json.load(f)\n",
" cat_ids = [x['CatID'] for x in ucs]\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "3a4b887d-5e72-4136-a7d9-650667619b12",
"metadata": {},
"outputs": [],
"source": [
"def ucs_catid(path: str) -> Optional[str]:\n",
" import os.path\n",
" 'True if the file at `path` has a valid UCS filename'\n",
"\n",
" basename = os.path.basename(path)\n",
" first_component = basename.split(\"_\")[0]\n",
"\n",
" if first_component in cat_ids:\n",
" return first_component\n",
" else:\n",
" return False"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "faedeeb7-8c4d-4e60-ab7a-9baf9add008a",
"metadata": {},
"outputs": [],
"source": [
"from typing import Optional\n",
"\n",
"def description(path: str) -> Optional[str]:\n",
" import json, subprocess\n",
" result = subprocess.run(['ffprobe', '-show_format', '-of', 'json', path], capture_output=True)\n",
" try:\n",
" result.check_returncode()\n",
" except:\n",
" return None\n",
" \n",
" stream = json.loads(result.stdout)\n",
" fmt = stream.get(\"format\", None)\n",
" if fmt:\n",
" tags = fmt.get(\"tags\", None)\n",
" if tags:\n",
" return tags.get(\"comment\", None)\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "f57c7c75-8cda-441a-bfb3-179e0afde861",
"metadata": {},
"outputs": [],
"source": [
"from typing import Optional, Tuple\n",
"\n",
"def test_data_for_file(path: str) -> Optional[Tuple[str, str]]:\n",
" 'CatID and description if both are present'\n",
"\n",
" catid = ucs_catid(path)\n",
" if catid is None:\n",
" return None\n",
" \n",
" desc = description(path)\n",
"\n",
" if desc is not None:\n",
" return (catid, desc)\n",
" else:\n",
" return None\n",
"\n",
"def collect_dataset(scan_root: str, set_name: str):\n",
" \"\"\"\n",
" Scans scan_root recursively and collects all catid/description pairs\n",
" it can find.\n",
" \"\"\"\n",
" import os, csv\n",
" test_data = []\n",
" for root, _, files in os.walk(scan_root):\n",
" for file in files:\n",
" if file.endswith(\".wav\") or file.endswith(\".flac\"):\n",
" if test_datum := test_data_for_file(os.path.join(root,file)):\n",
" test_data += [test_datum]\n",
"\n",
" with open(set_name + '.csv', 'w') as f:\n",
" writer = csv.writer(f)\n",
" writer.writerow(['Category', 'Description'])\n",
" for row in test_data:\n",
" writer.writerow(row)\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "1e05629d-15a5-406b-8064-879900e4b3c7",
"metadata": {},
"outputs": [],
"source": [
"collect_dataset(\"/Volumes/NAS SFX Library/JAMIELIB Libraries by Studio/_Designers/Jamie Hardt\",\"jamie_files\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7340f734-5ba7-4db0-a012-9e2bd46a4fc5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}