laura.wagner commited on
Commit
10d474d
·
1 Parent(s): 8b2ec70

llm query code update

Browse files
jupyter_notebooks/.ipynb_checkpoints/Section_2-3-4_Figure_8_deepfake_adapters-Copy1-checkpoint.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
jupyter_notebooks/.ipynb_checkpoints/Section_2-3-4_Figure_8_deepfake_adapters-checkpoint.ipynb CHANGED
@@ -121,77 +121,15 @@
121
  "id": "3c906826",
122
  "metadata": {},
123
  "source": [
124
- "## NER Code"
125
- ]
126
- },
127
- {
128
- "cell_type": "markdown",
129
- "id": "cb529f57",
130
- "metadata": {},
131
- "source": [
132
- "please put NER code here. on the first collumn of the adapter dataset in data/real_person_adapters.csv named entity recognition should be performed to extract the most plausible name."
133
  ]
134
  },
135
  {
136
  "cell_type": "code",
137
- "execution_count": 2,
138
  "id": "ner_code_cell",
139
  "metadata": {},
140
- "outputs": [
141
- {
142
- "name": "stdout",
143
- "output_type": "stream",
144
- "text": [
145
- "✅ spaCy model loaded: en_core_web_sm\n",
146
- "Loaded 18 rows\n",
147
- "\n",
148
- "🔄 Processing names with spaCy NER...\n",
149
- "\n",
150
- "📊 Name cleaning examples (with spaCy NER):\n",
151
- "====================================================================================================\n",
152
- "Original Name | Cleaned Name \n",
153
- "====================================================================================================\n",
154
- "Super Pose Book Vol.1 - ControlNet | Super Pose Book \n",
155
- "Liyuu LoRA | Liyuu \n",
156
- "HashimotoKanna/ 橋本環奈 _JP_Actress | HashimotoKanna \n",
157
- "Emma Watson (JG) | Emma Watson \n",
158
- "Gal Gadot「LoRa」 | Gal Gadot \n",
159
- "Scarlett Johansson「LoRa」 | Scarlett Johansson \n",
160
- "Gakki | Aragaki Yui | 新垣結衣 | Gakki \n",
161
- "Actress Satomi_石原○○ | Actress Satomi \n",
162
- "Game of Thrones Cast | Game Thrones Cast \n",
163
- "Natalie Portman「LoRa」 | Natalie Portman \n",
164
- "Emma Watson LoRA | Emma Watson \n",
165
- "====================================================================================================\n",
166
- "\n",
167
- "🧪 Leetspeak translation examples:\n",
168
- " 4kira LoRA -> akira\n",
169
- " 3mma Watson v2 -> Watson\n",
170
- " 1rene LORA -> irene\n",
171
- " L3vi Ackerman -> Levi Ackerman\n",
172
- "\n",
173
- "📈 Statistics:\n",
174
- " Total rows: 18\n",
175
- " Non-empty names: 18\n",
176
- " Empty names: 0\n",
177
- "\n",
178
- "🎯 Sample spaCy NER results:\n",
179
- " 1. IU\n",
180
- " 2. Super Pose Book\n",
181
- " 3. Liyuu\n",
182
- " 4. Irene\n",
183
- " 5. AESPA Karina\n",
184
- " 6. Saika Kawakita\n",
185
- " 7. Liu Yifei\n",
186
- " 8. HashimotoKanna\n",
187
- " 9. Emma Watson\n",
188
- " 10. Gal Gadot\n",
189
- "\n",
190
- "✅ Cleaned 18 names using spaCy NER\n",
191
- "💾 Saved to /home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/data/CSV/NER_POI_step01_pre_annotation.csv\n"
192
- ]
193
- }
194
- ],
195
  "source": [
196
  "import pandas as pd\n",
197
  "import re\n",
@@ -214,7 +152,7 @@
214
  "# Set up paths\n",
215
  "current_dir = Path.cwd()\n",
216
  "#input_file = current_dir.parent / \"data/CSV/real_person_adapters.csv\"\n",
217
- "input_file = current_dir.parent / \"data/CSV/samples/real_person_adapters_sample.csv\"\n",
218
  "\n",
219
  "# Load dataset\n",
220
  "df = pd.read_csv(input_file)\n",
@@ -274,7 +212,7 @@
274
  " \n",
275
  " # Remove LoRA-related terms (case insensitive)\n",
276
  " lora_terms = ['lora', 'loha', 'lycoris', 'controlnet', 'textual inversion', \n",
277
- " 'embedding', 'ti', 'checkpoint', 'model', 'adapter']\n",
278
  " for term in lora_terms:\n",
279
  " name = re.sub(rf'\\b{term}\\b', '', name, flags=re.IGNORECASE)\n",
280
  " \n",
@@ -397,7 +335,7 @@
397
  "print(f\"\\n✅ Cleaned {len(df)} names using spaCy NER\")\n",
398
  "\n",
399
  "# Save intermediate result\n",
400
- "output_step1 = current_dir.parent / \"data/CSV/NER_POI_step01_pre_annotation.csv\"\n",
401
  "df.to_csv(output_step1, index=False)\n",
402
  "print(f\"💾 Saved to {output_step1}\")\n"
403
  ]
@@ -407,52 +345,16 @@
407
  "id": "d701d1cb",
408
  "metadata": {},
409
  "source": [
410
- "## nationality to Country\n",
411
  "here tags related to nationality gets converted to the country equivalent. make sure isle of man is shows never up in the country collumn.as well as other uninhabited places."
412
  ]
413
  },
414
  {
415
  "cell_type": "code",
416
- "execution_count": 3,
417
  "id": "36ce71f2",
418
  "metadata": {},
419
- "outputs": [
420
- {
421
- "name": "stdout",
422
- "output_type": "stream",
423
- "text": [
424
- "Built country/nationality mapping with 781 entries\n",
425
- "\n",
426
- "Processed 18 rows\n",
427
- "Rows with country: 0\n",
428
- "Rows with nationality: 0\n",
429
- "Rows with profession: 14\n",
430
- "\n",
431
- "Top 10 countries:\n",
432
- "Series([], Name: count, dtype: int64)\n",
433
- "\n",
434
- "Sample results:\n",
435
- " real_name likely_country likely_nationality likely_profession\n",
436
- "0 IU celebrity\n",
437
- "1 Super Pose Book \n",
438
- "2 Liyuu \n",
439
- "3 Irene celebrity\n",
440
- "4 AESPA Karina celebrity\n",
441
- "5 Saika Kawakita celebrity\n",
442
- "6 Liu Yifei celebrity\n",
443
- "7 HashimotoKanna actor\n",
444
- "8 Emma Watson actor\n",
445
- "9 Gal Gadot model\n",
446
- "\n",
447
- "🔍 Checking 'Irene' entries:\n",
448
- " Name: Irene\n",
449
- " Tags: ['girl', 'photorealistic', 'asian', 'woman', 'beautiful', 'celebrity', 'korean']\n",
450
- " Country: \n",
451
- " Nationality: \n",
452
- "\n"
453
- ]
454
- }
455
- ],
456
  "source": [
457
  "import pandas as pd\n",
458
  "from pathlib import Path\n",
@@ -461,8 +363,8 @@
461
  "current_dir = Path.cwd()\n",
462
  "countries_file = current_dir.parent / \"misc/lists/countries.csv\"\n",
463
  "professions_file = current_dir.parent / \"misc/lists/professions.csv\"\n",
464
- "input_file = current_dir.parent / \"data/CSV/NER_POI_step01_pre_annotation.csv\"\n",
465
- "output_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\n",
466
  "\n",
467
  "# Load datasets\n",
468
  "poi_df = pd.read_csv(input_file)\n",
@@ -620,12 +522,6 @@
620
  " print()\n"
621
  ]
622
  },
623
- {
624
- "cell_type": "markdown",
625
- "id": "29eec5be",
626
- "metadata": {},
627
- "source": []
628
- },
629
  {
630
  "cell_type": "markdown",
631
  "id": "deepseek_header",
@@ -644,31 +540,10 @@
644
  },
645
  {
646
  "cell_type": "code",
647
- "execution_count": 10,
648
  "id": "deepseek_code",
649
  "metadata": {},
650
- "outputs": [
651
- {
652
- "name": "stdout",
653
- "output_type": "stream",
654
- "text": [
655
- "❌ Error: deepseek_api_key.txt not found in misc/credentials/\n",
656
- " Please create this file with your API key\n"
657
- ]
658
- },
659
- {
660
- "ename": "FileNotFoundError",
661
- "evalue": "[Errno 2] No such file or directory: '/home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/misc/credentials/deepseek_api_key.txt'",
662
- "output_type": "error",
663
- "traceback": [
664
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
665
- "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
666
- "Cell \u001b[0;32mIn[10], line 37\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[38;5;66;03m# === LOAD API KEY ===\u001b[39;00m\n\u001b[1;32m 36\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 37\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mapi_key_file\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[1;32m 38\u001b[0m api_key \u001b[38;5;241m=\u001b[39m f\u001b[38;5;241m.\u001b[39mread()\u001b[38;5;241m.\u001b[39mstrip()\n\u001b[1;32m 39\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m✅ Deepseek API key loaded\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
667
- "File \u001b[0;32m~/.local/lib/python3.10/site-packages/IPython/core/interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[0;34m(file, *args, **kwargs)\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 319\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 320\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 322\u001b[0m )\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mio_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
668
- "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/misc/credentials/deepseek_api_key.txt'"
669
- ]
670
- }
671
- ],
672
  "source": [
673
  "import pandas as pd\n",
674
  "import json\n",
@@ -680,7 +555,7 @@
680
  "from tqdm import tqdm\n",
681
  "\n",
682
  "current_dir = Path.cwd()\n",
683
- "input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\n",
684
  "professions_file = current_dir.parent / \"misc/lists/professions.csv\"\n",
685
  "professions_mapped_file = current_dir.parent / \"misc/lists/professions_mapped.csv\"\n",
686
  "api_key_file = current_dir.parent / \"misc/credentials/deepseek_api_key.txt\"\n",
@@ -858,8 +733,8 @@
858
  " return fields\n",
859
  "\n",
860
  "# === PROCESS DATA ===\n",
861
- "output_file = current_dir.parent / f\"data/CSV/deepseek_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
862
- "index_file = current_dir.parent / \"misc/deepseek_query_index.txt\"\n",
863
  "\n",
864
  "# Check for existing progress\n",
865
  "current_index = 0\n",
@@ -1663,63 +1538,44 @@
1663
  },
1664
  {
1665
  "cell_type": "markdown",
1666
- "id": "01086b35",
1667
- "metadata": {},
 
 
 
 
 
 
 
 
1668
  "source": [
1669
- "## Qwen-2.5-32B Local Annotation (Ollama)\n",
1670
- "\n",
1671
- "Run **Qwen-2.5-32B-Instruct** locally using Ollama - NO API COSTS!\n",
1672
- "\n",
1673
- "**Requirements:**\n",
1674
- "- Ollama installed: https://ollama.com/\n",
1675
- "- GPU: NVIDIA A100 80GB (recommended)\n",
1676
- "- RAM: 265GB system RAM\n",
1677
- "- Model cache: `data/models/` (auto-downloaded on first run)\n",
1678
- "- Model size: ~20GB download\n",
1679
- "- VRAM usage: ~22-25GB during inference\n",
1680
- "\n",
1681
- "**Setup:**\n",
1682
- "```bash\n",
1683
- "# 1. Install Ollama (if not installed)\n",
1684
- "curl -fsSL https://ollama.com/install.sh | sh\n",
1685
- "\n",
1686
- "# 2. Pull Qwen-2.5-32B-Instruct\n",
1687
- "ollama pull qwen2.5:32b-instruct\n",
1688
- "\n",
1689
- "# 3. Verify model is available\n",
1690
- "ollama list\n",
1691
- "```\n",
1692
- "\n",
1693
- "**Advantages:**\n",
1694
- "- ✅ FREE - No API costs\n",
1695
- "- ✅ Fast - Local inference on A100\n",
1696
- "- ✅ Privacy - Data never leaves your machine\n",
1697
- "- ✅ Offline - Works without internet\n",
1698
- "- ✅ High quality - 32B parameter model\n",
1699
- "\n",
1700
- "**Performance:**\n",
1701
- "- Speed: ~5-10 tokens/sec on A100\n",
1702
- "- Throughput: ~100-200 samples/hour (depends on prompt length)\n",
1703
- "- Cost: $0 (after model download)"
1704
  ]
1705
  },
1706
  {
1707
- "cell_type": "code",
1708
- "execution_count": null,
1709
- "id": "5dd7a803",
1710
- "metadata": {},
1711
- "outputs": [],
 
 
 
 
 
 
1712
  "source": [
1713
  "import pandas as pd\n",
1714
  "import json\n",
1715
  "import time\n",
1716
  "import re\n",
1717
- "import subprocess\n",
1718
  "from pathlib import Path\n",
1719
  "from tqdm import tqdm\n",
 
 
1720
  "\n",
1721
  "current_dir = Path.cwd()\n",
1722
- "input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\n",
1723
  "\n",
1724
  "# === CONFIGURATION ===\n",
1725
  "TEST_MODE = True\n",
@@ -1727,9 +1583,11 @@
1727
  "MAX_ROWS = 20000\n",
1728
  "SAVE_INTERVAL = 10\n",
1729
  "\n",
1730
- "# Ollama settings\n",
1731
- "MODEL_NAME = \"qwen2.5:32b-instruct\" # or \"qwen2.5:32b\" for base model\n",
1732
- "OLLAMA_HOST = \"http://localhost:11434\" # Default Ollama port\n",
 
 
1733
  "\n",
1734
  "PROFESSION_CATEGORIES = [\n",
1735
  " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
@@ -1737,46 +1595,61 @@
1737
  " \"sports professional\", \"tv personality\"\n",
1738
  "]\n",
1739
  "\n",
1740
- "# === CHECK OLLAMA ===\n",
1741
- "def check_ollama():\n",
1742
- " \"\"\"Check if Ollama is installed and model is available.\"\"\"\n",
1743
- " try:\n",
1744
- " result = subprocess.run(\n",
1745
- " [\"ollama\", \"list\"],\n",
1746
- " capture_output=True,\n",
1747
- " text=True,\n",
1748
- " timeout=5\n",
1749
- " )\n",
1750
- " \n",
1751
- " if result.returncode == 0:\n",
1752
- " print(\"✅ Ollama is installed\")\n",
1753
- " \n",
1754
- " # Check if model is available\n",
1755
- " if MODEL_NAME in result.stdout or \"qwen2.5\" in result.stdout:\n",
1756
- " print(f\"✅ Model {MODEL_NAME} is available\")\n",
1757
- " return True\n",
1758
- " else:\n",
1759
- " print(f\"⚠️ Model {MODEL_NAME} not found\")\n",
1760
- " print(f\" Run: ollama pull {MODEL_NAME}\")\n",
1761
- " return False\n",
1762
- " else:\n",
1763
- " print(\"❌ Ollama command failed\")\n",
1764
- " return False\n",
1765
- " except FileNotFoundError:\n",
1766
- " print(\"❌ Ollama not installed\")\n",
1767
- " print(\" Install: curl -fsSL https://ollama.com/install.sh | sh\")\n",
1768
- " return False\n",
1769
- " except Exception as e:\n",
1770
- " print(f\"❌ Error checking Ollama: {e}\")\n",
1771
- " return False\n",
1772
  "\n",
1773
- "# Check Ollama before proceeding\n",
1774
- "if not check_ollama():\n",
1775
- " raise RuntimeError(\"Ollama not ready. Please install Ollama and pull the model.\")\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1776
  "\n",
1777
  "# === LOAD DATA ===\n",
1778
  "df = pd.read_csv(input_file)\n",
1779
- "print(f\"\\nLoaded {len(df)} rows\")\n",
1780
  "\n",
1781
  "if TEST_MODE:\n",
1782
  " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
@@ -1808,72 +1681,84 @@
1808
  "\n",
1809
  "Return ONLY JSON, no extra text.\"\"\"\n",
1810
  "\n",
1811
- "# === QUERY QWEN LOCAL ===\n",
1812
- "def query_qwen_local(prompt: str) -> dict:\n",
1813
- " \"\"\"Query Qwen-2.5-32B via Ollama.\"\"\"\n",
1814
- " for attempt in range(3):\n",
1815
- " try:\n",
1816
- " result = subprocess.run(\n",
1817
- " [\n",
1818
- " \"ollama\", \"run\", MODEL_NAME,\n",
1819
- " prompt\n",
1820
- " ],\n",
1821
- " capture_output=True,\n",
1822
- " text=True,\n",
1823
- " timeout=60 # 60 second timeout per query\n",
 
 
1824
  " )\n",
1825
- " \n",
1826
- " if result.returncode == 0:\n",
1827
- " content = result.stdout.strip()\n",
1828
- " \n",
1829
- " # Parse JSON from response\n",
1830
- " json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)\n",
1831
- " if json_match:\n",
1832
- " return json.loads(json_match.group())\n",
1833
- " \n",
1834
- " # If no JSON found, try to extract from markdown code block\n",
1835
- " code_block = re.search(r'```(?:json)?\\s*({[^}]+})\\s*```', content, re.DOTALL)\n",
1836
- " if code_block:\n",
1837
- " return json.loads(code_block.group(1))\n",
1838
- " \n",
1839
- " return None\n",
1840
  " \n",
1841
- " except subprocess.TimeoutExpired:\n",
1842
- " print(f\"Qwen local timeout (attempt {attempt+1})\")\n",
1843
- " if attempt < 2:\n",
1844
- " time.sleep(2)\n",
1845
- " except json.JSONDecodeError as e:\n",
1846
- " print(f\"Qwen local JSON error (attempt {attempt+1}): {e}\")\n",
1847
- " if attempt < 2:\n",
1848
- " time.sleep(1)\n",
1849
- " except Exception as e:\n",
1850
- " print(f\"Qwen local error (attempt {attempt+1}): {e}\")\n",
1851
- " if attempt < 2:\n",
1852
- " time.sleep(2)\n",
1853
- " \n",
1854
- " return None\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1855
  "\n",
1856
  "# === PROCESS ===\n",
1857
- "output_file = current_dir.parent / f\"data/CSV/qwen_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
1858
- "index_file = current_dir.parent / \"misc/qwen_local_query_index.txt\"\n",
1859
  "\n",
1860
  "current_index = 0\n",
1861
  "if index_file.exists():\n",
1862
  " with open(index_file) as f:\n",
1863
  " current_index = int(f.read().strip())\n",
 
1864
  "\n",
1865
  "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
1866
  " if col not in df.columns:\n",
1867
  " df[col] = 'Unknown'\n",
1868
  "\n",
1869
- "print(f\"\\nAnnotating with QWEN-2.5-32B LOCAL - rows {current_index} to {len(df)}...\")\n",
1870
  "print(f\"Model: {MODEL_NAME}\")\n",
1871
- "print(f\"This may take a while (~100-200 samples/hour on A100)\\n\")\n",
1872
  "\n",
1873
  "try:\n",
1874
  " start_time = time.time()\n",
1875
  " \n",
1876
- " for i in tqdm(range(current_index, len(df)), desc=\"Qwen Local\"):\n",
1877
  " row = df.iloc[i]\n",
1878
  " \n",
1879
  " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
@@ -1885,7 +1770,7 @@
1885
  " row.get('likely_country', '')\n",
1886
  " )\n",
1887
  " \n",
1888
- " result = query_qwen_local(prompt)\n",
1889
  " \n",
1890
  " if result:\n",
1891
  " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
@@ -1903,7 +1788,7 @@
1903
  " \n",
1904
  " # Calculate stats\n",
1905
  " elapsed = time.time() - start_time\n",
1906
- " samples_done = i + 1 - (current_index - (i + 1))\n",
1907
  " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
1908
  " \n",
1909
  " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
@@ -1914,6 +1799,10 @@
1914
  " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
1915
  " \n",
1916
  " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
 
 
 
 
1917
  "\n",
1918
  "except KeyboardInterrupt:\n",
1919
  " print(f\"\\n⚠️ Interrupted by user\")\n",
@@ -1929,11 +1818,1021 @@
1929
  " f.write(str(current_index))\n",
1930
  " print(f\"Progress saved up to row {current_index}\")"
1931
  ]
1932
- }
1933
- ],
1934
- "metadata": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1935
  "language_info": {
1936
- "name": "python"
 
 
 
 
 
 
 
 
 
1937
  }
1938
  },
1939
  "nbformat": 4,
 
121
  "id": "3c906826",
122
  "metadata": {},
123
  "source": [
124
+ "## STEP 01 NER"
 
 
 
 
 
 
 
 
125
  ]
126
  },
127
  {
128
  "cell_type": "code",
129
+ "execution_count": null,
130
  "id": "ner_code_cell",
131
  "metadata": {},
132
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  "source": [
134
  "import pandas as pd\n",
135
  "import re\n",
 
152
  "# Set up paths\n",
153
  "current_dir = Path.cwd()\n",
154
  "#input_file = current_dir.parent / \"data/CSV/real_person_adapters.csv\"\n",
155
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter.csv\"\n",
156
  "\n",
157
  "# Load dataset\n",
158
  "df = pd.read_csv(input_file)\n",
 
212
  " \n",
213
  " # Remove LoRA-related terms (case insensitive)\n",
214
  " lora_terms = ['lora', 'loha', 'lycoris', 'controlnet', 'textual inversion', \n",
215
+ " 'embedding', 'ti', 'checkpoint', 'model', 'adapter', 'pony', 'sdxl', 'flux', 'illustrious', 'sd14', 'sd14', 'sd2', 'sd3', 'diffusion', 'stable', 'hunyuan']\n",
216
  " for term in lora_terms:\n",
217
  " name = re.sub(rf'\\b{term}\\b', '', name, flags=re.IGNORECASE)\n",
218
  " \n",
 
335
  "print(f\"\\n✅ Cleaned {len(df)} names using spaCy NER\")\n",
336
  "\n",
337
  "# Save intermediate result\n",
338
+ "output_step1 = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_01_NER.csv\"\n",
339
  "df.to_csv(output_step1, index=False)\n",
340
  "print(f\"💾 Saved to {output_step1}\")\n"
341
  ]
 
345
  "id": "d701d1cb",
346
  "metadata": {},
347
  "source": [
348
+ "## STEP 02: Nationality tag to Country\n",
349
  "here tags related to nationality gets converted to the country equivalent. make sure isle of man is shows never up in the country collumn.as well as other uninhabited places."
350
  ]
351
  },
