{ "cells": [ { "cell_type": "markdown", "id": "9371cf89", "metadata": {}, "source": [ "# Loading Script" ] }, { "cell_type": "code", "execution_count": 2, "id": "f67fdbad", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "๐Ÿš€ ChemQ3-MTP Model Loader Starting...\n", "\n", "๐Ÿ“ฅ Downloading model files from gbyuvd/ChemMiniQ3-SAbRLo...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "d:\\ProgramData\\miniconda3\\Lib\\site-packages\\huggingface_hub\\file_download.py:945: FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. If you want to force a new download, use `force_download=True`.\n", " warnings.warn(\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1859ad9097334d0f9a426bba84277c98", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Fetching 17 files: 0%| | 0/17 [00:00 [[0, 379, 379, 377, 1]]\n", " '[C]' -> [[0, 379, 1]]\n", " '[O]' -> [[0, 377, 1]]\n", "\n", "๐ŸŽฏ Testing generation...\n", "\n", " Prompt: '[C]'\n", " 1: [C] [#C] [#C] [C] [#C] [C] [#C] [C]\n", " 2: [C] [P] [#C] [=C] [Branch1] [=Branch2] [C] [=C] [C] [=C] [C] [=C] [Ring1] [=Branch1] [N] [Branch1] [=C] [C] [=C] [Ring1] [#Branch2] [C] [=C] [C] [=C] [C] [=C] [Ring1] [=Branch1] [C] [C]\n", " 3: [C] [Branch1] [Ring2] [C] [Ring1] [Branch1] [C] [Ring1] [Ring2] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [=C] [C] [=C] [Branch1] [C] [Br] [C] [=C] [Ring1] [#Branch1]\n", "\n", " Prompt: '[C][C]'\n", " 1: [C] [C] [O] [P] [=Branch1] [C] [=O] [Branch1] [C] [O] [O]\n", " 2: [C] [C] [Ring2] [Ring2] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [C] [Branch1] [C] [C] [C]\n", " 3: [C] [C] [=C] [Branch1] [Ring1] [C] [C] [C] [C] [C] [C] [C] [C]\n", "\n", "๐Ÿ”ฌ Testing MTP functionality...\n", " โœ… MTP training methods available\n", " โœ… MTP generation methods available\n", "\n", "๐ŸŽ‰ Model loading and testing completed successfully!\n" ] } ], "source": [ "import torch\n", "import sys\n", "import os\n", "from pathlib import Path\n", "import importlib.util\n", "import huggingface_hub\n", "from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer\n", "\n", "def download_and_setup_model(model_name=\"gbyuvd/ChemMiniQ3-SAbRLo\", local_dir=\"./chemq3_model\"):\n", " \"\"\"Download model files and set up the custom modules\"\"\"\n", " \n", " print(f\"๐Ÿ“ฅ Downloading model files from {model_name}...\")\n", " \n", " try:\n", " # Download all files to a local directory\n", " model_path = huggingface_hub.snapshot_download(\n", " repo_id=model_name,\n", " local_dir=local_dir,\n", " local_files_only=False,\n", " resume_download=True\n", " )\n", " \n", " print(f\"โœ… Model downloaded to: {model_path}\")\n", " \n", " # List downloaded files\n", " print(\"๐Ÿ“ Downloaded files:\")\n", " for file in Path(model_path).iterdir():\n", " if file.is_file():\n", " print(f\" {file.name} ({file.stat().st_size} bytes)\")\n", " \n", " return Path(model_path)\n", " \n", " except Exception as e:\n", " print(f\"โŒ Download failed: {e}\")\n", " return None\n", "\n", "def load_custom_modules(model_path):\n", " \"\"\"Load all the custom modules required by the model\"\"\"\n", " \n", " model_path = Path(model_path)\n", " \n", " # Add the model directory to Python path\n", " if str(model_path) not in sys.path:\n", " sys.path.insert(0, str(model_path))\n", " \n", " print(f\"๐Ÿ”ง Loading custom modules from {model_path}...\")\n", " \n", " # Required module files\n", " required_files = {\n", " 'configuration_chemq3mtp.py': 'configuration_chemq3mtp',\n", " 'modeling_chemq3mtp.py': 'modeling_chemq3mtp', \n", " 'FastChemTokenizerHF.py': 'FastChemTokenizerHF'\n", " }\n", " \n", " loaded_modules = {}\n", " \n", " # Load each required module\n", " for filename, module_name in required_files.items():\n", " file_path = model_path / filename\n", " \n", " if not file_path.exists():\n", " print(f\"โŒ Required file not found: {filename}\")\n", " return None\n", " \n", " try:\n", " spec = importlib.util.spec_from_file_location(module_name, file_path)\n", " module = importlib.util.module_from_spec(spec)\n", " \n", " # Execute the module\n", " spec.loader.exec_module(module)\n", " loaded_modules[module_name] = module\n", " \n", " print(f\" โœ… Loaded {filename}\")\n", " \n", " except Exception as e:\n", " print(f\" โŒ Failed to load {filename}: {e}\")\n", " return None\n", " \n", " return loaded_modules\n", "\n", "def register_model_components(loaded_modules):\n", " \"\"\"Register the model components with transformers\"\"\"\n", " \n", " print(\"๐Ÿ”— Registering model components...\")\n", " \n", " try:\n", " # Get the classes from loaded modules\n", " ChemQ3MTPConfig = loaded_modules['configuration_chemq3mtp'].ChemQ3MTPConfig\n", " ChemQ3MTPForCausalLM = loaded_modules['modeling_chemq3mtp'].ChemQ3MTPForCausalLM\n", " FastChemTokenizerSelfies = loaded_modules['FastChemTokenizerHF'].FastChemTokenizerSelfies\n", " \n", " # Register with transformers\n", " AutoConfig.register(\"chemq3_mtp\", ChemQ3MTPConfig)\n", " AutoModelForCausalLM.register(ChemQ3MTPConfig, ChemQ3MTPForCausalLM)\n", " AutoTokenizer.register(ChemQ3MTPConfig, FastChemTokenizerSelfies)\n", " \n", " print(\"โœ… Model components registered successfully\")\n", " \n", " return ChemQ3MTPConfig, ChemQ3MTPForCausalLM, FastChemTokenizerSelfies\n", " \n", " except Exception as e:\n", " print(f\"โŒ Registration failed: {e}\")\n", " return None, None, None\n", "\n", "def load_model(model_path):\n", " \"\"\"Load the model using the registered components\"\"\"\n", " \n", " print(\"๐Ÿš€ Loading model...\")\n", " \n", " try:\n", " # Load config\n", " config = AutoConfig.from_pretrained(str(model_path), trust_remote_code=False)\n", " print(f\"โœ… Config loaded: {config.__class__.__name__}\")\n", " \n", " # Load model\n", " model = AutoModelForCausalLM.from_pretrained(\n", " str(model_path),\n", " config=config,\n", " torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,\n", " trust_remote_code=False # We've already registered everything\n", " )\n", " print(f\"โœ… Model loaded: {model.__class__.__name__}\")\n", " \n", " # Load tokenizer\n", " tokenizer = AutoTokenizer.from_pretrained(str(model_path), trust_remote_code=False)\n", " print(f\"โœ… Tokenizer loaded: {tokenizer.__class__.__name__}\")\n", " \n", " return model, tokenizer, config\n", " \n", " except Exception as e:\n", " print(f\"โŒ Model loading failed: {e}\")\n", " import traceback\n", " traceback.print_exc()\n", " return None, None, None\n", "\n", "def test_model(model, tokenizer, config):\n", " \"\"\"Test the loaded model\"\"\"\n", " \n", " print(\"\\n๐Ÿงช Testing model...\")\n", " \n", " # Setup device\n", " device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", " print(f\"๐Ÿ–ฅ๏ธ Using device: {device}\")\n", " \n", " model = model.to(device)\n", " model.eval()\n", " \n", " # Model info\n", " print(f\"\\n๐Ÿ“Š Model Information:\")\n", " print(f\" Model class: {model.__class__.__name__}\")\n", " print(f\" Config class: {config.__class__.__name__}\")\n", " print(f\" Tokenizer class: {tokenizer.__class__.__name__}\")\n", " print(f\" Model type: {config.model_type}\")\n", " print(f\" Vocab size: {config.vocab_size}\")\n", " \n", " # Set pad token if needed\n", " if not hasattr(tokenizer, 'pad_token') or tokenizer.pad_token is None:\n", " if hasattr(tokenizer, 'eos_token'):\n", " tokenizer.pad_token = tokenizer.eos_token\n", " print(\"โœ… Set pad_token to eos_token\")\n", " \n", " # Test tokenization\n", " print(\"\\n๐Ÿ”ค Testing tokenization...\")\n", " test_inputs = [\"[C][C][O]\", \"[C]\", \"[O]\"]\n", " \n", " for test_input in test_inputs:\n", " try:\n", " tokens = tokenizer(test_input, return_tensors=\"pt\")\n", " print(f\" '{test_input}' -> {tokens.input_ids.tolist()}\")\n", " except Exception as e:\n", " print(f\" โŒ Tokenization failed for '{test_input}': {e}\")\n", " continue\n", " \n", " # Test generation\n", " print(\"\\n๐ŸŽฏ Testing generation...\")\n", " test_prompts = [\"[C]\", \"[C][C]\"]\n", " \n", " for prompt in test_prompts:\n", " try:\n", " input_ids = tokenizer(prompt, return_tensors=\"pt\").input_ids.to(device)\n", " \n", " with torch.no_grad():\n", " outputs = model.generate(\n", " input_ids,\n", " max_length=input_ids.shape[1] + 20,\n", " temperature=0.8,\n", " top_p=0.9,\n", " top_k=50,\n", " do_sample=True,\n", " pad_token_id=tokenizer.pad_token_id if hasattr(tokenizer, 'pad_token_id') else 0,\n", " num_return_sequences=3\n", " )\n", " \n", " print(f\"\\n Prompt: '{prompt}'\")\n", " for i, output in enumerate(outputs):\n", " generated = tokenizer.decode(output, skip_special_tokens=True)\n", " print(f\" {i+1}: {generated}\")\n", " \n", " except Exception as e:\n", " print(f\" โŒ Generation failed for '{prompt}': {e}\")\n", " \n", " # Test MTP functionality if available\n", " print(\"\\n๐Ÿ”ฌ Testing MTP functionality...\")\n", " try:\n", " if hasattr(model, 'set_mtp_training'):\n", " print(\" โœ… MTP training methods available\")\n", " if hasattr(model, 'generate_with_logprobs'):\n", " print(\" โœ… MTP generation methods available\")\n", " else:\n", " print(\" โ„น๏ธ Standard model - no MTP methods detected\")\n", " except Exception as e:\n", " print(f\" โš ๏ธ MTP test error: {e}\")\n", "\n", "def main():\n", " print(\"๐Ÿš€ ChemQ3-MTP Model Loader Starting...\\n\")\n", " \n", " model_name = \"gbyuvd/ChemMiniQ3-SAbRLo\"\n", " local_dir = \"./chemq3_model\"\n", " \n", " # Step 1: Download model files\n", " model_path = download_and_setup_model(model_name, local_dir)\n", " if model_path is None:\n", " return None, None, None\n", " \n", " print()\n", " \n", " # Step 2: Load custom modules\n", " loaded_modules = load_custom_modules(model_path)\n", " if loaded_modules is None:\n", " return None, None, None\n", " \n", " print()\n", " \n", " # Step 3: Register components\n", " config_class, model_class, tokenizer_class = register_model_components(loaded_modules)\n", " if config_class is None:\n", " return None, None, None\n", " \n", " print()\n", " \n", " # Step 4: Load the model\n", " model, tokenizer, config = load_model(model_path)\n", " if model is None:\n", " return None, None, None\n", " \n", " # Step 5: Test the model\n", " test_model(model, tokenizer, config)\n", " \n", " print(\"\\n๐ŸŽ‰ Model loading and testing completed successfully!\")\n", " \n", " return model, tokenizer, config\n", "\n", "if __name__ == \"__main__\":\n", " model, tokenizer, config = main()" ] }, { "cell_type": "markdown", "id": "cf544bee", "metadata": {}, "source": [ "# Ordinary Generate" ] }, { "cell_type": "code", "execution_count": 3, "id": "b2ea169c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[O] [C] [=C] [C] [=C] [Branch1] [C] [Cl] [C] [=C] [Ring1] [#Branch1] [C] [=C] [C] [C] [Branch1] [=N] [C] [=C] [C] [=C] [C] [=C] [Ring1] [=Branch1] [N] [C] [Ring1] [=N] [=O] [C] [Ring1] [S] [C] [=C] [C] [=C] [Branch1] [Ring1] [O] [C] [C] [=C] [Ring1] [Branch2]\n" ] } ], "source": [ "# Generate SELFIES\n", "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", "model.to(device)\n", "input_ids = tokenizer(\"\", return_tensors=\"pt\").input_ids.to(device)\n", "gen = model.generate(input_ids, max_length=256, top_k=50, temperature=1, do_sample=True, pad_token_id=tokenizer.pad_token_id)\n", "print(tokenizer.decode(gen[0], skip_special_tokens=True))" ] }, { "cell_type": "code", "execution_count": 4, "id": "bcd4f1fa", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OC1=CC=C(Cl)C=C1C=CCC(C2=CC=CC=C2NC)=O\n" ] } ], "source": [ "# Manually convert it to SMILES\n", "import selfies as sf\n", "\n", "test = tokenizer.decode(gen[0], skip_special_tokens=True)\n", "test = test.replace(' ', '')\n", "print(sf.decoder(test))\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "eaf273a0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OC=C1C=CC(OC)=C1OCCCNCC2=CC=CC=C2C\n" ] }, { "data": { "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAEsASwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKF7qi2t1HaRWs93cyIZPKg2gqgIG4lmAHJx1yfwNMsdctdQuI4IklWR43ch1AKFHCMrc/eBP0460y+tLyLVF1Ox8mRxAYZYpmZQy53AgqCcjnjBzntWHoOkWOtJbaw7W99bzJOzFoyB5jy5OAegGCOeaxcpc1kehCjQdHnl9/nrp26ad/wAuosL2PULQXESuqF3TDgZyrFT+oNWaz9E046VpUdmdnyPIRs6AM7MB+AIrQrWN7K5x1VBVJKG13b0CiiimZhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVyHhL/iV6/r/h88JHOLy2H/TOTkgewPH4119efeM5H0D4geE/EYdltLiVtIvBn5cScxE+mHByfpUSjdp9jopV+SnOm1dSS+TTun+a+Z6DRRRVnOFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRWX4i8Q6d4X0S41bVJvLt4R0HLO3ZVHdj6UAVfF3iuy8IaMb66Vpp5GEVrax8yXEp+6ij+vavLtcm8SeJNHXwReSxXnijU51vrgIAsOiwBlZQWXktwB3PzHrxmO5vtZm1y11m9s1uPGmpoU0LR35j0q3PWeX0bHJJ/xA9P8GeELfwlpjoZmu9Sun86/vpOXuJT1JPoMnA7fUmgDoYUeOCNJJPNkVQGfGNxxycds0+iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArlfHXiG98N2mjXNmIjHcavb2t15i5xC5IYjng9Oa6quB+MyMPhnf3SDMlnNb3C/VZU/oTQB31FNR1kjWRDlWAIPsadQAUUUUAFFFFABRRRQAVHPPFbW8txO6xwxIXd2PCqBkk/hUlcD8Ubye7sNO8IafIVvvENx9nZl6x26/NM/wD3zx9CaAM7SfiP4w1fTo9UtPh3PcaZOWa3mj1K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0OuY8ZeC4PFyWEo1C707UNOlM1nd2xGY2OM5B6jgccdOvWgCj8JrW+sPhrpdjqNrPbXVsZo2jmjKNgSvtODzggiu1rzk6/478Inbr+jp4i01f+YhpK7Z1Hq8B6n/AHeBXT+HPGnh7xXGTpGpRTSr9+3b5JU9cocH8elAG/RVLVtXsNC0ufUtTuo7azgXdJK/QdgPck8ADk15N4k8UXnibTGv9Wurjwz4Mc7Y1Axf6r/sovVVP6jrweADo9d8f3Wo30+h+CIob2+hyLvU5TizsB3LN0ZhzwP1wRWTpeqT+LvijoOo6SjX1ho1pPbalqyR+XBNIydIwTz8wB4z19OSzQ/BV/4qsIINRsW8O+D4iGt9CgJWa6H9+4Yc89dvX15GT6rZWVrptnFZ2VvFb20K7Y4olCqo9gKAJ6KKKACiiigAooqve31pp1s1xe3MVvCvV5WCj9aG7bjjFydkrsmdtiM2CcDOB1Nc34As7iy8GWUd3DJDcs0kkiSKVYEyMeQfbFU7nxBpniE2kiLNLo0F3tupZYWWGTKPtJz1UNjOeAdua0/DogF3qZ09VXSzInkeWMRltvzlO23p04zn3rFSUppr+v6selKhUo4adOaabab07XVvX3r2tsb9FFFbHmBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFcx4j+H/hzxPILi9sRFfKcpfWreVOh7HeOuPfNdPRQB5hf6R8RtAtHtNPm0/wAX6dJhVh1VQk8fcFmJCyAEA5Jz0xWx4b8Am31NfEPii7GseISMrIw/c2g/uwp0GP73X6ZOe3ooAKKKKACiiigAqtqF9BpmnXN/dFlt7aJpZCqFiFUZJAHJ4FWaKAPOT4o8aeLfl8LaGNI09v8AmKayuHI9Y4Rz7gnIPtW1pvgSzR4rrXbubXNQVQDNd/cB77Y/uge3NdZRUyipbo1pV6lK/s5NX00EVVRQqKFUDAAGABS0UVRkFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAf//Z", "image/png": "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", "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Generate Mol Viz\n", "from rdkit import Chem\n", "from rdkit.Chem import Draw\n", "\n", "input_ids = tokenizer(\"\", return_tensors=\"pt\").input_ids.to(device)\n", "gen = model.generate(input_ids, max_length=25, top_k=50, temperature=1, do_sample=True, pad_token_id=tokenizer.pad_token_id)\n", "generatedmol = tokenizer.decode(gen[0], skip_special_tokens=True)\n", "\n", "test = generatedmol.replace(' ', '')\n", "csmi_gen = sf.decoder(test)\n", "print(csmi_gen)\n", "mol = Chem.MolFromSmiles(csmi_gen)\n", "\n", "# Draw the molecule\n", "Draw.MolToImage(mol)" ] }, { "cell_type": "markdown", "id": "ab1ec3d4", "metadata": {}, "source": [ "# Testing the MTP Generation" ] }, { "cell_type": "code", "execution_count": 21, "id": "db78ea04", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using MTP-specific generation...\n", "Generated SELFIES: [O][=C][Branch1][=Branch2][C][=C][C][=C][C][=C][Ring1][=Branch1][C][=C][C][=C][C][=C][C][Ring1][=Branch1][=C][Ring1][#Branch2][C][O]\n", "Decoded SMILES: O=C(C1=CC=CC2=C1)C=C3C=CC=CC3=C2CO\n" ] }, { "data": { "image/jpeg": "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", "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Generate Mol Viz with MTP-specific generation\n", "from rdkit import Chem\n", "from rdkit.Chem import Draw\n", "import selfies as sf\n", "import torch\n", "\n", "# Setup device first\n", "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", "\n", "# Check if MTP-specific generation is available\n", "if hasattr(model, 'generate_with_logprobs'):\n", " print(\"Using MTP-specific generation...\")\n", " input_ids = tokenizer(\"\", return_tensors=\"pt\").input_ids.to(device)\n", " \n", " # Try MTP-specific generation with log probabilities\n", " try:\n", " outputs = model.generate_with_logprobs(\n", " input_ids,\n", " max_new_tokens=25, # Correct parameter name\n", " temperature=1,\n", " top_k=50,\n", " do_sample=True,\n", " return_probs=True, # This returns action probabilities\n", " tokenizer=tokenizer # Pass tokenizer for decoding\n", " )\n", " \n", " # Handle the output (returns: decoded_list, logprobs, tokens, probs)\n", " gen = outputs[2] # Get the generated token IDs (index 2)\n", " except Exception as e:\n", " print(f\"MTP generation failed: {e}, falling back to standard generation\")\n", " gen = model.generate(input_ids, max_length=25, top_k=50, temperature=1, do_sample=True, pad_token_id=tokenizer.pad_token_id)\n", "else:\n", " print(\"Using standard generation...\")\n", " input_ids = tokenizer(\"\", return_tensors=\"pt\").input_ids.to(device)\n", " gen = model.generate(input_ids, max_length=25, top_k=50, temperature=1, do_sample=True, pad_token_id=tokenizer.pad_token_id)\n", "\n", "# Decode and process the generated molecule\n", "generatedmol = tokenizer.decode(gen[0], skip_special_tokens=True)\n", "test = generatedmol.replace(' ', '')\n", "csmi_gen = sf.decoder(test)\n", "print(f\"Generated SELFIES: {test}\")\n", "print(f\"Decoded SMILES: {csmi_gen}\")\n", "\n", "mol = Chem.MolFromSmiles(csmi_gen)\n", "\n", "# Draw the molecule\n", "if mol is not None:\n", " img = Draw.MolToImage(mol)\n", " display(img) # Use display() in Jupyter notebooks\n", "else:\n", " print(\"โŒ Could not create molecule from generated SMILES\")" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.0" } }, "nbformat": 4, "nbformat_minor": 5 }