{
  "id": 435042,
  "title": "[0.58 No QuickGO] A brief overview of my solution in CAFA5 Kaggle competition",
  "url": "/competitions/cafa-5-protein-function-prediction/discussion/435042",
  "author_name": "Dmitriy Ershov",
  "post_date": "2023-08-27T18:53:59.912000",
  "votes": 19,
  "comment_count": 0,
  "views": 0,
  "content": "<p>First of all, I want to thank the organizers for this very important and interesting competition. It was very difficult and unusual (it's not every day you have to do multilabel classification for such a large number of classes), but that makes it even more interesting.</p>\n<h1>Data</h1>\n<h3>What worked for me</h3>\n<p>In my solution, I used data from embedding models such as the <strong>T5</strong> and <strong>ESM2 T33 650M</strong>. <strong>BERT</strong> showed much worse results, <strong>ESM2 3B</strong> gave more overfitting. </p>\n<p>I've used this in the following variations:</p>\n<ul>\n<li>Separately (only T5/only ESM)</li>\n<li>Combined (simple concatenation)</li>\n<li>Combined after PCA512</li>\n<li>Combined after feature selection based on RF features importances</li>\n</ul>\n<p>Also I have used data extracted with <em>ProteinAnalysis</em> from <em>Biopython</em> module, and amino acid count information.</p>\n<h3>What didn't worked for me</h3>\n<ul>\n<li>K-MER data</li>\n<li>TF-IDF</li>\n<li>tSVD for embeddings</li>\n<li>tSVD for labels</li>\n</ul>\n<h3>Targets</h3>\n<p>The models were trained on different target sets selected and sorted by frequency. <br>\nNo model has been trained on more than 2000 classes at a time if it is a neural network, and on 3100 classes if it is a <strong>Ridge</strong> model (due to RAM limitations on the :D). But NNs showed better results with fewer classes (1000-1500).<br>\nAlso as we have a lot of classes, the clustering of targets also performed well. I used K-means.</p>\n<h1>Modeling part</h1>\n<h3>Models</h3>\n<p>First I tried many <em>sklearn</em>, <em>tensorflow</em> and <em>pytorch</em> models, but after that I left only <strong>Ridge</strong> from <em>sklearn</em>, and these <em>pytorch</em> architectures:</p>\n<ul>\n<li>FCNN</li>\n<li>NN with both conv and FC encoders</li>\n<li>Residual FCNN</li>\n<li>Residual CNN</li>\n<li>All variations mentioned above, but with 3 heads (one head for one subontology)</li>\n</ul>\n<p>I tried using a metamodel for stacking, but it didn't work out well.</p>\n<h3>Training</h3>\n<ul>\n<li>Training only on samples containing all subontologies</li>\n<li>For data splitting I used <strong>MultilabelStratifiedKFold</strong> with 4/5/6 folds</li>\n<li><strong>Quantile Transformer</strong> &amp; <strong>MinMax Scaler</strong> (0-1) from <em>sklearn</em> as preprocessing</li>\n<li>Adam optimizer</li>\n<li>MacroF1 metric for best model choosing</li>\n<li>MacroF1Loss</li>\n<li>Pseudo-labeling</li>\n</ul>\n<p>I tried BCE/Focal losses, but F1 performed much better for me (especially after thresholds calculation).<br>\nAlso I wrote custom SampledF1Loss. The main idea is to select a random set of targets (of a given range, e.g. from 20 to 80%) from each batches, and compute the loss only on them. This increases the speed, and also increases the variety of gradients.<br>\nLion optimizer, Sophia, augmentations also didn't work good enough.</p>\n<h3>Postprocessing</h3>\n<ol>\n<li>For each model I calculated best thresholds based on F1 metric (I have calculated it for each class, not for each subontology).</li>\n<li>For submission I used values only exceeding the threshold for each trained class.</li>\n<li>Blended all submissions with pandas (group by ID &amp; class, taking an averaged value, taking the top-50 highest values for each protein ID).</li>\n</ol>\n<p>Taking the N-top values is important, because I've noticed that models don't realize how many terms a protein actually has. I've tried to make regression on the terms count, and the results were awful.</p>",
  "messages": [
    {
      "id": 2411640,
      "postDate": "2023-08-27T18:53:59.913Z",
      "content": "<p>First of all, I want to thank the organizers for this very important and interesting competition. It was very difficult and unusual (it's not every day you have to do multilabel classification for such a large number of classes), but that makes it even more interesting.</p>\n<h1>Data</h1>\n<h3>What worked for me</h3>\n<p>In my solution, I used data from embedding models such as the <strong>T5</strong> and <strong>ESM2 T33 650M</strong>. <strong>BERT</strong> showed much worse results, <strong>ESM2 3B</strong> gave more overfitting. </p>\n<p>I've used this in the following variations:</p>\n<ul>\n<li>Separately (only T5/only ESM)</li>\n<li>Combined (simple concatenation)</li>\n<li>Combined after PCA512</li>\n<li>Combined after feature selection based on RF features importances</li>\n</ul>\n<p>Also I have used data extracted with <em>ProteinAnalysis</em> from <em>Biopython</em> module, and amino acid count information.</p>\n<h3>What didn't worked for me</h3>\n<ul>\n<li>K-MER data</li>\n<li>TF-IDF</li>\n<li>tSVD for embeddings</li>\n<li>tSVD for labels</li>\n</ul>\n<h3>Targets</h3>\n<p>The models were trained on different target sets selected and sorted by frequency. <br>\nNo model has been trained on more than 2000 classes at a time if it is a neural network, and on 3100 classes if it is a <strong>Ridge</strong> model (due to RAM limitations on the :D). But NNs showed better results with fewer classes (1000-1500).<br>\nAlso as we have a lot of classes, the clustering of targets also performed well. I used K-means.</p>\n<h1>Modeling part</h1>\n<h3>Models</h3>\n<p>First I tried many <em>sklearn</em>, <em>tensorflow</em> and <em>pytorch</em> models, but after that I left only <strong>Ridge</strong> from <em>sklearn</em>, and these <em>pytorch</em> architectures:</p>\n<ul>\n<li>FCNN</li>\n<li>NN with both conv and FC encoders</li>\n<li>Residual FCNN</li>\n<li>Residual CNN</li>\n<li>All variations mentioned above, but with 3 heads (one head for one subontology)</li>\n</ul>\n<p>I tried using a metamodel for stacking, but it didn't work out well.</p>\n<h3>Training</h3>\n<ul>\n<li>Training only on samples containing all subontologies</li>\n<li>For data splitting I used <strong>MultilabelStratifiedKFold</strong> with 4/5/6 folds</li>\n<li><strong>Quantile Transformer</strong> &amp; <strong>MinMax Scaler</strong> (0-1) from <em>sklearn</em> as preprocessing</li>\n<li>Adam optimizer</li>\n<li>MacroF1 metric for best model choosing</li>\n<li>MacroF1Loss</li>\n<li>Pseudo-labeling</li>\n</ul>\n<p>I tried BCE/Focal losses, but F1 performed much better for me (especially after thresholds calculation).<br>\nAlso I wrote custom SampledF1Loss. The main idea is to select a random set of targets (of a given range, e.g. from 20 to 80%) from each batches, and compute the loss only on them. This increases the speed, and also increases the variety of gradients.<br>\nLion optimizer, Sophia, augmentations also didn't work good enough.</p>\n<h3>Postprocessing</h3>\n<ol>\n<li>For each model I calculated best thresholds based on F1 metric (I have calculated it for each class, not for each subontology).</li>\n<li>For submission I used values only exceeding the threshold for each trained class.</li>\n<li>Blended all submissions with pandas (group by ID &amp; class, taking an averaged value, taking the top-50 highest values for each protein ID).</li>\n</ol>\n<p>Taking the N-top values is important, because I've noticed that models don't realize how many terms a protein actually has. I've tried to make regression on the terms count, and the results were awful.</p>",
      "rawMarkdown": "First of all, I want to thank the organizers for this very important and interesting competition. It was very difficult and unusual (it's not every day you have to do multilabel classification for such a large number of classes), but that makes it even more interesting.\n\n# Data \n\n### What worked for me\n\nIn my solution, I used data from embedding models such as the **T5** and **ESM2 T33 650M**. **BERT** showed much worse results, **ESM2 3B** gave more overfitting. \n\nI've used this in the following variations:\n- Separately (only T5/only ESM)\n- Combined (simple concatenation)\n- Combined after PCA512\n- Combined after feature selection based on RF features importances\n\nAlso I have used data extracted with *ProteinAnalysis* from *Biopython* module, and amino acid count information.\n\n### What didn't worked for me\n\n- K-MER data\n- TF-IDF\n- tSVD for embeddings\n- tSVD for labels\n\n### Targets\n\nThe models were trained on different target sets selected and sorted by frequency. \nNo model has been trained on more than 2000 classes at a time if it is a neural network, and on 3100 classes if it is a **Ridge** model (due to RAM limitations on the :D). But NNs showed better results with fewer classes (1000-1500).\nAlso as we have a lot of classes, the clustering of targets also performed well. I used K-means.\n\n# Modeling part\n\n### Models\n\nFirst I tried many *sklearn*, *tensorflow* and *pytorch* models, but after that I left only **Ridge** from *sklearn*, and these *pytorch* architectures:\n- FCNN\n- NN with both conv and FC encoders\n- Residual FCNN\n- Residual CNN\n- All variations mentioned above, but with 3 heads (one head for one subontology)\n\nI tried using a metamodel for stacking, but it didn't work out well.\n\n### Training\n\n- Training only on samples containing all subontologies\n- For data splitting I used **MultilabelStratifiedKFold** with 4/5/6 folds\n- **Quantile Transformer** & **MinMax Scaler** (0-1) from *sklearn* as preprocessing\n- Adam optimizer\n- MacroF1 metric for best model choosing\n- MacroF1Loss\n- Pseudo-labeling\n\nI tried BCE/Focal losses, but F1 performed much better for me (especially after thresholds calculation).\nAlso I wrote custom SampledF1Loss. The main idea is to select a random set of targets (of a given range, e.g. from 20 to 80%) from each batches, and compute the loss only on them. This increases the speed, and also increases the variety of gradients.\nLion optimizer, Sophia, augmentations also didn't work good enough.\n\n### Postprocessing\n\n1. For each model I calculated best thresholds based on F1 metric (I have calculated it for each class, not for each subontology).\n2. For submission I used values only exceeding the threshold for each trained class.\n3. Blended all submissions with pandas (group by ID & class, taking an averaged value, taking the top-50 highest values for each protein ID).\n\nTaking the N-top values is important, because I've noticed that models don't realize how many terms a protein actually has. I've tried to make regression on the terms count, and the results were awful.",
      "votes": 19
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "2411640": "First of all, I want to thank the organizers for this very important and interesting competition. It was very difficult and unusual (it's not every day you have to do multilabel classification for such a large number of classes), but that makes it even more interesting.\n\n# Data \n\n### What worked for me\n\nIn my solution, I used data from embedding models such as the **T5** and **ESM2 T33 650M**. **BERT** showed much worse results, **ESM2 3B** gave more overfitting. \n\nI've used this in the following variations:\n- Separately (only T5/only ESM)\n- Combined (simple concatenation)\n- Combined after PCA512\n- Combined after feature selection based on RF features importances\n\nAlso I have used data extracted with *ProteinAnalysis* from *Biopython* module, and amino acid count information.\n\n### What didn't worked for me\n\n- K-MER data\n- TF-IDF\n- tSVD for embeddings\n- tSVD for labels\n\n### Targets\n\nThe models were trained on different target sets selected and sorted by frequency. \nNo model has been trained on more than 2000 classes at a time if it is a neural network, and on 3100 classes if it is a **Ridge** model (due to RAM limitations on the :D). But NNs showed better results with fewer classes (1000-1500).\nAlso as we have a lot of classes, the clustering of targets also performed well. I used K-means.\n\n# Modeling part\n\n### Models\n\nFirst I tried many *sklearn*, *tensorflow* and *pytorch* models, but after that I left only **Ridge** from *sklearn*, and these *pytorch* architectures:\n- FCNN\n- NN with both conv and FC encoders\n- Residual FCNN\n- Residual CNN\n- All variations mentioned above, but with 3 heads (one head for one subontology)\n\nI tried using a metamodel for stacking, but it didn't work out well.\n\n### Training\n\n- Training only on samples containing all subontologies\n- For data splitting I used **MultilabelStratifiedKFold** with 4/5/6 folds\n- **Quantile Transformer** & **MinMax Scaler** (0-1) from *sklearn* as preprocessing\n- Adam optimizer\n- MacroF1 metric for best model choosing\n- MacroF1Loss\n- Pseudo-labeling\n\nI tried BCE/Focal losses, but F1 performed much better for me (especially after thresholds calculation).\nAlso I wrote custom SampledF1Loss. The main idea is to select a random set of targets (of a given range, e.g. from 20 to 80%) from each batches, and compute the loss only on them. This increases the speed, and also increases the variety of gradients.\nLion optimizer, Sophia, augmentations also didn't work good enough.\n\n### Postprocessing\n\n1. For each model I calculated best thresholds based on F1 metric (I have calculated it for each class, not for each subontology).\n2. For submission I used values only exceeding the threshold for each trained class.\n3. Blended all submissions with pandas (group by ID & class, taking an averaged value, taking the top-50 highest values for each protein ID).\n\nTaking the N-top values is important, because I've noticed that models don't realize how many terms a protein actually has. I've tried to make regression on the terms count, and the results were awful."
  }
}