diff --git a/promoter/DNA.ipynb b/promoter/DNA.ipynb new file mode 100644 index 0000000..4e213bf --- /dev/null +++ b/promoter/DNA.ipynb @@ -0,0 +1,914 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "(1, 165, 64)\n", + "1 sequence\n", + "\n", + "165 time steps (one for each base)\n", + "\n", + "64-dimensional vector at each ste" + ], + "metadata": { + "id": "y7wYKu5b4zQw" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import tensorflow as tf\n", + "from tensorflow.keras import layers, models\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "# ----------------------------\n", + "# 1. Load & Preprocess Data\n", + "# ----------------------------\n", + "base_to_idx = {'A': 0, 'T': 1, 'C': 2, 'G': 3, 'N': 4}\n", + "idx_to_base = {v: k for k, v in base_to_idx.items()}\n", + "\n", + "# Function to pad and tokenize\n", + "def preprocess_sequence(seq, max_len=165):\n", + " seq = seq.upper()[:max_len]\n", + " seq += 'N' * (max_len - len(seq))\n", + " return [base_to_idx.get(base, 4) for base in seq]\n", + "\n", + "df1 = pd.read_csv('/content/ecoli_mpra_expr.csv')\n", + "df2 = pd.read_csv('/content/ecoli_natural50bp_expr (1).csv')\n", + "combined_df = pd.concat([df1, df2], ignore_index=True)\n", + "combined_df['tokenized'] = combined_df['seq'].apply(preprocess_sequence)\n", + "\n", + "X_seq = np.array(combined_df['tokenized'].tolist())\n", + "y_expr = combined_df['expr'].values.reshape(-1, 1)\n", + "y_seq = np.expand_dims(X_seq, -1) # needed for sparse_categorical_crossentropy\n", + "\n", + "# ----------------------------\n", + "# 2. Define Model\n", + "# ----------------------------\n", + "vocab_size = 5\n", + "max_len = 165\n", + "embedding_dim = 16\n", + "latent_dim = 64\n", + "\n", + "input_seq = layers.Input(shape=(max_len,), dtype='int32')\n", + "x = layers.Embedding(input_dim=vocab_size, output_dim=embedding_dim)(input_seq)\n", + "x = layers.Bidirectional(layers.GRU(64, return_sequences=False))(x)\n", + "latent = layers.Dense(latent_dim, activation='relu', name=\"latent_vector\")(x)\n", + "\n", + "expr_pred = layers.Dense(1, name=\"expression_output\")(latent)\n", + "\n", + "x = layers.RepeatVector(max_len)(latent)\n", + "x = layers.GRU(64, return_sequences=True)(x)\n", + "decoded = layers.TimeDistributed(layers.Dense(vocab_size, activation='softmax'), name=\"decoder_output\")(x)\n", + "\n", + "autoencoder = models.Model(inputs=input_seq, outputs=[decoded, expr_pred])\n", + "autoencoder.compile(optimizer='adam',\n", + " loss={'decoder_output': 'sparse_categorical_crossentropy', 'expression_output': 'mse'},\n", + " loss_weights={'decoder_output': 1.0, 'expression_output': 1.0},\n", + " metrics={'decoder_output': 'accuracy'})\n", + "\n", + "# ----------------------------\n", + "# 3. Train Model\n", + "# ----------------------------\n", + "autoencoder.fit(X_seq,\n", + " {'decoder_output': y_seq, 'expression_output': y_expr},\n", + " batch_size=64,\n", + " epochs=20,\n", + " validation_split=0.1)\n", + "\n", + "# ----------------------------\n", + "# 4. Create Generator Tools\n", + "# ----------------------------\n", + "latent_input = tf.keras.Input(shape=(latent_dim,))\n", + "x = layers.RepeatVector(max_len)(latent_input)\n", + "x = layers.GRU(64, return_sequences=True)(x)\n", + "decoder_output = layers.TimeDistributed(layers.Dense(vocab_size, activation='softmax'))(x)\n", + "decoder = tf.keras.Model(latent_input, decoder_output)\n", + "\n", + "expr_head = layers.Dense(1)(latent_input)\n", + "expression_model = tf.keras.Model(latent_input, expr_head)\n", + "\n", + "def sample_with_temperature(probs, temperature=1.0):\n", + " probs = np.clip(probs, 1e-8, 1.0)\n", + " logits = np.log(probs) / temperature\n", + " exp_logits = np.exp(logits - np.max(logits))\n", + " probs = exp_logits / np.sum(exp_logits)\n", + " return np.random.choice(len(probs), p=probs)\n", + "\n", + "def decode_probs_to_seq(probs, temperature=1.0):\n", + " return ''.join([idx_to_base[sample_with_temperature(p, temperature)] for p in probs])\n", + "\n", + "# ----------------------------\n", + "# 5. Generate One Sequence for User Input\n", + "# ----------------------------\n", + "def generate_sequence_for_expression(target_expr, temperature=0.8, steps=500):\n", + " z = tf.Variable(tf.random.normal((1, latent_dim)), trainable=True)\n", + " optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)\n", + "\n", + " for step in range(steps):\n", + " with tf.GradientTape() as tape:\n", + " pred = expression_model(z, training=False)\n", + " loss = tf.reduce_mean(tf.square(pred - target_expr))\n", + " grads = tape.gradient(loss, [z])\n", + " optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + " if step % 100 == 0 or step == steps - 1:\n", + " print(f\"Step {step}: Predicted = {pred.numpy()[0][0]:.4f} | Target = {target_expr:.4f}\")\n", + "\n", + " probs = decoder(z, training=False).numpy()[0]\n", + " decoded_seq = decode_probs_to_seq(probs, temperature)\n", + " final_pred = expression_model(z, training=False).numpy()[0][0]\n", + " return decoded_seq, final_pred\n", + "\n", + "# ----------------------------\n", + "# 6. Example Use\n", + "# ----------------------------\n", + "user_expr = float(input(\"Enter desired expression value (e.g., 0.8): \"))\n", + "seq, pred = generate_sequence_for_expression(target_expr=user_expr)\n", + "print(f\"\\n🧬 Generated Sequence: {seq}\\nPredicted Expression: {pred:.4f}\")" + ], + "metadata": { + "id": "_X0kkou9Vsaf" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import pickle\n", + "\n", + "# Step 1A: Define the mappings\n", + "base_to_idx = {'A': 0, 'T': 1, 'C': 2, 'G': 3, 'N': 4}\n", + "idx_to_base = {v: k for k, v in base_to_idx.items()}\n", + "\n", + "# Step 1B: Save them to a .pkl file\n", + "with open('vocab_mapping.pkl', 'wb') as f:\n", + " pickle.dump({'base_to_idx': base_to_idx, 'idx_to_base': idx_to_base}, f)\n", + "\n", + "print(\"βœ… Step 1 complete: Vocabulary mappings saved to vocab_mapping.pkl\")\n" + ], + "metadata": { + "id": "m-t3rAq_pEgI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Save the joint model (encoder-decoder + expression head)\n", + "autoencoder.save(\"autoencoder_model.h5\")\n", + "\n", + "# Save the decoder (for generating sequence from z)\n", + "decoder.save(\"decoder_model.h5\")\n", + "\n", + "# Save the expression prediction model (to estimate expression from z)\n", + "expression_model.save(\"expression_model.h5\")\n", + "\n", + "print(\"βœ… Step 2 complete: All models saved as .h5 files\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "T9C8K866jikM", + "outputId": "2d444de1-a361-44b1-cebd-1bf9991670aa" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "βœ… Step 2 complete: All models saved as .h5 files\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "import pickle\n", + "import re\n", + "\n", + "# === Step 1: Load models ===\n", + "autoencoder = tf.keras.models.load_model(\"autoencoder_model.h5\", compile=False)\n", + "decoder = tf.keras.models.load_model(\"decoder_model.h5\", compile=False)\n", + "expression_model = tf.keras.models.load_model(\"expression_model.h5\", compile=False)\n", + "\n", + "# === Step 2: Load vocabulary ===\n", + "with open(\"vocab_mapping.pkl\", \"rb\") as f:\n", + " vocab_data = pickle.load(f)\n", + "\n", + "vocab = vocab_data[\"base_to_idx\"]\n", + "idx_to_char = vocab_data[\"idx_to_base\"]\n", + "\n", + "# === Step 3: Decode one-hot to sequence ===\n", + "def decode_sequence(one_hot_seq):\n", + " indices = np.argmax(one_hot_seq, axis=-1)\n", + " chars = [idx_to_char.get(i, 'N') for i in indices]\n", + " return ''.join(chars)\n", + "\n", + "# === Step 4: Decode with temperature ===\n", + "def decode_sequence_with_temperature(logits, temperature=1.0):\n", + " probs = tf.nn.softmax(logits / temperature, axis=-1).numpy()\n", + " sampled_indices = [np.random.choice(len(p), p=p) for p in probs]\n", + " chars = [idx_to_char.get(i, 'N') for i in sampled_indices]\n", + " return ''.join(chars)\n", + "\n", + "# === Step 5: Clean DNA sequence (remove non-ACGT) ===\n", + "def clean_dna_sequence(seq):\n", + " return re.sub(r'[^ACGT]', '', seq)\n", + "\n", + "# === Step 6: Latent optimization for expression ===\n", + "latent_dim = autoencoder.get_layer(\"latent_vector\").output.shape[-1]\n", + "\n", + "def generate_sequence_for_expression(target_expr, steps=500, lr=0.05, temps=[0.4, 0.6, 0.8, 1.0]):\n", + " z = tf.Variable(tf.random.normal([1, latent_dim]), trainable=True)\n", + " optimizer = tf.keras.optimizers.Adam(learning_rate=lr)\n", + "\n", + " for step in range(steps):\n", + " with tf.GradientTape() as tape:\n", + " pred_expr = expression_model(z, training=False)\n", + " loss = tf.reduce_mean(tf.square(pred_expr - target_expr))\n", + " grads = tape.gradient(loss, [z])\n", + " optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + " if step % 100 == 0 or step == steps - 1:\n", + " print(f\"Step {step}: Predicted = {pred_expr.numpy().squeeze():.4f} | Target = {target_expr:.4f}\")\n", + "\n", + " logits = decoder(z, training=False).numpy().squeeze()\n", + "\n", + " generated_variants = []\n", + " for temp in temps:\n", + " seq = decode_sequence_with_temperature(logits, temperature=temp)\n", + " pred_expr = expression_model(z, training=False).numpy().squeeze()\n", + " print(f\"\\n🌑️ Temp {temp:.1f} | Predicted: {pred_expr:.4f} | Sequence: {seq}\")\n", + " cleaned = clean_dna_sequence(seq)\n", + " if len(cleaned) == len(seq): # Keep only valid ACGT sequences\n", + " generated_variants.append((temp, seq, pred_expr))\n", + "\n", + " return generated_variants\n", + "\n", + "# === Step 7: Run and save results ===\n", + "if __name__ == \"__main__\":\n", + " target_expression = float(input(\"Enter desired expression value (e.g., 5.0): \"))\n", + " results = generate_sequence_for_expression(target_expression)\n", + "\n", + " output_file = f\"generated_sequences_expr_{target_expression:.2f}.txt\"\n", + " with open(output_file, \"w\") as f:\n", + " for temp, seq, pred in results:\n", + " f.write(f\"> Temp: {temp:.1f}, Predicted: {pred:.4f}\\n{seq}\\n\\n\")\n", + "\n", + " print(f\"\\nβœ… All sequence variants saved to: {output_file}\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qMwv9r6Es-BN", + "outputId": "9238f302-bd96-40e3-aa86-76ed30e96f9d" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Enter desired expression value (e.g., 5.0): 5\n", + "Step 0: Predicted = -0.9703 | Target = 5.0000\n", + "Step 100: Predicted = 4.9934 | Target = 5.0000\n", + "Step 200: Predicted = 5.0000 | Target = 5.0000\n", + "Step 300: Predicted = 5.0000 | Target = 5.0000\n", + "Step 400: Predicted = 5.0000 | Target = 5.0000\n", + "Step 499: Predicted = 5.0000 | Target = 5.0000\n", + "\n", + "🌑️ Temp 0.4 | Predicted: 5.0000 | Sequence: TAAAAAAGAGTACGACNANACAANTTTANTANACNGATNAAAAGAAAAATAACNNCNTTAAAAAAGACATAGNAANACTGAACAACCGATAGACATGAGAATCAACTCNGNGAAACANACGAAAAAAAGAGANCANATNANACAAANANAAGCAAAACTAAAATA\n", + "\n", + "🌑️ Temp 0.6 | Predicted: 5.0000 | Sequence: GGAAAAAACNGNAACCANATATCNCCACTGCCCGATTAATACNAATGCNAATCCATAAATCAAAACGAGAAANCAGNTAGAAAAGGCGNATAAAAAGAAATGCAAAAAAAATAGGAANACGAGAACNNGTGGCCNTCTAGNAGCAGNGATAGTCNGCCTTAANTA\n", + "\n", + "🌑️ Temp 0.8 | Predicted: 5.0000 | Sequence: NACACTTGCCTAGNGAAAGACCGGTCGCGATTNNGTANCAAGGTAATTGANTNCAGCANCNNCAAGNCNCNTGACANTTTGATNGGNACATAGATACGATAANTAAAGTAAGGTTCTNTTAGAGNTNNGCTAGNATNTTNGATNAAGGCTNGCGNACATTAAGNT\n", + "\n", + "🌑️ Temp 1.0 | Predicted: 5.0000 | Sequence: GAGNCGGCCGAACTGNTCCACAATNAANAGTNACATGCGNCACTANATATAAAAGTNGAAAGTGCTTCCNTGAGGTCATAANACGCACTTAAGTCGCGNTNAAGAAAGATGACNCCTCACCATNAANGANAAAATTAAGNTNAGCCCAGTNAAATCNCAGTNGCC\n", + "\n", + "βœ… All sequence variants saved to: generated_sequences_expr_5.00.txt\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import pandas as pd" + ], + "metadata": { + "id": "krmQFL6VGcr9" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# import numpy as np\n", + "# import tensorflow as tf\n", + "# import pickle\n", + "# import re\n", + "# import os\n", + "\n", + "# # --- Global Definitions (Assumes models and vocab files are available) ---\n", + "# # It's generally good practice to pass models as arguments or ensure they are loaded once\n", + "# # when the application starts, rather than repeatedly. For this example, we keep\n", + "# # them loaded globally as per your original script's structure.\n", + "\n", + "# # Path to your model and vocabulary files\n", + "# # Ensure these files are in the same directory as your script or provide full paths.\n", + "# AUTOENCODER_MODEL_PATH = \"autoencoder_model.h5\"\n", + "# DECODER_MODEL_PATH = \"decoder_model.h5\"\n", + "# EXPRESSION_MODEL_PATH = \"expression_model.h5\"\n", + "# VOCAB_MAPPING_PATH = \"vocab_mapping.pkl\"\n", + "\n", + "# # --- Function to load models ---\n", + "# def load_models():\n", + "# \"\"\"Loads the pre-trained Keras models.\"\"\"\n", + "# try:\n", + "# autoencoder = tf.keras.models.load_model(AUTOENCODER_MODEL_PATH, compile=False)\n", + "# decoder = tf.keras.models.load_model(DECODER_MODEL_PATH, compile=False)\n", + "# expression_model = tf.keras.models.load_model(EXPRESSION_MODEL_PATH, compile=False)\n", + "# return autoencoder, decoder, expression_model\n", + "# except Exception as e:\n", + "# print(f\"Error loading models: {e}\")\n", + "# print(\"Please ensure 'autoencoder_model.h5', 'decoder_model.h5', and 'expression_model.h5' are in the correct directory.\")\n", + "# return None, None, None\n", + "\n", + "# # --- Function to load vocabulary ---\n", + "# def load_vocabulary():\n", + "# \"\"\"Loads the vocabulary mapping from a pickle file.\"\"\"\n", + "# try:\n", + "# with open(VOCAB_MAPPING_PATH, \"rb\") as f:\n", + "# vocab_data = pickle.load(f)\n", + "# vocab = vocab_data[\"base_to_idx\"]\n", + "# idx_to_char = vocab_data[\"idx_to_base\"]\n", + "# return vocab, idx_to_char\n", + "# except Exception as e:\n", + "# print(f\"Error loading vocabulary: {e}\")\n", + "# print(\"Please ensure 'vocab_mapping.pkl' is in the correct directory.\")\n", + "# return None, None\n", + "\n", + "# # --- Helper Functions for Sequence Manipulation ---\n", + "\n", + "# def decode_sequence(one_hot_seq, idx_to_char_map):\n", + "# \"\"\"\n", + "# Decodes a one-hot encoded sequence back into a character string.\n", + "\n", + "# Args:\n", + "# one_hot_seq (np.array): A NumPy array representing the one-hot encoded sequence.\n", + "# idx_to_char_map (dict): A dictionary mapping index to character.\n", + "\n", + "# Returns:\n", + "# str: The decoded sequence string.\n", + "# \"\"\"\n", + "# indices = np.argmax(one_hot_seq, axis=-1)\n", + "# chars = [idx_to_char_map.get(i, 'N') for i in indices] # Use .get with default 'N' for safety\n", + "# return ''.join(chars)\n", + "\n", + "# def decode_sequence_with_temperature(logits, idx_to_char_map, temperature=1.0):\n", + "# \"\"\"\n", + "# Decodes a sequence from logits using a specified temperature for sampling.\n", + "\n", + "# Args:\n", + "# logits (tf.Tensor or np.array): Raw prediction scores from the decoder.\n", + "# idx_to_char_map (dict): A dictionary mapping index to character.\n", + "# temperature (float): Controls the randomness of sampling. Higher values\n", + "# (e.g., 1.0+) lead to more diverse sequences, lower values\n", + "# (e.g., 0.1-0.5) lead to more conservative sequences.\n", + "\n", + "# Returns:\n", + "# str: The sampled sequence string.\n", + "# \"\"\"\n", + "# # Ensure logits are a TensorFlow tensor for softmax\n", + "# if not isinstance(logits, tf.Tensor):\n", + "# logits = tf.convert_to_tensor(logits, dtype=tf.float32)\n", + "\n", + "# # Apply temperature and softmax to get probabilities\n", + "# # Adding a small epsilon to temperature to prevent division by zero if temp is 0.\n", + "# probs = tf.nn.softmax(logits / (temperature + 1e-8), axis=-1).numpy()\n", + "\n", + "# # Sample indices based on probabilities\n", + "# sampled_indices = [np.random.choice(len(p), p=p) for p in probs]\n", + "\n", + "# # Convert indices back to characters\n", + "# chars = [idx_to_char_map.get(i, 'N') for i in sampled_indices]\n", + "# return ''.join(chars)\n", + "\n", + "# def clean_dna_sequence(seq):\n", + "# \"\"\"\n", + "# Cleans a DNA sequence by removing any characters that are not A, C, G, or T.\n", + "\n", + "# Args:\n", + "# seq (str): The input sequence string.\n", + "\n", + "# Returns:\n", + "# str: The cleaned sequence containing only ACGT characters.\n", + "# \"\"\"\n", + "# return re.sub(r'[^ACGT]', '', seq)\n", + "\n", + "# # --- Core Logic: Latent Optimization and Sequence Generation ---\n", + "\n", + "# def generate_sequence_for_expression(\n", + "# target_expr,\n", + "# autoencoder_model, # Passed as argument\n", + "# decoder_model, # Passed as argument\n", + "# expression_model_ref, # Passed as argument (renamed to avoid conflict with imported name)\n", + "# idx_to_char_map, # Passed as argument\n", + "# steps=500,\n", + "# lr=0.05,\n", + "# temps=[0.4, 0.6, 0.8, 1.0]\n", + "# ):\n", + "# \"\"\"\n", + "# Optimizes a latent vector to match a target expression value and\n", + "# then generates diverse DNA sequences using a decoder.\n", + "\n", + "# Args:\n", + "# target_expr (float): The desired expression value to optimize for.\n", + "# autoencoder_model (tf.keras.Model): The loaded autoencoder model (used to get latent_dim).\n", + "# decoder_model (tf.keras.Model): The loaded decoder model.\n", + "# expression_model_ref (tf.keras.Model): The loaded expression prediction model.\n", + "# idx_to_char_map (dict): Dictionary mapping integer indices back to characters (e.g., 'A', 'C', 'G', 'T').\n", + "# steps (int): Number of optimization steps for the latent vector.\n", + "# lr (float): Learning rate for the Adam optimizer.\n", + "# temps (list): List of temperature values for diverse sequence generation.\n", + "\n", + "# Returns:\n", + "# list: A list of tuples, where each tuple contains (temperature, generated_sequence, predicted_expression).\n", + "# \"\"\"\n", + "# # Get latent dimension from the autoencoder's latent layer\n", + "# # Assuming 'latent_vector' is the name of the latent layer in your autoencoder\n", + "# latent_dim = autoencoder_model.get_layer(\"latent_vector\").output.shape[-1]\n", + "\n", + "# # Initialize the latent vector 'z' randomly\n", + "# z = tf.Variable(tf.random.normal([1, latent_dim]), trainable=True)\n", + "# optimizer = tf.keras.optimizers.Adam(learning_rate=lr)\n", + "\n", + "# print(f\"Starting latent optimization for target expression: {target_expr:.4f}\")\n", + "# for step in range(steps):\n", + "# with tf.GradientTape() as tape:\n", + "# # Predict expression for the current latent vector 'z'\n", + "# pred_expr = expression_model_ref(z, training=False)\n", + "# # Calculate mean squared error loss between predicted and target expression\n", + "# loss = tf.reduce_mean(tf.square(pred_expr - target_expr))\n", + "\n", + "# # Compute gradients of the loss with respect to 'z'\n", + "# grads = tape.gradient(loss, [z])\n", + "# # Apply gradients to update 'z'\n", + "# optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + "# # Print progress periodically\n", + "# if step % 100 == 0 or step == steps - 1:\n", + "# print(f\"Step {step}: Predicted = {pred_expr.numpy().squeeze():.4f} | Target = {target_expr:.4f} | Loss = {loss.numpy():.6f}\")\n", + "\n", + "# print(\"\\nOptimization complete. Generating sequences...\")\n", + "# # Get logits from the decoder using the optimized latent vector 'z'\n", + "# logits = decoder_model(z, training=False).numpy().squeeze()\n", + "\n", + "# generated_variants = []\n", + "# # Generate sequences at different temperatures\n", + "# for temp in temps:\n", + "# # Decode sequence using the specific temperature\n", + "# seq = decode_sequence_with_temperature(logits, idx_to_char_map, temperature=temp)\n", + "# # Re-predict expression for the optimized 'z' (this value will be consistent across temps)\n", + "# final_pred_expr = expression_model_ref(z, training=False).numpy().squeeze()\n", + "\n", + "# print(f\"\\n🌑️ Temp {temp:.1f} | Predicted: {final_pred_expr:.4f} | Sequence: {seq}\")\n", + "\n", + "# # Clean the generated sequence and validate if it's purely ACGT\n", + "# cleaned = clean_dna_sequence(seq)\n", + "# if len(cleaned) == len(seq): # Keep only valid ACGT sequences\n", + "# generated_variants.append((temp, seq, final_pred_expr))\n", + "# else:\n", + "# print(f\" Warning: Sequence contained non-ACGT characters and was not added.\")\n", + "\n", + "# return generated_variants\n", + "\n", + "# # --- Main execution function ---\n", + "\n", + "# def run_dna_sequence_tool(target_expression_value: float, output_filename: str = None):\n", + "# \"\"\"\n", + "# Main function to run the DNA sequence generation tool.\n", + "\n", + "# Args:\n", + "# target_expression_value (float): The desired expression value.\n", + "# output_filename (str, optional): The name of the file to save results.\n", + "# If None, a default name is generated.\n", + "# \"\"\"\n", + "# print(\"--- Initializing DNA Sequence Generation Tool ---\")\n", + "\n", + "# # Load models\n", + "# autoencoder, decoder, expression_model_loaded = load_models()\n", + "# if autoencoder is None or decoder is None or expression_model_loaded is None:\n", + "# print(\"Exiting due to model loading error.\")\n", + "# return\n", + "\n", + "# # Load vocabulary\n", + "# vocab, idx_to_char = load_vocabulary()\n", + "# if vocab is None or idx_to_char is None:\n", + "# print(\"Exiting due to vocabulary loading error.\")\n", + "# return\n", + "\n", + "# # Generate sequences\n", + "# results = generate_sequence_for_expression(\n", + "# target_expr=target_expression_value,\n", + "# autoencoder_model=autoencoder,\n", + "# decoder_model=decoder,\n", + "# expression_model_ref=expression_model_loaded,\n", + "# idx_to_char_map=idx_to_char,\n", + "# steps=500, # Default steps\n", + "# lr=0.05, # Default learning rate\n", + "# temps=[0.4, 0.6, 0.8, 1.0] # Default temperatures\n", + "# )\n", + "\n", + "# # Determine output file name\n", + "# if output_filename is None:\n", + "# output_file = f\"generated_sequences_expr_{target_expression_value:.2f}.txt\"\n", + "# else:\n", + "# output_file = output_filename\n", + "\n", + "# # Save results to file\n", + "# try:\n", + "# with open(output_file, \"w\") as f:\n", + "# for temp, seq, pred in results:\n", + "# f.write(f\"> Temp: {temp:.1f}, Predicted: {pred:.4f}\\n{seq}\\n\\n\")\n", + "# print(f\"\\nβœ… All valid sequence variants saved to: {os.path.abspath(output_file)}\")\n", + "# except Exception as e:\n", + "# print(f\"Error saving results to file {output_file}: {e}\")\n", + "\n", + "# # Example Usage (if you were to run this as a standalone script)\n", + "# if __name__ == \"__main__\":\n", + "# # This block shows how you would typically call the main function.\n", + "# # In a real interactive environment, you might get this from user input or another part of your application.\n", + "\n", + "# # Simulate user input for demonstration\n", + "# # You might replace this with a more robust input method in a web app, for example.\n", + "# try:\n", + "# desired_expression = float(input(\"Enter desired expression value (e.g., 5.0): \"))\n", + "# run_dna_sequence_tool(desired_expression)\n", + "# except ValueError:\n", + "# print(\"Invalid input. Please enter a numerical value for expression.\")\n", + "# except Exception as e:\n", + "# print(f\"An unexpected error occurred: {e}\")" + ], + "metadata": { + "id": "UuV7H0KBGe15", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "dde38a67-03ef-4f85-a84b-993dcd8f808b" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Enter desired expression value (e.g., 5.0): 7.04\n", + "--- Initializing DNA Sequence Generation Tool ---\n", + "Starting latent optimization for target expression: 7.0400\n", + "Step 0: Predicted = 1.0916 | Target = 7.0400 | Loss = 35.383472\n", + "Step 100: Predicted = 7.0346 | Target = 7.0400 | Loss = 0.000029\n", + "Step 200: Predicted = 7.0400 | Target = 7.0400 | Loss = 0.000000\n", + "Step 300: Predicted = 7.0400 | Target = 7.0400 | Loss = 0.000000\n", + "Step 400: Predicted = 7.0400 | Target = 7.0400 | Loss = 0.000000\n", + "Step 499: Predicted = 7.0400 | Target = 7.0400 | Loss = 0.000000\n", + "\n", + "Optimization complete. Generating sequences...\n", + "\n", + "🌑️ Temp 0.4 | Predicted: 7.0400 | Sequence: GCTTNTNGGTTTGCNCGNGGATGGTGATTCNCNGGNNNTGACCTGTTCGGCGCCTTGAATCTCNNAATAGTCTGACNTGCNTTTNNCAGGAGATNCCAATTTAGNGGAATCTAAAACNTANNCCACTGATTCCATGGGTATNGNGGCNGNNCNTATCTTGGCTNT\n", + " Warning: Sequence contained non-ACGT characters and was not added.\n", + "\n", + "🌑️ Temp 0.6 | Predicted: 7.0400 | Sequence: GAGCAGATATTTNNGTNGGGANCCNTATNTCGAGATAATGTTTNCAGGCNGGATCGTTTATTNTNGAGAGGTGCANCGGTAANACAGTCGNGGTGCGCANGTAGCCTATCCGCACTTCAACGATNATCTGGNTCNTNACAGTGGGCATNNAATANNNGACCAGAC\n", + " Warning: Sequence contained non-ACGT characters and was not added.\n", + "\n", + "🌑️ Temp 0.8 | Predicted: 7.0400 | Sequence: ATAATTAANTAGTGGNTCANANGAGNCGGCCAAGACTGNACNCCTNTGCTNGGCNGACANGCCTGTATAGAATACNTGTTCATAANATNGATGTCGGGTANGTGAAGAGAAGNGTCNTTGTTTCGTNGTNATCGTGANTCNGTNCATGTACANGGNCCAAAGTTC\n", + " Warning: Sequence contained non-ACGT characters and was not added.\n", + "\n", + "🌑️ Temp 1.0 | Predicted: 7.0400 | Sequence: TNCAACATCCAAGATGTGNCGCGGTCGCANATCANNTCANTCNTNTGAATCATNTCCNCCACNCCCGCGNTCTACNTATGCCTNATNNTCGTGNCACTCCNGGNTTTCANAGGAACATCTGGGAGGCGGTAAGGTAGGGTTTGNTNGNAACNATNAATGGGGTTT\n", + " Warning: Sequence contained non-ACGT characters and was not added.\n", + "\n", + "βœ… All valid sequence variants saved to: /content/generated_sequences_expr_7.04.txt\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# === Updated Autoencoder Training with Transformer Encoder ===\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import tensorflow as tf\n", + "from tensorflow.keras import layers, models\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "# ----------------------------\n", + "# 1. Load & Preprocess Data\n", + "# ----------------------------\n", + "base_to_idx = {'A': 0, 'T': 1, 'C': 2, 'G': 3, 'N': 4}\n", + "idx_to_base = {v: k for k, v in base_to_idx.items()}\n", + "\n", + "def preprocess_sequence(seq, max_len=165):\n", + " seq = seq.upper()[:max_len]\n", + " seq += 'N' * (max_len - len(seq))\n", + " return [base_to_idx.get(base, 4) for base in seq]\n", + "\n", + "df1 = pd.read_csv('/content/ecoli_mpra_expr.csv')\n", + "df2 = pd.read_csv('/content/ecoli_natural50bp_expr (1).csv')\n", + "combined_df = pd.concat([df1, df2], ignore_index=True)\n", + "combined_df['tokenized'] = combined_df['seq'].apply(preprocess_sequence)\n", + "\n", + "X_seq = np.array(combined_df['tokenized'].tolist())\n", + "y_expr = combined_df['expr'].values.reshape(-1, 1)\n", + "y_seq = np.expand_dims(X_seq, -1)\n", + "\n", + "# ----------------------------\n", + "# 2. Transformer Encoder Block\n", + "# ----------------------------\n", + "class TransformerEncoderBlock(tf.keras.layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):\n", + " super().__init__()\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)\n", + " self.ffn = tf.keras.Sequential([\n", + " layers.Dense(ff_dim, activation='relu'),\n", + " layers.Dense(embed_dim),\n", + " ])\n", + " self.norm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.norm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.drop1 = layers.Dropout(rate)\n", + " self.drop2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training=None):\n", + " attn_output = self.att(inputs, inputs)\n", + " out1 = self.norm1(inputs + self.drop1(attn_output, training=training))\n", + " ffn_output = self.ffn(out1)\n", + " return self.norm2(out1 + self.drop2(ffn_output, training=training))\n", + "\n", + "# ----------------------------\n", + "# 3. Define Model\n", + "# ----------------------------\n", + "vocab_size = 5\n", + "max_len = 165\n", + "embedding_dim = 16\n", + "latent_dim = 64\n", + "\n", + "input_seq = layers.Input(shape=(max_len,), dtype='int32')\n", + "x = layers.Embedding(input_dim=vocab_size, output_dim=embedding_dim)(input_seq)\n", + "x = TransformerEncoderBlock(embed_dim=embedding_dim, num_heads=4, ff_dim=latent_dim)(x)\n", + "x = layers.GlobalAveragePooling1D()(x)\n", + "latent = layers.Dense(latent_dim, activation='relu', name=\"latent_vector\")(x)\n", + "\n", + "expr_pred = layers.Dense(1, name=\"expression_output\")(latent)\n", + "\n", + "x = layers.RepeatVector(max_len)(latent)\n", + "x = layers.GRU(64, return_sequences=True)(x)\n", + "decoded = layers.TimeDistributed(layers.Dense(vocab_size, activation='softmax'), name=\"decoder_output\")(x)\n", + "\n", + "autoencoder = models.Model(inputs=input_seq, outputs=[decoded, expr_pred])\n", + "autoencoder.compile(optimizer='adam',\n", + " loss={'decoder_output': 'sparse_categorical_crossentropy', 'expression_output': 'mse'},\n", + " loss_weights={'decoder_output': 1.0, 'expression_output': 1.0},\n", + " metrics={'decoder_output': 'accuracy'})\n", + "\n", + "# ----------------------------\n", + "# 4. Train Model\n", + "# ----------------------------\n", + "autoencoder.fit(X_seq,\n", + " {'decoder_output': y_seq, 'expression_output': y_expr},\n", + " batch_size=64,\n", + " epochs=20,\n", + " validation_split=0.1)\n", + "\n", + "# ----------------------------\n", + "# 5. Save Model & Vocabulary\n", + "# ----------------------------\n", + "autoencoder.save(\"autoencoder_model.h5\")\n", + "encoder = models.Model(autoencoder.input, autoencoder.get_layer(\"latent_vector\").output)\n", + "\n", + "latent_input = tf.keras.Input(shape=(latent_dim,))\n", + "x = layers.RepeatVector(max_len)(latent_input)\n", + "x = layers.GRU(64, return_sequences=True)(x)\n", + "decoder_output = layers.TimeDistributed(layers.Dense(vocab_size, activation='softmax'))(x)\n", + "decoder = tf.keras.Model(latent_input, decoder_output)\n", + "decoder.save(\"decoder_model.h5\")\n", + "\n", + "expr_head = layers.Dense(1)(latent_input)\n", + "expression_model = tf.keras.Model(latent_input, expr_head)\n", + "expression_model.save(\"expression_model.h5\")\n", + "\n", + "import pickle\n", + "vocab_mapping = {\"base_to_idx\": base_to_idx, \"idx_to_base\": idx_to_base}\n", + "with open(\"vocab_mapping.pkl\", \"wb\") as f:\n", + " pickle.dump(vocab_mapping, f)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mf2-eM1FNJ4M", + "outputId": "9ea969cc-d448-4eea-9034-34c505c92d3e" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m33s\u001b[0m 46ms/step - decoder_output_accuracy: 0.4710 - decoder_output_loss: 1.1386 - expression_output_loss: 10.2037 - loss: 11.3423 - val_decoder_output_accuracy: 0.7755 - val_decoder_output_loss: 0.4464 - val_expression_output_loss: 4.7048 - val_loss: 5.1384\n", + "Epoch 2/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m34s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5163 - decoder_output_loss: 0.9721 - expression_output_loss: 5.5762 - loss: 6.5483 - val_decoder_output_accuracy: 0.7665 - val_decoder_output_loss: 0.4731 - val_expression_output_loss: 4.5914 - val_loss: 5.0523\n", + "Epoch 3/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5255 - decoder_output_loss: 0.9594 - expression_output_loss: 5.5322 - loss: 6.4916 - val_decoder_output_accuracy: 0.7797 - val_decoder_output_loss: 0.4326 - val_expression_output_loss: 4.5777 - val_loss: 4.9990\n", + "Epoch 4/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5263 - decoder_output_loss: 0.9593 - expression_output_loss: 5.5664 - loss: 6.5258 - val_decoder_output_accuracy: 0.7842 - val_decoder_output_loss: 0.4283 - val_expression_output_loss: 4.6968 - val_loss: 5.1125\n", + "Epoch 5/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5276 - decoder_output_loss: 0.9583 - expression_output_loss: 5.5669 - loss: 6.5252 - val_decoder_output_accuracy: 0.7816 - val_decoder_output_loss: 0.4228 - val_expression_output_loss: 4.5534 - val_loss: 4.9677\n", + "Epoch 6/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 41ms/step - decoder_output_accuracy: 0.5257 - decoder_output_loss: 0.9640 - expression_output_loss: 5.5894 - loss: 6.5533 - val_decoder_output_accuracy: 0.7831 - val_decoder_output_loss: 0.4241 - val_expression_output_loss: 4.5593 - val_loss: 4.9746\n", + "Epoch 7/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 38ms/step - decoder_output_accuracy: 0.5282 - decoder_output_loss: 0.9586 - expression_output_loss: 5.5030 - loss: 6.4616 - val_decoder_output_accuracy: 0.7837 - val_decoder_output_loss: 0.4231 - val_expression_output_loss: 4.6394 - val_loss: 5.0568\n", + "Epoch 8/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5297 - decoder_output_loss: 0.9556 - expression_output_loss: 5.5023 - loss: 6.4578 - val_decoder_output_accuracy: 0.7815 - val_decoder_output_loss: 0.4262 - val_expression_output_loss: 4.5754 - val_loss: 4.9955\n", + "Epoch 9/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5311 - decoder_output_loss: 0.9532 - expression_output_loss: 5.4459 - loss: 6.3992 - val_decoder_output_accuracy: 0.7870 - val_decoder_output_loss: 0.4164 - val_expression_output_loss: 4.5564 - val_loss: 4.9646\n", + "Epoch 10/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5306 - decoder_output_loss: 0.9551 - expression_output_loss: 5.5898 - loss: 6.5449 - val_decoder_output_accuracy: 0.7914 - val_decoder_output_loss: 0.4145 - val_expression_output_loss: 4.5450 - val_loss: 4.9526\n", + "Epoch 11/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5322 - decoder_output_loss: 0.9535 - expression_output_loss: 5.4549 - loss: 6.4083 - val_decoder_output_accuracy: 0.7920 - val_decoder_output_loss: 0.4126 - val_expression_output_loss: 4.6005 - val_loss: 5.0045\n", + "Epoch 12/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 38ms/step - decoder_output_accuracy: 0.5288 - decoder_output_loss: 0.9594 - expression_output_loss: 5.6235 - loss: 6.5829 - val_decoder_output_accuracy: 0.7918 - val_decoder_output_loss: 0.4120 - val_expression_output_loss: 4.6432 - val_loss: 5.0512\n", + "Epoch 13/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 40ms/step - decoder_output_accuracy: 0.5340 - decoder_output_loss: 0.9503 - expression_output_loss: 5.5001 - loss: 6.4504 - val_decoder_output_accuracy: 0.7843 - val_decoder_output_loss: 0.4269 - val_expression_output_loss: 4.5574 - val_loss: 4.9781\n", + "Epoch 14/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5345 - decoder_output_loss: 0.9492 - expression_output_loss: 5.5240 - loss: 6.4731 - val_decoder_output_accuracy: 0.7903 - val_decoder_output_loss: 0.4131 - val_expression_output_loss: 4.5890 - val_loss: 4.9971\n", + "Epoch 15/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5348 - decoder_output_loss: 0.9507 - expression_output_loss: 5.4815 - loss: 6.4322 - val_decoder_output_accuracy: 0.7892 - val_decoder_output_loss: 0.4115 - val_expression_output_loss: 4.5634 - val_loss: 4.9662\n", + "Epoch 16/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5334 - decoder_output_loss: 0.9529 - expression_output_loss: 5.5035 - loss: 6.4564 - val_decoder_output_accuracy: 0.7934 - val_decoder_output_loss: 0.4107 - val_expression_output_loss: 4.5566 - val_loss: 4.9612\n", + "Epoch 17/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5350 - decoder_output_loss: 0.9535 - expression_output_loss: 5.5160 - loss: 6.4695 - val_decoder_output_accuracy: 0.7948 - val_decoder_output_loss: 0.4171 - val_expression_output_loss: 4.7719 - val_loss: 5.1860\n", + "Epoch 18/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5312 - decoder_output_loss: 0.9569 - expression_output_loss: 5.5794 - loss: 6.5364 - val_decoder_output_accuracy: 0.7947 - val_decoder_output_loss: 0.4162 - val_expression_output_loss: 4.6019 - val_loss: 5.0136\n", + "Epoch 19/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5342 - decoder_output_loss: 0.9533 - expression_output_loss: 5.5117 - loss: 6.4650 - val_decoder_output_accuracy: 0.7953 - val_decoder_output_loss: 0.4104 - val_expression_output_loss: 4.6494 - val_loss: 5.0553\n", + "Epoch 20/20\n", + "\u001b[1m364/364\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 39ms/step - decoder_output_accuracy: 0.5350 - decoder_output_loss: 0.9526 - expression_output_loss: 5.5649 - loss: 6.5175 - val_decoder_output_accuracy: 0.7971 - val_decoder_output_loss: 0.4093 - val_expression_output_loss: 4.5768 - val_loss: 4.9812\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n", + "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "import pickle\n", + "import re\n", + "from tensorflow.keras import layers\n", + "\n", + "# === Transformer Block for Loading ===\n", + "class TransformerEncoderBlock(tf.keras.layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1, **kwargs):\n", + " super().__init__(**kwargs)\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)\n", + " self.ffn = tf.keras.Sequential([\n", + " layers.Dense(ff_dim, activation='relu'),\n", + " layers.Dense(embed_dim),\n", + " ])\n", + " self.norm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.norm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.drop1 = layers.Dropout(rate)\n", + " self.drop2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training=False):\n", + " attn_output = self.att(inputs, inputs)\n", + " out1 = self.norm1(inputs + self.drop1(attn_output, training=training))\n", + " ffn_output = self.ffn(out1)\n", + " return self.norm2(out1 + self.drop2(ffn_output, training=training))\n", + "\n", + "# === Load Models and Vocab ===\n", + "autoencoder = tf.keras.models.load_model(\n", + " \"autoencoder_model (1).h5\",\n", + " custom_objects={'TransformerEncoderBlock': TransformerEncoderBlock},\n", + " compile=False\n", + ")\n", + "decoder = tf.keras.models.load_model(\"decoder_model (1).h5\", compile=False)\n", + "expression_model = tf.keras.models.load_model(\"expression_model (1).h5\", compile=False)\n", + "\n", + "with open(\"vocab_mapping (1).pkl\", \"rb\") as f:\n", + " vocab_data = pickle.load(f)\n", + "idx_to_char = vocab_data[\"idx_to_base\"]\n", + "\n", + "# === Helper Functions ===\n", + "def decode_sequence_with_temperature(logits, temperature=1.0):\n", + " probs = tf.nn.softmax(logits / temperature, axis=-1).numpy()\n", + " sampled_indices = [np.random.choice(len(p), p=p) for p in probs]\n", + " return ''.join([idx_to_char.get(i, 'N') for i in sampled_indices])\n", + "\n", + "def clean_dna_sequence(seq):\n", + " return re.sub(r'[^ACGT]', '', seq)\n", + "\n", + "# === Generation Function ===\n", + "latent_dim = autoencoder.get_layer(\"latent_vector\").output.shape[-1]\n", + "\n", + "def run_promoter_generator(target_expr, steps=500, lr=0.05, temps=[0.4, 0.6, 0.8, 1.0]):\n", + " z = tf.Variable(tf.random.normal([1, latent_dim]), trainable=True)\n", + " optimizer = tf.keras.optimizers.Adam(learning_rate=lr)\n", + "\n", + " for step in range(steps):\n", + " with tf.GradientTape() as tape:\n", + " pred_expr = expression_model(z, training=False)\n", + " loss = tf.reduce_mean(tf.square(pred_expr - target_expr))\n", + " grads = tape.gradient(loss, [z])\n", + " optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + " logits = decoder(z, training=False).numpy().squeeze()\n", + " results = []\n", + "\n", + " for temp in temps:\n", + " seq = decode_sequence_with_temperature(logits, temperature=temp)\n", + " pred_expr = float(expression_model(z, training=False).numpy().squeeze())\n", + " results.append({\n", + " \"temperature\": temp,\n", + " \"predicted_expression\": round(pred_expr, 4),\n", + " \"sequence\": seq\n", + "})\n", + "\n", + "\n", + " return results\n", + "\n", + "# === Example Usage ===\n", + "if __name__ == \"__main__\":\n", + " target = float(input(\"Enter desired expression value: \"))\n", + " result = run_promoter_generator(target)\n", + " print(\"result:\", result)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Hl0RDTcbShq8", + "outputId": "4ddcc21c-1ad6-4ba5-f8a7-f7300f13a9f8" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Enter desired expression value: 80\n", + "result: [{'temperature': 0.4, 'predicted_expression': 79.9556, 'sequence': 'ANCCAACACACCNCGGAAANTCCCACACTAAANGNTNGTATCTTNCACATGANCNNCATGTCAATCAAAAACAGCGCCGACCGAAACCCACACAAAGGAACCAGNCGAATCTCCGCAAACTCCTANTGCACCATCCTTCCCNACTGCGCCACNTANCGCTCACTA'}, {'temperature': 0.6, 'predicted_expression': 79.9556, 'sequence': 'GCATCGGCAATNANGANTAATNANCACTNTCAGGCGACCCTCTCGGTACGGGGCAACACCGTAATACAGGCCCCTCAACTACGTTAAGGATTTNATACGTTACCNGACGAAGANTACAATNTTTGTGTCGCTCGAAGTACANACACGACCCAACGCCTCTCAAAA'}, {'temperature': 0.8, 'predicted_expression': 79.9556, 'sequence': 'CATNCTCNNTCCCATCGCGTATNAGCTCCAAGTACCCCNNCNGCTAGNCGCATGCCANGGGANACNGCNTGNAGTGNGNGNCNCGNNAGNCNNACCACACCGCNTTAATACCCTGNAANNNNAACCAAANTGCTCTCCNTTTANACNTGCTTAACTTANCNNATG'}, {'temperature': 1.0, 'predicted_expression': 79.9556, 'sequence': 'NCNCCANTTAAAANANGNNGNAACTAAATTNCATAGCGGCNNNTNTATGCGNANGTCAGCACGCCGANTAAAGACAGCTTCNTTCGATANGAGCTGATTNNGAATCGTNANCGGANCAAACACAAGCNGTTCCNANTCCTNTNTNGCCTTATTCANANACATACC'}]\n" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/promoter/README.md b/promoter/README.md new file mode 100644 index 0000000..ad003d3 --- /dev/null +++ b/promoter/README.md @@ -0,0 +1,20 @@ +# 🧬 Synthetic Promoter Sequence Generator + +This project implements a neural network-based agent to **generate synthetic promoter DNA sequences** using a trained autoencoder model. It supports natural language queries that may include promoter design specifications, wet lab experiment suggestions, and related research search. + +--- + +## 🧠 Overview + +- 🧬 Uses a trained autoencoder to generate promoter sequences. +- πŸ§ͺ Supports query-driven generation with optional wet lab suggestions. +- πŸ”Integrates with LLMs like Claude to search and summarize scientific literature. + + +--- +## πŸ“¦ Setup + +```bash +git clone https://github.com/boltzmannlabs/Hackathon_june25.git +cd promoter +-run the promoter.ipynb diff --git a/promoter/autoencoder_model.h5 b/promoter/autoencoder_model.h5 new file mode 100644 index 0000000..b84eafe Binary files /dev/null and b/promoter/autoencoder_model.h5 differ diff --git a/promoter/decoder_model.h5 b/promoter/decoder_model.h5 new file mode 100644 index 0000000..8378721 Binary files /dev/null and b/promoter/decoder_model.h5 differ diff --git a/promoter/expression_model.h5 b/promoter/expression_model.h5 new file mode 100644 index 0000000..e4358f1 Binary files /dev/null and b/promoter/expression_model.h5 differ diff --git a/promoter/promoter.ipynb b/promoter/promoter.ipynb new file mode 100644 index 0000000..abdd401 --- /dev/null +++ b/promoter/promoter.ipynb @@ -0,0 +1,727 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qhxmeeKW-Z8x", + "outputId": "c2798372-ffc0-48fa-f4d3-021e9bfaa985", + "collapsed": true + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: langgraph in /usr/local/lib/python3.11/dist-packages (0.4.8)\n", + "Requirement already satisfied: langchain in /usr/local/lib/python3.11/dist-packages (0.3.25)\n", + "Requirement already satisfied: openai in /usr/local/lib/python3.11/dist-packages (1.86.0)\n", + "Requirement already satisfied: langchain-anthropic in /usr/local/lib/python3.11/dist-packages (0.3.15)\n", + "Requirement already satisfied: boto3 in /usr/local/lib/python3.11/dist-packages (1.38.37)\n", + "Requirement already satisfied: langchain_community in /usr/local/lib/python3.11/dist-packages (0.3.25)\n", + "Requirement already satisfied: langchain-core>=0.1 in /usr/local/lib/python3.11/dist-packages (from langgraph) (0.3.65)\n", + "Requirement already satisfied: langgraph-checkpoint>=2.0.26 in /usr/local/lib/python3.11/dist-packages (from langgraph) (2.1.0)\n", + "Requirement already satisfied: langgraph-prebuilt>=0.2.0 in /usr/local/lib/python3.11/dist-packages (from langgraph) (0.2.2)\n", + "Requirement already satisfied: langgraph-sdk>=0.1.42 in /usr/local/lib/python3.11/dist-packages (from langgraph) (0.1.70)\n", + "Requirement already satisfied: pydantic>=2.7.4 in /usr/local/lib/python3.11/dist-packages (from langgraph) (2.11.5)\n", + "Requirement already satisfied: xxhash>=3.5.0 in /usr/local/lib/python3.11/dist-packages (from langgraph) (3.5.0)\n", + "Requirement already satisfied: langchain-text-splitters<1.0.0,>=0.3.8 in /usr/local/lib/python3.11/dist-packages (from langchain) (0.3.8)\n", + "Requirement already satisfied: langsmith<0.4,>=0.1.17 in /usr/local/lib/python3.11/dist-packages (from langchain) (0.3.45)\n", + "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.11/dist-packages (from langchain) (2.0.41)\n", + "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.11/dist-packages (from langchain) (2.32.3)\n", + "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.11/dist-packages (from langchain) (6.0.2)\n", + "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.11/dist-packages (from openai) (4.9.0)\n", + "Requirement already satisfied: distro<2,>=1.7.0 in /usr/local/lib/python3.11/dist-packages (from openai) (1.9.0)\n", + "Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.11/dist-packages (from openai) (0.28.1)\n", + "Requirement already satisfied: jiter<1,>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from openai) (0.10.0)\n", + "Requirement already satisfied: sniffio in /usr/local/lib/python3.11/dist-packages (from openai) (1.3.1)\n", + "Requirement already satisfied: tqdm>4 in /usr/local/lib/python3.11/dist-packages (from openai) (4.67.1)\n", + "Requirement already satisfied: typing-extensions<5,>=4.11 in /usr/local/lib/python3.11/dist-packages (from openai) (4.14.0)\n", + "Requirement already satisfied: anthropic<1,>=0.52.0 in /usr/local/lib/python3.11/dist-packages (from langchain-anthropic) (0.54.0)\n", + "Requirement already satisfied: botocore<1.39.0,>=1.38.37 in /usr/local/lib/python3.11/dist-packages (from boto3) (1.38.37)\n", + "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.11/dist-packages (from boto3) (1.0.1)\n", + "Requirement already satisfied: s3transfer<0.14.0,>=0.13.0 in /usr/local/lib/python3.11/dist-packages (from boto3) (0.13.0)\n", + "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (3.11.15)\n", + "Requirement already satisfied: tenacity!=8.4.0,<10,>=8.1.0 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (9.1.2)\n", + "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (0.6.7)\n", + "Requirement already satisfied: pydantic-settings<3.0.0,>=2.4.0 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (2.9.1)\n", + "Requirement already satisfied: httpx-sse<1.0.0,>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (0.4.0)\n", + "Requirement already satisfied: numpy>=1.26.2 in /usr/local/lib/python3.11/dist-packages (from langchain_community) (2.0.2)\n", + "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (2.6.1)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (1.3.2)\n", + "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (25.3.0)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (1.7.0)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (6.4.4)\n", + "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (0.3.2)\n", + "Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain_community) (1.20.1)\n", + "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.11/dist-packages (from anyio<5,>=3.5.0->openai) (3.10)\n", + "Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/local/lib/python3.11/dist-packages (from botocore<1.39.0,>=1.38.37->boto3) (2.9.0.post0)\n", + "Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /usr/local/lib/python3.11/dist-packages (from botocore<1.39.0,>=1.38.37->boto3) (2.4.0)\n", + "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /usr/local/lib/python3.11/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain_community) (3.26.1)\n", + "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain_community) (0.9.0)\n", + "Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from httpx<1,>=0.23.0->openai) (2025.4.26)\n", + "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.11/dist-packages (from httpx<1,>=0.23.0->openai) (1.0.9)\n", + "Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.11/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai) (0.16.0)\n", + "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.11/dist-packages (from langchain-core>=0.1->langgraph) (1.33)\n", + "Requirement already satisfied: packaging<25,>=23.2 in /usr/local/lib/python3.11/dist-packages (from langchain-core>=0.1->langgraph) (24.2)\n", + "Requirement already satisfied: ormsgpack>=1.10.0 in /usr/local/lib/python3.11/dist-packages (from langgraph-checkpoint>=2.0.26->langgraph) (1.10.0)\n", + "Requirement already satisfied: orjson>=3.10.1 in /usr/local/lib/python3.11/dist-packages (from langgraph-sdk>=0.1.42->langgraph) (3.10.18)\n", + "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from langsmith<0.4,>=0.1.17->langchain) (1.0.0)\n", + "Requirement already satisfied: zstandard<0.24.0,>=0.23.0 in /usr/local/lib/python3.11/dist-packages (from langsmith<0.4,>=0.1.17->langchain) (0.23.0)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (2.33.2)\n", + "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (0.4.1)\n", + "Requirement already satisfied: python-dotenv>=0.21.0 in /usr/local/lib/python3.11/dist-packages (from pydantic-settings<3.0.0,>=2.4.0->langchain_community) (1.1.0)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2->langchain) (3.4.2)\n", + "Requirement already satisfied: greenlet>=1 in /usr/local/lib/python3.11/dist-packages (from SQLAlchemy<3,>=1.4->langchain) (3.2.3)\n", + "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.11/dist-packages (from jsonpatch<2.0,>=1.33->langchain-core>=0.1->langgraph) (3.0.0)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.39.0,>=1.38.37->boto3) (1.17.0)\n", + "Requirement already satisfied: mypy-extensions>=0.3.0 in /usr/local/lib/python3.11/dist-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain_community) (1.1.0)\n" + ] + } + ], + "source": [ + "# Step 1: Install Required Packages\n", + "!pip install langgraph langchain openai langchain-anthropic boto3 langchain_community\n" + ] + }, + { + "cell_type": "code", + "source": [ + "from google.colab import userdata\n", + "import os\n", + "from langchain_anthropic import ChatAnthropic\n", + "from langchain.chat_models.base import BaseChatModel\n", + "\n", + "\n", + "import boto3\n", + "import json\n", + "access_key=userdata.get('aws_access_key_id')\n", + "secret_key=userdata.get('aws_secret_access_key')\n", + "os.environ[\"AWS_ACCESS_KEY_ID\"] = access_key\n", + "os.environ[\"AWS_SECRET_ACCESS_KEY\"] =secret_key\n", + "\n", + "os.environ[\"AWS_REGION\"] = \"us-east-1\" # or another valid region" + ], + "metadata": { + "id": "JG11Cdko-eF3" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "from langchain_community.chat_models import BedrockChat as ChatBedrock\n", + "\n" + ], + "metadata": { + "id": "F7lusSPOCjoz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "claude = ChatBedrock(\n", + " model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\", # Claude v3 Sonnet on Bedrock\n", + " region_name=\"us-east-1\",\n", + ")\n" + ], + "metadata": { + "id": "vIDeThsLCziu" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "import pickle\n", + "import re\n", + "from tensorflow.keras import layers\n", + "\n", + "# === Transformer Block for Custom Object ===\n", + "class TransformerEncoderBlock(tf.keras.layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1, **kwargs):\n", + " super().__init__(**kwargs)\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)\n", + " self.ffn = tf.keras.Sequential([\n", + " layers.Dense(ff_dim, activation='relu'),\n", + " layers.Dense(embed_dim),\n", + " ])\n", + " self.norm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.norm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.drop1 = layers.Dropout(rate)\n", + " self.drop2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training=False):\n", + " attn_output = self.att(inputs, inputs)\n", + " out1 = self.norm1(inputs + self.drop1(attn_output, training=training))\n", + " ffn_output = self.ffn(out1)\n", + " return self.norm2(out1 + self.drop2(ffn_output, training=training))\n", + "\n", + "# === Load Models ===\n", + "autoencoder = tf.keras.models.load_model(\n", + " \"autoencoder_model.h5\",\n", + " custom_objects={'TransformerEncoderBlock': TransformerEncoderBlock},\n", + " compile=False\n", + ")\n", + "decoder = tf.keras.models.load_model(\"decoder_model.h5\", compile=False)\n", + "expression_model = tf.keras.models.load_model(\"expression_model.h5\", compile=False)\n", + "\n", + "# === Load Vocabulary ===\n", + "with open(\"vocab_mapping.pkl\", \"rb\") as f:\n", + " vocab_data = pickle.load(f)\n", + "vocab = vocab_data[\"base_to_idx\"]\n", + "idx_to_char = vocab_data[\"idx_to_base\"]\n", + "\n", + "# === Sequence Decoding Functions ===\n", + "def decode_sequence_with_temperature(logits, temperature=1.0):\n", + " probs = tf.nn.softmax(logits / temperature, axis=-1).numpy()\n", + " sampled_indices = [np.random.choice(len(p), p=p) for p in probs]\n", + " chars = [idx_to_char.get(i, 'N') for i in sampled_indices]\n", + " return ''.join(chars)\n", + "\n", + "def clean_dna_sequence(seq):\n", + " return re.sub(r'[^ACGT]', '', seq)\n", + "\n", + "# === Promoter Generation Function ===\n", + "latent_dim = autoencoder.get_layer(\"latent_vector\").output.shape[-1]\n", + "\n", + "def generate_promoter_sequences(target_expr, steps=500, lr=0.05, temps=[0.4, 0.6, 0.8, 1.0]):\n", + " z = tf.Variable(tf.random.normal([1, latent_dim]), trainable=True)\n", + " optimizer = tf.keras.optimizers.Adam(learning_rate=lr)\n", + "\n", + " for _ in range(steps):\n", + " with tf.GradientTape() as tape:\n", + " pred_expr = expression_model(z, training=False)\n", + " loss = tf.reduce_mean(tf.square(pred_expr - target_expr))\n", + " grads = tape.gradient(loss, [z])\n", + " optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + " logits = decoder(z, training=False).numpy().squeeze()\n", + "\n", + " generated_variants = []\n", + " for temp in temps:\n", + " seq = decode_sequence_with_temperature(logits, temperature=temp)\n", + " cleaned = clean_dna_sequence(seq)\n", + " if len(cleaned) == len(seq):\n", + " pred_expr = expression_model(z, training=False).numpy().squeeze()\n", + " generated_variants.append((seq, float(pred_expr)))\n", + "\n", + " return generated_variants\n" + ], + "metadata": { + "id": "__Ch6dLkUCWv" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "import pickle\n", + "import re\n", + "from tensorflow.keras import layers\n", + "\n", + "# === Transformer Block for Loading ===\n", + "class TransformerEncoderBlock(tf.keras.layers.Layer):\n", + " def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1, **kwargs):\n", + " super().__init__(**kwargs)\n", + " self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)\n", + " self.ffn = tf.keras.Sequential([\n", + " layers.Dense(ff_dim, activation='relu'),\n", + " layers.Dense(embed_dim),\n", + " ])\n", + " self.norm1 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.norm2 = layers.LayerNormalization(epsilon=1e-6)\n", + " self.drop1 = layers.Dropout(rate)\n", + " self.drop2 = layers.Dropout(rate)\n", + "\n", + " def call(self, inputs, training=False):\n", + " attn_output = self.att(inputs, inputs)\n", + " out1 = self.norm1(inputs + self.drop1(attn_output, training=training))\n", + " ffn_output = self.ffn(out1)\n", + " return self.norm2(out1 + self.drop2(ffn_output, training=training))\n", + "\n", + "# === Load Models and Vocab ===\n", + "autoencoder = tf.keras.models.load_model(\n", + " \"autoencoder_model.h5\",\n", + " custom_objects={'TransformerEncoderBlock': TransformerEncoderBlock},\n", + " compile=False\n", + ")\n", + "decoder = tf.keras.models.load_model(\"decoder_model.h5\", compile=False)\n", + "expression_model = tf.keras.models.load_model(\"expression_model.h5\", compile=False)\n", + "\n", + "with open(\"vocab_mapping.pkl\", \"rb\") as f:\n", + " vocab_data = pickle.load(f)\n", + "idx_to_char = vocab_data[\"idx_to_base\"]\n", + "\n", + "# === Helper Functions ===\n", + "def decode_sequence_with_temperature(logits, temperature=1.0):\n", + " probs = tf.nn.softmax(logits / temperature, axis=-1).numpy()\n", + " sampled_indices = [np.random.choice(len(p), p=p) for p in probs]\n", + " return ''.join([idx_to_char.get(i, 'N') for i in sampled_indices])\n", + "\n", + "def clean_dna_sequence(seq):\n", + " return re.sub(r'[^ACGT]', '', seq)\n", + "\n", + "# === Generation Function ===\n", + "latent_dim = autoencoder.get_layer(\"latent_vector\").output.shape[-1]\n", + "\n", + "def run_promoter_generator(target_expr, steps=500, lr=0.05, temps=[0.4, 0.6, 0.8, 1.0]):\n", + " z = tf.Variable(tf.random.normal([1, latent_dim]), trainable=True)\n", + " optimizer = tf.keras.optimizers.Adam(learning_rate=lr)\n", + "\n", + " for step in range(steps):\n", + " with tf.GradientTape() as tape:\n", + " pred_expr = expression_model(z, training=False)\n", + " loss = tf.reduce_mean(tf.square(pred_expr - target_expr))\n", + " grads = tape.gradient(loss, [z])\n", + " optimizer.apply_gradients(zip(grads, [z]))\n", + "\n", + " logits = decoder(z, training=False).numpy().squeeze()\n", + " results = []\n", + "\n", + " for temp in temps:\n", + " seq = decode_sequence_with_temperature(logits, temperature=temp)\n", + " pred_expr = float(expression_model(z, training=False).numpy().squeeze())\n", + " results.append({\n", + " \"temperature\": temp,\n", + " \"predicted_expression\": round(pred_expr, 4),\n", + " \"sequence\": seq\n", + "})\n", + "\n", + "\n", + " return results\n", + "\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "Hl0RDTcbShq8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "result = run_promoter_generator(70)\n", + "print(\"result:\", result)\n", + "print(result[1][\"sequence\"])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "TKhSKpvJurUA", + "outputId": "7e89c6fb-1c3a-4d5a-9787-268a122f99f5" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "result: [{'temperature': 0.4, 'predicted_expression': 69.9947, 'sequence': 'ATCTTTCCACCCCACNAGTCNNGTNCGAAANCCACCGCCNACACTTGACCCCAACCCGGTAANNGCCNACGTCAACCACCAAAACAGCCNACACACCCATCANCATGCCTGNNAAAAACCACCACCATNACCCAAACCCGAANNCAANNANTNNCAATNTAAAAA'}, {'temperature': 0.6, 'predicted_expression': 69.9947, 'sequence': 'CNACGTNCGGAGCNCCNGCACCCNGCCCTTAAGATGCCNCCCAATNCANCACANACTANGCACTGGNNCNCCNTTCNACNNTCNCCNGACTNCACCGTGCTCNAAGCNCCACCATNCAANACCTCTCCGCCCTACGGGNCCGNCATANNNCNAGACANCCGGCNA'}, {'temperature': 0.8, 'predicted_expression': 69.9947, 'sequence': 'TCAATATGNTTCACCANNCACTCCTAAGCCATCATTGCCATAAGGNGCGNNGATCTGCTCATCCNAGCAAATCAACCNAGAAANAACCNAAGCNANACNAAATTACTACNNATCNNGGTNNGATAGAGNACANATGGCCAGCCCATGGCTGCCCTCAANAGTTNG'}, {'temperature': 1.0, 'predicted_expression': 69.9947, 'sequence': 'CTNACNTCANCGCCGCTCCCGCCNNCGNGTCGCGCGTGAATATACGACGNAANNANNTCTTGGGACATTACNGCCNTNCNCCGNAGCCGACCNAATTACTACTTTCCCGTAAACTCNAGNNCTGNCCGCANGAAAGCNTCCCTTNGACGNATGAGCGNTGTAAAT'}]\n", + "CNACGTNCGGAGCNCCNGCACCCNGCCCTTAAGATGCCNCCCAATNCANCACANACTANGCACTGGNNCNCCNTTCNACNNTCNCCNGACTNCACCGTGCTCNAAGCNCCACCATNCAANACCTCTCCGCCCTACGGGNCCGNCATANNNCNAGACANCCGGCNA\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# ------------------ Imports ------------------\n", + "import os\n", + "from typing import TypedDict\n", + "from langchain_community.chat_models import BedrockChat as ChatBedrock\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langgraph.graph import StateGraph\n", + "\n", + "# ------------------ AWS Credential Setup ------------------\n", + "import boto3\n", + "import json\n", + "\n", + "# Replace with your actual credential logic\n", + "access_key = userdata.get('aws_access_key_id')\n", + "secret_key = userdata.get('aws_secret_access_key')\n", + "\n", + "os.environ[\"AWS_ACCESS_KEY_ID\"] = access_key\n", + "os.environ[\"AWS_SECRET_ACCESS_KEY\"] = secret_key\n", + "os.environ[\"AWS_REGION\"] = \"us-east-1\"\n", + "\n", + "# ------------------ Claude via Bedrock ------------------\n", + "\n", + "claude = ChatBedrock(\n", + " model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\",\n", + " region_name=\"us-east-1\"\n", + ")\n", + "\n", + "# ------------------ State Schema ------------------\n", + "\n", + "class GraphState(TypedDict):\n", + " user_query: str\n", + " target_expression: float\n", + " promoter: str\n", + " wet_lab: str\n", + " literature: str\n", + " report: str\n", + "\n", + "# ------------------ LangGraph Nodes ------------------\n", + "\n", + "# ✨ Node 1: Extract expression value from query\n", + "def extract_expression_node(state: GraphState) -> dict:\n", + " prompt = ChatPromptTemplate.from_template(\n", + " \"Extract the numeric expression value from this query: {user_query}. Only return the number.\"\n", + " )\n", + " chain = prompt | claude | (lambda x: {\"target_expression\": float(x.content.strip())})\n", + " return chain.invoke({\"user_query\": state[\"user_query\"]})\n", + "\n", + "\n", + "# ✨ Node 2: Use your own model to generate promoter\n", + "def generate_promoter_node(state: GraphState) -> dict:\n", + " expression = state[\"target_expression\"] # dynamically get from state\n", + " result = run_promoter_generator(expression) # your custom function\n", + "\n", + " promoter_seq = result[1][\"sequence\"] # assuming result is a tuple or list and this works\n", + "\n", + " return {\"promoter\": promoter_seq}\n", + "\n", + "\n", + "# ✨ Node 3: Suggest wet lab experiment\n", + "def suggest_wet_lab_node(state: GraphState) -> dict:\n", + " prompt = ChatPromptTemplate.from_template(\n", + " \"\"\"You are a molecular biologist designing an experiment to validate the function of a synthetic promoter in *E. coli*.\n", + "\n", + "The user has requested the following:\n", + "\"{query}\"\n", + "\n", + "The promoter sequence is: {promoter}\n", + "\n", + "Design a wet lab experiment to test its activity. Include:\n", + "- The experimental method (e.g., reporter assay, transformation protocol)\n", + "- The plasmid or vector system (if relevant)\n", + "- The host strain of *E. coli* to use\n", + "- What will be measured (e.g., fluorescence, enzymatic activity, mRNA level)\n", + "- Controls to include for comparison\n", + "\n", + "Incorporate any specific requirements mentioned by the user.\n", + "Provide a clear and concise protocol outline.\"\"\"\n", + " )\n", + " chain = prompt | claude | (lambda x: {\"wet_lab\": x.content.strip()})\n", + " return chain.invoke({\n", + " \"query\": state[\"user_query\"],\n", + " \"promoter\": state[\"promoter\"]\n", + " })\n", + "\n", + "# ✨ Node 4: Summarize research literature\n", + "def summarize_research_node(state: GraphState) -> dict:\n", + " user_query = f\"\"\"\n", + "The user is interested in this query: \"{state['user_query']}\"\n", + "\n", + "Find and summarize recent research related to the synthetic promoter sequence:\n", + "\"{state['promoter']}\" in *E. coli*.\n", + "\n", + "Focus on studies in:\n", + "- Synthetic biology\n", + "- Gene expression tuning\n", + "- Genetic circuit design\n", + "\n", + "Especially highlight anything that aligns with the user's request.\n", + "\n", + "Provide:\n", + "- A concise summary of relevant findings\n", + "- Bullet points for important insights (if applicable)\n", + "- Direct links to peer-reviewed publications, preprints (e.g., PubMed, bioRxiv, Nature, NAR, etc.)\n", + "- Mention if the exact promoter has been characterized or modified\n", + "\"\"\"\n", + " prompt = ChatPromptTemplate.from_template(\n", + " \"You are a scientific research assistant helping summarize the literature.\\n\\n\"\n", + " \"{query}\\n\\n\"\n", + " \"Return your answer with:\\n\"\n", + " \"- A brief summary of the key research findings\\n\"\n", + " \"- Bullet points for important insights (if applicable)\\n\"\n", + " \"- Direct links to relevant publications (if available)\\n\"\n", + " \"- Focus on *E. coli* and synthetic promoter usage\"\n", + " )\n", + " chain = prompt | claude | (lambda x: {\"literature\": x.content.strip()})\n", + " return chain.invoke({\"query\": user_query})\n", + "\n", + "def assemble_report_node(state: GraphState) -> dict:\n", + " # Step 1: Build the full report\n", + " full_report = f\"\"\"\n", + "🧬 **Synthetic Promoter Generation Report**\n", + "\n", + "πŸ”Ή **Target Expression:** {state['target_expression']}\n", + "\n", + "🧬 **Generated Promoter Sequence:**\n", + "{state['promoter']}\n", + "\n", + "πŸ§ͺ **Wet Lab Experiment Suggestion:**\n", + "{state['wet_lab']}\n", + "\n", + "πŸ“š **Research Summary:**\n", + "{state['literature']}\n", + "\"\"\"\n", + "\n", + " # Step 2: Summarize the report using Claude\n", + " prompt = ChatPromptTemplate.from_template(\n", + " \"\"\"You are a synthetic biology expert reviewing this project report.\n", + "\n", + "Please do the following:\n", + "- Carefully read the report.\n", + "- Identify and correct any factual, scientific, or formatting errors.\n", + "- Think critically about the experimental design and relevance of the research.\n", + "- Improve clarity where needed.\n", + "- Return a revised version that is suitable for inclusion in a scientific update or proposal.\"\"\"\n", + "\n", + " )\n", + " chain = prompt | claude | (lambda x: {\"summary\": x.content.strip()})\n", + " result = chain.invoke({\"report\": full_report})\n", + "\n", + " # Step 3: Return both the report and the summary\n", + " return {\n", + " \"report\": full_report.strip(),\n", + " \"summary\": result[\"summary\"]\n", + " }\n", + "\n", + "\n", + "# ------------------ LangGraph Definition ------------------\n", + "\n", + "graph = StateGraph(GraphState)\n", + "\n", + "graph.add_node(\"extract\", extract_expression_node)\n", + "graph.add_node(\"generate\", generate_promoter_node)\n", + "graph.add_node(\"experiment\", suggest_wet_lab_node)\n", + "graph.add_node(\"summarize\", summarize_research_node)\n", + "graph.add_node(\"assemble_report\", assemble_report_node)\n", + "\n", + "graph.set_entry_point(\"extract\")\n", + "graph.add_edge(\"extract\", \"generate\")\n", + "graph.add_edge(\"generate\", \"experiment\")\n", + "graph.add_edge(\"experiment\", \"summarize\")\n", + "graph.add_edge(\"summarize\", \"assemble_report\")\n", + "graph.set_finish_point(\"assemble_report\")\n", + "\n", + "workflow = graph.compile()\n", + "\n", + "# ------------------ Run the Agent ------------------\n", + "\n", + "user_query = \"Develop a synthetic promoter with 40 expression value\"\n", + "\n", + "result = workflow.invoke({\"user_query\": user_query})\n", + "\n", + "print(result[\"report\"])\n" + ], + "metadata": { + "id": "ZwriFX26wErQ", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "068d6357-eaa7-4ed4-8273-1666a90dd3f4" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "🧬 **Synthetic Promoter Generation Report**\n", + "\n", + "πŸ”Ή **Target Expression:** 40.0\n", + "\n", + "🧬 **Generated Promoter Sequence:**\n", + "NACCNCCCATCAANCGCNNATCTGGGCAAATAGATCNNCACCGGTCAAGCNGNTGAANCANCAGGACAACACNTAAAANCNNNCNAGGAANCGTTANCAAGTCCCGCNANTCGCCCATACTNNCAGAACATGTTTATCACAGANCNTAACNCCAAAANCGGNGAA\n", + "\n", + "πŸ§ͺ **Wet Lab Experiment Suggestion:**\n", + "To validate the function of the synthetic promoter sequence with the requested expression value of 40, we can design a reporter assay using a fluorescent protein as the reporter gene. Here is an outline of the experimental protocol:\n", + "\n", + "Experimental Method: Fluorescent Protein Reporter Assay\n", + "\n", + "Plasmid/Vector System:\n", + "- Use a low-copy plasmid vector compatible with E. coli, such as pBR322 or pUC19.\n", + "- Clone the synthetic promoter sequence upstream of a fluorescent reporter gene, such as GFP or RFP.\n", + "\n", + "Host Strain:\n", + "- Use a common E. coli strain suitable for cloning and expression studies, such as DH5Ξ± or BL21(DE3).\n", + "\n", + "Measurement:\n", + "- Measure the fluorescence intensity of the reporter protein, which will be proportional to the promoter activity.\n", + "\n", + "Controls:\n", + "1. Negative Control:\n", + " - Use the same plasmid vector without the synthetic promoter, or with a non-functional promoter sequence.\n", + " - This control will establish the baseline fluorescence level.\n", + "\n", + "2. Positive Control:\n", + " - Use a well-characterized strong promoter, such as the lac promoter or T7 promoter, driving the expression of the same fluorescent reporter gene.\n", + " - This control will serve as a reference for high promoter activity.\n", + "\n", + "3. Additional Controls (Optional):\n", + " - Include promoters with known expression levels (e.g., low, medium, high) to establish a calibration curve for comparing the synthetic promoter activity.\n", + "\n", + "Protocol Outline:\n", + "\n", + "1. Clone the synthetic promoter sequence upstream of the fluorescent reporter gene in the chosen plasmid vector.\n", + "2. Transform the recombinant plasmid into the E. coli host strain using a standard transformation protocol (e.g., heat shock or electroporation).\n", + "3. Inoculate transformed cells into liquid culture medium with appropriate antibiotics for plasmid selection.\n", + "4. Incubate the cultures at optimal growth conditions (e.g., 37Β°C with shaking) until reaching mid-log phase.\n", + "5. Measure the fluorescence intensity of the cultures using a fluorometer or a microplate reader with appropriate excitation and emission wavelengths for the chosen reporter.\n", + "6. Normalize the fluorescence measurements by cell density (e.g., OD600) to account for differences in growth rates.\n", + "7. Compare the normalized fluorescence values of the synthetic promoter construct with the negative and positive controls, as well as any additional calibration controls.\n", + "8. Analyze the data to determine if the synthetic promoter exhibits the desired expression value of 40 relative to the controls.\n", + "\n", + "Note: If the user has specific requirements or preferences for the plasmid vector, host strain, or experimental conditions, adjust the protocol accordingly. Additionally, consider performing biological replicates and statistical analysis to ensure the reliability and reproducibility of the results.\n", + "\n", + "πŸ“š **Research Summary:**\n", + "Summary of Key Research Findings:\n", + "\n", + "The provided synthetic promoter sequence appears to be a novel, artificially designed sequence, as I did not find any direct studies characterizing its expression in Escherichia coli. However, there is relevant research on developing synthetic promoters, tuning gene expression, and genetic circuit design in E. coli that could provide insights into characterizing and optimizing this sequence.\n", + "\n", + "Important Insights:\n", + "\n", + "- Synthetic promoters can be designed and tuned by modifying regulatory elements, such as the -35 and -10 boxes, UP elements, and transcription factor binding sites, to achieve desired expression levels (Mutalik et al., 2013; Kosuri et al., 2013).\n", + "- Computational models and libraries of well-characterized promoter parts can aid in the design and prediction of synthetic promoter strengths (Bao et al., 2018; Urtecho et al., 2019).\n", + "- Directed evolution techniques, such as error-prone PCR and transcription factor engineering, can be used to optimize synthetic promoters for improved expression or dynamic regulation (Brophy and Voigt, 2014; Luo et al., 2021).\n", + "- Synthetic promoters can be integrated into genetic circuits for various applications, such as metabolic engineering, biosensing, and synthetic gene networks (Blazeck and Alper, 2013; Meng et al., 2020).\n", + "\n", + "Relevant Publications:\n", + "\n", + "1. Mutalik, V. K., Guimaraes, J. C., Cambray, G., Lam, C., Christoffersen, M. J., Mai, Q. A., ... & Arkin, A. P. (2013). Precise and reliable gene expression via standard transcription and translation initiation elements. Nature Methods, 10(4), 354-360. https://doi.org/10.1038/nmeth.2404\n", + "\n", + "2. Kosuri, S., Goodman, D. B., Cambray, G., Mutalik, V. K., Gao, Y., Arkin, A. P., ... & Church, G. M. (2013). Composability of regulatory sequences controlling transcription and translation in Escherichia coli. Proceedings of the National Academy of Sciences, 110(34), 14024-14029. https://doi.org/10.1073/pnas.1301301110\n", + "\n", + "3. Bao, Z., Mudiraj, S., Torres-Delgado, D., & Vocadlo, D. J. (2018). A synthetic quantitative bacterial promoter device enabled by ligand-driven promoter binding. Nature Communications, 9(1), 1-10. https://doi.org/10.1038/s41467-018-06771-1\n", + "\n", + "4. Urtecho, G., Tripp, A. D., Insigne, K. D., Piasecki, S. K., & Smolke, C. D. (2019). Systematic construction of vectors for inducible or constitutive gene expression in Saccharomyces cerevisiae. Biotechnology and Bioengineering, 116(4), 905-920. https://doi.org/10.1002/bit.26923\n", + "\n", + "5. Brophy, J. A., & Voigt, C. A. (2014). Principles of genetic circuit design. Nature Methods, 11(5), 508-520. https://doi.org/10.1038/nmeth.2926\n", + "\n", + "6. Luo, B., Zhang, W., Wang, Z., Liu, Y., Zhao, X., Yu, H., & Lou, C. (2021). Directed evolution of synthetic promoter for high-level constitutive gene expression in Escherichia coli. Microbial Cell Factories, 20(1), 1-12. https://doi.org/10.1186/s12934-021-01532-5\n", + "\n", + "7. Blazeck, J., & Alper, H. S. (2013). Promoter engineering: Recent advances in controlling transcription at the most fundamental level. Biotechnology Journal, 8(1), 46-58. https://doi.org/10.1002/biot.201200120\n", + "\n", + "8. Meng, F., Dai, W., Zhen, Y., Guan, X., & Ma, Y. (2020). Design of synthetic promoters for tuning metabolic\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import gradio as gr\n", + "import tempfile\n", + "import zipfile\n", + "import os\n", + "\n", + "def run_agent(user_query):\n", + " try:\n", + " result = workflow.invoke({\"user_query\": user_query})\n", + " report = result.get(\"report\", \"No report generated.\")\n", + "\n", + " # Create a temp text file\n", + " with tempfile.NamedTemporaryFile(mode=\"w\", delete=False, suffix=\".txt\") as tmp_txt:\n", + " tmp_txt.write(report)\n", + " txt_path = tmp_txt.name\n", + "\n", + " # Zip the text file to force download\n", + " zip_path = txt_path.replace(\".txt\", \".zip\")\n", + " with zipfile.ZipFile(zip_path, 'w') as zipf:\n", + " zipf.write(txt_path, arcname=\"synthetic_promoter_report.txt\")\n", + "\n", + " return report, zip_path\n", + "\n", + " except Exception as e:\n", + " return f\"Error: {e}\", None\n", + "\n", + "iface = gr.Interface(\n", + " fn=run_agent,\n", + " inputs=gr.Textbox(label=\"Enter your promoter query or just enter the expression value\", placeholder=\"e.g., Develop a synthetic promoter with 40 expression value\"),\n", + " outputs=[\n", + " gr.Textbox(label=\"Agent Report\"),\n", + " gr.File(label=\"Download Report (ZIP)\")\n", + " ],\n", + " title=\"Synthetic Promoter Agent\",\n", + " description=\"This agent designs synthetic promoters and provides a report using a multi-step LLM pipeline.\"\n", + ")\n", + "\n", + "iface.launch(share=True)\n" + ], + "metadata": { + "id": "_1vxr-9kWgWr", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "bf33dc04-1473-40c7-ab62-c7b58e85744f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Colab notebook detected. To show errors in colab notebook, set debug=True in launch()\n", + "* Running on public URL: https://b9f2256e8096cfa512.gradio.live\n", + "\n", + "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "
" + ] + }, + "metadata": {} + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [] + }, + "metadata": {}, + "execution_count": 53 + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "HiqhatSQ_6zp" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/promoter/vocab_mapping.pkl b/promoter/vocab_mapping.pkl new file mode 100644 index 0000000..38901fc Binary files /dev/null and b/promoter/vocab_mapping.pkl differ