352
  {
353
  "cell_type": "code",
354
+ "execution_count": null,
355
  "id": "36ce71f2",
356
  "metadata": {},
357
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  "source": [
359
  "import pandas as pd\n",
360
  "from pathlib import Path\n",
 
363
  "current_dir = Path.cwd()\n",
364
  "countries_file = current_dir.parent / \"misc/lists/countries.csv\"\n",
365
  "professions_file = current_dir.parent / \"misc/lists/professions.csv\"\n",
366
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_01_NER.csv\"\n",
367
+ "output_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
368
  "\n",
369
  "# Load datasets\n",
370
  "poi_df = pd.read_csv(input_file)\n",
 
522
  " print()\n"
523
  ]
524
  },
 
 
 
 
 
 
525
  {
526
  "cell_type": "markdown",
527
  "id": "deepseek_header",
 
540
  },
541
  {
542
  "cell_type": "code",
543
+ "execution_count": null,
544
  "id": "deepseek_code",
545
  "metadata": {},
546
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  "source": [
548
  "import pandas as pd\n",
549
  "import json\n",
 
555
  "from tqdm import tqdm\n",
556
  "\n",
557
  "current_dir = Path.cwd()\n",
558
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
559
  "professions_file = current_dir.parent / \"misc/lists/professions.csv\"\n",
560
  "professions_mapped_file = current_dir.parent / \"misc/lists/professions_mapped.csv\"\n",
561
  "api_key_file = current_dir.parent / \"misc/credentials/deepseek_api_key.txt\"\n",
 
733
  " return fields\n",
734
  "\n",
735
  "# === PROCESS DATA ===\n",
736
+ "output_file = current_dir.parent / f\"data/CSV/model_adapter/real_person_adapter_step_03_deepseek{'_test' if TEST_MODE else ''}.csv\"\n",
737
+ "index_file = current_dir.parent / \"misc/query_indicies/deepseek_query_index.txt\"\n",
738
  "\n",
739
  "# Check for existing progress\n",
740
  "current_index = 0\n",
 
1538
  },
1539
  {
1540
  "cell_type": "markdown",
1541
+ "id": "92126791-1705-4a8a-a15a-115f52af4af3",
1542
+ "metadata": {
1543
+ "execution": {
1544
+ "iopub.execute_input": "2025-11-21T16:35:17.398813Z",
1545
+ "iopub.status.busy": "2025-11-21T16:35:17.398624Z",
1546
+ "iopub.status.idle": "2025-11-21T16:35:17.400755Z",
1547
+ "shell.execute_reply": "2025-11-21T16:35:17.400352Z",
1548
+ "shell.execute_reply.started": "2025-11-21T16:35:17.398797Z"
1549
+ }
1550
+ },
1551
  "source": [
1552
+ "## Mistral local annotation(hf transformers) mistralai/Mistral-Small-3.2-24B-Instruct-2506"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1553
  ]
1554
  },
1555
  {
1556
+ "cell_type": "markdown",
1557
+ "id": "7768f9b2-d70f-4c0a-b157-97556c48b8dc",
1558
+ "metadata": {
1559
+ "execution": {
1560
+ "iopub.execute_input": "2025-11-21T18:46:21.419056Z",
1561
+ "iopub.status.busy": "2025-11-21T18:46:21.418806Z",
1562
+ "iopub.status.idle": "2025-11-21T18:46:23.987724Z",
1563
+ "shell.execute_reply": "2025-11-21T18:46:23.987032Z",
1564
+ "shell.execute_reply.started": "2025-11-21T18:46:21.419028Z"
1565
+ }
1566
+ },
1567
  "source": [
1568
  "import pandas as pd\n",
1569
  "import json\n",
1570
  "import time\n",
1571
  "import re\n",
 
1572
  "from pathlib import Path\n",
1573
  "from tqdm import tqdm\n",
1574
+ "import torch\n",
1575
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
1576
  "\n",
1577
  "current_dir = Path.cwd()\n",
1578
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
1579
  "\n",
1580
  "# === CONFIGURATION ===\n",
1581
  "TEST_MODE = True\n",
 
1583
  "MAX_ROWS = 20000\n",
1584
  "SAVE_INTERVAL = 10\n",
1585
  "\n",
1586
+ "# Model settings\n",
1587
+ "MODEL_NAME = \"mistralai/Mistral-Small-3.2-24B-Instruct-2506\"\n",
1588
+ "#MODEL_NAME = \"mistralai/Mistral-7B-Instruct-v0.3\"\n",
1589
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
1590
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
1591
  "\n",
1592
  "PROFESSION_CATEGORIES = [\n",
1593
  " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
 
1595
  " \"sports professional\", \"tv personality\"\n",
1596
  "]\n",
1597
  "\n",
1598
+ "# === LOAD MODEL ===\n",
1599
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
1600
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
1601
+ "print(f\"This may take a while on first run (~65GB download)...\\n\")\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1602
  "\n",
1603
+ "# Check GPU availability\n",
1604
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
1605
+ "print(f\"Device: {device}\")\n",
1606
+ "\n",
1607
+ "if device == \"cpu\":\n",
1608
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
1609
+ " print(\" Consider using a GPU or reducing model size.\")\n",
1610
+ "\n",
1611
+ "# Load tokenizer - FIX: Remove trust_remote_code and add use_fast=True\n",
1612
+ "print(\"Loading tokenizer...\")\n",
1613
+ "try:\n",
1614
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1615
+ " MODEL_NAME,\n",
1616
+ " cache_dir=str(CACHE_DIR),\n",
1617
+ " use_fast=True # Use the fast tokenizer\n",
1618
+ " )\n",
1619
+ "except Exception as e:\n",
1620
+ " print(f\"Failed with use_fast=True, trying use_fast=False...\")\n",
1621
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1622
+ " MODEL_NAME,\n",
1623
+ " cache_dir=str(CACHE_DIR),\n",
1624
+ " use_fast=False # Fall back to slow tokenizer if fast fails\n",
1625
+ " )\n",
1626
+ "\n",
1627
+ "# Ensure pad token is set\n",
1628
+ "if tokenizer.pad_token is None:\n",
1629
+ " tokenizer.pad_token = tokenizer.eos_token\n",
1630
+ "\n",
1631
+ "print(\"✅ Tokenizer loaded\")\n",
1632
+ "\n",
1633
+ "# Load model with optimizations\n",
1634
+ "print(\"Loading model (this may take several minutes)...\")\n",
1635
+ "model = AutoModelForCausalLM.from_pretrained(\n",
1636
+ " MODEL_NAME,\n",
1637
+ " cache_dir=str(CACHE_DIR),\n",
1638
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
1639
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
1640
+ " trust_remote_code=False # Changed from True - Mistral doesn't need this\n",
1641
+ ")\n",
1642
+ "model.eval() # Set to evaluation mode\n",
1643
+ "print(\"✅ Model loaded\")\n",
1644
+ "\n",
1645
+ "# Check VRAM usage\n",
1646
+ "if torch.cuda.is_available():\n",
1647
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
1648
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
1649
  "\n",
1650
  "# === LOAD DATA ===\n",
1651
  "df = pd.read_csv(input_file)\n",
1652
+ "print(f\"Loaded {len(df)} rows\")\n",
1653
  "\n",
1654
  "if TEST_MODE:\n",
1655
  " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
 
1681
  "\n",
1682
  "Return ONLY JSON, no extra text.\"\"\"\n",
1683
  "\n",
1684
+ "# === QUERY MISTRAL LOCAL ===\n",
1685
+ "def query_mistral_local(prompt: str) -> dict:\n",
1686
+ " \"\"\"Query Mistral-7B locally via transformers.\"\"\"\n",
1687
+ " try:\n",
1688
+ " # Format as chat message for Mistral\n",
1689
+ " messages = [\n",
1690
+ " {\"role\": \"user\", \"content\": prompt}\n",
1691
+ " ]\n",
1692
+ " \n",
1693
+ " # Tokenize - check if chat template is available\n",
1694
+ " if hasattr(tokenizer, 'apply_chat_template'):\n",
1695
+ " text = tokenizer.apply_chat_template(\n",
1696
+ " messages,\n",
1697
+ " tokenize=False,\n",
1698
+ " add_generation_prompt=True\n",
1699
  " )\n",
1700
+ " else:\n",
1701
+ " # Fallback for older tokenizers\n",
1702
+ " text = f\"[INST] {prompt} [/INST]\"\n",
 
 
 
 
 
 
 
 
 
 
 
 
1703
  " \n",
1704
+ " inputs = tokenizer([text], return_tensors=\"pt\", padding=True).to(device)\n",
1705
+ " \n",
1706
+ " # Generate\n",
1707
+ " with torch.no_grad():\n",
1708
+ " outputs = model.generate(\n",
1709
+ " **inputs,\n",
1710
+ " max_new_tokens=512,\n",
1711
+ " temperature=0.1,\n",
1712
+ " do_sample=True,\n",
1713
+ " top_p=0.9,\n",
1714
+ " pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id else tokenizer.eos_token_id\n",
1715
+ " )\n",
1716
+ " \n",
1717
+ " # Decode\n",
1718
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
1719
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n",
1720
+ " \n",
1721
+ " # Parse JSON from response\n",
1722
+ " json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n",
1723
+ " if json_match:\n",
1724
+ " return json.loads(json_match.group())\n",
1725
+ " \n",
1726
+ " # Try markdown code block\n",
1727
+ " code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n",
1728
+ " if code_block:\n",
1729
+ " return json.loads(code_block.group(1))\n",
1730
+ " \n",
1731
+ " return None\n",
1732
+ " \n",
1733
+ " except json.JSONDecodeError as e:\n",
1734
+ " print(f\"JSON parse error: {e}\")\n",
1735
+ " return None\n",
1736
+ " except Exception as e:\n",
1737
+ " print(f\"Generation error: {e}\")\n",
1738
+ " return None\n",
1739
  "\n",
1740
  "# === PROCESS ===\n",
1741
+ "output_file = current_dir.parent / f\"data/CSV/mistral_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
1742
+ "index_file = current_dir.parent / \"misc/mistral_local_query_index.txt\"\n",
1743
  "\n",
1744
  "current_index = 0\n",
1745
  "if index_file.exists():\n",
1746
  " with open(index_file) as f:\n",
1747
  " current_index = int(f.read().strip())\n",
1748
+ " print(f\"Resuming from index {current_index}\")\n",
1749
  "\n",
1750
  "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
1751
  " if col not in df.columns:\n",
1752
  " df[col] = 'Unknown'\n",
1753
  "\n",
1754
+ "print(f\"\\nAnnotating with Mistral-7B LOCAL - rows {current_index} to {len(df)}...\")\n",
1755
  "print(f\"Model: {MODEL_NAME}\")\n",
1756
+ "print(f\"This may take a while...\\n\")\n",
1757
  "\n",
1758
  "try:\n",
1759
  " start_time = time.time()\n",
1760
  " \n",
1761
+ " for i in tqdm(range(current_index, len(df)), desc=\"Mistral Local\"):\n",
1762
  " row = df.iloc[i]\n",
1763
  " \n",
1764
  " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
 
1770
  " row.get('likely_country', '')\n",
1771
  " )\n",
1772
  " \n",
1773
+ " result = query_mistral_local(prompt)\n",
1774
  " \n",
1775
  " if result:\n",
1776
  " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
 
1788
  " \n",
1789
  " # Calculate stats\n",
1790
  " elapsed = time.time() - start_time\n",
1791
+ " samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n",
1792
  " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
1793
  " \n",
1794
  " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
 
1799
  " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
1800
  " \n",
1801
  " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
1802
+ " \n",
1803
+ " # Show VRAM stats\n",
1804
+ " if torch.cuda.is_available():\n",
1805
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
1806
  "\n",
1807
  "except KeyboardInterrupt:\n",
1808
  " print(f\"\\n⚠️ Interrupted by user\")\n",
 
1818
  " f.write(str(current_index))\n",
1819
  " print(f\"Progress saved up to row {current_index}\")"
1820
  ]
1821
+ },
1822
+ {
1823
+ "cell_type": "markdown",
1824
+ "id": "62ba9af9-a831-4ccb-8d12-31a06acf38a6",
1825
+ "metadata": {},
1826
+ "source": [
1827
+ "## BLOOM local"
1828
+ ]
1829
+ },
1830
+ {
1831
+ "cell_type": "code",
1832
+ "execution_count": 6,
1833
+ "id": "72c468dc-1cbe-41d4-b71b-17c40ea4f9a1",
1834
+ "metadata": {
1835
+ "execution": {
1836
+ "iopub.execute_input": "2025-11-21T19:14:07.293031Z",
1837
+ "iopub.status.busy": "2025-11-21T19:14:07.292824Z",
1838
+ "iopub.status.idle": "2025-11-21T19:14:15.169912Z",
1839
+ "shell.execute_reply": "2025-11-21T19:14:15.169105Z",
1840
+ "shell.execute_reply.started": "2025-11-21T19:14:07.293014Z"
1841
+ }
1842
+ },
1843
+ "outputs": [
1844
+ {
1845
+ "name": "stdout",
1846
+ "output_type": "stream",
1847
+ "text": [
1848
+ "Loading model: bigscience/bloomz-7b1\n",
1849
+ "Cache directory: /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/models\n",
1850
+ "This may take a while on first run (~14GB download)...\n",
1851
+ "\n",
1852
+ "Device: cuda\n",
1853
+ "Loading tokenizer...\n",
1854
+ "✅ Tokenizer loaded\n",
1855
+ "Loading model (this may take several minutes)...\n",
1856
+ "✅ Model loaded\n",
1857
+ "VRAM used: 28.59 GB\n",
1858
+ "\n",
1859
+ "Loaded 50861 rows\n",
1860
+ "Running in TEST MODE with 10 samples\n",
1861
+ "Resuming from index 10\n",
1862
+ "Creating prompts...\n",
1863
+ "\n",
1864
+ "Annotating with BLOOMZ-7B1 LOCAL - rows 10 to 10...\n",
1865
+ "Model: bigscience/bloomz-7b1\n",
1866
+ "This may take a while...\n",
1867
+ "\n"
1868
+ ]
1869
+ },
1870
+ {
1871
+ "name": "stderr",
1872
+ "output_type": "stream",
1873
+ "text": [
1874
+ "BLOOMZ Local: 0it [00:00, ?it/s]"
1875
+ ]
1876
+ },
1877
+ {
1878
+ "name": "stdout",
1879
+ "output_type": "stream",
1880
+ "text": [
1881
+ "\n",
1882
+ "✅ Done! Results: /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/CSV/bloomz_annotated_POI_test.csv\n",
1883
+ "Total time: 0.0 minutes\n",
1884
+ "Average speed: 29043074.4 samples/hour\n",
1885
+ "Successful parses: 0/10 (0.0%)\n",
1886
+ "Failed parses: 0/10\n",
1887
+ "\n",
1888
+ "=== Summary Statistics ===\n",
1889
+ "Total processed: 10\n",
1890
+ "\n",
1891
+ "Gender distribution:\n",
1892
+ "gender\n",
1893
+ "Unknown 10\n",
1894
+ "Name: count, dtype: int64\n",
1895
+ "\n",
1896
+ "Top 10 profession combinations:\n",
1897
+ "profession_llm\n",
1898
+ "Unknown 10\n",
1899
+ "Name: count, dtype: int64\n",
1900
+ "\n",
1901
+ "Top 10 countries:\n",
1902
+ "country\n",
1903
+ "Unknown 10\n",
1904
+ "Name: count, dtype: int64\n",
1905
+ "\n",
1906
+ "=== Sample Results ===\n",
1907
+ " real_name full_name gender profession_llm country\n",
1908
+ " IU Unknown Unknown Unknown Unknown\n",
1909
+ "Super Pose Book Unknown Unknown Unknown Unknown\n",
1910
+ " Liyuu Unknown Unknown Unknown Unknown\n",
1911
+ " Irene Unknown Unknown Unknown Unknown\n",
1912
+ " AESPA Karina Unknown Unknown Unknown Unknown\n",
1913
+ " Saika Kawakita Unknown Unknown Unknown Unknown\n",
1914
+ " Liu Yifei Unknown Unknown Unknown Unknown\n",
1915
+ " HashimotoKanna Unknown Unknown Unknown Unknown\n",
1916
+ " Emma Watson Unknown Unknown Unknown Unknown\n",
1917
+ " Gal Gadot Unknown Unknown Unknown Unknown\n",
1918
+ "\n",
1919
+ "Final VRAM usage: 28.59 GB\n"
1920
+ ]
1921
+ },
1922
+ {
1923
+ "name": "stderr",
1924
+ "output_type": "stream",
1925
+ "text": [
1926
+ "\n"
1927
+ ]
1928
+ }
1929
+ ],
1930
+ "source": [
1931
+ "import pandas as pd\n",
1932
+ "import json\n",
1933
+ "import time\n",
1934
+ "import re\n",
1935
+ "from pathlib import Path\n",
1936
+ "from tqdm import tqdm\n",
1937
+ "import torch\n",
1938
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
1939
+ "\n",
1940
+ "# Import is used for pd.notna() and pd.isna() checks\n",
1941
+ "\n",
1942
+ "current_dir = Path.cwd()\n",
1943
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
1944
+ "\n",
1945
+ "# === CONFIGURATION ===\n",
1946
+ "TEST_MODE = True\n",
1947
+ "TEST_SIZE = 10\n",
1948
+ "MAX_ROWS = 20000\n",
1949
+ "SAVE_INTERVAL = 10\n",
1950
+ "\n",
1951
+ "# Model settings - BLOOMZ (BigScience - European consortium)\n",
1952
+ "MODEL_NAME = \"bigscience/bloomz-7b1\" # Largest instruction-tuned BLOOM model\n",
1953
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
1954
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
1955
+ "\n",
1956
+ "PROFESSION_CATEGORIES = [\n",
1957
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
1958
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
1959
+ " \"sports professional\", \"tv personality\"\n",
1960
+ "]\n",
1961
+ "\n",
1962
+ "# === LOAD MODEL ===\n",
1963
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
1964
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
1965
+ "print(f\"This may take a while on first run (~14GB download)...\\n\")\n",
1966
+ "\n",
1967
+ "# Check GPU availability\n",
1968
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
1969
+ "print(f\"Device: {device}\")\n",
1970
+ "\n",
1971
+ "if device == \"cpu\":\n",
1972
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
1973
+ " print(\" Consider using a GPU or reducing model size.\")\n",
1974
+ "\n",
1975
+ "# Load tokenizer\n",
1976
+ "print(\"Loading tokenizer...\")\n",
1977
+ "try:\n",
1978
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1979
+ " MODEL_NAME,\n",
1980
+ " cache_dir=str(CACHE_DIR)\n",
1981
+ " )\n",
1982
+ " print(\"✅ Tokenizer loaded\")\n",
1983
+ "except Exception as e:\n",
1984
+ " print(f\"❌ Error loading tokenizer: {e}\")\n",
1985
+ " raise\n",
1986
+ "\n",
1987
+ "# Ensure pad token is set\n",
1988
+ "if tokenizer.pad_token is None:\n",
1989
+ " tokenizer.pad_token = tokenizer.eos_token\n",
1990
+ " print(f\"Set pad_token to eos_token: {tokenizer.eos_token}\")\n",
1991
+ "\n",
1992
+ "# Load model with optimizations\n",
1993
+ "print(\"Loading model (this may take several minutes)...\")\n",
1994
+ "try:\n",
1995
+ " model = AutoModelForCausalLM.from_pretrained(\n",
1996
+ " MODEL_NAME,\n",
1997
+ " cache_dir=str(CACHE_DIR),\n",
1998
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
1999
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
2000
+ " low_cpu_mem_usage=True # Optimize memory usage\n",
2001
+ " )\n",
2002
+ " model.eval() # Set to evaluation mode\n",
2003
+ " print(\"✅ Model loaded\")\n",
2004
+ "except Exception as e:\n",
2005
+ " print(f\"❌ Error loading model: {e}\")\n",
2006
+ " raise\n",
2007
+ "\n",
2008
+ "# Check VRAM usage\n",
2009
+ "if torch.cuda.is_available():\n",
2010
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
2011
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
2012
+ "\n",
2013
+ "# === LOAD DATA ===\n",
2014
+ "df = pd.read_csv(input_file)\n",
2015
+ "print(f\"Loaded {len(df)} rows\")\n",
2016
+ "\n",
2017
+ "if TEST_MODE:\n",
2018
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
2019
+ " df = df.head(TEST_SIZE).copy()\n",
2020
+ "elif MAX_ROWS:\n",
2021
+ " df = df.head(MAX_ROWS).copy()\n",
2022
+ "\n",
2023
+ "# === CREATE PROMPT (Exact DeepSeek style) ===\n",
2024
+ "def create_prompt(row):\n",
2025
+ " \"\"\"Create prompt matching exact DeepSeek format.\"\"\"\n",
2026
+ " name = row.get('real_name', row.get('name', ''))\n",
2027
+ " if pd.isna(name):\n",
2028
+ " name = row.get('name', '')\n",
2029
+ " \n",
2030
+ " # Gather hints exactly like DeepSeek version\n",
2031
+ " hints = []\n",
2032
+ " if pd.notna(row.get('likely_profession')):\n",
2033
+ " hints.append(str(row['likely_profession']))\n",
2034
+ " if pd.notna(row.get('likely_nationality')):\n",
2035
+ " hints.append(str(row['likely_nationality']))\n",
2036
+ " if pd.notna(row.get('likely_country')):\n",
2037
+ " hints.append(str(row['likely_country']))\n",
2038
+ " \n",
2039
+ " # Add tags if we don't have enough hints\n",
2040
+ " if len(hints) < 3:\n",
2041
+ " for i in range(1, 8):\n",
2042
+ " tag_col = f'tag_{i}'\n",
2043
+ " if tag_col in row and pd.notna(row[tag_col]):\n",
2044
+ " tag_val = str(row[tag_col])\n",
2045
+ " if tag_val not in hints:\n",
2046
+ " hints.append(tag_val)\n",
2047
+ " if len(hints) >= 5:\n",
2048
+ " break\n",
2049
+ " \n",
2050
+ " hint_text = \", \".join(hints[:5]) if hints else \"none\"\n",
2051
+ " \n",
2052
+ " return f\"\"\"Given '{name}' ({hint_text}), provide:\n",
2053
+ "1. Full legal name (Western order if non-latin script)\n",
2054
+ "2. Any stage names/aliases (comma separated)\n",
2055
+ "3. Gender (Male/Female/Other/Unknown)\n",
2056
+ "4. Top 3 most likely professions from ONLY these categories:\n",
2057
+ " - actor\n",
2058
+ " - adult performer\n",
2059
+ " - singer/musician\n",
2060
+ " - model\n",
2061
+ " - online personality (includes streamers, cosplayers, influencers)\n",
2062
+ " - public figure (includes politicians, activists, journalists, authors)\n",
2063
+ " - voice actor/ASMR\n",
2064
+ " - sports professional\n",
2065
+ " - tv personality (includes hosts, presenters, reality TV)\n",
2066
+ "\n",
2067
+ "5. Primary country associated\n",
2068
+ "\n",
2069
+ "IMPORTANT:\n",
2070
+ "- Choose professions ONLY from the 9 categories above\n",
2071
+ "- Provide up to 3 professions, comma-separated, ordered by relevance\n",
2072
+ "- Be SPECIFIC: choose the most accurate category for each role\n",
2073
+ "- \"online personality\" includes: streamers, cosplayers, YouTubers, influencers, content creators\n",
2074
+ "- Use 'Unknown' when uncertain or for fictional characters/places\n",
2075
+ "- For multi-role people, list all relevant categories (e.g., \"actor, singer/musician, online personality\")\n",
2076
+ "\n",
2077
+ "Respond with exactly 5 numbered lines.\"\"\"\n",
2078
+ "\n",
2079
+ "# === QUERY BLOOMZ LOCAL ===\n",
2080
+ "def query_bloomz_local(prompt: str) -> dict:\n",
2081
+ " \"\"\"Query BLOOMZ-7B1 locally via transformers, parse numbered response.\"\"\"\n",
2082
+ " try:\n",
2083
+ " # Add system message context to the prompt (BLOOMZ doesn't have separate system/user roles)\n",
2084
+ " full_prompt = \"\"\"You are an assistant that extracts key data on a person based on the name. Respond with exactly 5 numbered lines. For professions, choose ONLY from these categories: actor, adult performer, singer/musician, model, online personality, public figure, voice actor/ASMR, sports professional, tv personality.\n",
2085
+ "\n",
2086
+ "\"\"\" + prompt\n",
2087
+ " \n",
2088
+ " inputs = tokenizer(\n",
2089
+ " full_prompt, \n",
2090
+ " return_tensors=\"pt\", \n",
2091
+ " padding=True,\n",
2092
+ " truncation=True,\n",
2093
+ " max_length=2048 # BLOOMZ has 2048 token context\n",
2094
+ " ).to(device)\n",
2095
+ " \n",
2096
+ " # Generate with BLOOMZ-optimized parameters\n",
2097
+ " with torch.no_grad():\n",
2098
+ " outputs = model.generate(\n",
2099
+ " **inputs,\n",
2100
+ " max_new_tokens=256, # Enough for 5 numbered lines\n",
2101
+ " temperature=0.05, # Match DeepSeek's low temperature\n",
2102
+ " do_sample=True,\n",
2103
+ " top_p=0.8, # Match DeepSeek's top_p\n",
2104
+ " top_k=50,\n",
2105
+ " repetition_penalty=1.2,\n",
2106
+ " pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id else tokenizer.eos_token_id,\n",
2107
+ " eos_token_id=tokenizer.eos_token_id\n",
2108
+ " )\n",
2109
+ " \n",
2110
+ " # Decode only the generated part\n",
2111
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
2112
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True).strip()\n",
2113
+ " \n",
2114
+ " # Debug: print first response to see format\n",
2115
+ " if not hasattr(query_bloomz_local, 'printed_example'):\n",
2116
+ " print(f\"\\n📝 Example BLOOMZ response:\\n{response}\\n\")\n",
2117
+ " query_bloomz_local.printed_example = True\n",
2118
+ " \n",
2119
+ " # Parse the numbered response (same as DeepSeek)\n",
2120
+ " return parse_response(response)\n",
2121
+ " \n",
2122
+ " except Exception as e:\n",
2123
+ " print(f\"Generation error: {e}\")\n",
2124
+ " return None\n",
2125
+ "\n",
2126
+ "\n",
2127
+ "# === PARSE RESPONSE (Exact DeepSeek format) ===\n",
2128
+ "def parse_response(response):\n",
2129
+ " \"\"\"Parse numbered response into structured fields.\"\"\"\n",
2130
+ " if not response:\n",
2131
+ " return {\n",
2132
+ " 'full_name': 'Unknown',\n",
2133
+ " 'aliases': 'Unknown',\n",
2134
+ " 'gender': 'Unknown',\n",
2135
+ " 'profession_llm': 'Unknown',\n",
2136
+ " 'country': 'Unknown'\n",
2137
+ " }\n",
2138
+ " \n",
2139
+ " # Split into lines and clean\n",
2140
+ " lines = [line.strip() for line in response.split('\\n') if line.strip()]\n",
2141
+ " \n",
2142
+ " # Initialize with Unknown values\n",
2143
+ " fields = {\n",
2144
+ " 'full_name': 'Unknown',\n",
2145
+ " 'aliases': 'Unknown',\n",
2146
+ " 'gender': 'Unknown',\n",
2147
+ " 'profession_llm': 'Unknown',\n",
2148
+ " 'country': 'Unknown'\n",
2149
+ " }\n",
2150
+ " \n",
2151
+ " # Extract information from each numbered line\n",
2152
+ " for line in lines:\n",
2153
+ " if line.startswith('1.') or line.startswith('1)'):\n",
2154
+ " fields['full_name'] = line[2:].strip()\n",
2155
+ " elif line.startswith('2.') or line.startswith('2)'):\n",
2156
+ " fields['aliases'] = line[2:].strip()\n",
2157
+ " elif line.startswith('3.') or line.startswith('3)'):\n",
2158
+ " fields['gender'] = line[2:].strip()\n",
2159
+ " elif line.startswith('4.') or line.startswith('4)'):\n",
2160
+ " fields['profession_llm'] = line[2:].strip()\n",
2161
+ " elif line.startswith('5.') or line.startswith('5)'):\n",
2162
+ " fields['country'] = line[2:].strip()\n",
2163
+ " \n",
2164
+ " return fields\n",
2165
+ "\n",
2166
+ "# === PROCESS ===\n",
2167
+ "output_file = current_dir.parent / f\"data/CSV/BLOOM_annotated_POI{'_test' if TEST_MODE else 'BLOOM'}.csv\"\n",
2168
+ "index_file = current_dir.parent / \"misc/bloomz_query_index.txt\"\n",
2169
+ "\n",
2170
+ "current_index = 0\n",
2171
+ "if index_file.exists():\n",
2172
+ " with open(index_file) as f:\n",
2173
+ " current_index = int(f.read().strip())\n",
2174
+ " print(f\"Resuming from index {current_index}\")\n",
2175
+ "\n",
2176
+ "# Initialize columns (same as DeepSeek)\n",
2177
+ "for col in ['full_name', 'gender', 'profession_llm', 'country', 'aliases']:\n",
2178
+ " if col not in df.columns:\n",
2179
+ " df[col] = 'Unknown'\n",
2180
+ "\n",
2181
+ "# Create prompts for all rows (same as DeepSeek)\n",
2182
+ "print(\"Creating prompts...\")\n",
2183
+ "df['prompt'] = df.apply(create_prompt, axis=1)\n",
2184
+ "\n",
2185
+ "print(f\"\\nAnnotating with BLOOMZ-7B1 LOCAL - rows {current_index} to {len(df)}...\")\n",
2186
+ "print(f\"Model: {MODEL_NAME}\")\n",
2187
+ "print(f\"This may take a while...\\n\")\n",
2188
+ "\n",
2189
+ "try:\n",
2190
+ " start_time = time.time()\n",
2191
+ " successful_parses = 0\n",
2192
+ " failed_parses = 0\n",
2193
+ " \n",
2194
+ " for i in tqdm(range(current_index, len(df)), desc=\"BLOOMZ Local\"):\n",
2195
+ " row = df.iloc[i]\n",
2196
+ " \n",
2197
+ " # Query model with the pre-created prompt\n",
2198
+ " result = query_bloomz_local(row['prompt'])\n",
2199
+ " \n",
2200
+ " if result:\n",
2201
+ " successful_parses += 1\n",
2202
+ " # Update dataframe with all fields (same structure as DeepSeek)\n",
2203
+ " for key, value in result.items():\n",
2204
+ " df.at[i, key] = value\n",
2205
+ " else:\n",
2206
+ " failed_parses += 1\n",
2207
+ " \n",
2208
+ " current_index = i + 1\n",
2209
+ " \n",
2210
+ " # Save progress periodically\n",
2211
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2212
+ " df.to_csv(output_file, index=False)\n",
2213
+ " with open(index_file, 'w') as f:\n",
2214
+ " f.write(str(current_index))\n",
2215
+ " \n",
2216
+ " # Calculate stats\n",
2217
+ " elapsed = time.time() - start_time\n",
2218
+ " samples_done = i + 1\n",
2219
+ " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
2220
+ " success_rate = (successful_parses / samples_done) * 100 if samples_done > 0 else 0\n",
2221
+ " \n",
2222
+ " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour, {success_rate:.1f}% success rate)\")\n",
2223
+ " \n",
2224
+ " elapsed_total = time.time() - start_time\n",
2225
+ " print(f\"\\n✅ Done! Results: {output_file}\")\n",
2226
+ " print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
2227
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2228
+ " print(f\"Successful parses: {successful_parses}/{len(df)} ({(successful_parses/len(df))*100:.1f}%)\")\n",
2229
+ " print(f\"Failed parses: {failed_parses}/{len(df)}\")\n",
2230
+ " \n",
2231
+ " # Summary statistics (same as DeepSeek)\n",
2232
+ " print(\"\\n=== Summary Statistics ===\")\n",
2233
+ " print(f\"Total processed: {len(df)}\")\n",
2234
+ " print(f\"\\nGender distribution:\")\n",
2235
+ " print(df['gender'].value_counts())\n",
2236
+ " print(f\"\\nTop 10 profession combinations:\")\n",
2237
+ " print(df['profession_llm'].value_counts().head(10))\n",
2238
+ " print(f\"\\nTop 10 countries:\")\n",
2239
+ " print(df['country'].value_counts().head(10))\n",
2240
+ " \n",
2241
+ " # Sample results\n",
2242
+ " print(\"\\n=== Sample Results ===\")\n",
2243
+ " display_cols = ['real_name', 'full_name', 'gender', 'profession_llm', 'country']\n",
2244
+ " available_cols = [col for col in display_cols if col in df.columns]\n",
2245
+ " print(df[available_cols].head(10).to_string(index=False))\n",
2246
+ " \n",
2247
+ " # Show VRAM stats\n",
2248
+ " if torch.cuda.is_available():\n",
2249
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2250
+ "\n",
2251
+ "except KeyboardInterrupt:\n",
2252
+ " print(f\"\\n⚠️ Interrupted by user\")\n",
2253
+ " df.to_csv(output_file, index=False)\n",
2254
+ " with open(index_file, 'w') as f:\n",
2255
+ " f.write(str(current_index))\n",
2256
+ " print(f\"Progress saved up to row {current_index}\")\n",
2257
+ "\n",
2258
+ "except Exception as e:\n",
2259
+ " print(f\"⚠️ Error: {e}\")\n",
2260
+ " import traceback\n",
2261
+ " traceback.print_exc()\n",
2262
+ " df.to_csv(output_file, index=False)\n",
2263
+ " with open(index_file, 'w') as f:\n",
2264
+ " f.write(str(current_index))\n",
2265
+ " print(f\"Progress saved up to row {current_index}\")"
2266
+ ]
2267
+ },
2268
+ {
2269
+ "cell_type": "markdown",
2270
+ "id": "24fb0c1f-a65e-4863-ad9b-5a9e8ffa2f94",
2271
+ "metadata": {
2272
+ "execution": {
2273
+ "iopub.execute_input": "2025-11-21T18:56:46.267902Z",
2274
+ "iopub.status.busy": "2025-11-21T18:56:46.267700Z",
2275
+ "iopub.status.idle": "2025-11-21T18:56:46.272355Z",
2276
+ "shell.execute_reply": "2025-11-21T18:56:46.271747Z",
2277
+ "shell.execute_reply.started": "2025-11-21T18:56:46.267886Z"
2278
+ }
2279
+ },
2280
+ "source": [
2281
+ "## Qwen-2.5-32B Local Annotation (Hugging Face Transformers)\n",
2282
+ "\n",
2283
+ "Run **Qwen-2.5-32B-Instruct** locally using Hugging Face Transformers - NO API COSTS!\n",
2284
+ "\n",
2285
+ "**Requirements:**\n",
2286
+ "- GPU: NVIDIA A100 80GB or similar (32B model needs ~60-70GB VRAM)\n",
2287
+ "- RAM: 128GB+ system RAM recommended\n",
2288
+ "- Model cache: `data/models/` (auto-downloaded on first run)\n",
2289
+ "- Model size: ~65GB download (BF16 weights)\n",
2290
+ "\n",
2291
+ "**Installation:**\n",
2292
+ "```bash\n",
2293
+ "# Install required packages\n",
2294
+ "pip install torch transformers accelerate\n",
2295
+ "```\n",
2296
+ "\n",
2297
+ "**Advantages:**\n",
2298
+ "- ✅ FREE - No API costs\n",
2299
+ "- ✅ Fast - Local inference with GPU acceleration\n",
2300
+ "- ✅ Privacy - Data never leaves your machine\n",
2301
+ "- ✅ Offline - Works without internet (after download)\n",
2302
+ "- ✅ High quality - 32B parameter instruction-tuned model\n",
2303
+ "\n",
2304
+ "**Performance:**\n",
2305
+ "- Speed: ~10-30 tokens/sec on A100 (depends on batch size)\n",
2306
+ "- Throughput: ~200-500 samples/hour\n",
2307
+ "- Cost: $0 (after model download)\n",
2308
+ "\n",
2309
+ "**Model Info:**\n",
2310
+ "- HuggingFace: `Qwen/Qwen2.5-32B-Instruct`\n",
2311
+ "- License: Apache 2.0 (commercial use allowed)\n",
2312
+ "- Context: 32K tokens"
2313
+ ]
2314
+ },
2315
+ {
2316
+ "cell_type": "code",
2317
+ "execution_count": null,
2318
+ "id": "5dd7a803",
2319
+ "metadata": {},
2320
+ "outputs": [],
2321
+ "source": [
2322
+ "import pandas as pd\n",
2323
+ "import json\n",
2324
+ "import time\n",
2325
+ "import re\n",
2326
+ "from pathlib import Path\n",
2327
+ "from tqdm import tqdm\n",
2328
+ "import torch\n",
2329
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
2330
+ "\n",
2331
+ "current_dir = Path.cwd()\n",
2332
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
2333
+ "\n",
2334
+ "# === CONFIGURATION ===\n",
2335
+ "TEST_MODE = True\n",
2336
+ "TEST_SIZE = 10\n",
2337
+ "MAX_ROWS = 20000\n",
2338
+ "SAVE_INTERVAL = 10\n",
2339
+ "\n",
2340
+ "# Model settings\n",
2341
+ "MODEL_NAME = \"Qwen/Qwen3-235B-A22B-Instruct-2507-FP8\"\n",
2342
+ "#MODEL_NAME = \"Qwen/Qwen3-max\"\n",
2343
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
2344
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
2345
+ "\n",
2346
+ "PROFESSION_CATEGORIES = [\n",
2347
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
2348
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
2349
+ " \"sports professional\", \"tv personality\"\n",
2350
+ "]\n",
2351
+ "\n",
2352
+ "# === LOAD MODEL ===\n",
2353
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
2354
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
2355
+ "print(f\"This may take a while on first run (~65GB download)...\\n\")\n",
2356
+ "\n",
2357
+ "# Check GPU availability\n",
2358
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
2359
+ "print(f\"Device: {device}\")\n",
2360
+ "\n",
2361
+ "if device == \"cpu\":\n",
2362
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
2363
+ " print(\" Consider using a GPU or reducing model size.\")\n",
2364
+ "\n",
2365
+ "# Load tokenizer\n",
2366
+ "print(\"Loading tokenizer...\")\n",
2367
+ "tokenizer = AutoTokenizer.from_pretrained(\n",
2368
+ " MODEL_NAME,\n",
2369
+ " cache_dir=str(CACHE_DIR),\n",
2370
+ " trust_remote_code=True\n",
2371
+ ")\n",
2372
+ "print(\"✅ Tokenizer loaded\")\n",
2373
+ "\n",
2374
+ "# Load model with optimizations\n",
2375
+ "print(\"Loading model (this may take several minutes)...\")\n",
2376
+ "model = AutoModelForCausalLM.from_pretrained(\n",
2377
+ " MODEL_NAME,\n",
2378
+ " cache_dir=str(CACHE_DIR),\n",
2379
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
2380
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
2381
+ " trust_remote_code=True\n",
2382
+ ")\n",
2383
+ "model.eval() # Set to evaluation mode\n",
2384
+ "print(\"✅ Model loaded\")\n",
2385
+ "\n",
2386
+ "# Check VRAM usage\n",
2387
+ "if torch.cuda.is_available():\n",
2388
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
2389
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
2390
+ "\n",
2391
+ "# === LOAD DATA ===\n",
2392
+ "df = pd.read_csv(input_file)\n",
2393
+ "print(f\"Loaded {len(df)} rows\")\n",
2394
+ "\n",
2395
+ "if TEST_MODE:\n",
2396
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
2397
+ " df = df.head(TEST_SIZE).copy()\n",
2398
+ "elif MAX_ROWS:\n",
2399
+ " df = df.head(MAX_ROWS).copy()\n",
2400
+ "\n",
2401
+ "# === CREATE PROMPT ===\n",
2402
+ "def create_prompt(name: str, tags: list, country: str) -> str:\n",
2403
+ " tags_str = \", \".join(tags[:5]) if tags else \"none\"\n",
2404
+ " country_str = country if country else \"unknown\"\n",
2405
+ " \n",
2406
+ " return f\"\"\"You are an expert at identifying public figures.\n",
2407
+ "\n",
2408
+ "Given: Name: {name}, Tags: {tags_str}, Country: {country_str}\n",
2409
+ "\n",
2410
+ "Provide in JSON format:\n",
2411
+ "{{\n",
2412
+ " \"full_name\": \"<full name>\",\n",
2413
+ " \"gender\": \"<Male/Female/Other/Unknown>\",\n",
2414
+ " \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n",
2415
+ " \"country\": \"<country>\"\n",
2416
+ "}}\n",
2417
+ "\n",
2418
+ "Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n",
2419
+ "- Max 3 professions, ordered by relevance\n",
2420
+ "- \"online personality\" includes streamers, cosplayers, influencers\n",
2421
+ "- Return \"Unknown\" if uncertain\n",
2422
+ "\n",
2423
+ "Return ONLY JSON, no extra text.\"\"\"\n",
2424
+ "\n",
2425
+ "# === QUERY QWEN LOCAL ===\n",
2426
+ "def query_qwen_local(prompt: str) -> dict:\n",
2427
+ " \"\"\"Query Qwen-2.5-32B locally via transformers.\"\"\"\n",
2428
+ " try:\n",
2429
+ " # Format as chat message\n",
2430
+ " messages = [\n",
2431
+ " {\"role\": \"user\", \"content\": prompt}\n",
2432
+ " ]\n",
2433
+ " \n",
2434
+ " # Tokenize\n",
2435
+ " text = tokenizer.apply_chat_template(\n",
2436
+ " messages,\n",
2437
+ " tokenize=False,\n",
2438
+ " add_generation_prompt=True\n",
2439
+ " )\n",
2440
+ " \n",
2441
+ " inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
2442
+ " \n",
2443
+ " # Generate\n",
2444
+ " with torch.no_grad():\n",
2445
+ " outputs = model.generate(\n",
2446
+ " **inputs,\n",
2447
+ " max_new_tokens=512,\n",
2448
+ " temperature=0.1,\n",
2449
+ " do_sample=True,\n",
2450
+ " top_p=0.9,\n",
2451
+ " pad_token_id=tokenizer.eos_token_id\n",
2452
+ " )\n",
2453
+ " \n",
2454
+ " # Decode\n",
2455
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
2456
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n",
2457
+ " \n",
2458
+ " # Parse JSON from response\n",
2459
+ " json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n",
2460
+ " if json_match:\n",
2461
+ " return json.loads(json_match.group())\n",
2462
+ " \n",
2463
+ " # Try markdown code block\n",
2464
+ " code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n",
2465
+ " if code_block:\n",
2466
+ " return json.loads(code_block.group(1))\n",
2467
+ " \n",
2468
+ " return None\n",
2469
+ " \n",
2470
+ " except json.JSONDecodeError as e:\n",
2471
+ " print(f\"JSON parse error: {e}\")\n",
2472
+ " return None\n",
2473
+ " except Exception as e:\n",
2474
+ " print(f\"Generation error: {e}\")\n",
2475
+ " return None\n",
2476
+ "\n",
2477
+ "# === PROCESS ===\n",
2478
+ "output_file = current_dir.parent / f\"data/CSV/qwen_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2479
+ "index_file = current_dir.parent / \"misc/qwen_local_query_index.txt\"\n",
2480
+ "\n",
2481
+ "current_index = 0\n",
2482
+ "if index_file.exists():\n",
2483
+ " with open(index_file) as f:\n",
2484
+ " current_index = int(f.read().strip())\n",
2485
+ " print(f\"Resuming from index {current_index}\")\n",
2486
+ "\n",
2487
+ "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
2488
+ " if col not in df.columns:\n",
2489
+ " df[col] = 'Unknown'\n",
2490
+ "\n",
2491
+ "print(f\"\\nAnnotating with QWEN-2.5-32B LOCAL - rows {current_index} to {len(df)}...\")\n",
2492
+ "print(f\"Model: {MODEL_NAME}\")\n",
2493
+ "print(f\"This may take a while (~200-500 samples/hour on A100)\\n\")\n",
2494
+ "\n",
2495
+ "try:\n",
2496
+ " start_time = time.time()\n",
2497
+ " \n",
2498
+ " for i in tqdm(range(current_index, len(df)), desc=\"Qwen Local\"):\n",
2499
+ " row = df.iloc[i]\n",
2500
+ " \n",
2501
+ " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
2502
+ " if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n",
2503
+ " \n",
2504
+ " prompt = create_prompt(\n",
2505
+ " row.get('real_name', row.get('name', '')),\n",
2506
+ " tags,\n",
2507
+ " row.get('likely_country', '')\n",
2508
+ " )\n",
2509
+ " \n",
2510
+ " result = query_qwen_local(prompt)\n",
2511
+ " \n",
2512
+ " if result:\n",
2513
+ " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
2514
+ " df.at[i, 'gender'] = result.get('gender', 'Unknown')\n",
2515
+ " profs = result.get('professions', [])\n",
2516
+ " df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n",
2517
+ " df.at[i, 'country'] = result.get('country', 'Unknown')\n",
2518
+ " \n",
2519
+ " current_index = i + 1\n",
2520
+ " \n",
2521
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2522
+ " df.to_csv(output_file, index=False)\n",
2523
+ " with open(index_file, 'w') as f:\n",
2524
+ " f.write(str(current_index))\n",
2525
+ " \n",
2526
+ " # Calculate stats\n",
2527
+ " elapsed = time.time() - start_time\n",
2528
+ " samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n",
2529
+ " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
2530
+ " \n",
2531
+ " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
2532
+ " \n",
2533
+ " elapsed_total = time.time() - start_time\n",
2534
+ " print(f\"\\n✅ Done! Results: {output_file}\")\n",
2535
+ " print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
2536
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2537
+ " \n",
2538
+ " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
2539
+ " \n",
2540
+ " # Show VRAM stats\n",
2541
+ " if torch.cuda.is_available():\n",
2542
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2543
+ "\n",
2544
+ "except KeyboardInterrupt:\n",
2545
+ " print(f\"\\n⚠️ Interrupted by user\")\n",
2546
+ " df.to_csv(output_file, index=False)\n",
2547
+ " with open(index_file, 'w') as f:\n",
2548
+ " f.write(str(current_index))\n",
2549
+ " print(f\"Progress saved up to row {current_index}\")\n",
2550
+ "\n",
2551
+ "except Exception as e:\n",
2552
+ " print(f\"⚠️ Error: {e}\")\n",
2553
+ " df.to_csv(output_file, index=False)\n",
2554
+ " with open(index_file, 'w') as f:\n",
2555
+ " f.write(str(current_index))\n",
2556
+ " print(f\"Progress saved up to row {current_index}\")"
2557
+ ]
2558
+ },
2559
+ {
2560
+ "cell_type": "markdown",
2561
+ "id": "84b144a0-7d24-4d6b-8f42-17d8e6100807",
2562
+ "metadata": {},
2563
+ "source": [
2564
+ "## Gemma 3 local"
2565
+ ]
2566
+ },
2567
+ {
2568
+ "cell_type": "code",
2569
+ "execution_count": null,
2570
+ "id": "4gb2vta3w5g",
2571
+ "metadata": {},
2572
+ "outputs": [],
2573
+ "source": [
2574
+ "import pandas as pd\n",
2575
+ "import json\n",
2576
+ "import time\n",
2577
+ "import re\n",
2578
+ "from pathlib import Path\n",
2579
+ "from tqdm import tqdm\n",
2580
+ "import torch\n",
2581
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
2582
+ "\n",
2583
+ "current_dir = Path.cwd()\n",
2584
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
2585
+ "\n",
2586
+ "# === CONFIGURATION ===\n",
2587
+ "TEST_MODE = True\n",
2588
+ "TEST_SIZE = 10\n",
2589
+ "MAX_ROWS = 20000\n",
2590
+ "SAVE_INTERVAL = 10\n",
2591
+ "\n",
2592
+ "# Model settings\n",
2593
+ "MODEL_NAME = \"google/gemma-3-27b-it\"\n",
2594
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
2595
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
2596
+ "\n",
2597
+ "PROFESSION_CATEGORIES = [\n",
2598
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
2599
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
2600
+ " \"sports professional\", \"tv personality\"\n",
2601
+ "]\n",
2602
+ "\n",
2603
+ "# === LOAD MODEL ===\n",
2604
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
2605
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
2606
+ "print(f\"This may take a while on first run (~54GB download)...\\n\")\n",
2607
+ "\n",
2608
+ "# Check GPU availability\n",
2609
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
2610
+ "print(f\"Device: {device}\")\n",
2611
+ "\n",
2612
+ "if device == \"cpu\":\n",
2613
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
2614
+ " print(\" Consider using a GPU or reducing model size.\")\n",
2615
+ "\n",
2616
+ "# Load tokenizer\n",
2617
+ "print(\"Loading tokenizer...\")\n",
2618
+ "tokenizer = AutoTokenizer.from_pretrained(\n",
2619
+ " MODEL_NAME,\n",
2620
+ " cache_dir=str(CACHE_DIR),\n",
2621
+ " trust_remote_code=True\n",
2622
+ ")\n",
2623
+ "print(\"✅ Tokenizer loaded\")\n",
2624
+ "\n",
2625
+ "# Load model with optimizations\n",
2626
+ "print(\"Loading model (this may take several minutes)...\")\n",
2627
+ "model = AutoModelForCausalLM.from_pretrained(\n",
2628
+ " MODEL_NAME,\n",
2629
+ " cache_dir=str(CACHE_DIR),\n",
2630
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
2631
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
2632
+ " trust_remote_code=True\n",
2633
+ ")\n",
2634
+ "model.eval() # Set to evaluation mode\n",
2635
+ "print(\"✅ Model loaded\")\n",
2636
+ "\n",
2637
+ "# Check VRAM usage\n",
2638
+ "if torch.cuda.is_available():\n",
2639
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
2640
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
2641
+ "\n",
2642
+ "# === LOAD DATA ===\n",
2643
+ "df = pd.read_csv(input_file)\n",
2644
+ "print(f\"Loaded {len(df)} rows\")\n",
2645
+ "\n",
2646
+ "if TEST_MODE:\n",
2647
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
2648
+ " df = df.head(TEST_SIZE).copy()\n",
2649
+ "elif MAX_ROWS:\n",
2650
+ " df = df.head(MAX_ROWS).copy()\n",
2651
+ "\n",
2652
+ "# === CREATE PROMPT ===\n",
2653
+ "def create_prompt(name: str, tags: list, country: str) -> str:\n",
2654
+ " tags_str = \", \".join(tags[:5]) if tags else \"none\"\n",
2655
+ " country_str = country if country else \"unknown\"\n",
2656
+ " \n",
2657
+ " return f\"\"\"You are an expert at identifying public figures.\n",
2658
+ "\n",
2659
+ "Given: Name: {name}, Tags: {tags_str}, Country: {country_str}\n",
2660
+ "\n",
2661
+ "Provide in JSON format:\n",
2662
+ "{{\n",
2663
+ " \"full_name\": \"<full name>\",\n",
2664
+ " \"gender\": \"<Male/Female/Other/Unknown>\",\n",
2665
+ " \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n",
2666
+ " \"country\": \"<country>\"\n",
2667
+ "}}\n",
2668
+ "\n",
2669
+ "Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n",
2670
+ "- Max 3 professions, ordered by relevance\n",
2671
+ "- \"online personality\" includes streamers, cosplayers, influencers\n",
2672
+ "- Return \"Unknown\" if uncertain\n",
2673
+ "\n",
2674
+ "Return ONLY JSON, no extra text.\"\"\"\n",
2675
+ "\n",
2676
+ "# === QUERY GEMMA LOCAL ===\n",
2677
+ "def query_gemma_local(prompt: str) -> dict:\n",
2678
+ " \"\"\"Query Gemma-3-27B locally via transformers.\"\"\"\n",
2679
+ " try:\n",
2680
+ " # Format as chat message\n",
2681
+ " messages = [\n",
2682
+ " {\"role\": \"user\", \"content\": prompt}\n",
2683
+ " ]\n",
2684
+ " \n",
2685
+ " # Tokenize\n",
2686
+ " text = tokenizer.apply_chat_template(\n",
2687
+ " messages,\n",
2688
+ " tokenize=False,\n",
2689
+ " add_generation_prompt=True\n",
2690
+ " )\n",
2691
+ " \n",
2692
+ " inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
2693
+ " \n",
2694
+ " # Generate\n",
2695
+ " with torch.no_grad():\n",
2696
+ " outputs = model.generate(\n",
2697
+ " **inputs,\n",
2698
+ " max_new_tokens=512,\n",
2699
+ " temperature=0.1,\n",
2700
+ " do_sample=True,\n",
2701
+ " top_p=0.9,\n",
2702
+ " pad_token_id=tokenizer.eos_token_id\n",
2703
+ " )\n",
2704
+ " \n",
2705
+ " # Decode\n",
2706
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
2707
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n",
2708
+ " \n",
2709
+ " # Parse JSON from response\n",
2710
+ " json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n",
2711
+ " if json_match:\n",
2712
+ " return json.loads(json_match.group())\n",
2713
+ " \n",
2714
+ " # Try markdown code block\n",
2715
+ " code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n",
2716
+ " if code_block:\n",
2717
+ " return json.loads(code_block.group(1))\n",
2718
+ " \n",
2719
+ " return None\n",
2720
+ " \n",
2721
+ " except json.JSONDecodeError as e:\n",
2722
+ " print(f\"JSON parse error: {e}\")\n",
2723
+ " return None\n",
2724
+ " except Exception as e:\n",
2725
+ " print(f\"Generation error: {e}\")\n",
2726
+ " return None\n",
2727
+ "\n",
2728
+ "# === PROCESS ===\n",
2729
+ "output_file = current_dir.parent / f\"data/CSV/gemma_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2730
+ "index_file = current_dir.parent / \"misc/gemma_local_query_index.txt\"\n",
2731
+ "\n",
2732
+ "current_index = 0\n",
2733
+ "if index_file.exists():\n",
2734
+ " with open(index_file) as f:\n",
2735
+ " current_index = int(f.read().strip())\n",
2736
+ " print(f\"Resuming from index {current_index}\")\n",
2737
+ "\n",
2738
+ "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
2739
+ " if col not in df.columns:\n",
2740
+ " df[col] = 'Unknown'\n",
2741
+ "\n",
2742
+ "print(f\"\\nAnnotating with GEMMA-3-27B LOCAL - rows {current_index} to {len(df)}...\")\n",
2743
+ "print(f\"Model: {MODEL_NAME}\")\n",
2744
+ "print(f\"This may take a while (~250-600 samples/hour on A100)\\n\")\n",
2745
+ "\n",
2746
+ "try:\n",
2747
+ " start_time = time.time()\n",
2748
+ " \n",
2749
+ " for i in tqdm(range(current_index, len(df)), desc=\"Gemma Local\"):\n",
2750
+ " row = df.iloc[i]\n",
2751
+ " \n",
2752
+ " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
2753
+ " if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n",
2754
+ " \n",
2755
+ " prompt = create_prompt(\n",
2756
+ " row.get('real_name', row.get('name', '')),\n",
2757
+ " tags,\n",
2758
+ " row.get('likely_country', '')\n",
2759
+ " )\n",
2760
+ " \n",
2761
+ " result = query_gemma_local(prompt)\n",
2762
+ " \n",
2763
+ " if result:\n",
2764
+ " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
2765
+ " df.at[i, 'gender'] = result.get('gender', 'Unknown')\n",
2766
+ " profs = result.get('professions', [])\n",
2767
+ " df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n",
2768
+ " df.at[i, 'country'] = result.get('country', 'Unknown')\n",
2769
+ " \n",
2770
+ " current_index = i + 1\n",
2771
+ " \n",
2772
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2773
+ " df.to_csv(output_file, index=False)\n",
2774
+ " with open(index_file, 'w') as f:\n",
2775
+ " f.write(str(current_index))\n",
2776
+ " \n",
2777
+ " # Calculate stats\n",
2778
+ " elapsed = time.time() - start_time\n",
2779
+ " samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n",
2780
+ " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
2781
+ " \n",
2782
+ " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
2783
+ " \n",
2784
+ " elapsed_total = time.time() - start_time\n",
2785
+ " print(f\"\\n✅ Done! Results: {output_file}\")\n",
2786
+ " print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
2787
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2788
+ " \n",
2789
+ " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
2790
+ " \n",
2791
+ " # Show VRAM stats\n",
2792
+ " if torch.cuda.is_available():\n",
2793
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2794
+ "\n",
2795
+ "except KeyboardInterrupt:\n",
2796
+ " print(f\"\\n⚠️ Interrupted by user\")\n",
2797
+ " df.to_csv(output_file, index=False)\n",
2798
+ " with open(index_file, 'w') as f:\n",
2799
+ " f.write(str(current_index))\n",
2800
+ " print(f\"Progress saved up to row {current_index}\")\n",
2801
+ "\n",
2802
+ "except Exception as e:\n",
2803
+ " print(f\"⚠️ Error: {e}\")\n",
2804
+ " df.to_csv(output_file, index=False)\n",
2805
+ " with open(index_file, 'w') as f:\n",
2806
+ " f.write(str(current_index))\n",
2807
+ " print(f\"Progress saved up to row {current_index}\")"
2808
+ ]
2809
+ },
2810
+ {
2811
+ "cell_type": "code",
2812
+ "execution_count": null,
2813
+ "id": "a5baf3c9-3901-4c43-9354-6877d30133e8",
2814
+ "metadata": {},
2815
+ "outputs": [],
2816
+ "source": []
2817
+ }
2818
+ ],
2819
+ "metadata": {
2820
+ "kernelspec": {
2821
+ "display_name": "pm-paper",
2822
+ "language": "python",
2823
+ "name": "pm-paper"
2824
+ },
2825
  "language_info": {
2826
+ "codemirror_mode": {
2827
+ "name": "ipython",
2828
+ "version": 3
2829
+ },
2830
+ "file_extension": ".py",
2831
+ "mimetype": "text/x-python",
2832
+ "name": "python",
2833
+ "nbconvert_exporter": "python",
2834
+ "pygments_lexer": "ipython3",
2835
+ "version": "3.11.13"
2836
  }
2837
  },
