{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "7678e528-e2d6-4ef4-bd11-8c745bbce7c4", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import torch\n", "import torch.nn as nn\n", "from torch.utils.data import Dataset, DataLoader\n", "from transformers import BertModel, BertConfig, AutoTokenizer\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from sklearn.decomposition import PCA\n", "from sklearn.manifold import TSNE\n", "from sklearn.metrics.pairwise import cosine_similarity\n", "from sklearn.cluster import KMeans\n", "import umap.umap_ as umap\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "# Set style for better plots\n", "plt.style.use('seaborn-v0_8')\n", "sns.set_palette(\"husl\")\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "ad8d5a02-6162-41f7-a730-e31e353ed9b8", "metadata": {}, "outputs": [], "source": [ "class PrecomputedContrastiveSmilesDataset(Dataset):\n", " \"\"\"\n", " A Dataset class that reads pre-augmented SMILES pairs from a Parquet file.\n", " This is significantly faster as it offloads the expensive SMILES randomization\n", " to a one-time preprocessing step.\n", " \"\"\"\n", " def __init__(self, tokenizer, file_path: str, max_length: int = 512):\n", " self.tokenizer = tokenizer\n", " self.max_length = max_length\n", " \n", " # Load the entire dataset from the Parquet file into memory.\n", " # This is fast and efficient for subsequent access.\n", " print(f\"Loading pre-computed data from {file_path}...\")\n", " self.data = pd.read_parquet(file_path)\n", " print(\"Data loaded successfully.\")\n", "\n", " def __len__(self):\n", " \"\"\"Returns the total number of pairs in the dataset.\"\"\"\n", " return len(self.data)\n", "\n", " def __getitem__(self, idx):\n", " \"\"\"\n", " Retrieves a pre-augmented pair, tokenizes it, and returns it\n", " in the format expected by the DataCollator.\n", " \"\"\"\n", " # Retrieve the pre-augmented pair from the DataFrame\n", " row = self.data.iloc[idx]\n", " smiles_1 = row['smiles_1']\n", " smiles_2 = row['smiles_2']\n", " \n", " # Tokenize the pair. This operation is fast and remains in the data loader.\n", " tokens_1 = self.tokenizer(smiles_1, max_length=self.max_length, truncation=True, padding='max_length')\n", " tokens_2 = self.tokenizer(smiles_2, max_length=self.max_length, truncation=True, padding='max_length')\n", " \n", " return {\n", " 'input_ids_1': torch.tensor(tokens_1['input_ids']),\n", " 'attention_mask_1': torch.tensor(tokens_1['attention_mask']),\n", " 'input_ids_2': torch.tensor(tokens_2['input_ids']),\n", " 'attention_mask_2': torch.tensor(tokens_2['attention_mask']),\n", " }\n", "\n", "def global_ap(x):\n", " return torch.mean(x.view(x.size(0), x.size(1), -1), dim=1)\n", "\n", "class SimSonEncoder(nn.Module):\n", " def __init__(self, config: BertConfig, max_len: int, dropout: float = 0.1):\n", " super(SimSonEncoder, self).__init__()\n", " self.config = config\n", " self.max_len = max_len\n", " self.bert = BertModel(config, add_pooling_layer=False)\n", " self.linear = nn.Linear(config.hidden_size, max_len)\n", " self.dropout = nn.Dropout(dropout)\n", " \n", " def forward(self, input_ids, attention_mask=None):\n", " if attention_mask is None:\n", " attention_mask = input_ids.ne(self.config.pad_token_id)\n", " outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)\n", " hidden_states = self.dropout(outputs.last_hidden_state)\n", " pooled = global_ap(hidden_states)\n", " return self.linear(pooled)\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "476226dd-54f3-4d3e-adb4-cc30e922fd96", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OptimizedModule(\n", " (_orig_mod): SimSonEncoder(\n", " (bert): BertModel(\n", " (embeddings): BertEmbeddings(\n", " (word_embeddings): Embedding(591, 768, padding_idx=0)\n", " (position_embeddings): Embedding(512, 768)\n", " (token_type_embeddings): Embedding(2, 768)\n", " (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " (encoder): BertEncoder(\n", " (layer): ModuleList(\n", " (0-3): 4 x BertLayer(\n", " (attention): BertAttention(\n", " (self): BertSdpaSelfAttention(\n", " (query): Linear(in_features=768, out_features=768, bias=True)\n", " (key): Linear(in_features=768, out_features=768, bias=True)\n", " (value): Linear(in_features=768, out_features=768, bias=True)\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " (output): BertSelfOutput(\n", " (dense): Linear(in_features=768, out_features=768, bias=True)\n", " (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " )\n", " (intermediate): BertIntermediate(\n", " (dense): Linear(in_features=768, out_features=2048, bias=True)\n", " (intermediate_act_fn): GELUActivation()\n", " )\n", " (output): BertOutput(\n", " (dense): Linear(in_features=2048, out_features=768, bias=True)\n", " (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " )\n", " )\n", " )\n", " )\n", " (linear): Linear(in_features=768, out_features=512, bias=True)\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", ")" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenizer = AutoTokenizer.from_pretrained('DeepChem/ChemBERTa-77M-MTR')\n", "model_config = BertConfig(\n", " vocab_size=tokenizer.vocab_size,\n", " hidden_size=768,\n", " num_hidden_layers=4,\n", " num_attention_heads=12,\n", " intermediate_size=2048,\n", " max_position_embeddings=512\n", ")\n", "\n", "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", "\n", "model = SimSonEncoder(config=model_config, max_len=512).to(device)\n", "model = torch.compile(model)\n", "model.load_state_dict(torch.load('/home/jovyan/simson_training_bolgov/simson_checkpoints_polymer_1M/simson_model_single_gpu.bin'))\n", "model.eval()" ] }, { "cell_type": "code", "execution_count": 4, "id": "df28c332-c20b-4804-b4ca-97de9d652445", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test dataset shape: (5000, 2)\n", "Columns: ['smiles_1', 'smiles_2']\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
smiles_1smiles_2
0c1c(ccc(c1)OC(=O)CCCS(CCCc1ccc(C(O*)=O)cc1)(=O...c1cc(ccc1OC(CCCS(CCCc1ccc(C(=O)O*)cc1)(=O)=O)=...
1C(CC(=O)NCCC[Si](O*)(C)C)CCCCC(OCCCCCOC(Cc1cc(...CN(*)Cc1cccc(c1)CC(OCCCCCOC(CCCCCCC(=O)NCCC[Si...
2C(SCCNC(OCC*)=O)CSCCCOCCNC(=O)O*O=C(OCC*)NCCSCCSCCCOCCNC(O*)=O
3*CCCCOC(=O)CSCCCC[PH](C)(=O)O**CCCCOC(=O)CSCCCC[PH](C)(=O)O*
4C(O*)COCCOCCN(C(=O)OCCC*)C(=O)OCC(CC*)OC(=O)N(C(=O)OC)CCOCCOCCO*
\n", "
" ], "text/plain": [ " smiles_1 \\\n", "0 c1c(ccc(c1)OC(=O)CCCS(CCCc1ccc(C(O*)=O)cc1)(=O... \n", "1 C(CC(=O)NCCC[Si](O*)(C)C)CCCCC(OCCCCCOC(Cc1cc(... \n", "2 C(SCCNC(OCC*)=O)CSCCCOCCNC(=O)O* \n", "3 *CCCCOC(=O)CSCCCC[PH](C)(=O)O* \n", "4 C(O*)COCCOCCN(C(=O)OCCC*)C(=O)OC \n", "\n", " smiles_2 \n", "0 c1cc(ccc1OC(CCCS(CCCc1ccc(C(=O)O*)cc1)(=O)=O)=... \n", "1 CN(*)Cc1cccc(c1)CC(OCCCCCOC(CCCCCCC(=O)NCCC[Si... \n", "2 O=C(OCC*)NCCSCCSCCCOCCNC(O*)=O \n", "3 *CCCCOC(=O)CSCCCC[PH](C)(=O)O* \n", "4 C(CC*)OC(=O)N(C(=O)OC)CCOCCOCCO* " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test_data = pd.read_parquet('/home/jovyan/simson_training_bolgov/data/polymer_splits/test.parquet')\n", "print(f\"Test dataset shape: {test_data.shape}\")\n", "print(f\"Columns: {test_data.columns.tolist()}\")\n", "test_data.head()" ] }, { "cell_type": "code", "execution_count": 5, "id": "a7f2e2bc-12f5-443b-9d80-899542e07370", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Generating embeddings for original SMILES...\n", "Processed 2560 / 5000 SMILES\n", "Processed 5000 / 5000 SMILES\n", "Generating embeddings for augmented SMILES...\n", "Processed 2560 / 5000 SMILES\n", "Processed 5000 / 5000 SMILES\n", "Original embeddings shape: (5000, 512)\n", "Augmented embeddings shape: (5000, 512)\n" ] } ], "source": [ "def generate_embeddings(model, tokenizer, smiles_list, batch_size=256, max_length=512):\n", " \"\"\"Generate embeddings for a list of SMILES strings\"\"\"\n", " model.eval()\n", " embeddings = []\n", " \n", " with torch.no_grad():\n", " for i in range(0, len(smiles_list), batch_size):\n", " batch_smiles = smiles_list[i:i+batch_size]\n", " \n", " # Tokenize batch\n", " tokens = tokenizer(batch_smiles, \n", " max_length=max_length, \n", " truncation=True, \n", " padding='max_length', \n", " return_tensors='pt')\n", " \n", " # Move to device\n", " input_ids = tokens['input_ids'].to(device)\n", " attention_mask = tokens['attention_mask'].to(device)\n", " \n", " # Generate embeddings\n", " batch_embeddings = model(input_ids, attention_mask)\n", " embeddings.append(batch_embeddings.cpu().numpy())\n", " \n", " if (i // batch_size + 1) % 10 == 0:\n", " print(f\"Processed {i + len(batch_smiles)} / {len(smiles_list)} SMILES\")\n", " \n", " return np.vstack(embeddings)\n", "\n", "# Generate embeddings for original and augmented SMILES\n", "print(\"Generating embeddings for original SMILES...\")\n", "original_embeddings = generate_embeddings(model, tokenizer, test_data['smiles_1'].tolist())\n", "\n", "print(\"Generating embeddings for augmented SMILES...\")\n", "augmented_embeddings = generate_embeddings(model, tokenizer, test_data['smiles_2'].tolist())\n", "\n", "print(f\"Original embeddings shape: {original_embeddings.shape}\")\n", "print(f\"Augmented embeddings shape: {augmented_embeddings.shape}\")\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "c770d7f4-fa37-4519-bda2-9b084d2a4b32", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Average cosine similarity between original and augmented SMILES: 0.9874\n", "Standard deviation: 0.0197\n", "Min similarity: 0.7691\n", "Max similarity: 1.0000\n" ] }, { "data": { "image/png": "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azVq1CidPXtW/fv3d2i/detW/fbbb+rUqZPy5s2r7777Tn369NGff/6Z4s4+SUxMjLp06aLw8HB17txZJUqU0LJly9SvXz9dunRJXbt2VdmyZTVq1CgNHz5cRYoUsQ9L8Pb2TnGda9asUUJCQqrPlzl06JA6d+6svHnz6sUXX5Srq6tmz56tLl266Pvvv1eVKlUk3fjv2+TJk9W+fXsFBQXpypUr2rNnj/bu3at69erd8TVS8/5ERkbqqaeeksViUefOneXt7a01a9bo/fff15UrV+44nKxYsWKSbpzrU61atXQdbTp27JjefPNNdezYUa1bt9Y333yjnj17asiQIRo3bpyefvppSTe+vPft21fLli2Ti0vq/0d2/Phx/f7773rsscdUokQJRUZGavbs2XrmmWf066+/qnDhwg7tP//8c7m5ualbt26Ki4tL8Shsz549dfnyZZ05c8Z+XkLevHlvW8OhQ4f09NNPq3DhwnrppZeUJ08eLV26VK+88oomTJigJk2aSMrYZy3duMDL+fPnJd04erN48WIdPHgw2YVevvjiC3322Wdq1qyZnnzySZ0/f17ff/+9OnfurF9++UUFChS47TZaLBZVq1ZNmzdvtq/vwIEDunz5slxcXLRt2zY1aNBA0o3+V6FCBft7k9r34fr163rmmWd09uxZdezYUUWLFtX27ds1duxYRURE6P3333fYnsWLF+vq1avq0KGDLBaLpk6dqt69e+v333+/41H0P/74Q7ly5VLz5s1TnF+yZElVr15dGzduVExMjMO+b8iQIfL29tYrr7yia9eu3fY1xowZo6lTp6phw4aqX7++9u/fr27duik2Nva2y9zs4sWLevHFF9WkSRM1a9ZMy5cv1+jRo+Xv728PeleuXNHPP/+sli1bqn379rp69armzJmjF198UT///HOaz51N6/pS8/7/9ddf6t27t8qVK6c333xTFy5c0HvvvZem4dU7d+7UsWPHNGzYMLm7u6tJkyZatGhRsqMradGvXz8tXbpUjz/+uKpUqaLNmzffcZjy66+/rrJly+rNN9/U6tWr9cUXX6hgwYKaNWuW6tSpo7feekuLFi3SyJEjFRgYqJo1a0q6Ebxffvllbd26VU899ZTKli2rgwcPasaMGTp69Kg+//xzh9e52767SZMmOnr0qBYvXqz33nvPvj9P+vuUmt9xSfr55581cOBA+z/8jh8/rpdfflmenp4qWrToHd+79Oz/ixcvrqpVq+rXX3+19981a9bo8uXLat68ub777ru7riMtEhIS7PvEm+XJk8f++1ysWDGtX79eZ86cyfTh/kiBAZhg7ty5hr+/v7Fr167btqlevbrxxBNP2J+PHz/e8Pf3tz+fNm2a4e/vb0RFRd12Hbt27TL8/f2NuXPnJpv3zDPPGP7+/saPP/6Y4rxnnnnG/nzDhg2Gv7+/Ub9+fePy5cv26UuWLDH8/f2NGTNm2Kc1bNjQePfdd++6zjvV9u677xoNGza0P1+xYoXh7+9vfP755w7tevfubQQEBBjHjh2zT/P39zcqVarkMG3fvn2Gv7+/8d133yV7rZtNnz7d8Pf3NxYsWGCfFhcXZ3To0MGoWrWqw7Y3bNjQ6N69+x3XZxiGMWzYMMPf39/4559/7trWMAyjV69eRqVKlYzw8HD7tLNnzxrBwcFG586d7dNat25919e/tc8YRurfn/79+xv16tUzzp8/77D866+/blSvXt24fv36bV83MTHR3r/q1q1rvPHGG8b3339vnDx5MlnbpN+F48eP26c1bNjQ8Pf3N7Zt22aftnbtWsPf398ICgpyWM+sWbMMf39/Y8OGDXfc7lv7ZWxsrGGz2RzaHD9+3KhcubIxceJE+7Skvv/II48k2+akeTe/dvfu3R367s3rvrW/d+3a1WjZsqURGxvr8N516NDBaNq0qX1aaj7rlCTVd+tP+fLljS+++MKh7YkTJ4wKFSokm37gwAGjYsWKDtNvt41Tp041KlSoYP89+fbbb42GDRsaTz75pPHJJ58YhmEYNpvNqFGjhjFs2LA0vw+TJk0yqlatavz3338Orzt69GijQoUKxqlTpwzD+N97XatWLSM6Otre7vfffzf8/f2NP/74447vW40aNYzWrVvfsc2HH35o+Pv7G/v37zcM43/9+OmnnzYSEhIc2t7axyMiIoyKFSsavXr1cmg3YcIEw9/f36GfptTHkn635s+fb58WGxtr1KtXz+jdu7d9WkJCgsN7ahiGcfHiRaNu3brGe++95zDd39/fGD9+/B23ObXrS8v7//jjjxv16tUzLl26ZJ/2119/Gf7+/in2sZQMHTrUCAsLMxITEx2Wv3Wfe+vflSS37i/27Nlj+Pv7Gx9//LFDu379+iV7n5KW/eCDD+zTEhISjIcfftgICAgwJk+ebJ9+8eJFIygoyOHz/eWXX4zy5csbmzdvdnitH3/80fD39ze2bt1qn5bafffUqVOT7VMNI/W/43FxcUZISIjx+OOPO3zes2fPNvz9/R3+jqckPfv/Xbt2Gd9//70RHBxs38/26dPH6NKli2EYKf+99ff3N4YMGWJ/ntTvpk6desf6kv6+pPRz8+f1888/29/zLl26GJ9++qmxefPmZH83kDkYUginyZMnj8OQm1sl/Sdq5cqVDsNp0sLd3V1t27ZNdfsnnnjC4eqJjz32mPz8/LR69ep0vX5qrVmzRlarNdkwxxdeeEGGYSQbDle3bl2HoUDly5dXvnz57EMd7vQ6fn5+atmypX2am5ubunTpomvXrjn89z61rly5IunORzqS2Gw2/f3332rcuLFKlixpn16oUCG1bNlSW7duta+vQIECOnTokI4ePZrmmu72/hiGod9++80+VOz8+fP2n9DQUF2+fFl79+697fotFou+/vpr9e3bVwUKFNDixYs1dOhQNWzYUH379k1xDP+typUrp+DgYPvzpCN7derUsf8H9ebpd/tsb+Xu7m4/Imaz2XThwgXlyZNHZcqUSTZEUbrR99NyFPduoqOjtWHDBjVr1kxXrlyxv78XLlxQaGiojh49qrNnz0rK2GctSa+88oqmTZumadOmady4cWrRooXGjRunGTNm2NusWLFCiYmJatasmcPn7evrqwceeCBVlyWvUaOGbDabtm/fLunGFb6qV6+uGjVq2IcjHTx4UJcuXbKfHJ+W92HZsmWqXr26ChQo4FBj3bp1ZbPZkv1+Nm/eXJ6eng71SXfvK1evXr3r72vS/KTfxyRPPfXUXc/XWr9+vRISEpJd2OGZZ56543I3y5Mnj8M5KO7u7goMDHTYNqvVah8OlZiYqOjoaCUkJKhy5cop9vG7Sev67vb+nzt3Tvv27VObNm2UP39+e7t69eql+vzYhIQELVmyRM2aNZPFYpF0Yx/h4+PjMCQ/LdauXStJafp8kobISzfep8qVK8swDIfpBQoUUJkyZRw+o2XLlqls2bJ68MEHHfp0nTp1JCnZ7116/7ZJqf8d37Nnj6KiotSxY0eH4XS3fk63k979f7NmzRQbG6s///xTV65c0apVq0wbTlilShX7PvHmnxYtWtjbPPnkk5o6dapq166tbdu2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Hn74YUVERGjJkiX2aQkJCfruu++UJ08e+5Wl0qJo0aJq3769/vrrrxSvtJSYmKhvvvlGZ86ckdVqVb169bRy5UqHy/hGRkZq8eLFql69uj1wXrhwwWE9efPmValSpZJdSjg9rFarHn30US1fvlwHDx5MNv9uwwmPHj2a4vDLS5cuafv27fL09LztVR3vFavVmuy/wkuXLrWfL5ReHh4eunz58l3b+fj4qFatWpo9e7bOnTuXbP7N77EZn/WqVask/e9IZdOmTWW1WjVx4sRk74thGA413Gkba9Soobi4OM2YMUPVq1e3f/mrXr26FixYoHPnztmHE0ppex+aNWum7du328+xudmlS5eUkJCQyq2/sw4dOsjHx0effPJJsiM3sbGxeu+992QYhl555ZV0rT8kJESurq768ccfHabfun/LqKSjGDd/njt37kx2iwlnra9QoUKqUKGC5s+f79Cf/v77bx0+fPiuy69YsULXrl1T586d9dhjjyX7adiwoX777Tf770mpUqV0+fJlh1s/nDt3Ltll6JP+0fnDDz84TP/+++/TtZ130qxZM509e1Y//fRTsnkxMTF3vNLl7ST9bb31dzS1v+OVK1eWt7e3Zs2a5bCPmT9/fqqHLqZ3/583b14NHjxYvXv3TvES/vfS+vXrU5yedM763f4xhbThCBdMtWbNGh05ckQ2m02RkZHauHGj/v77bxUrVkxffPHFHYenTJo0SVu2bFFYWJiKFy+uqKgo/fDDDypSpIj9C02pUqVUoEABzZo1S3nz5lWePHkUFBSU6nHYt/L09FSnTp3Utm1b+2XhH3jgAYdL17dv317Lly/Xiy++qGbNmik8PFyLFi1KNjwyLbU1atRItWvX1rhx4+z3//n777+1cuVKde3a9Y5DL9OiQ4cOmj17tvr166e9e/eqePHiWr58ubZt26b+/fsnO4cstfr166fjx4/ro48+0m+//aaGDRuqQIECOn36tJYtW6YjR47YT9bt27ev1q1bp06dOqlTp06yWq2aPXu24uLi9Pbbb9vX2aJFC9WqVUuVKlVSwYIFtXv3bi1fvjxNJ97fyZtvvqmNGzfqqaeeUvv27VWuXDldvHhRe/fu1fr167Vp06bbLrt//3699dZbql+/vmrUqCFPT0+dPXtWv/zyi86dO6f+/fvfs+Glt9OgQQNNmjRJ7733noKDg3Xw4EEtWrQo3b8bSSpVqqQlS5Zo+PDhCgwMVJ48eW77xWHQoEHq1KmTWrVqpaeeekolS5ZUZGSkduzYoTNnztiHS2X0s96yZYv9cuMXL17UH3/8oU2bNqlFixb28xNLlSqlvn37asyYMTp58qQaN26svHnz6sSJE/r999/11FNPqVu3bnfdxqpVq8rV1VX//fefOnToYK+hZs2a9oCRdPGEtL4P3bp10x9//KGePXuqTZs2qlSpkq5fv66DBw9q+fLlWrlyZaYEeS8vL40fP17du3dXmzZt1L59e5UtW1aRkZGaP3++jh07pvfff/+ONz2+E19fXz377LP2Wx3Ur19fBw4c0Jo1a+Tl5ZVpRzoaNGig3377Ta+88ooaNGigEydOaNasWSpXrly6vshn9vok6Y033lCPHj3UqVMntWvXTtHR0fr+++/10EMP3XWdixYtUsGCBR0urnOzRo0a6aefftKqVavUtGlTNW/eXKNHj9arr76qLl26KCYmRj/++KPKlCnjcBGgpPs8zpgxQ9HR0fbLwiddtCYzR448/vjjWrp0qQYNGqSNGzeqWrVqstlsOnLkiJYtW6apU6cqMDAwTeusVKmSJGncuHFq3ry53Nzc1LBhw1T/jru5ualv374aOHCgunbtqubNm+vEiROaN29eqvaPGd3/Z3SY3vr161O8vULjxo3l7+8v6cY9JpNGEt0sb968aty4sSSpV69eKlGihBo2bKiSJUvq+vXrWrdunf78808FBgY6HKlHxhG4YKqkoRhubm4qWLCg/P391b9/f7Vt2/auX+4bNWqkkydPau7cubpw4YK8vLxUq1Yt9e7d236BATc3N40YMUJjx47V4MGDlZCQoOHDh6f7S2XPnj114MABffXVV7p69apCQkI0aNAg+3/UpBsnmfbr10/Tpk3TsGHDVLlyZX355ZcaOXKkw7rSUpuLi4u++OILjR8/XkuWLNG8efNUvHhxvfPOO3rhhRfStS0pyZ07t7777juNHj1a8+fP15UrV1SmTBkNHz48TVdzvJWHh4emTJmiefPm6ZdfftHnn3+umJgYFSpUSLVr19bo0aPt93166KGHNHPmTI0ZM0aTJ0+WYRgKCgrSJ598Yr8in3Tj5qd//PGH/v77b8XFxalYsWLq27ev/UtxRvn6+urnn3/WpEmTtGLFCv34448qWLCgypUr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D0OSPXv26Nlnn7U/Hz58uCSpTZs2GjFihCIiInT69Gn7/JIlS2ry5MkaPny4vv32WxUpUkQfffSR6tevb2+TVfdhFuN241QAAAAAABnCOVwAAAAAYBICFwAAAACYhMAFAAAAACYhcAEAAACASQhcAAAAAGASAhcAAAAAmITABQAAAAAmIXABAAAAgEkIXACADFm5cqVeeOEF1apVS5UrV1ajRo00cOBA/ffff5n6Ov369VPLli0zdZ13s2PHDr344ouqV6+egoKC1KhRI/Xp00c7d+40pa4JEyYoODjY/nzjxo0KCAjQ7t27M2X9Ka1vwoQJ2rZtW6asHwCQnKuzCwAAZF+jR4/WlClT9Oijj+rDDz+Ut7e3wsPDNXfuXL3++uv65ZdfMu21evXqpWvXrmXa+u5m69atevbZZ1W/fn0NGTJEefPm1bFjx/T7779r165dqlKlSqbX1b59e4WFhWXKulJSqVIlzZ49W2XLlrVPmzhxovLkyaNq1aqZ9roAcD8jcAEA0mX16tWaMmWKevXqpddee80+vWbNmmrXrp3+/PPPTH29UqVKZer67ubHH39U8eLFNWnSJFmtVklSSEiIOnbsqMTERFPqKlKkiIoUKZJp60tiGIbi4+OVL18+Va1aNdPXDwC4PYYUAgDS5ZtvvpGvr6969eqV4vyGDRvaH8fGxmr48OEKDQ1VYGCgHn/8ca1YscKh/aFDh/TSSy+pdu3aqlKlih599FFNmTLFPv/WoXvz5s1TQECA/vnnH7344ouqWrWqmjZtmuJRtVWrVql9+/YKCgpSnTp1NGjQoLselbp06ZK8vb3tYetmLi7/+/N5u7p2796tF154wb4t69atU2JiosaNG6e6deuqbt26GjNmjEN4u3VIYUq++eYbtWvXTtWrV1dISIh69OiRbPhmUk2rV69W69atFRgYqD/++CPZkMKAgABJ0qhRoxQQEKCAgABt3LhRvXv3VseOHZO99g8//KDAwEBFR0ffsUYAwP8QuAAAaZaQkKBt27apTp06cnNzu2v7t956S7Nnz9aLL76oSZMmqVy5curdu7dWrlxpb9OzZ09dunRJH3/8sSZPnqxu3brp+vXrqVp3aGioJk2apAoVKqhfv376999/7fOXLVuml19+Wf7+/po4caLefvttrVixQu+///4d11upUiVt375dn376qcP6Uuvdd99VgwYNNHHiRBUqVEivvvqqPv74Y505c0YjR45Up06d9NVXX+nXX39N03rPnDmjZ555Rp9//rk++ugjJSYmqmPHjslC0Llz5/TRRx/pueee05QpU1ShQoVk65o9e7YkqUuXLpo9e7Zmz56tSpUqqX379tq+fbuOHDni0H7u3Llq0qSJChYsmKaaAeB+xpBCAECaRUdHKy4uTsWKFbtr2/379+u3337TkCFD7EdNHn74YZ08eVKTJk3SI488ovPnz+vEiRN6//331ahRI0lSnTp1UlVL586d1blzZ0lScHCwVq9ereXLl6tXr14yDEOjRo1S8+bN9fHHH9uX8fPzU/fu3dWrVy899NBDKa63W7du2rlzp7744gt98cUXKliwoEJDQ/X000+rRo0ad63rmWeeUadOnSRJhQsXVqtWrbRnzx57yKlfv77++OMPLVu2TK1atUrVtkpS//797Y9tNpvq1aunkJAQLV++XB06dLDPu3jxoqZMmWI/10y6EdZuljS8sGjRog5DDUNDQ1WsWDHNnTtXb7/9tiTp4MGD2rNnj954441U1woA4AgXACADLBbLXdts3bpVkvTYY485TG/WrJn++ecfXbt2TV5eXipevLjGjh2r+fPnJwsGdxIaGmp/nCdPHhUrVsy+/H///aeTJ0+qWbNmSkhIsP/UqlVLLi4u2rNnz23Xmy9fPn3zzTf6+eef9corr6h8+fJavny5nnnmGf388893ratevXr2x6VLl5aUPESWKVNGp0+fTvW2SjeunPj888+rdu3aqlixoqpUqaJr167p6NGjDu0KFizoELbSwsXFRe3atdOCBQuUkJAg6cbRreLFiyskJCRd6wSA+xWBCwCQZgULFlSuXLl06tSpu7a9ePGi3Nzckg1D8/X1lWEYunz5siwWi77++ms9+OCDGjp0qMLCwtS2bVtt3rz5ruvPnz+/w3M3NzfFxcVJki5cuCBJeuWVV1SpUiX7T5UqVWSz2VIVdoKCgtSnTx/NmDFDS5cuVZEiRTR69Og01eXu7i5JKlCgwG1rTY1Tp07phRdekM1m05AhQ/Tjjz9qzpw58vHxUWxsrENbX1/fVK83JU8++aTOnz+v1atXKz4+XgsXLlSbNm0czl8DANwdQwoBAGnm6uqqatWqacOGDUpISJCr6+3/nHh6eio+Pl4XL16Up6enfXpkZKQsFos9mJQpU0bjx49XfHy8tm/frrFjx6pnz55as2aN8ubNm646k0LewIEDFRQUlGx+oUKF0rS+kiVL6rHHHtO0adMUGRmZ4VCTVmvXrtW1a9c0ceJEe3hLSEjQxYsXk7VNzdHHOylSpIjq16+vuXPnymaz6cKFC2rbtm2G1gkA9yP+TQUASJfnn39eERER+vLLL1Ocv3r1aklS9erVJd24eMXNli1bpooVKypPnjwO093c3FSrVi11795dV65c0blz59Jd44MPPqgiRYro+PHjCgwMTPZTuHDh2y4bGRmZ4vSjR4/K3d092dGqeyEmJkYWi8Uh4C5dutQ+7C893Nzckh0dS9K+fXutXr1a33zzjUJCQlS8ePF0vw4A3K84wgUASJewsDC9+OKLmjBhgg4fPqwWLVrIy8tLJ06c0Ny5c3X58mWFhYWpfPnyatq0qUaMGKGYmBiVKVNGCxcu1Pbt2/X5559LunFhjZEjR6p58+YqWbKkrly5osmTJ6t48eIZus+VxWJRv3799NZbb+natWtq0KCBPDw8dOrUKa1evVqvv/66ypQpk+KyAwYMkM1mU9OmTVW6dGlduXJFy5cv159//qmuXbvahwneS0nngL333nvq2LGjDh06pGnTpmUo/D344INauXKlatSoIQ8PD5UpU0b58uWTJDVo0EBeXl72I44AgLQjcAEA0u3tt99WcHCwZs6cqf79++v69esqVKiQQkND1a1bN3u7Tz75RGPHjtWUKVMUHR2tBx98UOPHj7dfkdDPz0++vr6aPHmyzp49q/z586tGjRr65JNPUrwPVlo0a9ZMBQoU0JdffqlFixZJkooXL6769evfcUhg586d9csvv2jy5MmKiIhQ7ty5VapUKX388cdq06ZNhmpKr4CAAA0fPlwTJ05Ujx49VKFCBX322Wfq27dvutc5cOBADRs2TC+99JJiYmL07bffqnbt2pJuDB1t1KiRli1bpiZNmmTSVgDA/cViGIbh7CIAAEDWk5iYqMaNG6thw4b64IMPnF0OAGRLHOECAAAO4uLitH//fi1fvlxnzpyx3+cMAJB2BC4AAODg3Llzat++vby9vfXBBx/owQcfdHZJAJBtMaQQAAAAAEzCZeEBAAAAwCQELgAAAAAwCYELAAAAAExC4AIAAAAAkxC4AAAAAMAkBC4AAAAAMAmBCwAAAABMQuACAAAAAJP8H/xUKjM38qPDAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def calculate_pairwise_similarities(embeddings1, embeddings2):\n", " \"\"\"Calculate cosine similarities between corresponding pairs\"\"\"\n", " similarities = []\n", " for i in range(len(embeddings1)):\n", " sim = cosine_similarity([embeddings1[i]], [embeddings2[i]])[0][0]\n", " similarities.append(sim)\n", " return np.array(similarities)\n", "\n", "# Calculate cosine similarities\n", "pairwise_similarities = calculate_pairwise_similarities(original_embeddings, augmented_embeddings)\n", "\n", "print(f\"Average cosine similarity between original and augmented SMILES: {np.mean(pairwise_similarities):.4f}\")\n", "print(f\"Standard deviation: {np.std(pairwise_similarities):.4f}\")\n", "print(f\"Min similarity: {np.min(pairwise_similarities):.4f}\")\n", "print(f\"Max similarity: {np.max(pairwise_similarities):.4f}\")\n", "\n", "# Plot similarity distribution\n", "plt.figure(figsize=(10, 6))\n", "plt.hist(pairwise_similarities, bins=50, alpha=0.7, edgecolor='black')\n", "plt.axvline(np.mean(pairwise_similarities), color='red', linestyle='--', \n", " label=f'Mean: {np.mean(pairwise_similarities):.4f}')\n", "plt.xlabel('Cosine Similarity')\n", "plt.ylabel('Frequency')\n", "plt.title('Distribution of Cosine Similarities Between Original and Augmented SMILES')\n", "plt.legend()\n", "plt.grid(True, alpha=0.3)\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "d7fa6ed4-b546-4544-bb00-4d90a99678da", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== Embedding Space Analysis ===\n", "Embedding dimensionality: 512\n", "Average L2 norm (original): 11.9105\n", "Average L2 norm (augmented): 11.9072\n", "Average intra-class similarity (original): 0.0047\n", "Average intra-class similarity (augmented): 0.0048\n", "Average inter-class similarity: 0.0049\n", "\n", "=== Nearest Neighbor Analysis (k=5) ===\n", "Augmented SMILES in top-5 neighbors: 5000/5000 (100.0%)\n", "Augmented SMILES as top-1 neighbor: 4872/5000 (97.4%)\n" ] } ], "source": [ "# 1. Embedding Space Statistics\n", "def analyze_embedding_space(original_emb, augmented_emb):\n", " \"\"\"Analyze the embedding space properties\"\"\"\n", " print(\"=== Embedding Space Analysis ===\")\n", " \n", " # Dimensionality and norms\n", " print(f\"Embedding dimensionality: {original_emb.shape[1]}\")\n", " print(f\"Average L2 norm (original): {np.mean(np.linalg.norm(original_emb, axis=1)):.4f}\")\n", " print(f\"Average L2 norm (augmented): {np.mean(np.linalg.norm(augmented_emb, axis=1)):.4f}\")\n", " \n", " # Intra-class similarities\n", " orig_similarities = cosine_similarity(original_emb)\n", " aug_similarities = cosine_similarity(augmented_emb)\n", " \n", " # Remove diagonal (self-similarity)\n", " orig_similarities_off_diag = orig_similarities[np.triu_indices_from(orig_similarities, k=1)]\n", " aug_similarities_off_diag = aug_similarities[np.triu_indices_from(aug_similarities, k=1)]\n", " \n", " print(f\"Average intra-class similarity (original): {np.mean(orig_similarities_off_diag):.4f}\")\n", " print(f\"Average intra-class similarity (augmented): {np.mean(aug_similarities_off_diag):.4f}\")\n", " \n", " # Inter-class similarities\n", " inter_similarities = cosine_similarity(original_emb, augmented_emb)\n", " print(f\"Average inter-class similarity: {np.mean(inter_similarities):.4f}\")\n", "\n", "analyze_embedding_space(original_embeddings, augmented_embeddings)\n", "\n", "# 2. Nearest Neighbor Analysis\n", "def nearest_neighbor_analysis(original_emb, augmented_emb, k=5):\n", " \"\"\"Analyze nearest neighbors between original and augmented embeddings\"\"\"\n", " print(f\"\\n=== Nearest Neighbor Analysis (k={k}) ===\")\n", " \n", " # For each original embedding, find its k nearest neighbors in augmented set\n", " similarities = cosine_similarity(original_emb, augmented_emb)\n", " \n", " # Find cases where augmented version is among top-k neighbors\n", " correct_matches = 0\n", " top1_matches = 0\n", " \n", " for i in range(len(original_emb)):\n", " # Get similarity scores for i-th original embedding\n", " sim_scores = similarities[i]\n", " top_k_indices = np.argsort(sim_scores)[-k:][::-1]\n", " \n", " if i in top_k_indices:\n", " correct_matches += 1\n", " if np.argmax(sim_scores) == i:\n", " top1_matches += 1\n", " \n", " print(f\"Augmented SMILES in top-{k} neighbors: {correct_matches}/{len(original_emb)} ({100*correct_matches/len(original_emb):.1f}%)\")\n", " print(f\"Augmented SMILES as top-1 neighbor: {top1_matches}/{len(original_emb)} ({100*top1_matches/len(original_emb):.1f}%)\")\n", "\n", "nearest_neighbor_analysis(original_embeddings, augmented_embeddings)" ] }, { "cell_type": "markdown", "id": "f136743a-c742-469b-a9b8-9a4da8eb4c08", "metadata": {}, "source": [ "Объяснение\n", "\n", "* Embedding Space Analysis. Показывает, что различные величины (L2 norm - длина вектора, близости) практически идентичны для оригинальных, и для аугментированных молекул (показывая, что они отображаются практически одними и теми же для модели)\n", "* Nearest Neighbor Analysis (k=5). Показывает, что топ 5 ближайших векторов к любому из векторов - всегда его аугментация (кроме его самого, естественно). В 97.4 % случаях вектор, соответствующий аугментации, является ближайшим." ] }, { "cell_type": "markdown", "id": "133fb52e-bea8-4159-ab06-386998b71ed0", "metadata": {}, "source": [ "С разными SMILES - ровно обратная картина, как и должно быть (различные smiles являются очень разными)" ] }, { "cell_type": "code", "execution_count": 8, "id": "cc48f04e-b8bf-415b-89f0-b51d98f7e6b6", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1MAAAIkCAYAAAD76HFRAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAdSBJREFUeJzt3Xl4TOf///HXZLNFkAQhkVrSxE7sS9RSparUWkrporS1VhdLq5aiVNVHLS1FdVNLqbWWVltaRau1Ky0tHRFLFhEhJJPM7w+/zNdIkDlJTJbn47pcMufc95n3mfvMOfM+577PMVmtVqsAAAAAAA5xcXYAAAAAAJAbkUwBAAAAgAEkUwAAAABgAMkUAAAAABhAMgUAAAAABpBMAQAAAIABJFMAAAAAYADJFAAAAAAYQDIFAAAAAAaQTCHfCQkJ0ezZs50dxh21atVKo0aNytJl3rreX3/9tUJCQhQeHp6l79OnTx/16dMnS5eZVUaNGqVWrVrdk/e6tQ1TP+9Dhw7dk/fPye2QKioqSkOHDlXDhg0VEhKiTz75JMuWHR4erpCQEH399dd203/66Sc99thjqlGjhkJCQhQXFydJWrNmjR5++GFVq1ZN9erVy7I48oOcsk+dPXu2QkJCnPLe/fv315gxY5zy3kbkxP1Ddh2Tcrvhw4dr2LBhzg4Dd+Dm7ACQv5nNZi1cuFC//PKLLly4IHd3dwUHB6tdu3bq0aOHChYs6OwQs9Rff/2luXPn6tChQ4qKilLx4sUVFBSkVq1a5bgDW1Y5f/68VqxYodatW6tKlSpZttzZs2drzpw5ttcFCxZUiRIlVLlyZT300EPq0KGDPDw8Mv0+J06c0KZNm9S5c2cFBARkenlZKSfHlhFTpkzRzz//rMGDB8vX11fVq1e/bdmbfyS7urrK09NTAQEBqlOnjnr27KmgoKC7vt/Fixf10ksv6f7779fYsWPl4eGhQoUK6Z9//tHo0aPVrFkzDRgwIEfvdxxt89Tviclk0o8//qgyZcrYzY+Pj1eTJk10/fp19e7dW2PHjs2u0POsP/74Q7/88os2bdpkm/b1119r9OjRWrlypWrUqJGmzvPPP6/jx4/rhx9+uJehZlpCQoIWLlyoBg0aqGHDhk6L4/fff9e8efP0119/KTY2Vj4+PqpcubLat2+vDh062Mql7je6deumyZMnp1nO//73P82bN0+StGvXLnl7e0u6ceJty5Yt2rdvn61snz59dPHiRW3YsOG2cd16XLrVjh07VLJkSUlSTEyMPvjgA+3YsUMREREqUqSI/P391bBhQw0cOFBFihSRdCNR79q1q44dO6bKlStn9CPCPUQyBafZtm2bhg0bJg8PDz322GMKDg5WUlKS/vjjD7377rs6ceKEJk6cmOXve/DgQbm6umb5cu9m79696tu3r8qWLavu3burZMmSOnv2rA4cOKDPPvvMLpnavHmzTCZTlr7/vVrvRYsW2b2+cOGC5syZI39//yxNplKNHz9ehQsXVmJios6fP68dO3bo9ddf16effqr58+fb/XicOHGirFarQ8s/ceKE5syZowYNGjiUsGRHG97qTrHd2g450e7du/Xggw+qX79+GSrftGlTPfbYY7JarYqPj9exY8e0Zs0aLV26VK+++qqeeeYZW1l/f38dPHhQbm7/d5g7dOiQrly5omHDhqlJkya26b/99ptSUlL0xhtv6L777su6FcwGRrdHDw8PbdiwQf3797eb/u2332Z1iPnOokWL1Lhx4xy/7WSFhIQEzZkzR4MHD3ZaMrVp0yYNHz5cVapUUd++fVWsWDGFh4drz549WrFihV0yJUkFChTQt99+q3HjxqU5wbZhwwYVKFBA169fz9IYU49Lt/Ly8pIkxcbGqmvXroqPj1fXrl1VsWJFxcbG6q+//tLSpUv1xBNP2JKpqlWrqnr16vr44481bdq0LI0TWYNkCk5x+vRpDR8+XGXLltWnn36qUqVK2eb17t1b//33n7Zt25Yt712gQIFsWe7dzJs3T0WLFtXKlSttO9RU0dHRdq+z4orKrbJ7vRMSElSoUKFsif1O2rZtazubKEmDBw/WunXrNHLkSA0bNkwrVqywzXN3d8/WWKxWq65fv66CBQve88/hVs5+/4yIjo5O8124k/Lly+uxxx6zm/bKK6/oxRdf1NSpU1WxYkU1b95ckmQymdJs8zExMZKkokWLpokjvemZcfXq1XR/TDlL8+bN9c0336RJpjZs2KAWLVpoy5YtToosd4uOjtb27ds1fvx4p8aR07a37DRnzhwFBQVp+fLlafZztx5LJalZs2b64Ycf9NNPP6l169a26Xv37lV4eLjatm2b5dv/rcelW61cuVIRERFaunSp6tSpYzcvPj4+zbGqXbt2mj17tq5cuWJLspBzMGYKTrFw4UJdvXpVkydPtkukUt1333166qmnbK8tFovmzp2r1q1bq3r16mrVqpVmzJihxMREu3qHDh1Sv3791LBhQ9WsWVOtWrXS6NGj7crc2r8/tZ/9f//9p1GjRqlevXqqW7euRo8erYSEhDSxrV27Vl26dFHNmjXVoEEDDR8+XGfPnr3rOpvNZgUFBaX749HHx8fu9e3G2/z++++aNGmSGjVqpHr16mns2LFKTExUXFycRowYofr166t+/fqaNm1amiswGRnXsHXrVg0YMEBhYWGqXr26Wrdurblz5yo5OdmuXJ8+ffToo4/q8OHD6t27t2rVqqUZM2bY5qVeZfv111/VrVs3SdLo0aMVEhJiG8cya9YsVatWzfYD92Zvvvmm6tWrZ/hsYceOHdW9e3cdOHBAv/zyi216emOmvvnmG3Xp0kWhoaGqU6eOOnTooE8//VTSjc89ta963759bfH/+uuvkm600/PPP6+ff/7Ztk0sW7bMNi+9cW/Xrl3T2LFj1bBhQ9WpU0cjRozQpUuX7Mrcrq1uXubdYktvTER0dLRef/11NWnSRDVq1FDHjh21evVquzKpY40WLVqk5cuX275zXbt21cGDB+/0sducPn1aQ4cOVYMGDVSrVi09/vjjdidHUrdnq9WqJUuW2GI3okSJEpoxY4bc3Nz04YcfplmP1DFTffr00ciRIyXd6PITEhJi2x5SP+vGjRun+ey3b9+uXr16qXbt2goNDdWAAQN0/PhxuxhGjRql0NBQmc1m9e/fX6GhoXr11VclSSkpKfrkk0/Uvn171ahRQ02aNNHYsWPTtHnqtvT777+rW7duqlGjhh588EGtWbPG7nO7U5vfyaOPPqqjR4/qn3/+sU2LjIzU7t279eijj6ZbJyPby+2cP39eo0ePVpMmTVS9enW1b99eK1euTFPu+vXrmj17ttq2basaNWooLCxMgwcPltlslnRjH5LeOt5uTFx6MrLPPnXqlIYMGaKmTZuqRo0aeuCBBzR8+HBdvnz5jsvetm2bLBaL3ZVOIxz53mXF9narxMREvf/+++rSpYvq1q2r2rVrq1evXtq9e7ddjI0bN5Z0I6FJ3f5u/r78888/tu9+jRo11KVLF33//fdp3u/48ePq27evatasqQceeEAffPCBUlJSMvRZmc1m1ahRI90TRrceSyWpdOnSqlevXprueevXr1dwcLDuv//+DL1vVjKbzXJ1dVXt2rXTzPP09ExzIqhJkya6evWqdu7ceY8ihCO4MgWn+PHHH1WuXLk0Z2RuZ8yYMVq9erXatm2rZ555RgcPHtT8+fP1zz//aO7cuZJuHPj79eunEiVKaMCAAfLy8lJ4eLi+++67DL3HSy+9pICAAL388sv6888/9dVXX8nb21uvvfaarcyHH36o999/X+3atVO3bt0UExOjL774Qr1799aaNWvueJbd399f+/bt099//63g4OAMxXSrSZMmydfXV0OGDNGBAwe0fPlyFS1aVPv27VOZMmU0fPhw/fTTT1q0aJGCg4PVqVMnh5a/evVqFS5cWM8884wKFy6s3bt3a9asWYqPj7f9EE0VGxur/v37q3379urYsWO6B7FKlSpp6NChmjVrlnr06KG6detKkurUqaO6detq7ty52rhxo5588klbncTERG3ZskVt2rTJ1NW0jh07avny5dqxY4eaNm2abplffvlFL7/8sho3bmz7MfLvv/9q7969euqpp1S/fn316dNHn3/+uV544QVVrFjRtl6pTp48qVdeeUU9evTQ448/rgoVKtwxrrfeekteXl4aPHiwTp48qaVLlyoiIkKff/65Q90CMxLbza5du6Y+ffrIbDard+/eCggI0ObNmzVq1CjFxcXZnbyQblyxuHLlinr06CGTyaSFCxdqyJAh2rp16x2v8EVFRalnz55KSEhQnz59VKJECa1evVovvviiZs2apYceesiW8I8YMcLWdS8zypYtq/r16+vXX39VfHy8PD0905R54YUXVKFCBS1fvlxDhw5VQECAAgMD1bp1a61Zs0bfffedrWtOamK3Zs0ajRo1SmFhYXr11VeVkJCgpUuXqlevXlq9erVdNzuLxaJ+/fqpbt26GjlypG3c1dixY7V69Wp16dJFffr0UXh4uJYsWaI///xTS5cutfss//vvPw0bNkzdunVT586dtWrVKo0aNUrVqlXT/fff73Cb36x+/fry8/PThg0bbAnZxo0bVbhwYbVo0SJNeUe3l5tFRUXp8ccfl8lkUu/eveXt7a2ffvpJb7zxhuLj4/X0009LkpKTk/X8889r165dat++vfr27asrV67ol19+0d9//63AwMC7rtfdZGSfnZiYqH79+ikxMVFPPvmkfH19df78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z549WXJVav369frqq68UGhp62y4vktK0mYuLi+2seeo2kxr/3W6RnFHLly+360KzdOlSWSwWu2SqXLly+v333+3qrVixIs2VKUdie+CBBxQZGamNGzfaplksFn3++ecqXLiwXQKdGc2bN9fBgwe1b98+27SrV69qxYoV8vf3v2tXVkfFxsbq5ZdfVnJysl544YUsW26zZs3k6emp+fPnpzsGM71b+t+qXbt2Sk5O1gcffJBmnsViuWuXyfRkdnsMDAzU66+/rldeecVuzMqtjG4vrq6utuf2pF4dvtnNn1ubNm108eJFLVmyJE251P2Qv7+/XF1d04zRWrp06Z1XVBnfZ8fHx8tisdjNDw4OlouLy12PHbVr19alS5fSXL2pVq2afHx89NVXX6VZxtatW3X+/HmHuhNnRGa2t9QrYjd/TgcOHND+/fvtyt1uf+7j46MGDRpo+fLl6Z4YvLndmzdvrv3799vd8j0mJkbr16+/w9r9n127dqU7PfVYeqfEuV+/fho8eLAGDhyYoffKLgcOHLB1Tb7ZwYMHFRsbm2YdTpw4oevXr9/15DOcgytTcIrAwEBNnz5dw4cP1yOPPKLHHntMwcHBSkxM1L59+7R582bbzQ0qV66szp07a/ny5YqLi1P9+vV16NAhrV69Wq1bt7ad5V+9erWWLl2q1q1bKzAwUFeuXNGKFSvk6emZJQetwMBAvfTSS3rvvfd05swZtW7dWkWKFFF4eLi2bt2qxx9/XP369btt/UmTJikhIUEPPfSQKlasqKSkJO3du1ebNm2Sv79/pm/mkFmhoaEqVqyYRo0apT59+shkMmnt2rWZ7tYVGBgoLy8vLVu2TEWKFFHhwoVVs2ZNuzOZ7du31xdffCFXV1e1b9/eoeVv2bJFhQsXVlJSks6fP68dO3Zo7969qly58m377qcaM2aMLl26pEaNGtn68n/xxReqUqWK7SpolSpV5OrqqgULFujy5cvy8PBQo0aN0u2TnxFJSUl6+umn1a5dO508eVJffvml6tatqwcffNBWpnv37ho3bpyGDBmiJk2a6NixY9qxY4dKlChhtyxHYuvRo4eWL1+uUaNG6ciRI/L399eWLVu0d+9evf7661l2RWfAgAG2h8P26dNHxYoV05o1axQeHq7Zs2dnqlvZqVOnbNvklStXdOzYMW3evFlXr17VqFGjsvTHqaenp8aPH68RI0aoS5cueuSRR+Tt7a2IiAht375dderU0dixY++4jAYNGqhHjx6aP3++jh49qqZNm8rd3V2nTp3S5s2b9cYbb+jhhx92KK6s2B7vdFvzVJnZXl555RX9+uuvevzxx9W9e3cFBQXp0qVLOnLkiHbt2qXffvtNktSpUyetWbNGU6ZM0cGDB1W3bl0lJCRo165deuKJJ9S6dWsVLVpUDz/8sL744guZTCaVK1dO27Ztu+v4Hynj++zdu3frrbfe0sMPP6zy5cvbblmdmhjeSYsWLeTm5qadO3eqR48etukeHh4aMWKERo0apa5du+qRRx5R8eLFdfToUa1atUohISF25bNCZra3Fi1a6Ntvv9WgQYPUokULhYeHa9myZQoKCrL70V+wYEEFBQVp06ZNKl++vIoXL677779fwcHBGjdunHr16qUOHTro8ccfV7ly5RQVFaX9+/fr3Llztt4Czz33nNauXavnnntOffv2td0avWzZsvrrr7/uup4DBw5UQECAWrZsqXLlyikhIUE7d+7Ujz/+qBo1aqhly5a3rVu5cmVVrlzZwU/2/8TExKSbrAYEBNidCEw9Lt2qadOmtptPrF+/3vY8MXd3d/3zzz9atWqVChQokObE0M6dO1WoUKFMP88M2YNkCk7z4IMPat26dVq0aJG+//57LV26VB4eHraHaT7++OO2spMmTVJAQIBWr16trVu3ytfXV88//7zdGKMGDRro0KFD2rhxo6KiolS0aFHVrFlT06dPt/1wz6wBAwaofPny+uSTT2zPt/Lz81PTpk3vevl9xIgR2rx5s7Zv3267OlG2bFn16tVLL7744h2fUXUvlChRQvPmzdM777yjmTNnysvLSx07dlTjxo3vmCTejbu7u6ZOnaoZM2Zo/PjxslgsmjJlil2bPPbYY/riiy/UuHHjdB/ifCfjx4+XdGOMQokSJVSlShW9/fbbGbrxSMeOHbVixQp9+eWXiouLU8mSJdWuXTsNGTLE9qO/ZMmSmjBhgubPn6833nhDycnJ+uyzzwwnU2PHjtX69es1a9YsJSUlqX379hozZoxd95nHH39c4eHhWrlypX7++WfVrVtXixcvtj2fJ5UjsRUsWFCff/65pk+frtWrVys+Pl4VKlTQlClTsjSR9/X11bJly/Tuu+/qiy++0PXr1xUSEqJ58+al+zwj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/VWdO3dW9erV9dBDD+nrr7++B5E6hmQqD3r11Vd14sQJLV68WPPmzdPvv/+usWPHZqjup59+KpPJlM0R5g+OtsOFCxd04cIFjRw5Uhs2bNCUKVP0888/64033riHUeduGzdu1JQpUzRo0CCtXr1alStXVr9+/RQdHZ1u+b179+qVV15Rt27dtGbNGj344IMaNGiQ/v7773sced7iaDv8+uuvat++vT777DMtW7ZMZcqU0bPPPqvz58/f48jzFkfbIVV4eLjeeecd1atX7x5Fmrc52g6JiYl65plndObMGb3//vvavHmzJk6cqNKlS9/jyPMOR9tg/fr1eu+99zR48GBt3LhRkydP1saNGzVjxox7HHnecvXqVYWEhGjcuHEZKn/69Gk9//zzatiwodauXaunnnpKY8aM0c8//5zNkTrIijzlxIkT1uDgYOvBgwdt07Zv324NCQmxnjt37o51//zzT2uzZs2sFy5csAYHB1u/++677A43z8pMO9xs48aN1mrVqlmTkpKyI8w8p1u3btYJEybYXicnJ1vDwsKs8+fPT7f8sGHDrAMGDLCb1r17d+ubb76ZrXHmdY62w60sFos1NDTUunr16myKMH8w0g4Wi8Xao0cP64oVK6wjR460vvjii/ci1DzN0Xb48ssvrQ8++KA1MTHxXoWY5znaBhMmTLD27dvXbtqUKVOsPXv2zNY485OM/M6cNm2atX379nbTXnrpJeuzzz6bnaE5jCtTecy+ffvk5eWlGjVq2KY1adJELi4ud7yknZCQoFdeeUVjx45VyZIl70WoeZrRdrhVfHy8PD095eaWZ56vnW0SExN15MgRNWnSxDbNxcVFTZo00b59+9Kts3//fjVu3NhuWlhYmPbv35+doeZpRtrhVgkJCbJYLCpWrFh2hZnnGW2HuXPnysfHR927d78XYeZ5Rtrhhx9+UO3atfXWW2+pSZMmevTRRzVv3jwlJyffq7DzFCNtEBoaqiNHjtiO16dPn9b27dvVvHnzexIzbsgtx2h+oeUxUVFR8vb2tpvm5uamYsWKKTIy8rb1pkyZotDQULVu3Tq7Q8wXjLbDzWJiYvTBBx+oR48e2RFinnPx4kUlJyfLx8fHbrqPj4/+/fffdOtERUXJ19c3TfmoqKhsizOvM9IOt5o+fbpKlSpl9+MHjjHSDr///rtWrlypNWvW3IMI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xscffyxfX18NHDgw3fktW7a0/X39+nVNmTJFYWFhqlGjhh577DF99913duWPHz+u/v37q2HDhqpVq5batm2rBQsW2Obf2p3u66+/VkhIiP78808999xzql27ttq0aZPu1bBt27ape/fuqlmzpho1aqRx48bd9WpSXFycvL29bYnUzVxc/u/QeLu4Dh06pGeffda2Ljt37lRKSor+97//qUmTJmrSpInee+89u8Ts1m5+6fn444/VtWtX1a1bV40bN9bzzz+fpktlakzbt29Xx44dVaNGDf3www9puvmFhIRIkqZNm6aQkBCFhITo119/1ZAhQ9SzZ8807/3ll1+qRo0aio2NvWOMAID/QzIFALBjsVi0d+9eNWrUSO7u7nct/+qrr2r58uV67rnnNHfuXAUFBWnIkCH6/vvvbWVeeOEFxcXFafLkyZo/f7769eunhISEDC07LCxMc+fOVZUqVTRq1Cj9888/tvmbN2/Wiy++qODgYM2ZM0evvfaavvvuO73xxht3XG61atW0b98+zZw50255GTVy5Ei1aNFCc+bMUalSpTR48GBNnjxZ586d0zvvvKNevXrpo48+0jfffOPQcs+dO6cnn3xSH3zwgSZNmqSUlBT17NkzTYJz4cIFTZo0SU8//bQWLFigKlWqpFnW8uXLJUl9+vTR8uXLtXz5clWrVk3du3fXvn379O+//9qVX7VqlR566CEVL17coZgBID+jmx8AwE5sbKwSExNVtmzZu5Y9duyYvv32W02YMMF2teOBBx7QmTNnNHfuXD344IOKiYlReHi43njjDbVq1UqS1KhRowzF0rt3b/Xu3VuSFBoaqu3bt2vLli0aOHCgrFarpk2bpkceeUSTJ0+21SlZsqQGDBiggQMH6v777093uf369dOBAwf04Ycf6sMPP1Tx4sUVFhamJ554QvXq1btrXE8++aR69eolSSpdurQ6dOigw4cP2xKYZs2a6YcfftDmzZvVoUOHDK2rJL3++uu2v5OTk9W0aVM1btxYW7ZsUY8ePWzzLl26pAULFtjGdkk3ErGbpXb5K1OmjF33v7CwMJUtW1arVq3Sa6+9Jkn6+++/dfjwYb388ssZjhUAwJUpAMBtmEymu5b5448/JEkPP/yw3fR27drpzz//1NWrV1WiRAn5+/trxowZWr16dZof/XcSFhZm+7tw4cIqW7asrf7Jkyd15swZtWvXThaLxfavQYMGcnFx0eHDh2+7XE9PT3388cf66quvNGjQIFWuXFlbtmzRk08+qa+++uqucTVt2tT2d/ny5SWlTRArVKigs2fPZnhdpRt3GHzmmWfUsGFDVa1aVbVq1dLVq1d16tQpu3LFixe3S6Qc4eLioq5du2rt2rWyWCySblyV8vf3V+PGjQ0tEwDyK5IpAICd4sWLq0CBAoqIiLhr2UuXLsnd3T1N1zBfX19ZrVZdvnxZJpNJixYtUsWKFfXWW2+pefPm6tKli/bs2XPX5RctWtTutbu7uxITEyVJFy9elCQNGjRI1apVs/2rVauWkpOTM5TI1KxZU0OHDtWnn36qTZs2yc/PT9OnT3coLg8PD0mSl5fXbWPNiIiICD377LNKTk7WhAkTtHTpUq1cuVI+Pj66fv26XVlfX98MLzc93bp1U0xMjLZv366kpCStW7dOnTt3thsvBgC4O7r5AQDsuLm5qU6dOtq9e7csFovc3G5/qChWrJiSkpJ06dIlFStWzDY9KipKJpPJlnRUqFBBs2bNUlJSkvbt26cZM2bohRde0E8//aQiRYoYijM1gRs7dqxq1qyZZn6pUqUcWl65cuX08MMPa/HixYqKisp0wuKon3/+WVevXtWcOXNsiZnFYtGlS5fSlM3IVcM78fPzU7NmzbRq1SolJyfr4sWL6tKlS6aWCQD5EaegAABpPPPMM4qMjNS8efPSnb99+3ZJUt26dSXduBHEzTZv3qyqVauqcOHCdtPd3d3VoEEDDRgwQPHx8bpw4YLhGCtWrCg/Pz+dPn1aNWrUSPOvdOnSt60bFRWV7vRTp07Jw8MjzVWme+HatWsymUx2yeumTZtsXfGMcHd3T3NVK1X37t21fft2ffzxx2rcuLH8/f0Nvw8A5FdcmQIApNG8eXM999xzmj17tk6cOKH27durRIkSCg8P16pVq3T58mU1b95clStXVps2bTR16lRdu3ZNFSpU0Lp167Rv3z598MEHkm7cpOKdd97RI488onLlyik+Pl7z58+Xv79/pp7jZDKZNGrUKL366qu6evWqWrRooUKFCikiIkLbt2/X8OHDVaFChXTrjhkzRsnJyWrTpo3Kly+v+Ph4bdmyRT/++KOeeuopW9e9eyl1zNXo0aPVs2dPHT9+XIsXL85UYlexYkV9//33qlevngoVKqQKFSrI09NTktSiRQuVKFHCdqUQAOA4kikAQLpee+01hYaGasmSJXr99deVkJCgUqVKKSwsTP369bOVe/fddzVjxgwtWLBAsbGxqlixombNmmW7c1/JkiXl6+ur+fPn6/z58ypatKjq1aund999N93nPDmiXbt28vLy0rx587R+/XpJkr+/v5o1a3bHbnq9e/fWmjVrNH/+fEVGRqpgwYIKDAzU5MmT1blz50zFZFRISIimTJmiOXPm6Pnnn1eVKlX0/vvv66WXXjK8zLFjx+rtt99W//79de3aNX322Wdq2LChpBvdOVu1aqXNmzfroYceyqK1AID8xWS1Wq3ODgIAANxbKSkpat26tVq2bKk333zT2eEAQK7ElSkAAPKRxMREHTt2TFu2bNG5c+dsz/ECADiOZAoAgHzkwoUL6t69u7y9vfXmm2+qYsWKzg4JAHItuvkBAAAAgAHcGh0AAAAADCCZAgAAAAADSKYAAAAAwACSKQAAAAAwgGQKAAAAAAwgmQIAAAAAA0imAAAAAMAAkikAAAAAMOD/AVD6M+wfaD2YAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "\n", "num_molecules = original_embeddings.shape[0]\n", "\n", "# Shuffle indices for unrelated molecules\n", "unrelated_indices = np.random.permutation(num_molecules)\n", "unrelated_embeddings = augmented_embeddings[unrelated_indices]\n", "\n", "# Compute pairwise cosine similarity between original and unrelated\n", "pairwise_unrelated_similarities = np.array([\n", " cosine_similarity([original_embeddings[i]], [unrelated_embeddings[i]])[0][0]\n", " for i in range(num_molecules)\n", "])\n", "\n", "\n", "plt.figure(figsize=(10,6))\n", "plt.hist(pairwise_unrelated_similarities, bins=50, alpha=0.7, color='skyblue', edgecolor='black')\n", "mean_sim = pairwise_unrelated_similarities.mean()\n", "plt.axvline(mean_sim, color='red', linestyle='--', label=f'Mean = {mean_sim:.4f}')\n", "plt.xlabel('Cosine Similarity')\n", "plt.ylabel('Frequency')\n", "plt.title('Cosine Similarity Distribution of Different Molecules (Unrelated SMILES)')\n", "plt.legend()\n", "plt.grid(True, alpha=0.3)\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "881eca62-7bf5-4b84-b0df-659942930a73", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mean cosine similarity: 0.0037\n", "Std deviation: 0.1393\n", "Range: -0.4398 to 1.0000\n" ] } ], "source": [ "print(f\"Mean cosine similarity: {pairwise_unrelated_similarities.mean():.4f}\")\n", "print(f\"Std deviation: {pairwise_unrelated_similarities.std():.4f}\")\n", "print(f\"Range: {pairwise_unrelated_similarities.min():.4f} to {pairwise_unrelated_similarities.max():.4f}\")\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "051f4149-d3eb-472b-b6d0-7060662efb6a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unrelated in top-5 neighbors: 7/5000\n", "Unrelated as top-1 neighbor: 2/5000\n" ] } ], "source": [ "from sklearn.metrics.pairwise import cosine_similarity\n", "\n", "k = 5\n", "similarities = cosine_similarity(original_embeddings, unrelated_embeddings)\n", "correct_matches = sum(i in np.argsort(similarities[i])[-k:] for i in range(num_molecules))\n", "top1_matches = sum(np.argmax(similarities[i]) == i for i in range(num_molecules))\n", "\n", "print(f\"Unrelated in top-{k} neighbors: {correct_matches}/{num_molecules}\")\n", "print(f\"Unrelated as top-1 neighbor: {top1_matches}/{num_molecules}\")\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python [conda env:.mlspace-bolgov_simson_training]", "language": "python", "name": "conda-env-.mlspace-bolgov_simson_training-py" }, "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.12.11" } }, "nbformat": 4, "nbformat_minor": 5 }