2838
  "nbformat": 4,
jupyter_notebooks/Section_2-3-4_Figure_8_deepfake_adapters-Copy1.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
jupyter_notebooks/Section_2-3-4_Figure_8_deepfake_adapters.ipynb CHANGED
@@ -126,79 +126,10 @@
126
  },
127
  {
128
  "cell_type": "code",
129
- "execution_count": 7,
130
  "id": "ner_code_cell",
131
- "metadata": {
132
- "execution": {
133
- "iopub.execute_input": "2025-11-21T10:50:51.775852Z",
134
- "iopub.status.busy": "2025-11-21T10:50:51.775660Z",
135
- "iopub.status.idle": "2025-11-21T10:53:16.141998Z",
136
- "shell.execute_reply": "2025-11-21T10:53:16.141295Z",
137
- "shell.execute_reply.started": "2025-11-21T10:50:51.775836Z"
138
- }
139
- },
140
- "outputs": [
141
- {
142
- "name": "stdout",
143
- "output_type": "stream",
144
- "text": [
145
- "✅ spaCy model loaded: en_core_web_sm\n",
146
- "Loaded 50861 rows\n",
147
- "\n",
148
- "🔄 Processing names with spaCy NER...\n",
149
- "\n",
150
- "📊 Name cleaning examples (with spaCy NER):\n",
151
- "====================================================================================================\n",
152
- "Original Name | Cleaned Name \n",
153
- "====================================================================================================\n",
154
- "Super Pose Book Vol.1 - ControlNet | Super Pose Book \n",
155
- "Liyuu LoRA | Liyuu \n",
156
- "HashimotoKanna/ 橋本環奈 _JP_Actress | HashimotoKanna \n",
157
- "Emma Watson (JG) | Emma Watson \n",
158
- "Gal Gadot「LoRa」 | Gal Gadot \n",
159
- "Scarlett Johansson「LoRa」 | Scarlett Johansson \n",
160
- "Gakki | Aragaki Yui | 新垣結衣 | Gakki \n",
161
- "Actress Satomi_石原○○ | Actress Satomi \n",
162
- "Game of Thrones Cast | Game Thrones Cast \n",
163
- "Natalie Portman「LoRa」 | Natalie Portman \n",
164
- "Emma Watson LoRA | Emma Watson \n",
165
- "Karina Makina Lora | Karina Makina \n",
166
- "WRAV YUA_三xx亜 | WRAV YUA \n",
167
- "Dilraba Dilmurat 迪丽热巴 | Dilraba Dilmurat \n",
168
- "MIMI,大幂幂 | MIMI \n",
169
- "Chinese Idol - YangMi杨幂 | Chinese Idol YangMi杨幂 \n",
170
- "Xiaorouseeu / 小柔SeeU - Chinese cosplayer and influencer | Xiaorouseeu \n",
171
- "Jennifer Connelly (80s/90s) | Jennifer Connelly \n",
172
- "====================================================================================================\n",
173
- "\n",
174
- "🧪 Leetspeak translation examples:\n",
175
- " 4kira LoRA -> akira\n",
176
- " 3mma Watson v2 -> Watson\n",
177
- " 1rene LORA -> irene\n",
178
- " L3vi Ackerman -> Levi Ackerman\n",
179
- "\n",
180
- "📈 Statistics:\n",
181
- " Total rows: 50861\n",
182
- " Non-empty names: 50858\n",
183
- " Empty names: 3\n",
184
- "\n",
185
- "🎯 Sample spaCy NER results:\n",
186
- " 1. IU\n",
187
- " 2. Super Pose Book\n",
188
- " 3. Liyuu\n",
189
- " 4. Irene\n",
190
- " 5. AESPA Karina\n",
191
- " 6. Saika Kawakita\n",
192
- " 7. Liu Yifei\n",
193
- " 8. HashimotoKanna\n",
194
- " 9. Emma Watson\n",
195
- " 10. Gal Gadot\n",
196
- "\n",
197
- "✅ Cleaned 50861 names using spaCy NER\n",
198
- "💾 Saved to /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/CSV/model_adapter/real_person_adapter_step_01_NER.csv\n"
199
- ]
200
- }
201
- ],
202
  "source": [
203
  "import pandas as pd\n",
204
  "import re\n",
@@ -420,225 +351,10 @@
420
  },
421
  {
422
  "cell_type": "code",
423
- "execution_count": 11,
424
  "id": "36ce71f2",
425
- "metadata": {
426
- "execution": {
427
- "iopub.execute_input": "2025-11-21T10:57:51.803570Z",
428
- "iopub.status.busy": "2025-11-21T10:57:51.803378Z",
429
- "iopub.status.idle": "2025-11-21T10:57:58.819903Z",
430
- "shell.execute_reply": "2025-11-21T10:57:58.819309Z",
431
- "shell.execute_reply.started": "2025-11-21T10:57:51.803555Z"
432
- }
433
- },
434
- "outputs": [
435
- {
436
- "name": "stdout",
437
- "output_type": "stream",
438
- "text": [
439
- "Built country/nationality mapping with 781 entries\n",
440
- "\n",
441
- "Processed 50861 rows\n",
442
- "Rows with country: 1883\n",
443
- "Rows with nationality: 0\n",
444
- "Rows with profession: 43674\n",
445
- "\n",
446
- "Top 10 countries:\n",
447
- "likely_country\n",
448
- "American Samoa 973\n",
449
- "Japan 250\n",
450
- "Indonesia 73\n",
451
- "Argentina 73\n",
452
- "Ireland 53\n",
453
- "France 38\n",
454
- "Netherlands 38\n",
455
- "Hong Kong 35\n",
456
- "Brazil 29\n",
457
- "Germany 24\n",
458
- "Name: count, dtype: int64\n",
459
- "\n",
460
- "Sample results:\n",
461
- " real_name likely_country likely_nationality likely_profession\n",
462
- "0 IU celebrity\n",
463
- "1 Super Pose Book \n",
464
- "2 Liyuu \n",
465
- "3 Irene celebrity\n",
466
- "4 AESPA Karina celebrity\n",
467
- "5 Saika Kawakita celebrity\n",
468
- "6 Liu Yifei celebrity\n",
469
- "7 HashimotoKanna actor\n",
470
- "8 Emma Watson actor\n",
471
- "9 Gal Gadot model\n",
472
- "\n",
473
- "🔍 Checking 'Irene' entries:\n",
474
- " Name: Irene\n",
475
- " Tags: ['girl', 'photorealistic', 'asian', 'woman', 'beautiful', 'celebrity', 'korean']\n",
476
- " Country: \n",
477
- " Nationality: \n",
478
- "\n",
479
- " Name: Irene Makina\n",
480
- " Tags: ['woman', 'celebrity']\n",
481
- " Country: \n",
482
- " Nationality: \n",
483
- "\n",
484
- " Name: Red Velvet Irene\n",
485
- " Tags: ['kpop', 'woman', 'celebrity', 'kpop idol']\n",
486
- " Country: \n",
487
- " Nationality: \n",
488
- "\n",
489
- " Name: RED VELVET Irene\n",
490
- " Tags: ['kpop', 'woman', 'celebrity', 'irene', 'redvelvet']\n",
491
- " Country: \n",
492
- " Nationality: \n",
493
- "\n",
494
- " Name: Irene\n",
495
- " Tags: ['singer', 'k-pop idol', 'actress', 'celebrity', 'korean', 'irene', 'bae joo-hyun']\n",
496
- " Country: \n",
497
- " Nationality: \n",
498
- "\n",
499
- " Name: Irene\n",
500
- " Tags: ['singer', 'photorealistic', 'asian', 'idol', 'dancer', 'woman', 'celebrity']\n",
501
- " Country: \n",
502
- " Nationality: \n",
503
- "\n",
504
- " Name: Irene Makina\n",
505
- " Tags: ['kpop', 'celebrity']\n",
506
- " Country: \n",
507
- " Nationality: \n",
508
- "\n",
509
- " Name: irene주현\n",
510
- " Tags: ['photorealistic', 'sexy', 'female', 'woman', 'celebrity', 'girls', 'realistic']\n",
511
- " Country: \n",
512
- " Nationality: \n",
513
- "\n",
514
- " Name: Irene\n",
515
- " Tags: ['singer', 'woman', 'celebrity']\n",
516
- " Country: \n",
517
- " Nationality: \n",
518
- "\n",
519
- " Name: Red Velvet Irene\n",
520
- " Tags: ['kpop', 'celebrity']\n",
521
- " Country: \n",
522
- " Nationality: \n",
523
- "\n",
524
- " Name: Irene Schouten\n",
525
- " Tags: ['instagram', 'woman', 'celebrity', 'dutch', 'sporty', 'speed skating']\n",
526
- " Country: \n",
527
- " Nationality: \n",
528
- "\n",
529
- " Name: Irene\n",
530
- " Tags: ['photorealistic', 'female', 'woman', 'celebrity', 'realistic']\n",
531
- " Country: \n",
532
- " Nationality: \n",
533
- "\n",
534
- " Name: Irene\n",
535
- " Tags: ['photorealistic', 'female', 'kpop', 'idol', 'woman', 'celebrity', 'girls']\n",
536
- " Country: \n",
537
- " Nationality: \n",
538
- "\n",
539
- " Name: Irene\n",
540
- " Tags: ['kpop', 'woman', 'celebrity', 'kpop girl']\n",
541
- " Country: \n",
542
- " Nationality: \n",
543
- "\n",
544
- " Name: Irene Rouse\n",
545
- " Tags: ['person', 'photorealistic', 'female', 'cosplay', 'woman', 'celebrity', 'girls']\n",
546
- " Country: \n",
547
- " Nationality: \n",
548
- "\n",
549
- " Name: IreneDiffusion\n",
550
- " Tags: ['irene', 'irene montero', 'montero']\n",
551
- " Country: \n",
552
- " Nationality: \n",
553
- "\n",
554
- " Name: Valory Irene\n",
555
- " Tags: ['female', 'woman', 'celebrity']\n",
556
- " Country: \n",
557
- " Nationality: \n",
558
- "\n",
559
- " Name: Irene\n",
560
- " Tags: ['singer', 'asian', 'kpop', 'actress', 'celeb', 'celebrity', 'korean']\n",
561
- " Country: \n",
562
- " Nationality: \n",
563
- "\n",
564
- " Name: Irene Red Velvet\n",
565
- " Tags: ['kpop', 'celebrity']\n",
566
- " Country: \n",
567
- " Nationality: \n",
568
- "\n",
569
- " Name: Irene Rouse - Adult Film Actress\n",
570
- " Tags: ['photorealistic', 'sexy', 'woman', 'celebrity', 'girls', 'realistic', 'lora']\n",
571
- " Country: \n",
572
- " Nationality: \n",
573
- "\n",
574
- " Name: Irene Rouse - Adult Film Actress\n",
575
- " Tags: ['photorealistic', 'sexy', 'woman', 'celebrity', 'girls', 'realistic', 'lora']\n",
576
- " Country: \n",
577
- " Nationality: \n",
578
- "\n",
579
- " Name: Irene Red Velvet\n",
580
- " Tags: ['photorealistic', 'kpop', 'woman', 'celebrity', 'korean', 'kpop idol']\n",
581
- " Country: \n",
582
- " Nationality: \n",
583
- "\n",
584
- " Name: 麦橘复古少女IreneMajicflus\n",
585
- " Tags: ['style']\n",
586
- " Country: \n",
587
- " Nationality: \n",
588
- "\n",
589
- " Name: Irene F1\n",
590
- " Tags: ['woman', 'actor', 'celebrity']\n",
591
- " Country: \n",
592
- " Nationality: \n",
593
- "\n",
594
- " Name: Irene\n",
595
- " Tags: ['celebrity']\n",
596
- " Country: \n",
597
- " Nationality: \n",
598
- "\n",
599
- " Name: IRENE\n",
600
- " Tags: ['realism', 'kpop', 'idol', 'woman', 'celebrity']\n",
601
- " Country: \n",
602
- " Nationality: \n",
603
- "\n",
604
- " Name: Irene Rouse\n",
605
- " Tags: ['photorealistic', 'sexy', 'woman', 'celebrity', 'girls', 'realistic', 'lora']\n",
606
- " Country: \n",
607
- " Nationality: \n",
608
- "\n",
609
- " Name: Valory Irene\n",
610
- " Tags: ['girl', 'sexy', 'model', 'woman', 'celebrity']\n",
611
- " Country: \n",
612
- " Nationality: \n",
613
- "\n",
614
- " Name: Irene Rouse\n",
615
- " Tags: ['woman', 'celebrity']\n",
616
- " Country: \n",
617
- " Nationality: \n",
618
- "\n",
619
- " Name: Irene Dirdal\n",
620
- " Tags: ['photorealistic', 'woman', 'celebrity', 'girls', 'realistic', 'lora']\n",
621
- " Country: \n",
622
- " Nationality: \n",
623
- "\n",
624
- " Name: Irene Cara\n",
625
- " Tags: ['singer', 'woman', 'actress', 'celebrity', 'irene cara']\n",
626
- " Country: \n",
627
- " Nationality: \n",
628
- "\n",
629
- " Name: Irene Rouse\n",
630
- " Tags: ['colombia', 'instagram', 'latina', 'woman', 'celebrity', 'realistic', 'sd 1.5']\n",
631
- " Country: Colombia\n",
632
- " Nationality: \n",
633
- "\n",
634
- " Name: Irene Caruso -\n",
635
- " Tags: ['model', 'celebrity', 'influencer']\n",
636
- " Country: \n",
637
- " Nationality: \n",
638
- "\n"
639
- ]
640
- }
641
- ],
642
  "source": [
643
  "import pandas as pd\n",
644
  "from pathlib import Path\n",
@@ -824,124 +540,10 @@
824
  },
825
  {
826
  "cell_type": "code",
827
- "execution_count": 13,
828
  "id": "deepseek_code",
829
- "metadata": {
830
- "execution": {
831
- "iopub.execute_input": "2025-11-21T11:01:40.377178Z",
832
- "iopub.status.busy": "2025-11-21T11:01:40.376988Z",
833
- "iopub.status.idle": "2025-11-21T11:02:15.369105Z",
834
- "shell.execute_reply": "2025-11-21T11:02:15.368626Z",
835
- "shell.execute_reply.started": "2025-11-21T11:01:40.377164Z"
836
- }
837
- },
838
- "outputs": [
839
- {
840
- "name": "stdout",
841
- "output_type": "stream",
842
- "text": [
843
- "✅ Deepseek API key loaded\n",
844
- "✅ Loaded profession mapping with 9 categories\n",
845
- "Loaded 50861 rows\n",
846
- "\n",
847
- "Profession categories (9):\n",
848
- " - actor\n",
849
- " - adult performer\n",
850
- " - singer/musician\n",
851
- " - model\n",
852
- " - online personality\n",
853
- " - public figure\n",
854
- " - voice actor/ASMR\n",
855
- " - sports professional\n",
856
- " - tv personality\n",
857
- "\n",
858
- "Running in TEST MODE with 10 samples\n",
859
- "\n",
860
- "Annotating with DEEPSEEK...\n",
861
- "Processing rows 0 to 10\n"
862
- ]
863
- },
864
- {
865
- "name": "stderr",
866
- "output_type": "stream",
867
- "text": [
868
- "Annotating: 90%|█████████ | 9/10 [00:30<00:03, 3.39s/it]"
869
- ]
870
- },
871
- {
872
- "name": "stdout",
873
- "output_type": "stream",
874
- "text": [
875
- "✅ Progress saved after 10 rows\n"
876
- ]
877
- },
878
- {
879
- "name": "stderr",
880
- "output_type": "stream",
881
- "text": [
882
- "Annotating: 100%|██████████| 10/10 [00:34<00:00, 3.40s/it]"
883
- ]
884
- },
885
- {
886
- "name": "stdout",
887
- "output_type": "stream",
888
- "text": [
889
- "\n",
890
- "✅ Done! Final results saved to /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/CSV/model_adapter/real_person_adapter_step_03_deepseek_test.csv\n",
891
- "\n",
892
- "=== Summary Statistics ===\n",
893
- "Total processed: 10\n",
894
- "\n",
895
- "Gender distribution:\n",
896
- "gender\n",
897
- "Female 10\n",
898
- "Name: count, dtype: int64\n",
899
- "\n",
900
- "Top 10 profession combinations:\n",
901
- "profession_llm\n",
902
- "actor, singer/musician, model 2\n",
903
- "singer/musician, actor, tv personality 1\n",
904
- "model, online personality 1\n",
905
- "singer/musician, actor, model 1\n",
906
- "singer/musician, voice actor/ASMR, online personality 1\n",
907
- "singer/musician, model, online personality 1\n",
908
- "model, online personality, actor 1\n",
909
- "actor, public figure, model 1\n",
910
- "actor, model, public figure 1\n",
911
- "Name: count, dtype: int64\n",
912
- "\n",
913
- "Top 10 countries:\n",
914
- "country\n",
915
- "South Korea 3\n",
916
- "China 2\n",
917
- "Japan 2\n",
918
- "Unknown 1\n",
919
- "United Kingdom 1\n",
920
- "Israel 1\n",
921
- "Name: count, dtype: int64\n",
922
- "\n",
923
- "=== Sample Results ===\n",
924
- " real_name full_name gender profession_llm country\n",
925
- " IU Lee Ji-eun Female singer/musician, actor, tv personality South Korea\n",
926
- "Super Pose Book Unknown Female model, online personality Unknown\n",
927
- " Liyuu Liyuu Female singer/musician, voice actor/ASMR, online personality China\n",
928
- " Irene Irene Bae Female singer/musician, actor, model South Korea\n",
929
- " AESPA Karina Yu Ji-min Female singer/musician, model, online personality South Korea\n",
930
- " Saika Kawakita Saika Kawakita Female model, online personality, actor Japan\n",
931
- " Liu Yifei Liu Yifei Female actor, singer/musician, model China\n",
932
- " HashimotoKanna Kanna Hashimoto Female actor, singer/musician, model Japan\n",
933
- " Emma Watson Emma Charlotte Duerre Watson Female actor, public figure, model United Kingdom\n",
934
- " Gal Gadot Gal Gadot Female actor, model, public figure Israel\n"
935
- ]
936
- },
937
- {
938
- "name": "stderr",
939
- "output_type": "stream",
940
- "text": [
941
- "\n"
942
- ]
943
- }
944
- ],
945
  "source": [
946
  "import pandas as pd\n",
947
  "import json\n",
@@ -1225,14 +827,7 @@
1225
  "cell_type": "code",
1226
  "execution_count": null,
1227
  "id": "qwen_code",
1228
- "metadata": {
1229
- "execution": {
1230
- "iopub.status.busy": "2025-11-20T21:12:14.048643Z",
1231
- "iopub.status.idle": "2025-11-20T21:12:14.048904Z",
1232
- "shell.execute_reply": "2025-11-20T21:12:14.048734Z",
1233
- "shell.execute_reply.started": "2025-11-20T21:12:14.048726Z"
1234
- }
1235
- },
1236
  "outputs": [],
1237
  "source": [
1238
  "import pandas as pd\n",
@@ -1943,88 +1538,32 @@
1943
  },
1944
  {
1945
  "cell_type": "markdown",
1946
- "id": "01086b35",
1947
- "metadata": {},
 
 
 
 
 
 
 
 
1948
  "source": [
1949
- "## Qwen-2.5-32B Local Annotation (Hugging Face Transformers)\n",
1950
- "\n",
1951
- "Run **Qwen-2.5-32B-Instruct** locally using Hugging Face Transformers - NO API COSTS!\n",
1952
- "\n",
1953
- "**Requirements:**\n",
1954
- "- GPU: NVIDIA A100 80GB or similar (32B model needs ~60-70GB VRAM)\n",
1955
- "- RAM: 128GB+ system RAM recommended\n",
1956
- "- Model cache: `data/models/` (auto-downloaded on first run)\n",
1957
- "- Model size: ~65GB download (BF16 weights)\n",
1958
- "\n",
1959
- "**Installation:**\n",
1960
- "```bash\n",
1961
- "# Install required packages\n",
1962
- "pip install torch transformers accelerate\n",
1963
- "```\n",
1964
- "\n",
1965
- "**Advantages:**\n",
1966
- "- ✅ FREE - No API costs\n",
1967
- "- ✅ Fast - Local inference with GPU acceleration\n",
1968
- "- ✅ Privacy - Data never leaves your machine\n",
1969
- "- ✅ Offline - Works without internet (after download)\n",
1970
- "- ✅ High quality - 32B parameter instruction-tuned model\n",
1971
- "\n",
1972
- "**Performance:**\n",
1973
- "- Speed: ~10-30 tokens/sec on A100 (depends on batch size)\n",
1974
- "- Throughput: ~200-500 samples/hour\n",
1975
- "- Cost: $0 (after model download)\n",
1976
- "\n",
1977
- "**Model Info:**\n",
1978
- "- HuggingFace: `Qwen/Qwen2.5-32B-Instruct`\n",
1979
- "- License: Apache 2.0 (commercial use allowed)\n",
1980
- "- Context: 32K tokens"
1981
  ]
1982
  },
1983
  {
1984
- "cell_type": "code",
1985
- "execution_count": 16,
1986
- "id": "5dd7a803",
1987
  "metadata": {
1988
  "execution": {
1989
- "iopub.execute_input": "2025-11-21T12:00:13.243854Z",
1990
- "iopub.status.busy": "2025-11-21T12:00:13.243658Z",
1991
- "iopub.status.idle": "2025-11-21T12:00:20.310062Z",
1992
- "shell.execute_reply": "2025-11-21T12:00:20.309328Z",
1993
- "shell.execute_reply.started": "2025-11-21T12:00:13.243840Z"
1994
  }
1995
  },
1996
- "outputs": [
1997
- {
1998
- "name": "stdout",
1999
- "output_type": "stream",
2000
- "text": [
2001
- "Loading model: Qwen/Qwen3-235B-A22B-Instruct-2507-FP8\n",
2002
- "Cache directory: /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/models\n",
2003
- "This may take a while on first run (~65GB download)...\n",
2004
- "\n",
2005
- "Device: cuda\n",
2006
- "Loading tokenizer...\n",
2007
- "✅ Tokenizer loaded\n",
2008
- "Loading model (this may take several minutes)...\n"
2009
- ]
2010
- },
2011
- {
2012
- "ename": "ValueError",
2013
- "evalue": "FP8 quantized models is only supported on GPUs with compute capability >= 8.9 (e.g 4090/H100), actual = `8.0`",
2014
- "output_type": "error",
2015
- "traceback": [
2016
- "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
2017
- "\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
2018
- "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 55\u001b[39m\n\u001b[32m 53\u001b[39m \u001b[38;5;66;03m# Load model with optimizations\u001b[39;00m\n\u001b[32m 54\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mLoading model (this may take several minutes)...\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m model = \u001b[43mAutoModelForCausalLM\u001b[49m\u001b[43m.\u001b[49m\u001b[43mfrom_pretrained\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 56\u001b[39m \u001b[43m \u001b[49m\u001b[43mMODEL_NAME\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 57\u001b[39m \u001b[43m \u001b[49m\u001b[43mcache_dir\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mCACHE_DIR\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 58\u001b[39m \u001b[43m \u001b[49m\u001b[43mtorch_dtype\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtorch\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbfloat16\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Use BF16 for efficiency\u001b[39;49;00m\n\u001b[32m 59\u001b[39m \u001b[43m \u001b[49m\u001b[43mdevice_map\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mauto\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Automatically distribute across GPUs\u001b[39;49;00m\n\u001b[32m 60\u001b[39m \u001b[43m \u001b[49m\u001b[43mtrust_remote_code\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\n\u001b[32m 61\u001b[39m \u001b[43m)\u001b[49m\n\u001b[32m 62\u001b[39m model.eval() \u001b[38;5;66;03m# Set to evaluation mode\u001b[39;00m\n\u001b[32m 63\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ Model loaded\u001b[39m\u001b[33m\"\u001b[39m)\n",
2019
- "\u001b[36mFile \u001b[39m\u001b[32m/shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/.venv/lib/python3.11/site-packages/transformers/models/auto/auto_factory.py:604\u001b[39m, in \u001b[36m_BaseAutoModelClass.from_pretrained\u001b[39m\u001b[34m(cls, pretrained_model_name_or_path, *model_args, **kwargs)\u001b[39m\n\u001b[32m 602\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m model_class.config_class == config.sub_configs.get(\u001b[33m\"\u001b[39m\u001b[33mtext_config\u001b[39m\u001b[33m\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[32m 603\u001b[39m config = config.get_text_config()\n\u001b[32m--> \u001b[39m\u001b[32m604\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmodel_class\u001b[49m\u001b[43m.\u001b[49m\u001b[43mfrom_pretrained\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 605\u001b[39m \u001b[43m \u001b[49m\u001b[43mpretrained_model_name_or_path\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43mmodel_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m=\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mhub_kwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\n\u001b[32m 606\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 607\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 608\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUnrecognized configuration class \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mconfig.\u001b[34m__class__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m for this kind of AutoModel: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 609\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mModel type should be one of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, \u001b[39m\u001b[33m'\u001b[39m.join(c.\u001b[34m__name__\u001b[39m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mfor\u001b[39;00m\u001b[38;5;250m \u001b[39mc\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01min\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28mcls\u001b[39m._model_mapping)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 610\u001b[39m )\n",
2020
- "\u001b[36mFile \u001b[39m\u001b[32m/shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/.venv/lib/python3.11/site-packages/transformers/modeling_utils.py:277\u001b[39m, in \u001b[36mrestore_default_dtype.<locals>._wrapper\u001b[39m\u001b[34m(*args, **kwargs)\u001b[39m\n\u001b[32m 275\u001b[39m old_dtype = torch.get_default_dtype()\n\u001b[32m 276\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m277\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 278\u001b[39m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[32m 279\u001b[39m torch.set_default_dtype(old_dtype)\n",
2021
- "\u001b[36mFile \u001b[39m\u001b[32m/shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/.venv/lib/python3.11/site-packages/transformers/modeling_utils.py:4881\u001b[39m, in \u001b[36mPreTrainedModel.from_pretrained\u001b[39m\u001b[34m(cls, pretrained_model_name_or_path, config, cache_dir, ignore_mismatched_sizes, force_download, local_files_only, token, revision, use_safetensors, weights_only, *model_args, **kwargs)\u001b[39m\n\u001b[32m 4872\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m transformers_explicit_filename.endswith(\n\u001b[32m 4873\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m.safetensors\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 4874\u001b[39m ) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m transformers_explicit_filename.endswith(\u001b[33m\"\u001b[39m\u001b[33m.safetensors.index.json\u001b[39m\u001b[33m\"\u001b[39m):\n\u001b[32m 4875\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 4876\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mThe transformers file in the config seems to be incorrect: it is neither a safetensors file \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 4877\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m(*.safetensors) nor a safetensors index file (*.safetensors.index.json): \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 4878\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtransformers_explicit_filename\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 4879\u001b[39m )\n\u001b[32m-> \u001b[39m\u001b[32m4881\u001b[39m hf_quantizer, config, dtype, device_map = \u001b[43mget_hf_quantizer\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 4882\u001b[39m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquantization_config\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfrom_tf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfrom_flax\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdevice_map\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mweights_only\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muser_agent\u001b[49m\n\u001b[32m 4883\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 4885\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m gguf_file \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m hf_quantizer \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 4886\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 4887\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mYou cannot combine Quantization and loading a model from a GGUF file, try again by making sure you did not passed a `quantization_config` or that you did not load a quantized model from the Hub.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 4888\u001b[39m )\n",
2022
- "\u001b[36mFile \u001b[39m\u001b[32m/shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/.venv/lib/python3.11/site-packages/transformers/quantizers/auto.py:319\u001b[39m, in \u001b[36mget_hf_quantizer\u001b[39m\u001b[34m(config, quantization_config, dtype, from_tf, from_flax, device_map, weights_only, user_agent)\u001b[39m\n\u001b[32m 316\u001b[39m hf_quantizer = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 318\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m hf_quantizer \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m319\u001b[39m \u001b[43mhf_quantizer\u001b[49m\u001b[43m.\u001b[49m\u001b[43mvalidate_environment\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 320\u001b[39m \u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 321\u001b[39m \u001b[43m \u001b[49m\u001b[43mfrom_tf\u001b[49m\u001b[43m=\u001b[49m\u001b[43mfrom_tf\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 322\u001b[39m \u001b[43m \u001b[49m\u001b[43mfrom_flax\u001b[49m\u001b[43m=\u001b[49m\u001b[43mfrom_flax\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 323\u001b[39m \u001b[43m \u001b[49m\u001b[43mdevice_map\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdevice_map\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 324\u001b[39m \u001b[43m \u001b[49m\u001b[43mweights_only\u001b[49m\u001b[43m=\u001b[49m\u001b[43mweights_only\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 325\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 326\u001b[39m dtype = hf_quantizer.update_dtype(dtype)\n\u001b[32m 327\u001b[39m device_map = hf_quantizer.update_device_map(device_map)\n",
2023
- "\u001b[36mFile \u001b[39m\u001b[32m/shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/.venv/lib/python3.11/site-packages/transformers/quantizers/quantizer_finegrained_fp8.py:54\u001b[39m, in \u001b[36mFineGrainedFP8HfQuantizer.validate_environment\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 52\u001b[39m major, minor = compute_capability\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m (major < \u001b[32m8\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (major == \u001b[32m8\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m minor < \u001b[32m9\u001b[39m):\n\u001b[32m---> \u001b[39m\u001b[32m54\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 55\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mFP8 quantized models is only supported on GPUs with compute capability >= 8.9 (e.g 4090/H100)\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 56\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m, actual = `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmajor\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mminor\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m`\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 57\u001b[39m )\n\u001b[32m 59\u001b[39m device_map = kwargs.get(\u001b[33m\"\u001b[39m\u001b[33mdevice_map\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 60\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m device_map \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
2024
- "\u001b[31mValueError\u001b[39m: FP8 quantized models is only supported on GPUs with compute capability >= 8.9 (e.g 4090/H100), actual = `8.0`"
2025
- ]
2026
- }
2027
- ],
2028
  "source": [
2029
  "import pandas as pd\n",
2030
  "import json\n",
@@ -2045,8 +1584,8 @@
2045
  "SAVE_INTERVAL = 10\n",
2046
  "\n",
2047
  "# Model settings\n",
2048
- "MODEL_NAME = \"Qwen/Qwen3-235B-A22B-Instruct-2507-FP8\"\n",
2049
- "#MODEL_NAME = \"Qwen/Qwen3-max\"\n",
2050
  "CACHE_DIR = current_dir.parent / \"data/models\"\n",
2051
  "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
2052
  "\n",
@@ -2069,13 +1608,26 @@
2069
  " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
2070
  " print(\" Consider using a GPU or reducing model size.\")\n",
2071
  "\n",
2072
- "# Load tokenizer\n",
2073
  "print(\"Loading tokenizer...\")\n",
2074
- "tokenizer = AutoTokenizer.from_pretrained(\n",
2075
- " MODEL_NAME,\n",
2076
- " cache_dir=str(CACHE_DIR),\n",
2077
- " trust_remote_code=True\n",
2078
- ")\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
2079
  "print(\"✅ Tokenizer loaded\")\n",
2080
  "\n",
2081
  "# Load model with optimizations\n",
@@ -2085,7 +1637,7 @@
2085
  " cache_dir=str(CACHE_DIR),\n",
2086
  " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
2087
  " device_map=\"auto\", # Automatically distribute across GPUs\n",
2088
- " trust_remote_code=True\n",
2089
  ")\n",
2090
  "model.eval() # Set to evaluation mode\n",
2091
  "print(\"✅ Model loaded\")\n",
@@ -2129,23 +1681,27 @@
2129
  "\n",
2130
  "Return ONLY JSON, no extra text.\"\"\"\n",
2131
  "\n",
2132
- "# === QUERY QWEN LOCAL ===\n",
2133
- "def query_qwen_local(prompt: str) -> dict:\n",
2134
- " \"\"\"Query Qwen-2.5-32B locally via transformers.\"\"\"\n",
2135
  " try:\n",
2136
- " # Format as chat message\n",
2137
  " messages = [\n",
2138
  " {\"role\": \"user\", \"content\": prompt}\n",
2139
  " ]\n",
2140
  " \n",
2141
- " # Tokenize\n",
2142
- " text = tokenizer.apply_chat_template(\n",
2143
- " messages,\n",
2144
- " tokenize=False,\n",
2145
- " add_generation_prompt=True\n",
2146
- " )\n",
 
 
 
 
2147
  " \n",
2148
- " inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
2149
  " \n",
2150
  " # Generate\n",
2151
  " with torch.no_grad():\n",
@@ -2155,7 +1711,7 @@
2155
  " temperature=0.1,\n",
2156
  " do_sample=True,\n",
2157
  " top_p=0.9,\n",
2158
- " pad_token_id=tokenizer.eos_token_id\n",
2159
  " )\n",
2160
  " \n",
2161
  " # Decode\n",
@@ -2182,8 +1738,8 @@
2182
  " return None\n",
2183
  "\n",
2184
  "# === PROCESS ===\n",
2185
- "output_file = current_dir.parent / f\"data/CSV/qwen_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2186
- "index_file = current_dir.parent / \"misc/qwen_local_query_index.txt\"\n",
2187
  "\n",
2188
  "current_index = 0\n",
2189
  "if index_file.exists():\n",
@@ -2195,14 +1751,14 @@
2195
  " if col not in df.columns:\n",
2196
  " df[col] = 'Unknown'\n",
2197
  "\n",
2198
- "print(f\"\\nAnnotating with QWEN-2.5-32B LOCAL - rows {current_index} to {len(df)}...\")\n",
2199
  "print(f\"Model: {MODEL_NAME}\")\n",
2200
- "print(f\"This may take a while (~200-500 samples/hour on A100)\\n\")\n",
2201
  "\n",
2202
  "try:\n",
2203
  " start_time = time.time()\n",
2204
  " \n",
2205
- " for i in tqdm(range(current_index, len(df)), desc=\"Qwen Local\"):\n",
2206
  " row = df.iloc[i]\n",
2207
  " \n",
2208
  " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
@@ -2214,7 +1770,7 @@
2214
  " row.get('likely_country', '')\n",
2215
  " )\n",
2216
  " \n",
2217
- " result = query_qwen_local(prompt)\n",
2218
  " \n",
2219
  " if result:\n",
2220
  " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
@@ -2264,20 +1820,945 @@
2264
  ]
2265
  },
2266
  {
2267
- "cell_type": "code",
2268
- "execution_count": null,
2269
- "id": "156a9416-e713-45ee-bb85-41bec08c2118",
2270
  "metadata": {},
2271
- "outputs": [],
2272
- "source": []
 
2273
  },
2274
  {
2275
  "cell_type": "code",
2276
- "id": "4gb2vta3w5g",
2277
- "source": "import pandas as pd\nimport json\nimport time\nimport re\nfrom pathlib import Path\nfrom tqdm import tqdm\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\ncurrent_dir = Path.cwd()\ninput_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n\n# === CONFIGURATION ===\nTEST_MODE = True\nTEST_SIZE = 10\nMAX_ROWS = 20000\nSAVE_INTERVAL = 10\n\n# Model settings\nMODEL_NAME = \"google/gemma-3-27b-it\"\nCACHE_DIR = current_dir.parent / \"data/models\"\nCACHE_DIR.mkdir(parents=True, exist_ok=True)\n\nPROFESSION_CATEGORIES = [\n \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n \"online personality\", \"public figure\", \"voice actor/ASMR\",\n \"sports professional\", \"tv personality\"\n]\n\n# === LOAD MODEL ===\nprint(f\"Loading model: {MODEL_NAME}\")\nprint(f\"Cache directory: {CACHE_DIR}\")\nprint(f\"This may take a while on first run (~54GB download)...\\n\")\n\n# Check GPU availability\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f\"Device: {device}\")\n\nif device == \"cpu\":\n print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n print(\" Consider using a GPU or reducing model size.\")\n\n# Load tokenizer\nprint(\"Loading tokenizer...\")\ntokenizer = AutoTokenizer.from_pretrained(\n MODEL_NAME,\n cache_dir=str(CACHE_DIR),\n trust_remote_code=True\n)\nprint(\"✅ Tokenizer loaded\")\n\n# Load model with optimizations\nprint(\"Loading model (this may take several minutes)...\")\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_NAME,\n cache_dir=str(CACHE_DIR),\n torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n device_map=\"auto\", # Automatically distribute across GPUs\n trust_remote_code=True\n)\nmodel.eval() # Set to evaluation mode\nprint(\"✅ Model loaded\")\n\n# Check VRAM usage\nif torch.cuda.is_available():\n vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n\n# === LOAD DATA ===\ndf = pd.read_csv(input_file)\nprint(f\"Loaded {len(df)} rows\")\n\nif TEST_MODE:\n print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n df = df.head(TEST_SIZE).copy()\nelif MAX_ROWS:\n df = df.head(MAX_ROWS).copy()\n\n# === CREATE PROMPT ===\ndef create_prompt(name: str, tags: list, country: str) -> str:\n tags_str = \", \".join(tags[:5]) if tags else \"none\"\n country_str = country if country else \"unknown\"\n \n return f\"\"\"You are an expert at identifying public figures.\n\nGiven: Name: {name}, Tags: {tags_str}, Country: {country_str}\n\nProvide in JSON format:\n{{\n \"full_name\": \"<full name>\",\n \"gender\": \"<Male/Female/Other/Unknown>\",\n \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n \"country\": \"<country>\"\n}}\n\nChoose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n- Max 3 professions, ordered by relevance\n- \"online personality\" includes streamers, cosplayers, influencers\n- Return \"Unknown\" if uncertain\n\nReturn ONLY JSON, no extra text.\"\"\"\n\n# === QUERY GEMMA LOCAL ===\ndef query_gemma_local(prompt: str) -> dict:\n \"\"\"Query Gemma-3-27B locally via transformers.\"\"\"\n try:\n # Format as chat message\n messages = [\n {\"role\": \"user\", \"content\": prompt}\n ]\n \n # Tokenize\n text = tokenizer.apply_chat_template(\n messages,\n tokenize=False,\n add_generation_prompt=True\n )\n \n inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n \n # Generate\n with torch.no_grad():\n outputs = model.generate(\n **inputs,\n max_new_tokens=512,\n temperature=0.1,\n do_sample=True,\n top_p=0.9,\n pad_token_id=tokenizer.eos_token_id\n )\n \n # Decode\n generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n \n # Parse JSON from response\n json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n if json_match:\n return json.loads(json_match.group())\n \n # Try markdown code block\n code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n if code_block:\n return json.loads(code_block.group(1))\n \n return None\n \n except json.JSONDecodeError as e:\n print(f\"JSON parse error: {e}\")\n return None\n except Exception as e:\n print(f\"Generation error: {e}\")\n return None\n\n# === PROCESS ===\noutput_file = current_dir.parent / f\"data/CSV/gemma_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\nindex_file = current_dir.parent / \"misc/gemma_local_query_index.txt\"\n\ncurrent_index = 0\nif index_file.exists():\n with open(index_file) as f:\n current_index = int(f.read().strip())\n print(f\"Resuming from index {current_index}\")\n\nfor col in ['full_name', 'gender', 'profession_llm', 'country']:\n if col not in df.columns:\n df[col] = 'Unknown'\n\nprint(f\"\\nAnnotating with GEMMA-3-27B LOCAL - rows {current_index} to {len(df)}...\")\nprint(f\"Model: {MODEL_NAME}\")\nprint(f\"This may take a while (~250-600 samples/hour on A100)\\n\")\n\ntry:\n start_time = time.time()\n \n for i in tqdm(range(current_index, len(df)), desc=\"Gemma Local\"):\n row = df.iloc[i]\n \n tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n \n prompt = create_prompt(\n row.get('real_name', row.get('name', '')),\n tags,\n row.get('likely_country', '')\n )\n \n result = query_gemma_local(prompt)\n \n if result:\n df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n df.at[i, 'gender'] = result.get('gender', 'Unknown')\n profs = result.get('professions', [])\n df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n df.at[i, 'country'] = result.get('country', 'Unknown')\n \n current_index = i + 1\n \n if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n \n # Calculate stats\n elapsed = time.time() - start_time\n samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n \n print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n \n elapsed_total = time.time() - start_time\n print(f\"\\n✅ Done! Results: {output_file}\")\n print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n \n print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n \n # Show VRAM stats\n if torch.cuda.is_available():\n print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n\nexcept KeyboardInterrupt:\n print(f\"\\n⚠️ Interrupted by user\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"Progress saved up to row {current_index}\")\n\nexcept Exception as e:\n print(f\"⚠️ Error: {e}\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"Progress saved up to row {current_index}\")",
2278
- "metadata": {},
2279
  "execution_count": null,
2280
- "outputs": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2281
  }
2282
  ],
2283
  "metadata": {
@@ -2301,4 +2782,4 @@
2301
  },
2302
  "nbformat": 4,
2303
  "nbformat_minor": 5
2304
- }
 
126
  },
127
  {
128
  "cell_type": "code",
129
+ "execution_count": null,
130
  "id": "ner_code_cell",
131
+ "metadata": {},
132
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  "source": [
134
  "import pandas as pd\n",
135
  "import re\n",
 
351
  },
352
  {
353
  "cell_type": "code",
354
+ "execution_count": null,
355
  "id": "36ce71f2",
356
+ "metadata": {},
357
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  "source": [
359
  "import pandas as pd\n",
360
  "from pathlib import Path\n",
 
540
  },
541
  {
542
  "cell_type": "code",
543
+ "execution_count": null,
544
  "id": "deepseek_code",
545
+ "metadata": {},
546
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  "source": [
548
  "import pandas as pd\n",
549
  "import json\n",
 
827
  "cell_type": "code",
828
  "execution_count": null,
829
  "id": "qwen_code",
830
+ "metadata": {},
 
 
 
 
 
 
 
831
  "outputs": [],
832
  "source": [
833
  "import pandas as pd\n",
 
1538
  },
1539
  {
1540
  "cell_type": "markdown",
1541
+ "id": "92126791-1705-4a8a-a15a-115f52af4af3",
1542
+ "metadata": {
1543
+ "execution": {
1544
+ "iopub.execute_input": "2025-11-21T16:35:17.398813Z",
1545
+ "iopub.status.busy": "2025-11-21T16:35:17.398624Z",
1546
+ "iopub.status.idle": "2025-11-21T16:35:17.400755Z",
1547
+ "shell.execute_reply": "2025-11-21T16:35:17.400352Z",
1548
+ "shell.execute_reply.started": "2025-11-21T16:35:17.398797Z"
1549
+ }
1550
+ },
1551
  "source": [
1552
+ "## Mistral local annotation(hf transformers) mistralai/Mistral-Small-3.2-24B-Instruct-2506"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1553
  ]
1554
  },
1555
  {
1556
+ "cell_type": "markdown",
1557
+ "id": "7768f9b2-d70f-4c0a-b157-97556c48b8dc",
 
1558
  "metadata": {
1559
  "execution": {
1560
+ "iopub.execute_input": "2025-11-21T18:46:21.419056Z",
1561
+ "iopub.status.busy": "2025-11-21T18:46:21.418806Z",
1562
+ "iopub.status.idle": "2025-11-21T18:46:23.987724Z",
1563
+ "shell.execute_reply": "2025-11-21T18:46:23.987032Z",
1564
+ "shell.execute_reply.started": "2025-11-21T18:46:21.419028Z"
1565
  }
1566
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1567
  "source": [
1568
  "import pandas as pd\n",
1569
  "import json\n",
 
1584
  "SAVE_INTERVAL = 10\n",
1585
  "\n",
1586
  "# Model settings\n",
1587
+ "MODEL_NAME = \"mistralai/Mistral-Small-3.2-24B-Instruct-2506\"\n",
1588
+ "#MODEL_NAME = \"mistralai/Mistral-7B-Instruct-v0.3\"\n",
1589
  "CACHE_DIR = current_dir.parent / \"data/models\"\n",
1590
  "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
1591
  "\n",
 
1608
  " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
1609
  " print(\" Consider using a GPU or reducing model size.\")\n",
1610
  "\n",
1611
+ "# Load tokenizer - FIX: Remove trust_remote_code and add use_fast=True\n",
1612
  "print(\"Loading tokenizer...\")\n",
1613
+ "try:\n",
1614
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1615
+ " MODEL_NAME,\n",
1616
+ " cache_dir=str(CACHE_DIR),\n",
1617
+ " use_fast=True # Use the fast tokenizer\n",
1618
+ " )\n",
1619
+ "except Exception as e:\n",
1620
+ " print(f\"Failed with use_fast=True, trying use_fast=False...\")\n",
1621
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1622
+ " MODEL_NAME,\n",
1623
+ " cache_dir=str(CACHE_DIR),\n",
1624
+ " use_fast=False # Fall back to slow tokenizer if fast fails\n",
1625
+ " )\n",
1626
+ "\n",
1627
+ "# Ensure pad token is set\n",
1628
+ "if tokenizer.pad_token is None:\n",
1629
+ " tokenizer.pad_token = tokenizer.eos_token\n",
1630
+ "\n",
1631
  "print(\"✅ Tokenizer loaded\")\n",
1632
  "\n",
1633
  "# Load model with optimizations\n",
 
1637
  " cache_dir=str(CACHE_DIR),\n",
1638
  " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
1639
  " device_map=\"auto\", # Automatically distribute across GPUs\n",
1640
+ " trust_remote_code=False # Changed from True - Mistral doesn't need this\n",
1641
  ")\n",
1642
  "model.eval() # Set to evaluation mode\n",
1643
  "print(\"✅ Model loaded\")\n",
 
1681
  "\n",
1682
  "Return ONLY JSON, no extra text.\"\"\"\n",
1683
  "\n",
1684
+ "# === QUERY MISTRAL LOCAL ===\n",
1685
+ "def query_mistral_local(prompt: str) -> dict:\n",
1686
+ " \"\"\"Query Mistral-7B locally via transformers.\"\"\"\n",
1687
  " try:\n",
1688
+ " # Format as chat message for Mistral\n",
1689
  " messages = [\n",
1690
  " {\"role\": \"user\", \"content\": prompt}\n",
1691
  " ]\n",
1692
  " \n",
1693
+ " # Tokenize - check if chat template is available\n",
1694
+ " if hasattr(tokenizer, 'apply_chat_template'):\n",
1695
+ " text = tokenizer.apply_chat_template(\n",
1696
+ " messages,\n",
1697
+ " tokenize=False,\n",
1698
+ " add_generation_prompt=True\n",
1699
+ " )\n",
1700
+ " else:\n",
1701
+ " # Fallback for older tokenizers\n",
1702
+ " text = f\"[INST] {prompt} [/INST]\"\n",
1703
  " \n",
1704
+ " inputs = tokenizer([text], return_tensors=\"pt\", padding=True).to(device)\n",
1705
  " \n",
1706
  " # Generate\n",
1707
  " with torch.no_grad():\n",
 
1711
  " temperature=0.1,\n",
1712
  " do_sample=True,\n",
1713
  " top_p=0.9,\n",
1714
+ " pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id else tokenizer.eos_token_id\n",
1715
  " )\n",
1716
  " \n",
1717
  " # Decode\n",
 
1738
  " return None\n",
1739
  "\n",
1740
  "# === PROCESS ===\n",
1741
+ "output_file = current_dir.parent / f\"data/CSV/mistral_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
1742
+ "index_file = current_dir.parent / \"misc/mistral_local_query_index.txt\"\n",
1743
  "\n",
1744
  "current_index = 0\n",
1745
  "if index_file.exists():\n",
 
1751
  " if col not in df.columns:\n",
1752
  " df[col] = 'Unknown'\n",
1753
  "\n",
1754
+ "print(f\"\\nAnnotating with Mistral-7B LOCAL - rows {current_index} to {len(df)}...\")\n",
1755
  "print(f\"Model: {MODEL_NAME}\")\n",
1756
+ "print(f\"This may take a while...\\n\")\n",
1757
  "\n",
1758
  "try:\n",
1759
  " start_time = time.time()\n",
1760
  " \n",
1761
+ " for i in tqdm(range(current_index, len(df)), desc=\"Mistral Local\"):\n",
1762
  " row = df.iloc[i]\n",
1763
  " \n",
1764
  " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
 
1770
  " row.get('likely_country', '')\n",
1771
  " )\n",
1772
  " \n",
1773
+ " result = query_mistral_local(prompt)\n",
1774
  " \n",
1775
  " if result:\n",
1776
  " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
 
1820
  ]
1821
  },
1822
  {
1823
+ "cell_type": "markdown",
1824
+ "id": "62ba9af9-a831-4ccb-8d12-31a06acf38a6",
 
1825
  "metadata": {},
1826
+ "source": [
1827
+ "## BLOOM local"
1828
+ ]
1829
  },
1830
  {
1831
  "cell_type": "code",
 
 
 
1832
  "execution_count": null,
1833
+ "id": "72c468dc-1cbe-41d4-b71b-17c40ea4f9a1",
1834
+ "metadata": {
1835
+ "execution": {
1836
+ "iopub.execute_input": "2025-11-21T19:50:12.690047Z",
1837
+ "iopub.status.busy": "2025-11-21T19:50:12.689854Z"
1838
+ }
1839
+ },
1840
+ "outputs": [
1841
+ {
1842
+ "name": "stdout",
1843
+ "output_type": "stream",
1844
+ "text": [
1845
+ "Loading model: bigscience/bloomz-7b1\n",
1846
+ "Cache directory: /shares/weddigen.ki.uzh/laura_wagner/phase_01/pm-paper/data/models\n",
1847
+ "This may take a while on first run (~14GB download)...\n",
1848
+ "\n",
1849
+ "Device: cuda\n",
1850
+ "Loading tokenizer...\n",
1851
+ "✅ Tokenizer loaded\n",
1852
+ "Loading model (this may take several minutes)...\n",
1853
+ "✅ Model loaded\n",
1854
+ "VRAM used: 28.59 GB\n",
1855
+ "\n",
1856
+ "Loaded 50861 rows\n",
1857
+ "Running in TEST MODE with 10 samples\n",
1858
+ "Creating prompts...\n",
1859
+ "\n",
1860
+ "Annotating with BLOOMZ-7B1 LOCAL - rows 0 to 10...\n",
1861
+ "Model: bigscience/bloomz-7b1\n",
1862
+ "This may take a while...\n",
1863
+ "\n"
1864
+ ]
1865
+ },
1866
+ {
1867
+ "name": "stderr",
1868
+ "output_type": "stream",
1869
+ "text": [
1870
+ "Annotating: 0%| | 0/10 [00:00<?, ?it/s]The following generation flags are not valid and may be ignored: ['early_stopping']. Set `TRANSFORMERS_VERBOSITY=info` for more details.\n"
1871
+ ]
1872
+ }
1873
+ ],
1874
+ "source": [
1875
+ "import pandas as pd\n",
1876
+ "import json\n",
1877
+ "import time\n",
1878
+ "import re\n",
1879
+ "from pathlib import Path\n",
1880
+ "from tqdm import tqdm\n",
1881
+ "import torch\n",
1882
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
1883
+ "\n",
1884
+ "# Import is used for pd.notna() and pd.isna() checks\n",
1885
+ "\n",
1886
+ "current_dir = Path.cwd()\n",
1887
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
1888
+ "\n",
1889
+ "# === CONFIGURATION ===\n",
1890
+ "TEST_MODE = True\n",
1891
+ "TEST_SIZE = 10\n",
1892
+ "MAX_ROWS = 20000\n",
1893
+ "SAVE_INTERVAL = 10\n",
1894
+ "\n",
1895
+ "# Model settings - BLOOMZ (BigScience - European consortium)\n",
1896
+ "MODEL_NAME = \"bigscience/bloomz-7b1\" # Largest instruction-tuned BLOOM model\n",
1897
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
1898
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
1899
+ "\n",
1900
+ "PROFESSION_CATEGORIES = [\n",
1901
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
1902
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
1903
+ " \"sports professional\", \"tv personality\"\n",
1904
+ "]\n",
1905
+ "\n",
1906
+ "# === LOAD MODEL ===\n",
1907
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
1908
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
1909
+ "print(f\"This may take a while on first run (~14GB download)...\\n\")\n",
1910
+ "\n",
1911
+ "# Check GPU availability\n",
1912
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
1913
+ "print(f\"Device: {device}\")\n",
1914
+ "\n",
1915
+ "if device == \"cpu\":\n",
1916
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
1917
+ " print(\" Consider using a GPU or reducing model size.\")\n",
1918
+ "\n",
1919
+ "# Load tokenizer\n",
1920
+ "print(\"Loading tokenizer...\")\n",
1921
+ "try:\n",
1922
+ " tokenizer = AutoTokenizer.from_pretrained(\n",
1923
+ " MODEL_NAME,\n",
1924
+ " cache_dir=str(CACHE_DIR)\n",
1925
+ " )\n",
1926
+ " print(\"✅ Tokenizer loaded\")\n",
1927
+ "except Exception as e:\n",
1928
+ " print(f\"❌ Error loading tokenizer: {e}\")\n",
1929
+ " raise\n",
1930
+ "\n",
1931
+ "# Ensure pad token is set\n",
1932
+ "if tokenizer.pad_token is None:\n",
1933
+ " tokenizer.pad_token = tokenizer.eos_token\n",
1934
+ " print(f\"Set pad_token to eos_token: {tokenizer.eos_token}\")\n",
1935
+ "\n",
1936
+ "# Load model with optimizations\n",
1937
+ "print(\"Loading model (this may take several minutes)...\")\n",
1938
+ "try:\n",
1939
+ " model = AutoModelForCausalLM.from_pretrained(\n",
1940
+ " MODEL_NAME,\n",
1941
+ " cache_dir=str(CACHE_DIR),\n",
1942
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
1943
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
1944
+ " low_cpu_mem_usage=True # Optimize memory usage\n",
1945
+ " )\n",
1946
+ " model.eval() # Set to evaluation mode\n",
1947
+ " print(\"✅ Model loaded\")\n",
1948
+ "except Exception as e:\n",
1949
+ " print(f\"❌ Error loading model: {e}\")\n",
1950
+ " raise\n",
1951
+ "\n",
1952
+ "# Check VRAM usage\n",
1953
+ "if torch.cuda.is_available():\n",
1954
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
1955
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
1956
+ "\n",
1957
+ "# === LOAD DATA ===\n",
1958
+ "df = pd.read_csv(input_file)\n",
1959
+ "print(f\"Loaded {len(df)} rows\")\n",
1960
+ "\n",
1961
+ "if TEST_MODE:\n",
1962
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
1963
+ " df = df.head(TEST_SIZE).copy()\n",
1964
+ "elif MAX_ROWS:\n",
1965
+ " df = df.head(MAX_ROWS).copy()\n",
1966
+ "\n",
1967
+ "# === CREATE PROMPT (Exact DeepSeek style) ===\n",
1968
+ "def create_prompt(row):\n",
1969
+ " \"\"\"Create prompt.\"\"\"\n",
1970
+ " name = row.get('real_name', row.get('name', ''))\n",
1971
+ " if pd.isna(name):\n",
1972
+ " name = row.get('name', '')\n",
1973
+ " \n",
1974
+ " # Gather hints exactly like DeepSeek version\n",
1975
+ " hints = []\n",
1976
+ " if pd.notna(row.get('likely_profession')):\n",
1977
+ " hints.append(str(row['likely_profession']))\n",
1978
+ " if pd.notna(row.get('likely_nationality')):\n",
1979
+ " hints.append(str(row['likely_nationality']))\n",
1980
+ " if pd.notna(row.get('likely_country')):\n",
1981
+ " hints.append(str(row['likely_country']))\n",
1982
+ " \n",
1983
+ " # Add tags if we don't have enough hints\n",
1984
+ " if len(hints) < 3:\n",
1985
+ " for i in range(1, 8):\n",
1986
+ " tag_col = f'tag_{i}'\n",
1987
+ " if tag_col in row and pd.notna(row[tag_col]):\n",
1988
+ " tag_val = str(row[tag_col])\n",
1989
+ " if tag_val not in hints:\n",
1990
+ " hints.append(tag_val)\n",
1991
+ " if len(hints) >= 5:\n",
1992
+ " break\n",
1993
+ " \n",
1994
+ " hint_text = \", \".join(hints[:5]) if hints else \"none\"\n",
1995
+ " \n",
1996
+ " return f\"\"\"Given '{name}' ({hint_text}), provide:\n",
1997
+ "1. Full legal name (Western order if non-latin script)\n",
1998
+ "2. Any stage names/aliases (comma separated)\n",
1999
+ "3. Gender (Male/Female/Other/Unknown)\n",
2000
+ "4. Top 3 most likely professions from ONLY these categories:\n",
2001
+ " - actor\n",
2002
+ " - adult performer\n",
2003
+ " - singer/musician\n",
2004
+ " - model\n",
2005
+ " - online personality (includes streamers, cosplayers, influencers)\n",
2006
+ " - public figure (includes politicians, activists, journalists, authors)\n",
2007
+ " - voice actor/ASMR\n",
2008
+ " - sports professional\n",
2009
+ " - tv personality (includes hosts, presenters, reality TV)\n",
2010
+ "\n",
2011
+ "5. Primary country associated\n",
2012
+ "\n",
2013
+ "IMPORTANT:\n",
2014
+ "- Choose professions ONLY from the 9 categories above\n",
2015
+ "- Provide up to 3 professions, comma-separated, ordered by relevance\n",
2016
+ "- Be SPECIFIC: choose the most accurate category for each role\n",
2017
+ "- \"online personality\" includes: streamers, cosplayers, YouTubers, influencers, content creators\n",
2018
+ "- Use 'Unknown' when uncertain or for fictional characters/places\n",
2019
+ "- For multi-role people, list all relevant categories (e.g., \"actor, singer/musician, online personality\")\n",
2020
+ "\n",
2021
+ "Respond with exactly 5 numbered lines.\"\"\"\n",
2022
+ "\n",
2023
+ "df['prompt'] = df.apply(create_prompt, axis=1)\n",
2024
+ "\n",
2025
+ "# === QUERY BLOOMZ LOCAL ===\n",
2026
+ "def query_bloomz_local(prompt: str) -> str:\n",
2027
+ " \"\"\"Query BLOOMZ-7B1 locally via transformers, return raw response string.\"\"\"\n",
2028
+ " try:\n",
2029
+ " # BLOOMZ works better with instruction-response format\n",
2030
+ " full_prompt = f\"\"\"Instruction: Extract key data on a person based on the name and hints.\n",
2031
+ "You must respond with exactly 5 numbered lines in this format:\n",
2032
+ "1. Full legal name\n",
2033
+ "2. Stage names/aliases \n",
2034
+ "3. Gender\n",
2035
+ "4. Professions (comma-separated, choose ONLY from: actor, adult performer, singer/musician, model, online personality, public figure, voice actor/ASMR, sports professional, tv personality)\n",
2036
+ "5. Country\n",
2037
+ "\n",
2038
+ "{prompt}\n",
2039
+ "\n",
2040
+ "Response:\"\"\"\n",
2041
+ " \n",
2042
+ " inputs = tokenizer(\n",
2043
+ " full_prompt, \n",
2044
+ " return_tensors=\"pt\", \n",
2045
+ " truncation=True,\n",
2046
+ " max_length=2048\n",
2047
+ " ).to(device)\n",
2048
+ " \n",
2049
+ " # Generate with adjusted parameters for BLOOMZ\n",
2050
+ " with torch.no_grad():\n",
2051
+ " outputs = model.generate(\n",
2052
+ " **inputs,\n",
2053
+ " max_new_tokens=256,\n",
2054
+ " temperature=0.3, # Increased for more variability\n",
2055
+ " do_sample=True,\n",
2056
+ " top_p=0.9,\n",
2057
+ " top_k=40,\n",
2058
+ " repetition_penalty=1.1,\n",
2059
+ " pad_token_id=tokenizer.eos_token_id, # Use EOS as pad token\n",
2060
+ " eos_token_id=tokenizer.eos_token_id,\n",
2061
+ " early_stopping=True\n",
2062
+ " )\n",
2063
+ " \n",
2064
+ " # Decode the entire output to see what's happening\n",
2065
+ " full_output = tokenizer.decode(outputs[0], skip_special_tokens=True)\n",
2066
+ " \n",
2067
+ " # Extract only the generated part (after the prompt)\n",
2068
+ " generated_text = full_output[len(tokenizer.decode(inputs['input_ids'][0], skip_special_tokens=True)):]\n",
2069
+ " \n",
2070
+ " # Debug output\n",
2071
+ " if not hasattr(query_bloomz_local, 'debug_count'):\n",
2072
+ " query_bloomz_local.debug_count = 0\n",
2073
+ " \n",
2074
+ " if query_bloomz_local.debug_count < 3:\n",
2075
+ " print(f\"\\n📝 BLOOMZ Debug #{query_bloomz_local.debug_count + 1}:\")\n",
2076
+ " print(f\"Prompt: {full_prompt[:200]}...\")\n",
2077
+ " print(f\"Full output: {full_output[:500]}...\")\n",
2078
+ " print(f\"Generated text: {generated_text}\")\n",
2079
+ " print(f\"{'='*60}\\n\")\n",
2080
+ " query_bloomz_local.debug_count += 1\n",
2081
+ " \n",
2082
+ " return generated_text.strip()\n",
2083
+ " \n",
2084
+ " except Exception as e:\n",
2085
+ " print(f\"Error querying BLOOMZ: {e}\")\n",
2086
+ " return None\n",
2087
+ "\n",
2088
+ "# === PARSE RESPONSE (Exact DeepSeek format) ===\n",
2089
+ "def parse_response(response):\n",
2090
+ " \"\"\"Parse numbered response into structured fields.\"\"\"\n",
2091
+ " if not response:\n",
2092
+ " return {\n",
2093
+ " 'full_name': 'Unknown',\n",
2094
+ " 'aliases': 'Unknown',\n",
2095
+ " 'gender': 'Unknown',\n",
2096
+ " 'profession_llm': 'Unknown',\n",
2097
+ " 'country': 'Unknown'\n",
2098
+ " }\n",
2099
+ " \n",
2100
+ " # Split into lines and clean\n",
2101
+ " lines = [line.strip() for line in response.split('\\n') if line.strip()]\n",
2102
+ " \n",
2103
+ " # Initialize with Unknown values\n",
2104
+ " fields = {\n",
2105
+ " 'full_name': 'Unknown',\n",
2106
+ " 'aliases': 'Unknown',\n",
2107
+ " 'gender': 'Unknown',\n",
2108
+ " 'profession_llm': 'Unknown',\n",
2109
+ " 'country': 'Unknown'\n",
2110
+ " }\n",
2111
+ " \n",
2112
+ " # Extract information from each numbered line\n",
2113
+ " for line in lines:\n",
2114
+ " if line.startswith('1.') or line.startswith('1)'):\n",
2115
+ " fields['full_name'] = line[2:].strip()\n",
2116
+ " elif line.startswith('2.') or line.startswith('2)'):\n",
2117
+ " fields['aliases'] = line[2:].strip()\n",
2118
+ " elif line.startswith('3.') or line.startswith('3)'):\n",
2119
+ " fields['gender'] = line[2:].strip()\n",
2120
+ " elif line.startswith('4.') or line.startswith('4)'):\n",
2121
+ " fields['profession_llm'] = line[2:].strip()\n",
2122
+ " elif line.startswith('5.') or line.startswith('5)'):\n",
2123
+ " fields['country'] = line[2:].strip()\n",
2124
+ " \n",
2125
+ " return fields\n",
2126
+ "\n",
2127
+ "# === PROCESS ===\n",
2128
+ "output_file = current_dir.parent / f\"data/CSV/bloomz_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2129
+ "index_file = current_dir.parent / \"misc/bloomz_query_index.txt\"\n",
2130
+ "\n",
2131
+ "current_index = 0\n",
2132
+ "if index_file.exists():\n",
2133
+ " with open(index_file) as f:\n",
2134
+ " current_index = int(f.read().strip())\n",
2135
+ " print(f\"Resuming from index {current_index}\")\n",
2136
+ "\n",
2137
+ "# Initialize columns (same as DeepSeek)\n",
2138
+ "for col in ['full_name', 'gender', 'profession_llm', 'country', 'aliases']:\n",
2139
+ " if col not in df.columns:\n",
2140
+ " df[col] = 'Unknown'\n",
2141
+ "\n",
2142
+ "# Create prompts for all rows (same as DeepSeek)\n",
2143
+ "print(\"Creating prompts...\")\n",
2144
+ "df['prompt'] = df.apply(create_prompt, axis=1)\n",
2145
+ "\n",
2146
+ "print(f\"\\nAnnotating with BLOOMZ-7B1 LOCAL - rows {current_index} to {len(df)}...\")\n",
2147
+ "print(f\"Model: {MODEL_NAME}\")\n",
2148
+ "print(f\"This may take a while...\\n\")\n",
2149
+ "\n",
2150
+ "try:\n",
2151
+ " start_time = time.time()\n",
2152
+ " \n",
2153
+ " for i in tqdm(range(current_index, len(df)), desc=\"Annotating\"):\n",
2154
+ " row = df.iloc[i]\n",
2155
+ " \n",
2156
+ " # Query BLOOMZ (equivalent to DeepSeek query)\n",
2157
+ " response = query_bloomz_local(row['prompt'])\n",
2158
+ " parsed_data = parse_response(response)\n",
2159
+ " \n",
2160
+ " # Update dataframe\n",
2161
+ " for key, value in parsed_data.items():\n",
2162
+ " df.at[i, key] = value\n",
2163
+ " \n",
2164
+ " current_index = i + 1\n",
2165
+ " \n",
2166
+ " # Save progress at intervals\n",
2167
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2168
+ " df.to_csv(output_file, index=False)\n",
2169
+ " with open(index_file, 'w') as f:\n",
2170
+ " f.write(str(current_index))\n",
2171
+ " print(f\"✅ Progress saved after {i+1} rows\")\n",
2172
+ " \n",
2173
+ " # Optional: Add small delay to prevent overheating (not needed for rate limiting like DeepSeek)\n",
2174
+ " # time.sleep(0.1)\n",
2175
+ " \n",
2176
+ " elapsed_total = time.time() - start_time\n",
2177
+ " print(f\"\\n✅ Done! Final results saved to {output_file}\")\n",
2178
+ " \n",
2179
+ " # Summary statistics (same as DeepSeek)\n",
2180
+ " print(\"\\n=== Summary Statistics ===\")\n",
2181
+ " print(f\"Total processed: {len(df)}\")\n",
2182
+ " print(f\"\\nGender distribution:\")\n",
2183
+ " print(df['gender'].value_counts())\n",
2184
+ " print(f\"\\nTop 10 profession combinations:\")\n",
2185
+ " print(df['profession_llm'].value_counts().head(10))\n",
2186
+ " print(f\"\\nTop 10 countries:\")\n",
2187
+ " print(df['country'].value_counts().head(10))\n",
2188
+ " \n",
2189
+ " # Sample results\n",
2190
+ " print(\"\\n=== Sample Results ===\")\n",
2191
+ " display_cols = ['real_name', 'full_name', 'gender', 'profession_llm', 'country']\n",
2192
+ " available_cols = [col for col in display_cols if col in df.columns]\n",
2193
+ " print(df[available_cols].head(10).to_string(index=False))\n",
2194
+ " \n",
2195
+ " # Additional info for local model\n",
2196
+ " print(f\"\\nTotal time: {elapsed_total/60:.1f} minutes\")\n",
2197
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2198
+ " if torch.cuda.is_available():\n",
2199
+ " print(f\"Final VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2200
+ "\n",
2201
+ "except Exception as e:\n",
2202
+ " print(f\"⚠️ Error encountered: {e}\")\n",
2203
+ " print(f\"⚠️ Last processed index: {current_index}\")\n",
2204
+ " \n",
2205
+ " # Save progress before exiting\n",
2206
+ " df.to_csv(output_file, index=False)\n",
2207
+ " with open(index_file, 'w') as f:\n",
2208
+ " f.write(str(current_index))\n",
2209
+ " \n",
2210
+ " print(f\"⚠️ Progress saved up to row {current_index}\")"
2211
+ ]
2212
+ },
2213
+ {
2214
+ "cell_type": "markdown",
2215
+ "id": "24fb0c1f-a65e-4863-ad9b-5a9e8ffa2f94",
2216
+ "metadata": {
2217
+ "execution": {
2218
+ "iopub.execute_input": "2025-11-21T18:56:46.267902Z",
2219
+ "iopub.status.busy": "2025-11-21T18:56:46.267700Z",
2220
+ "iopub.status.idle": "2025-11-21T18:56:46.272355Z",
2221
+ "shell.execute_reply": "2025-11-21T18:56:46.271747Z",
2222
+ "shell.execute_reply.started": "2025-11-21T18:56:46.267886Z"
2223
+ }
2224
+ },
2225
+ "source": [
2226
+ "## Qwen-2.5-32B Local Annotation (Hugging Face Transformers)\n",
2227
+ "\n",
2228
+ "Run **Qwen-2.5-32B-Instruct** locally using Hugging Face Transformers - NO API COSTS!\n",
2229
+ "\n",
2230
+ "**Requirements:**\n",
2231
+ "- GPU: NVIDIA A100 80GB or similar (32B model needs ~60-70GB VRAM)\n",
2232
+ "- RAM: 128GB+ system RAM recommended\n",
2233
+ "- Model cache: `data/models/` (auto-downloaded on first run)\n",
2234
+ "- Model size: ~65GB download (BF16 weights)\n",
2235
+ "\n",
2236
+ "**Installation:**\n",
2237
+ "```bash\n",
2238
+ "# Install required packages\n",
2239
+ "pip install torch transformers accelerate\n",
2240
+ "```\n",
2241
+ "\n",
2242
+ "**Advantages:**\n",
2243
+ "- ✅ FREE - No API costs\n",
2244
+ "- ✅ Fast - Local inference with GPU acceleration\n",
2245
+ "- ✅ Privacy - Data never leaves your machine\n",
2246
+ "- ✅ Offline - Works without internet (after download)\n",
2247
+ "- ✅ High quality - 32B parameter instruction-tuned model\n",
2248
+ "\n",
2249
+ "**Performance:**\n",
2250
+ "- Speed: ~10-30 tokens/sec on A100 (depends on batch size)\n",
2251
+ "- Throughput: ~200-500 samples/hour\n",
2252
+ "- Cost: $0 (after model download)\n",
2253
+ "\n",
2254
+ "**Model Info:**\n",
2255
+ "- HuggingFace: `Qwen/Qwen2.5-32B-Instruct`\n",
2256
+ "- License: Apache 2.0 (commercial use allowed)\n",
2257
+ "- Context: 32K tokens"
2258
+ ]
2259
+ },
2260
+ {
2261
+ "cell_type": "code",
2262
+ "execution_count": null,
2263
+ "id": "5dd7a803",
2264
+ "metadata": {},
2265
+ "outputs": [],
2266
+ "source": [
2267
+ "import pandas as pd\n",
2268
+ "import json\n",
2269
+ "import time\n",
2270
+ "import re\n",
2271
+ "from pathlib import Path\n",
2272
+ "from tqdm import tqdm\n",
2273
+ "import torch\n",
2274
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
2275
+ "\n",
2276
+ "current_dir = Path.cwd()\n",
2277
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
2278
+ "\n",
2279
+ "# === CONFIGURATION ===\n",
2280
+ "TEST_MODE = True\n",
2281
+ "TEST_SIZE = 10\n",
2282
+ "MAX_ROWS = 20000\n",
2283
+ "SAVE_INTERVAL = 10\n",
2284
+ "\n",
2285
+ "# Model settings\n",
2286
+ "MODEL_NAME = \"Qwen/Qwen3-235B-A22B-Instruct-2507-FP8\"\n",
2287
+ "#MODEL_NAME = \"Qwen/Qwen3-max\"\n",
2288
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
2289
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
2290
+ "\n",
2291
+ "PROFESSION_CATEGORIES = [\n",
2292
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
2293
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
2294
+ " \"sports professional\", \"tv personality\"\n",
2295
+ "]\n",
2296
+ "\n",
2297
+ "# === LOAD MODEL ===\n",
2298
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
2299
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
2300
+ "print(f\"This may take a while on first run (~65GB download)...\\n\")\n",
2301
+ "\n",
2302
+ "# Check GPU availability\n",
2303
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
2304
+ "print(f\"Device: {device}\")\n",
2305
+ "\n",
2306
+ "if device == \"cpu\":\n",
2307
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
2308
+ " print(\" Consider using a GPU or reducing model size.\")\n",
2309
+ "\n",
2310
+ "# Load tokenizer\n",
2311
+ "print(\"Loading tokenizer...\")\n",
2312
+ "tokenizer = AutoTokenizer.from_pretrained(\n",
2313
+ " MODEL_NAME,\n",
2314
+ " cache_dir=str(CACHE_DIR),\n",
2315
+ " trust_remote_code=True\n",
2316
+ ")\n",
2317
+ "print(\"✅ Tokenizer loaded\")\n",
2318
+ "\n",
2319
+ "# Load model with optimizations\n",
2320
+ "print(\"Loading model (this may take several minutes)...\")\n",
2321
+ "model = AutoModelForCausalLM.from_pretrained(\n",
2322
+ " MODEL_NAME,\n",
2323
+ " cache_dir=str(CACHE_DIR),\n",
2324
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
2325
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
2326
+ " trust_remote_code=True\n",
2327
+ ")\n",
2328
+ "model.eval() # Set to evaluation mode\n",
2329
+ "print(\"✅ Model loaded\")\n",
2330
+ "\n",
2331
+ "# Check VRAM usage\n",
2332
+ "if torch.cuda.is_available():\n",
2333
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
2334
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
2335
+ "\n",
2336
+ "# === LOAD DATA ===\n",
2337
+ "df = pd.read_csv(input_file)\n",
2338
+ "print(f\"Loaded {len(df)} rows\")\n",
2339
+ "\n",
2340
+ "if TEST_MODE:\n",
2341
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
2342
+ " df = df.head(TEST_SIZE).copy()\n",
2343
+ "elif MAX_ROWS:\n",
2344
+ " df = df.head(MAX_ROWS).copy()\n",
2345
+ "\n",
2346
+ "# === CREATE PROMPT ===\n",
2347
+ "def create_prompt(name: str, tags: list, country: str) -> str:\n",
2348
+ " tags_str = \", \".join(tags[:5]) if tags else \"none\"\n",
2349
+ " country_str = country if country else \"unknown\"\n",
2350
+ " \n",
2351
+ " return f\"\"\"You are an expert at identifying public figures.\n",
2352
+ "\n",
2353
+ "Given: Name: {name}, Tags: {tags_str}, Country: {country_str}\n",
2354
+ "\n",
2355
+ "Provide in JSON format:\n",
2356
+ "{{\n",
2357
+ " \"full_name\": \"<full name>\",\n",
2358
+ " \"gender\": \"<Male/Female/Other/Unknown>\",\n",
2359
+ " \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n",
2360
+ " \"country\": \"<country>\"\n",
2361
+ "}}\n",
2362
+ "\n",
2363
+ "Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n",
2364
+ "- Max 3 professions, ordered by relevance\n",
2365
+ "- \"online personality\" includes streamers, cosplayers, influencers\n",
2366
+ "- Return \"Unknown\" if uncertain\n",
2367
+ "\n",
2368
+ "Return ONLY JSON, no extra text.\"\"\"\n",
2369
+ "\n",
2370
+ "# === QUERY QWEN LOCAL ===\n",
2371
+ "def query_qwen_local(prompt: str) -> dict:\n",
2372
+ " \"\"\"Query Qwen-2.5-32B locally via transformers.\"\"\"\n",
2373
+ " try:\n",
2374
+ " # Format as chat message\n",
2375
+ " messages = [\n",
2376
+ " {\"role\": \"user\", \"content\": prompt}\n",
2377
+ " ]\n",
2378
+ " \n",
2379
+ " # Tokenize\n",
2380
+ " text = tokenizer.apply_chat_template(\n",
2381
+ " messages,\n",
2382
+ " tokenize=False,\n",
2383
+ " add_generation_prompt=True\n",
2384
+ " )\n",
2385
+ " \n",
2386
+ " inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
2387
+ " \n",
2388
+ " # Generate\n",
2389
+ " with torch.no_grad():\n",
2390
+ " outputs = model.generate(\n",
2391
+ " **inputs,\n",
2392
+ " max_new_tokens=512,\n",
2393
+ " temperature=0.1,\n",
2394
+ " do_sample=True,\n",
2395
+ " top_p=0.9,\n",
2396
+ " pad_token_id=tokenizer.eos_token_id\n",
2397
+ " )\n",
2398
+ " \n",
2399
+ " # Decode\n",
2400
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
2401
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n",
2402
+ " \n",
2403
+ " # Parse JSON from response\n",
2404
+ " json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n",
2405
+ " if json_match:\n",
2406
+ " return json.loads(json_match.group())\n",
2407
+ " \n",
2408
+ " # Try markdown code block\n",
2409
+ " code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n",
2410
+ " if code_block:\n",
2411
+ " return json.loads(code_block.group(1))\n",
2412
+ " \n",
2413
+ " return None\n",
2414
+ " \n",
2415
+ " except json.JSONDecodeError as e:\n",
2416
+ " print(f\"JSON parse error: {e}\")\n",
2417
+ " return None\n",
2418
+ " except Exception as e:\n",
2419
+ " print(f\"Generation error: {e}\")\n",
2420
+ " return None\n",
2421
+ "\n",
2422
+ "# === PROCESS ===\n",
2423
+ "output_file = current_dir.parent / f\"data/CSV/qwen_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2424
+ "index_file = current_dir.parent / \"misc/qwen_local_query_index.txt\"\n",
2425
+ "\n",
2426
+ "current_index = 0\n",
2427
+ "if index_file.exists():\n",
2428
+ " with open(index_file) as f:\n",
2429
+ " current_index = int(f.read().strip())\n",
2430
+ " print(f\"Resuming from index {current_index}\")\n",
2431
+ "\n",
2432
+ "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
2433
+ " if col not in df.columns:\n",
2434
+ " df[col] = 'Unknown'\n",
2435
+ "\n",
2436
+ "print(f\"\\nAnnotating with QWEN-2.5-32B LOCAL - rows {current_index} to {len(df)}...\")\n",
2437
+ "print(f\"Model: {MODEL_NAME}\")\n",
2438
+ "print(f\"This may take a while (~200-500 samples/hour on A100)\\n\")\n",
2439
+ "\n",
2440
+ "try:\n",
2441
+ " start_time = time.time()\n",
2442
+ " \n",
2443
+ " for i in tqdm(range(current_index, len(df)), desc=\"Qwen Local\"):\n",
2444
+ " row = df.iloc[i]\n",
2445
+ " \n",
2446
+ " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
2447
+ " if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n",
2448
+ " \n",
2449
+ " prompt = create_prompt(\n",
2450
+ " row.get('real_name', row.get('name', '')),\n",
2451
+ " tags,\n",
2452
+ " row.get('likely_country', '')\n",
2453
+ " )\n",
2454
+ " \n",
2455
+ " result = query_qwen_local(prompt)\n",
2456
+ " \n",
2457
+ " if result:\n",
2458
+ " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
2459
+ " df.at[i, 'gender'] = result.get('gender', 'Unknown')\n",
2460
+ " profs = result.get('professions', [])\n",
2461
+ " df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n",
2462
+ " df.at[i, 'country'] = result.get('country', 'Unknown')\n",
2463
+ " \n",
2464
+ " current_index = i + 1\n",
2465
+ " \n",
2466
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2467
+ " df.to_csv(output_file, index=False)\n",
2468
+ " with open(index_file, 'w') as f:\n",
2469
+ " f.write(str(current_index))\n",
2470
+ " \n",
2471
+ " # Calculate stats\n",
2472
+ " elapsed = time.time() - start_time\n",
2473
+ " samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n",
2474
+ " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
2475
+ " \n",
2476
+ " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
2477
+ " \n",
2478
+ " elapsed_total = time.time() - start_time\n",
2479
+ " print(f\"\\n✅ Done! Results: {output_file}\")\n",
2480
+ " print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
2481
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2482
+ " \n",
2483
+ " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
2484
+ " \n",
2485
+ " # Show VRAM stats\n",
2486
+ " if torch.cuda.is_available():\n",
2487
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2488
+ "\n",
2489
+ "except KeyboardInterrupt:\n",
2490
+ " print(f\"\\n⚠️ Interrupted by user\")\n",
2491
+ " df.to_csv(output_file, index=False)\n",
2492
+ " with open(index_file, 'w') as f:\n",
2493
+ " f.write(str(current_index))\n",
2494
+ " print(f\"Progress saved up to row {current_index}\")\n",
2495
+ "\n",
2496
+ "except Exception as e:\n",
2497
+ " print(f\"⚠️ Error: {e}\")\n",
2498
+ " df.to_csv(output_file, index=False)\n",
2499
+ " with open(index_file, 'w') as f:\n",
2500
+ " f.write(str(current_index))\n",
2501
+ " print(f\"Progress saved up to row {current_index}\")"
2502
+ ]
2503
+ },
2504
+ {
2505
+ "cell_type": "markdown",
2506
+ "id": "84b144a0-7d24-4d6b-8f42-17d8e6100807",
2507
+ "metadata": {},
2508
+ "source": [
2509
+ "## Gemma 3 local"
2510
+ ]
2511
+ },
2512
+ {
2513
+ "cell_type": "code",
2514
+ "execution_count": null,
2515
+ "id": "4gb2vta3w5g",
2516
+ "metadata": {},
2517
+ "outputs": [],
2518
+ "source": [
2519
+ "import pandas as pd\n",
2520
+ "import json\n",
2521
+ "import time\n",
2522
+ "import re\n",
2523
+ "from pathlib import Path\n",
2524
+ "from tqdm import tqdm\n",
2525
+ "import torch\n",
2526
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
2527
+ "\n",
2528
+ "current_dir = Path.cwd()\n",
2529
+ "input_file = current_dir.parent / \"data/CSV/model_adapter/real_person_adapter_step_02_NER.csv\"\n",
2530
+ "\n",
2531
+ "# === CONFIGURATION ===\n",
2532
+ "TEST_MODE = True\n",
2533
+ "TEST_SIZE = 10\n",
2534
+ "MAX_ROWS = 20000\n",
2535
+ "SAVE_INTERVAL = 10\n",
2536
+ "\n",
2537
+ "# Model settings\n",
2538
+ "MODEL_NAME = \"google/gemma-3-27b-it\"\n",
2539
+ "CACHE_DIR = current_dir.parent / \"data/models\"\n",
2540
+ "CACHE_DIR.mkdir(parents=True, exist_ok=True)\n",
2541
+ "\n",
2542
+ "PROFESSION_CATEGORIES = [\n",
2543
+ " \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n",
2544
+ " \"online personality\", \"public figure\", \"voice actor/ASMR\",\n",
2545
+ " \"sports professional\", \"tv personality\"\n",
2546
+ "]\n",
2547
+ "\n",
2548
+ "# === LOAD MODEL ===\n",
2549
+ "print(f\"Loading model: {MODEL_NAME}\")\n",
2550
+ "print(f\"Cache directory: {CACHE_DIR}\")\n",
2551
+ "print(f\"This may take a while on first run (~54GB download)...\\n\")\n",
2552
+ "\n",
2553
+ "# Check GPU availability\n",
2554
+ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
2555
+ "print(f\"Device: {device}\")\n",
2556
+ "\n",
2557
+ "if device == \"cpu\":\n",
2558
+ " print(\"⚠️ WARNING: No GPU detected! Inference will be VERY slow.\")\n",
2559
+ " print(\" Consider using a GPU or reducing model size.\")\n",
2560
+ "\n",
2561
+ "# Load tokenizer\n",
2562
+ "print(\"Loading tokenizer...\")\n",
2563
+ "tokenizer = AutoTokenizer.from_pretrained(\n",
2564
+ " MODEL_NAME,\n",
2565
+ " cache_dir=str(CACHE_DIR),\n",
2566
+ " trust_remote_code=True\n",
2567
+ ")\n",
2568
+ "print(\"✅ Tokenizer loaded\")\n",
2569
+ "\n",
2570
+ "# Load model with optimizations\n",
2571
+ "print(\"Loading model (this may take several minutes)...\")\n",
2572
+ "model = AutoModelForCausalLM.from_pretrained(\n",
2573
+ " MODEL_NAME,\n",
2574
+ " cache_dir=str(CACHE_DIR),\n",
2575
+ " torch_dtype=torch.bfloat16, # Use BF16 for efficiency\n",
2576
+ " device_map=\"auto\", # Automatically distribute across GPUs\n",
2577
+ " trust_remote_code=True\n",
2578
+ ")\n",
2579
+ "model.eval() # Set to evaluation mode\n",
2580
+ "print(\"✅ Model loaded\")\n",
2581
+ "\n",
2582
+ "# Check VRAM usage\n",
2583
+ "if torch.cuda.is_available():\n",
2584
+ " vram_gb = torch.cuda.max_memory_allocated() / 1024**3\n",
2585
+ " print(f\"VRAM used: {vram_gb:.2f} GB\\n\")\n",
2586
+ "\n",
2587
+ "# === LOAD DATA ===\n",
2588
+ "df = pd.read_csv(input_file)\n",
2589
+ "print(f\"Loaded {len(df)} rows\")\n",
2590
+ "\n",
2591
+ "if TEST_MODE:\n",
2592
+ " print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n",
2593
+ " df = df.head(TEST_SIZE).copy()\n",
2594
+ "elif MAX_ROWS:\n",
2595
+ " df = df.head(MAX_ROWS).copy()\n",
2596
+ "\n",
2597
+ "# === CREATE PROMPT ===\n",
2598
+ "def create_prompt(name: str, tags: list, country: str) -> str:\n",
2599
+ " tags_str = \", \".join(tags[:5]) if tags else \"none\"\n",
2600
+ " country_str = country if country else \"unknown\"\n",
2601
+ " \n",
2602
+ " return f\"\"\"You are an expert at identifying public figures.\n",
2603
+ "\n",
2604
+ "Given: Name: {name}, Tags: {tags_str}, Country: {country_str}\n",
2605
+ "\n",
2606
+ "Provide in JSON format:\n",
2607
+ "{{\n",
2608
+ " \"full_name\": \"<full name>\",\n",
2609
+ " \"gender\": \"<Male/Female/Other/Unknown>\",\n",
2610
+ " \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n",
2611
+ " \"country\": \"<country>\"\n",
2612
+ "}}\n",
2613
+ "\n",
2614
+ "Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n",
2615
+ "- Max 3 professions, ordered by relevance\n",
2616
+ "- \"online personality\" includes streamers, cosplayers, influencers\n",
2617
+ "- Return \"Unknown\" if uncertain\n",
2618
+ "\n",
2619
+ "Return ONLY JSON, no extra text.\"\"\"\n",
2620
+ "\n",
2621
+ "# === QUERY GEMMA LOCAL ===\n",
2622
+ "def query_gemma_local(prompt: str) -> dict:\n",
2623
+ " \"\"\"Query Gemma-3-27B locally via transformers.\"\"\"\n",
2624
+ " try:\n",
2625
+ " # Format as chat message\n",
2626
+ " messages = [\n",
2627
+ " {\"role\": \"user\", \"content\": prompt}\n",
2628
+ " ]\n",
2629
+ " \n",
2630
+ " # Tokenize\n",
2631
+ " text = tokenizer.apply_chat_template(\n",
2632
+ " messages,\n",
2633
+ " tokenize=False,\n",
2634
+ " add_generation_prompt=True\n",
2635
+ " )\n",
2636
+ " \n",
2637
+ " inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
2638
+ " \n",
2639
+ " # Generate\n",
2640
+ " with torch.no_grad():\n",
2641
+ " outputs = model.generate(\n",
2642
+ " **inputs,\n",
2643
+ " max_new_tokens=512,\n",
2644
+ " temperature=0.1,\n",
2645
+ " do_sample=True,\n",
2646
+ " top_p=0.9,\n",
2647
+ " pad_token_id=tokenizer.eos_token_id\n",
2648
+ " )\n",
2649
+ " \n",
2650
+ " # Decode\n",
2651
+ " generated_ids = outputs[0][inputs['input_ids'].shape[1]:]\n",
2652
+ " response = tokenizer.decode(generated_ids, skip_special_tokens=True)\n",
2653
+ " \n",
2654
+ " # Parse JSON from response\n",
2655
+ " json_match = re.search(r'\\{[^}]+\\}', response, re.DOTALL)\n",
2656
+ " if json_match:\n",
2657
+ " return json.loads(json_match.group())\n",
2658
+ " \n",
2659
+ " # Try markdown code block\n",
2660
+ " code_block = re.search(r'```(?:json)?\\s*(\\{[^}]+\\})\\s*```', response, re.DOTALL)\n",
2661
+ " if code_block:\n",
2662
+ " return json.loads(code_block.group(1))\n",
2663
+ " \n",
2664
+ " return None\n",
2665
+ " \n",
2666
+ " except json.JSONDecodeError as e:\n",
2667
+ " print(f\"JSON parse error: {e}\")\n",
2668
+ " return None\n",
2669
+ " except Exception as e:\n",
2670
+ " print(f\"Generation error: {e}\")\n",
2671
+ " return None\n",
2672
+ "\n",
2673
+ "# === PROCESS ===\n",
2674
+ "output_file = current_dir.parent / f\"data/CSV/gemma_local_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\n",
2675
+ "index_file = current_dir.parent / \"misc/gemma_local_query_index.txt\"\n",
2676
+ "\n",
2677
+ "current_index = 0\n",
2678
+ "if index_file.exists():\n",
2679
+ " with open(index_file) as f:\n",
2680
+ " current_index = int(f.read().strip())\n",
2681
+ " print(f\"Resuming from index {current_index}\")\n",
2682
+ "\n",
2683
+ "for col in ['full_name', 'gender', 'profession_llm', 'country']:\n",
2684
+ " if col not in df.columns:\n",
2685
+ " df[col] = 'Unknown'\n",
2686
+ "\n",
2687
+ "print(f\"\\nAnnotating with GEMMA-3-27B LOCAL - rows {current_index} to {len(df)}...\")\n",
2688
+ "print(f\"Model: {MODEL_NAME}\")\n",
2689
+ "print(f\"This may take a while (~250-600 samples/hour on A100)\\n\")\n",
2690
+ "\n",
2691
+ "try:\n",
2692
+ " start_time = time.time()\n",
2693
+ " \n",
2694
+ " for i in tqdm(range(current_index, len(df)), desc=\"Gemma Local\"):\n",
2695
+ " row = df.iloc[i]\n",
2696
+ " \n",
2697
+ " tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n",
2698
+ " if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n",
2699
+ " \n",
2700
+ " prompt = create_prompt(\n",
2701
+ " row.get('real_name', row.get('name', '')),\n",
2702
+ " tags,\n",
2703
+ " row.get('likely_country', '')\n",
2704
+ " )\n",
2705
+ " \n",
2706
+ " result = query_gemma_local(prompt)\n",
2707
+ " \n",
2708
+ " if result:\n",
2709
+ " df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n",
2710
+ " df.at[i, 'gender'] = result.get('gender', 'Unknown')\n",
2711
+ " profs = result.get('professions', [])\n",
2712
+ " df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n",
2713
+ " df.at[i, 'country'] = result.get('country', 'Unknown')\n",
2714
+ " \n",
2715
+ " current_index = i + 1\n",
2716
+ " \n",
2717
+ " if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n",
2718
+ " df.to_csv(output_file, index=False)\n",
2719
+ " with open(index_file, 'w') as f:\n",
2720
+ " f.write(str(current_index))\n",
2721
+ " \n",
2722
+ " # Calculate stats\n",
2723
+ " elapsed = time.time() - start_time\n",
2724
+ " samples_done = current_index - (0 if not index_file.exists() else int(open(index_file).read().strip()))\n",
2725
+ " samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
2726
+ " \n",
2727
+ " print(f\"✅ Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
2728
+ " \n",
2729
+ " elapsed_total = time.time() - start_time\n",
2730
+ " print(f\"\\n✅ Done! Results: {output_file}\")\n",
2731
+ " print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
2732
+ " print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
2733
+ " \n",
2734
+ " print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
2735
+ " \n",
2736
+ " # Show VRAM stats\n",
2737
+ " if torch.cuda.is_available():\n",
2738
+ " print(f\"\\nFinal VRAM usage: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB\")\n",
2739
+ "\n",
2740
+ "except KeyboardInterrupt:\n",
2741
+ " print(f\"\\n⚠️ Interrupted by user\")\n",
2742
+ " df.to_csv(output_file, index=False)\n",
2743
+ " with open(index_file, 'w') as f:\n",
2744
+ " f.write(str(current_index))\n",
2745
+ " print(f\"Progress saved up to row {current_index}\")\n",
2746
+ "\n",
2747
+ "except Exception as e:\n",
2748
+ " print(f\"⚠️ Error: {e}\")\n",
2749
+ " df.to_csv(output_file, index=False)\n",
2750
+ " with open(index_file, 'w') as f:\n",
2751
+ " f.write(str(current_index))\n",
2752
+ " print(f\"Progress saved up to row {current_index}\")"
2753
+ ]
2754
+ },
2755
+ {
2756
+ "cell_type": "code",
2757
+ "execution_count": null,
2758
+ "id": "a5baf3c9-3901-4c43-9354-6877d30133e8",
2759
+ "metadata": {},
2760
+ "outputs": [],
2761
+ "source": []
2762
  }
2763
  ],
2764
  "metadata": {
 
2782
  },
2783
  "nbformat": 4,
2784
  "nbformat_minor": 5
2785
+ }
misc/bloomz_query_index.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 10
misc/gemma_local_query_index.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 10
misc/mistral_local_query_index.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 10