<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Santosh Patapati</title>
<link>https://soontosh.github.io/</link>
<atom:link href="https://soontosh.github.io/index.xml" rel="self" type="application/rss+xml"/>
<description>A blog where I share whatever I&#39;m thinking about or interested in</description>
<generator>quarto-1.8.27</generator>
<lastBuildDate>Sat, 31 Jan 2026 06:00:00 GMT</lastBuildDate>
<item>
  <title>Multi-Task Learning</title>
  <dc:creator>Santosh Patapati</dc:creator>
  <link>https://soontosh.github.io/blog-mtl/</link>
  <description><![CDATA[ 




<section id="introduction" class="level1">
<h1>Introduction</h1>
<div id="fig-intro-MTL" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Illustration of multitasking">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-intro-MTL-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://soontosh.github.io/blog-mtl/multitasking.jpg" class="img-fluid figure-img" style="width:70.0%" alt="Illustration of multitasking">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-intro-MTL-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Multitasking may be difficult for us, but it can make machine learning models smarter. <a href="https://www.meetingdecisions.com/">Image courtesy of decisions</a>
</figcaption>
</figure>
</div>
<p>A couple of years ago, I was working on a music recommendation system for a small contract. The system weighed if somebody would click on a song and if they would actually finish listening to it. To integrate Machine Learning (ML) into such a system, the seemingly obvious answer would be to train two separate models to handle each of these tasks. But when you’re working with a small set of data–especially on a more niche task like this–it can simply be impossible to train two models from the ground up that are actually accurate. That’s when I learned about <strong>Multi-Task Learning (MTL)</strong>.</p>
<p>MTL has become one of the most interesting subfields of ML for me. Instead of training separate models for separate tasks, you train one model that learns to do multiple related things simultaneously. The model shares most of its parameters across tasks, only splitting apart near the end to make predictions on a task-by-task basis (see the visualization below).</p>
<div id="fig-mtl-arch" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Hard parameter sharing architecture for multi-task learning">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-arch-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://soontosh.github.io/blog-mtl/mtl_hard.png" class="img-fluid figure-img" style="width:75.0%" alt="Hard parameter sharing architecture for multi-task learning">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-arch-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Hard Parameter Sharing: The model learns a shared representation before branching out for specific tasks. <a href="https://ruder.io/multi-task/index.html#softparametersharing">Image courtesy of ruder.io</a>
</figcaption>
</figure>
</div>
<p>It sounds a little weird. Wouldn’t models perform better if you trained them with a focus on a particular task? Doesn’t training on multiple tasks just confuse a model?</p>
<p>It turns out that, when you are working on solving tasks that are closely related, using MTL can greatly improve performance on both (or all 10) tasks! This is because similar tasks often depend on the same underlying patterns. A model that has been forced to solve both tasks has to learn these shared patterns. MTL can essentially act as a form of regularization<sup>1</sup>. It can’t “cheat” (or overfit) by memorizing features, and it is encouraged to learn the deeper meaning behind given inputs.</p>
<div id="fig-dog-mtl" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Dog saying 'MTL'">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dog-mtl-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://soontosh.github.io/blog-mtl/dog-tricks.png" class="img-fluid figure-img" style="width:75.0%" alt="Dog saying 'MTL'">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dog-mtl-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: It can help to think of ML models like dogs when understanding Multi-Task Learning (MTL). Image courtesy of ChatGPT
</figcaption>
</figure>
</div>
<p>Think about it like teaching a dog a bunch of tricks at the same time. Naturally, it is a lot easier to teach a dog their fourth or fifth trick than to teach their first or second trick. This is because the dog has learned the basic underlying patterns or skills that can be transferred across all tricks. Particularly, the ability to pay attention and control their impulses.</p>
<p>If a dog were able to practice multiple commands together, the dog gets better at that underlying skill of focus and self-control.</p>
<div id="fig-tasks-fighting" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Tasks fighting">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-tasks-fighting-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://soontosh.github.io/blog-mtl/tasks-fighting.png" class="img-fluid figure-img" style="width:75.0%" alt="Tasks fighting">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-tasks-fighting-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: Tasks can conflict, causing them to “fight” for better performance!
</figcaption>
</figure>
</div>
<p>But, like all things in ML, multi-task learning is a lot harder than it looks.</p>
<p>The biggest problem in this field is when tasks fight each other. The model gets worse at both compared to training them separately. Sometimes one task dominates the training and the other barely learns anything. Sometimes everything works fine for 50 epochs and then suddenly collapses. This concept is known as negative transfer.</p>
<p>This was frustrating for me because, once you understand it, the core idea feels so intuitive. Of course related tasks should help each other. Of course sharing knowledge would make the learning more efficient. But making it work in practice requires understanding what’s happening internally in these models.</p>
<p>In this article, we’ll look at when multi-task learning helps, when it fails, and what you can do to make it work. It does have its struggles, but it remains one of the most elegant ideas in machine learning.</p>
</section>
<section id="defining-multi-task-learning" class="level1">
<h1>Defining Multi-Task Learning</h1>
<p>Let’s start with the simplest possible definition.</p>
<blockquote class="blockquote">
<p>Multi-task learning is when you train a single model to solve multiple related problems at the same time using shared internal representations.</p>
</blockquote>
<p>That’s it. But we should try and understand what that really means 😊</p>
<section id="basic-setup" class="level2">
<h2 class="anchored" data-anchor-id="basic-setup">Basic Setup</h2>
<p>Say you have three tasks: <em>Task A</em>, <em>Task B</em>, and <em>Task C</em>. In traditional machine learning, you’d train three separate models.</p>
<ul>
<li>Model A would learn from data labeled for Task A</li>
<li>Model B would learn from data labeled for Task B</li>
<li>Model C would learn from data labeled for Task C</li>
</ul>
<div class="cell" data-layout-align="center">
<div class="cell-output-display">
<div id="fig-mtl-separate-models" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-separate-models-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mtl-separate-models">flowchart LR
  I[(Input x)]

  subgraph A["Model A (θ_A)"]
    A1[Encoder / Layers] --&gt; A2[Head A] --&gt; OA[(ŷ_A)]
  end
  subgraph B["Model B (θ_B)"]
    B1[Encoder / Layers] --&gt; B2[Head B] --&gt; OB[(ŷ_B)]
  end
  subgraph C["Model C (θ_C)"]
    C1[Encoder / Layers] --&gt; C2[Head C] --&gt; OC[(ŷ_C)]
  end

  I --&gt; A1
  I --&gt; B1
  I --&gt; C1

  style A fill:#f2f2f2,stroke:#c9c9c9,color:#222
  style B fill:#f2f2f2,stroke:#c9c9c9,color:#222
  style C fill:#f2f2f2,stroke:#c9c9c9,color:#222
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-separate-models-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: The traditional approach is to use single task learning. Three separate models are trained independently for Tasks A, B, and C. Diagram courtesy of me.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Each model has its own parameters (the weights and connections inside the neural network). They don’t talk to each other. They don’t share anything.</p>
<p>In Multi-task learning, you train one model that has two kinds of parameters. The first kind is Shared Parameters, written as <img src="https://latex.codecogs.com/png.latex?%7B%5Ctheta%7D_shared">. These are parameters used by all tasks. They serve as the common foundation for the whole model.</p>
<p>The second kind of parameter is task-specific parameters, written as <img src="https://latex.codecogs.com/png.latex?(%7B%5Ctheta%7D_A,%20%7B%5Ctheta%7D_B,%20%7B%5Ctheta%7D_C)">. These are unique to each task</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div id="fig-mtl-shared-branch" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-shared-branch-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mtl-shared-branch">flowchart LR
  I[(Input x)]

  subgraph S["Shared Trunk (θ_shared)"]
    S1[Shared Encoder / Layers] --&gt; S2[Shared Representation h]
  end

  subgraph TA["Task A Head (θ_A)"]
    A1[Head A] --&gt; OA[(ŷ_A)]
  end
  subgraph TB["Task B Head (θ_B)"]
    B1[Head B] --&gt; OB[(ŷ_B)]
  end
  subgraph TC["Task C Head (θ_C)"]
    C1[Head C] --&gt; OC[(ŷ_C)]
  end

  I --&gt; S1
  S2 --&gt; A1
  S2 --&gt; B1
  S2 --&gt; C1

  style S fill:#eef6ff,stroke:#8fb7e8,color:#1f3a5f
  style TA fill:#f2f2f2,stroke:#c9c9c9,color:#222
  style TB fill:#f2f2f2,stroke:#c9c9c9,color:#222
  style TC fill:#f2f2f2,stroke:#c9c9c9,color:#222
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-shared-branch-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;6: Multi-task learning with shared parameters and task-specific heads. Diagram courtesy of me.
</figcaption>
</figure>
</div>
</div>
</div>
<p>The model processes input through the shared layers first. These layers learn features that help with all the tasks. Then the network splits, and each task gets its own set of final layers to make its specific prediction.</p>
</section>
<section id="optimization" class="level2">
<h2 class="anchored" data-anchor-id="optimization">Optimization</h2>
<p>We’re going to get slightly more formal here (but trust me when I say it’s simpler than it looks).</p>
<p>When you train a model for a single task, you’re minimizing one loss function. The loss measures how wrong your predictions are. Lower loss essentially means better predicitons.</p>
<p>When you train a multi-task model, you’re minimizing a combined loss that includes all your tasks.</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmin_%7B%5Ctheta_%7B%5Ctext%7Bshared%7D%7D,%20%5Ctheta_A,%20%5Ctheta_B,%20%5Ctheta_C%7D%20%5Cleft%5B%20w_A%20%5Ccdot%20%5Cmathcal%7BL%7D_A%20+%20w_B%20%5Ccdot%20%5Cmathcal%7BL%7D_B%20+%20w_C%20%5Ccdot%20%5Cmathcal%7BL%7D_C%20%5Cright%5D"></p>
<p>Here, <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BL%7D_A">, <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BL%7D_B">, <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BL%7D_C"> are the individual loss functions for each task. <img src="https://latex.codecogs.com/png.latex?w_A">, <img src="https://latex.codecogs.com/png.latex?w_B">, <img src="https://latex.codecogs.com/png.latex?w_C"> are weights that control how much each task matters (we’ll come back to why these are important later).</p>
<p>You’re trying to find one set of shared parameters that works well for all three tasks simultaneously</p>
</section>
<section id="another-way-of-thinking-about-it" class="level2">
<h2 class="anchored" data-anchor-id="another-way-of-thinking-about-it">Another Way of Thinking About It</h2>
<p>In case that was confusing, there’s another way we can think about this process that might be more intuitive for you.</p>
<p>Every machine learning model makes assumptions. It has to. There are infinite possible patterns in data, and the model needs some way to decide which patterns to pay attention to.</p>
<p>These assumptions are called inductive biases<sup>2</sup>. They guide the model toward certain kinds of solutions.</p>
<p>When learning with a single task, the main inductive bias comes from your model architecture and regularization techniques. The model assumes that simpler explanations are better, that certain structures matter, etc.</p>
<p>In multi-task learning, you add another inductive bias. That is, the assumption that your tasks share common structure. The model is told that whatever it learns has to be useful for Task A <em>AND</em> Task B <em>AND</em> Task c.</p>
<p>This is a really helpful constraint. It forces the model to pick up on features that generalize well. If a pattern only helps with Task A but hurts Task B, then the model can’t rely on it in the shared layers. That’s because, if it does, then the loss goes up, and the model is focused on minimizing that loss.</p>
<div class="cell" data-layout-align="center">
<div class="cell-output-display">
<div id="fig-mtl-hypothesis-space" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-hypothesis-space-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mtl-hypothesis-space">flowchart LR
  H[All possible models / hypotheses]

  subgraph ST["Single-task (Task A only)"]
    SA[Many models can fit Task A]
    SQ["Includes real patterns and quirks of dataset (overfitting)"]
  end

  subgraph MT["Multi-task (Task A and Task B)"]
    MA[Models that fit Task A]
    MB[Models that fit Task B]
    INT[Overlap: models that fit both tasks]
    GEN[Higher chance of learning shared structure]
  end

  H --&gt; SA
  SA --&gt; SQ

  H --&gt; MA
  H --&gt; MB
  MA --&gt; INT
  MB --&gt; INT
  INT --&gt; GEN

  style ST fill:#fff5e8,stroke:#e4b46a,color:#3f2b0c
  style MT fill:#eef6ff,stroke:#8fb7e8,color:#1f3a5f
  style INT fill:#d7ecff,stroke:#4f88c6,color:#123a63
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-hypothesis-space-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;7: A model of multi-task learning based on inductive bias. Requiring one model to satisfy multiple tasks forces it to select features that fit both tasks’ criteria. This causes it to learn more robust and important features. Diagram courtesy of me.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Think of it this way. When you train on Task A alone, there are many possible models that could achieve good performance (i.e., low loss). Some of these possible models learn actual patterns. Some of them just memorize things unique to your training data. Of course, the former is much better. The latter will often lead to overfitting<sup>3</sup>.</p>
<p>When you train on Task A and Task B together, far fewer models will work well for both. The methods that survive both are the ones that learned real underlying patterns. That is, something fundamental enough that can transfer across both tasks. It is a lot harder to overfit to the training data (i.e., memorize quirks that are specific to the training set) when you’re focusing on separate tasks.</p>
<p>Hopefully this second perspective is a lot more intuitive and easier to understand. This is how I first grasped MTL and the beauty behind it. I call this the “Inductive Bias Perspective”</p>
</section>
</section>
<section id="examples-of-where-it-helps" class="level1">
<h1>Examples of Where it Helps</h1>
<p>I’m going to show you a simple example where MTL clearly outperforms single task learning. We’ll use a simple problem where we control how related the tasks are. This lets us see the effect without all the noise of a real-world dataset. Since the point of this blog post is to learn, this should be enough for our purposes.</p>
<section id="setting-up-two-related-tasks" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-two-related-tasks">Setting Up Two Related Tasks</h2>
<p>You have data where each input has some hidden structure. Two tasks both depend on parts of that hidden structure in slightly different ways.</p>
<p>Our scenario is as follows: - Input: Some features <img src="https://latex.codecogs.com/png.latex?x"> - Hidden truth: There’s a shared underlying factor <img src="https://latex.codecogs.com/png.latex?z_shared"> and two private factors <img src="https://latex.codecogs.com/png.latex?z_A"> and <img src="https://latex.codecogs.com/png.latex?z_B">. - Task A: Predict <img src="https://latex.codecogs.com/png.latex?y_A%20=%20z_%7B%5Ctext%7Bshared%7D%7D%20+%20z_A%20+%20%5Ctext%7Bnoise%7D"> - Task B: Predict <img src="https://latex.codecogs.com/png.latex?y_B%20=%20z_%7B%5Ctext%7Bshared%7D%7D%20+%20z_B%20+%20%5Ctext%7Bnoise%7D"></p>
<p>Both tasks depend on the same shared factor. If a model can learn to extract <img src="https://latex.codecogs.com/png.latex?z_%7B%5Ctext%7Bshared%7D%7D">, it helps with both tasks. We can generate the data and see what happens using Python and PyTorch.</p>
<div id="187a3170" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.nn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> nn</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.optim <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> optim</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> plotly.subplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_subplots</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set random seeds for reproducibility</span></span>
<span id="cb1-9">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb1-10">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate synthetic data</span></span>
<span id="cb1-13">n_samples <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb1-14">n_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span></span>
<span id="cb1-15"></span>
<span id="cb1-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create input features</span></span>
<span id="cb1-17">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n_samples, n_features)</span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create hidden shared and private factors</span></span>
<span id="cb1-20">z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Shared underlying pattern</span></span>
<span id="cb1-21">z_private_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task A's private pattern</span></span>
<span id="cb1-22">z_private_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task B's private pattern</span></span>
<span id="cb1-23"></span>
<span id="cb1-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create targets for a strongly related-task setting:</span></span>
<span id="cb1-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># both tasks are mostly driven by the same shared factor.</span></span>
<span id="cb1-26">y_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> z_private_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb1-27">y_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> z_private_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb1-28"></span>
<span id="cb1-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Split into train and test</span></span>
<span id="cb1-30">split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span></span>
<span id="cb1-31">X_train, X_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:split], X[split:]</span>
<span id="cb1-32">y_A_train, y_A_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_A[:split], y_A[split:]</span>
<span id="cb1-33">y_B_train, y_B_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_B[:split], y_B[split:]</span>
<span id="cb1-34"></span>
<span id="cb1-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Convert to PyTorch tensors</span></span>
<span id="cb1-36">X_train_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X_train)</span>
<span id="cb1-37">X_test_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X_test)</span>
<span id="cb1-38">y_A_train_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A_train).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-39">y_A_test_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A_test).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-40">y_B_train_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B_train).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-41">y_B_test_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B_test).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-42"></span>
<span id="cb1-43"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Training samples: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(X_train)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb1-44"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Test samples: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(X_test)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb1-45"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Input features: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n_features<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Training samples: 800
Test samples: 200
Input features: 20</code></pre>
</div>
</div>
</section>
<section id="single-task-models" class="level2">
<h2 class="anchored" data-anchor-id="single-task-models">Single Task Models</h2>
<p>First let’s train two separate models. Each one only sees data for its own task.</p>
<div id="ac7829ce" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> SingleTaskModel(nn.Module):</span>
<span id="cb3-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, input_size, hidden_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>):</span>
<span id="cb3-3">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">super</span>().<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>()</span>
<span id="cb3-4">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.network <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Sequential(</span>
<span id="cb3-5">            nn.Linear(input_size, hidden_size),</span>
<span id="cb3-6">            nn.ReLU(),</span>
<span id="cb3-7">            nn.Linear(hidden_size, hidden_size),</span>
<span id="cb3-8">            nn.ReLU(),</span>
<span id="cb3-9">            nn.Linear(hidden_size, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-10">        )</span>
<span id="cb3-11">    </span>
<span id="cb3-12">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> forward(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, x):</span>
<span id="cb3-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.network(x)</span>
<span id="cb3-14"></span>
<span id="cb3-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_single_task(model, X_train, y_train, X_test, y_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>):</span>
<span id="cb3-16">    optimizer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optim.Adam(model.parameters(), lr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb3-17">    criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.MSELoss()</span>
<span id="cb3-18">    </span>
<span id="cb3-19">    train_losses <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb3-20">    test_losses <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb3-21">    </span>
<span id="cb3-22">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> epoch <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs):</span>
<span id="cb3-23">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Training</span></span>
<span id="cb3-24">        model.train()</span>
<span id="cb3-25">        optimizer.zero_grad()</span>
<span id="cb3-26">        predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_train)</span>
<span id="cb3-27">        loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(predictions, y_train)</span>
<span id="cb3-28">        loss.backward()</span>
<span id="cb3-29">        optimizer.step()</span>
<span id="cb3-30">        train_losses.append(loss.item())</span>
<span id="cb3-31">        </span>
<span id="cb3-32">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Testing</span></span>
<span id="cb3-33">        model.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">eval</span>()</span>
<span id="cb3-34">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad():</span>
<span id="cb3-35">            test_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_test)</span>
<span id="cb3-36">            test_loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(test_pred, y_test)</span>
<span id="cb3-37">            test_losses.append(test_loss.item())</span>
<span id="cb3-38">    </span>
<span id="cb3-39">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> train_losses, test_losses</span>
<span id="cb3-40"></span>
<span id="cb3-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train separate models (fixed init seeds for fair comparison)</span></span>
<span id="cb3-42">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1100</span>)</span>
<span id="cb3-43">model_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(n_features)</span>
<span id="cb3-44">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1200</span>)</span>
<span id="cb3-45">model_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(n_features)</span>
<span id="cb3-46"></span>
<span id="cb3-47"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Training model for Task A"</span>)</span>
<span id="cb3-48">train_A, test_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(model_A, X_train_t, y_A_train_t, X_test_t, y_A_test_t)</span>
<span id="cb3-49"></span>
<span id="cb3-50"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Training model for Task B"</span>)</span>
<span id="cb3-51">train_B, test_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(model_B, X_train_t, y_B_train_t, X_test_t, y_B_test_t)</span>
<span id="cb3-52"></span>
<span id="cb3-53"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Final test MSE on Task A (single): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-54"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Final test MSE on Task B (single): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Training model for Task A
Training model for Task B

Final test MSE on Task A (single): 0.2845
Final test MSE on Task B (single): 0.3471</code></pre>
</div>
</div>
</section>
<section id="multi-task-models" class="level2">
<h2 class="anchored" data-anchor-id="multi-task-models">Multi-Task Models</h2>
<p>Now let’s build one model that learns both tasks together. It has shared layers that both tasks use. It then splits into heads for each task.</p>
<div id="782c1f21" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MultiTaskModel(nn.Module):</span>
<span id="cb5-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, input_size, hidden_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>):</span>
<span id="cb5-3">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">super</span>().<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>()</span>
<span id="cb5-4">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Shared layers</span></span>
<span id="cb5-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Sequential(</span>
<span id="cb5-6">            nn.Linear(input_size, hidden_size),</span>
<span id="cb5-7">            nn.ReLU(),</span>
<span id="cb5-8">            nn.Linear(hidden_size, hidden_size),</span>
<span id="cb5-9">            nn.ReLU()</span>
<span id="cb5-10">        )</span>
<span id="cb5-11">        </span>
<span id="cb5-12">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task heads</span></span>
<span id="cb5-13">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.head_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Linear(hidden_size, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb5-14">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.head_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Linear(hidden_size, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb5-15">    </span>
<span id="cb5-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> forward(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, x):</span>
<span id="cb5-17">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Everyone goes through shared layers first</span></span>
<span id="cb5-18">        shared_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.shared(x)</span>
<span id="cb5-19">        </span>
<span id="cb5-20">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We split to make predictions for each task</span></span>
<span id="cb5-21">        out_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.head_A(shared_features)</span>
<span id="cb5-22">        out_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.head_B(shared_features)</span>
<span id="cb5-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> out_A, out_B</span>
<span id="cb5-24"></span>
<span id="cb5-25"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_multi_task(model, X_train, y_A_train, y_B_train, X_test, y_A_test, y_B_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>):</span>
<span id="cb5-26">    optimizer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optim.Adam(model.parameters(), lr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb5-27">    criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.MSELoss()</span>
<span id="cb5-28">    </span>
<span id="cb5-29">    train_losses_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-30">    train_losses_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-31">    test_losses_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-32">    test_losses_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-33">    </span>
<span id="cb5-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> epoch <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs):</span>
<span id="cb5-35">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Training</span></span>
<span id="cb5-36">        model.train()</span>
<span id="cb5-37">        optimizer.zero_grad()</span>
<span id="cb5-38">        pred_A, pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_train)</span>
<span id="cb5-39">        </span>
<span id="cb5-40">        loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_A, y_A_train)</span>
<span id="cb5-41">        loss_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_B, y_B_train)</span>
<span id="cb5-42">        </span>
<span id="cb5-43">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Average keeps gradient scale comparable to single-task training</span></span>
<span id="cb5-44">        total_loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> loss_B) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb5-45">        total_loss.backward()</span>
<span id="cb5-46">        optimizer.step()</span>
<span id="cb5-47">        </span>
<span id="cb5-48">        train_losses_A.append(loss_A.item())</span>
<span id="cb5-49">        train_losses_B.append(loss_B.item())</span>
<span id="cb5-50">        </span>
<span id="cb5-51">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Testing</span></span>
<span id="cb5-52">        model.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">eval</span>()</span>
<span id="cb5-53">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad():</span>
<span id="cb5-54">            test_pred_A, test_pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_test)</span>
<span id="cb5-55">            test_loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(test_pred_A, y_A_test)</span>
<span id="cb5-56">            test_loss_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(test_pred_B, y_B_test)</span>
<span id="cb5-57">            test_losses_A.append(test_loss_A.item())</span>
<span id="cb5-58">            test_losses_B.append(test_loss_B.item())</span>
<span id="cb5-59">    </span>
<span id="cb5-60">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> train_losses_A, train_losses_B, test_losses_A, test_losses_B</span>
<span id="cb5-61"></span>
<span id="cb5-62"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train MTL model (fixed init seed for fair comparison)</span></span>
<span id="cb5-63">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1300</span>)</span>
<span id="cb5-64">model_mtl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb5-65"></span>
<span id="cb5-66"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Training multi-task model..."</span>)</span>
<span id="cb5-67">train_mtl_A, train_mtl_B, test_mtl_A, test_mtl_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_multi_task(</span>
<span id="cb5-68">    model_mtl, X_train_t, y_A_train_t, y_B_train_t, X_test_t, y_A_test_t, y_B_test_t</span>
<span id="cb5-69">)</span>
<span id="cb5-70"></span>
<span id="cb5-71"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Final test MSE on Task A (multi-task): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_mtl_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-72"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Final test MSE on Task B (multi-task): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_mtl_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-73"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Improvement on Task A: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>((test_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> test_mtl_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> test_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb5-74"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Improvement on Task B: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>((test_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> test_mtl_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> test_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Training multi-task model...

Final test MSE on Task A (multi-task): 0.2593
Final test MSE on Task B (multi-task): 0.3167

Improvement on Task A: 8.9%
Improvement on Task B: 8.8%</code></pre>
</div>
</div>
</section>
<section id="results" class="level2">
<h2 class="anchored" data-anchor-id="results">Results</h2>
<div id="cell-fig-mtl-comparison" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create interactive comparison plot</span></span>
<span id="cb7-2">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_subplots(</span>
<span id="cb7-3">    rows<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, cols<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb7-4">    subplot_titles<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task A Test Loss'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task B Test Loss'</span>)</span>
<span id="cb7-5">)</span>
<span id="cb7-6"></span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task A comparison</span></span>
<span id="cb7-8">fig.add_trace(</span>
<span id="cb7-9">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_A, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task A'</span>, </span>
<span id="cb7-10">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)),</span>
<span id="cb7-11">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb7-12">)</span>
<span id="cb7-13">fig.add_trace(</span>
<span id="cb7-14">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_mtl_A, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task A'</span>, </span>
<span id="cb7-15">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#3498db'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)),</span>
<span id="cb7-16">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb7-17">)</span>
<span id="cb7-18"></span>
<span id="cb7-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task B comparison</span></span>
<span id="cb7-20">fig.add_trace(</span>
<span id="cb7-21">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_B, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task B'</span>, </span>
<span id="cb7-22">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>)),</span>
<span id="cb7-23">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb7-24">)</span>
<span id="cb7-25">fig.add_trace(</span>
<span id="cb7-26">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_mtl_B, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task B'</span>, </span>
<span id="cb7-27">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#3498db'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>)),</span>
<span id="cb7-28">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb7-29">)</span>
<span id="cb7-30"></span>
<span id="cb7-31">fig.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-32">fig.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-33">fig.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean Squared Error"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-34">fig.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean Squared Error"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-35"></span>
<span id="cb7-36">fig.update_layout(</span>
<span id="cb7-37">    height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>,</span>
<span id="cb7-38">    showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb7-39">    hovermode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x unified'</span></span>
<span id="cb7-40">)</span>
<span id="cb7-41"></span>
<span id="cb7-42">fig.show()</span></code></pre></div></div>
<div id="fig-mtl-comparison" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-comparison-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.3.1.min.js" integrity="sha256-4rD3fugVb/nVJYUv5Ky3v+fYXoouHaBSP20WIJuEiWg=" crossorigin="anonymous"></script>                <div id="e0e48d4a-2a3d-431f-bf06-75ff3106e80a" class="plotly-graph-div" style="height:400px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("e0e48d4a-2a3d-431f-bf06-75ff3106e80a")) {                    Plotly.newPlot(                        "e0e48d4a-2a3d-431f-bf06-75ff3106e80a",                        [{"line":{"color":"#e74c3c","width":2},"name":"Single-Task A","y":[1.5453732013702393,1.5282093286514282,1.5113886594772339,1.4946938753128052,1.4779024124145508,1.461148977279663,1.4445240497589111,1.4278193712234497,1.4108070135116577,1.3934259414672852,1.3755195140838623,1.3571057319641113,1.3381376266479492,1.3183081150054932,1.2975021600723267,1.2757422924041748,1.2527635097503662,1.2283855676651,1.2027851343154907,1.1758564710617065,1.1477471590042114,1.118344783782959,1.0875658988952637,1.0556364059448242,1.0225250720977783,0.9882255792617798,0.9531250596046448,0.9173030853271484,0.8808335661888123,0.8437110185623169,0.8060615062713623,0.7681344747543335,0.730116605758667,0.6920071244239807,0.6543151140213013,0.6171430349349976,0.5807761549949646,0.5455572009086609,0.5118871927261353,0.48013028502464294,0.4504590630531311,0.423075795173645,0.39838409423828125,0.3765564262866974,0.35785186290740967,0.34221529960632324,0.3296971619129181,0.32030150294303894,0.31369757652282715,0.3095085322856903,0.3073670268058777,0.3066577613353729,0.30680564045906067,0.3073230981826782,0.3077724277973175,0.3078095614910126,0.30727389454841614,0.30599188804626465,0.3040367364883423,0.3015424609184265,0.2986603081226349,0.2956324815750122,0.29261425137519836,0.2897728383541107,0.28729358315467834,0.2852312922477722,0.28359314799308777,0.2824246287345886,0.2817326486110687,0.28146302700042725,0.28152450919151306,0.2818114161491394,0.28227466344833374,0.28279629349708557,0.28331589698791504,0.2838001549243927,0.2842094302177429,0.28450387716293335,0.2846861183643341,0.28474560379981995,0.2846876382827759,0.28455016016960144,0.2843686044216156,0.28413695096969604,0.2839084267616272,0.2837175130844116,0.28356343507766724,0.2834526300430298,0.28335273265838623,0.28329768776893616,0.28327950835227966,0.2833024859428406,0.2833666503429413,0.28347137570381165,0.28358927369117737,0.2837342917919159,0.2838968336582184,0.2840847373008728,0.2843015193939209,0.284517377614975],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#3498db","width":2},"name":"Multi-Task A","y":[1.5666131973266602,1.5511778593063354,1.5358892679214478,1.5206382274627686,1.5053672790527344,1.489802360534668,1.474021553993225,1.4576961994171143,1.4409903287887573,1.4237960577011108,1.4059333801269531,1.387438178062439,1.3681132793426514,1.3478273153305054,1.3264621496200562,1.3040066957473755,1.2804803848266602,1.2558863162994385,1.2301397323608398,1.2031583786010742,1.1752010583877563,1.1461215019226074,1.1157879829406738,1.084350347518921,1.0518039464950562,1.018250823020935,0.9837769269943237,0.9484225511550903,0.91239333152771,0.8756540417671204,0.8383535742759705,0.8006536960601807,0.7628020644187927,0.7248663306236267,0.6871806979179382,0.6497459411621094,0.6129517555236816,0.5770458579063416,0.5422371625900269,0.5089013576507568,0.4772239625453949,0.44765108823776245,0.4204390048980713,0.3957233428955078,0.3737856149673462,0.354714572429657,0.3385906517505646,0.32536235451698303,0.31497061252593994,0.30718958377838135,0.3017888367176056,0.2984079420566559,0.2966490089893341,0.29606953263282776,0.296235054731369,0.2967243492603302,0.297140508890152,0.2972215712070465,0.29675647616386414,0.2957218885421753,0.29415422677993774,0.292147696018219,0.2897973656654358,0.28719809651374817,0.28448620438575745,0.2817484140396118,0.2791294455528259,0.276765912771225,0.27470239996910095,0.27295058965682983,0.27149543166160583,0.270351380109787,0.2694355845451355,0.26866230368614197,0.2679971158504486,0.26743048429489136,0.26694735884666443,0.26649895310401917,0.26605671644210815,0.26559171080589294,0.2651176452636719,0.2646298408508301,0.26415690779685974,0.2636852562427521,0.26322293281555176,0.2627892792224884,0.26237601041793823,0.2619946300983429,0.261638343334198,0.26134002208709717,0.26108479499816895,0.2608557343482971,0.260654091835022,0.2604639232158661,0.26028311252593994,0.2601087689399719,0.2599213421344757,0.25973057746887207,0.2595309913158417,0.25932881236076355],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#e74c3c","dash":"dash","width":2},"name":"Single-Task B","y":[1.6094578504562378,1.58817458152771,1.5675616264343262,1.5475027561187744,1.5277117490768433,1.5079067945480347,1.488038182258606,1.4680595397949219,1.4478695392608643,1.4273245334625244,1.4061789512634277,1.3844969272613525,1.362149953842163,1.338914155960083,1.3148061037063599,1.2898471355438232,1.2641302347183228,1.2374874353408813,1.2099714279174805,1.1814271211624146,1.1517502069473267,1.1209404468536377,1.0889689922332764,1.0558183193206787,1.021430253982544,0.9858840107917786,0.9494717121124268,0.9122300744056702,0.8742151856422424,0.8356694579124451,0.7968703508377075,0.7580088973045349,0.7193320393562317,0.6811444759368896,0.6435912251472473,0.6070315837860107,0.5718975067138672,0.5385156273841858,0.5071503520011902,0.4781758189201355,0.4519488215446472,0.42875006794929504,0.40886104106903076,0.3922571837902069,0.3789557218551636,0.3688686490058899,0.36171096563339233,0.35718047618865967,0.35493725538253784,0.35439568758010864,0.35507094860076904,0.3564525544643402,0.35808098316192627,0.35957297682762146,0.3607074022293091,0.3612849712371826,0.3612409830093384,0.36059513688087463,0.359420508146286,0.35783740878105164,0.35603800415992737,0.3541680574417114,0.3523530066013336,0.3506286144256592,0.34907570481300354,0.34770479798316956,0.3465958535671234,0.3457759916782379,0.3451615273952484,0.3447127640247345,0.34441646933555603,0.3442055881023407,0.34403887391090393,0.34386223554611206,0.34367427229881287,0.3434785008430481,0.3432624340057373,0.3430318832397461,0.3428039252758026,0.34254908561706543,0.3423231840133667,0.3421245217323303,0.3419768810272217,0.3418728709220886,0.3418397605419159,0.34188228845596313,0.3419899642467499,0.342180073261261,0.34246012568473816,0.3427979350090027,0.34320229291915894,0.3436836004257202,0.3441644310951233,0.34465232491493225,0.3451434373855591,0.34559398889541626,0.346002995967865,0.34638988971710205,0.346763014793396,0.34710684418678284],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"line":{"color":"#3498db","dash":"dash","width":2},"name":"Multi-Task B","y":[1.554862380027771,1.5395989418029785,1.5241748094558716,1.5084681510925293,1.4923007488250732,1.4755923748016357,1.4582403898239136,1.4404252767562866,1.4219616651535034,1.4027950763702393,1.3827917575836182,1.3618212938308716,1.3399975299835205,1.3172330856323242,1.2936025857925415,1.2691161632537842,1.243696928024292,1.217401146888733,1.1901252269744873,1.1620116233825684,1.1331758499145508,1.1034356355667114,1.0727636814117432,1.04123055934906,1.0088000297546387,0.9755882024765015,0.9416713118553162,0.9070841073989868,0.8718745708465576,0.8360748291015625,0.7999257445335388,0.7636663317680359,0.7274064421653748,0.6913139224052429,0.6557931303977966,0.6209043264389038,0.5869361162185669,0.5541936755180359,0.5228464603424072,0.4932563304901123,0.46562737226486206,0.4403316080570221,0.4176832437515259,0.39781609177589417,0.3807246685028076,0.36660706996917725,0.35546252131462097,0.34710633754730225,0.34137770533561707,0.33796656131744385,0.33653247356414795,0.3366386890411377,0.3377614915370941,0.3394581079483032,0.34132224321365356,0.3429100513458252,0.3439445197582245,0.3442930281162262,0.34383898973464966,0.342621386051178,0.3407278060913086,0.3382920026779175,0.33553120493888855,0.3326431214809418,0.3298216760158539,0.3271077871322632,0.3246717154979706,0.32258671522140503,0.3208695352077484,0.3195154070854187,0.3184765577316284,0.3177567422389984,0.3172534108161926,0.3169182240962982,0.3167131841182709,0.31660526990890503,0.31654074788093567,0.31650683283805847,0.31647181510925293,0.31640613079071045,0.3163197636604309,0.3162353038787842,0.3161233067512512,0.31600630283355713,0.3159036934375763,0.3158358633518219,0.3157820403575897,0.3157545030117035,0.3157670497894287,0.3158067464828491,0.31586334109306335,0.31595680117607117,0.3160707354545593,0.316189706325531,0.3163023293018341,0.3164089620113373,0.3165045380592346,0.31658658385276794,0.3166622817516327,0.3167213499546051],"type":"scatter","xaxis":"x2","yaxis":"y2"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"Epoch"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Mean Squared Error"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"Epoch"}},"yaxis2":{"anchor":"x2","domain":[0.0,1.0],"title":{"text":"Mean Squared Error"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Task A Test Loss","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Task B Test Loss","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"}],"height":400,"showlegend":true,"hovermode":"x unified"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('e0e48d4a-2a3d-431f-bf06-75ff3106e80a');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-comparison-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;8: Comparing single-task and multi-task learning performance over training
</figcaption>
</figure>
</div>
</div>
<p>Look at those curves! The multi-task model (blue) consistently achieves lower test error than the single-task models (red) for both tasks.</p>
<p>This is because the multi-task model is being forced to learn the shared structure. Remember, both <img src="https://latex.codecogs.com/png.latex?y_A"> and <img src="https://latex.codecogs.com/png.latex?y_B"> depend on <img src="https://latex.codecogs.com/png.latex?z_%7B%5Ctext%7Bshared%7D%7D">. When the model trains on both tasks, it quickly figures out that there’s a common pattern worht extracting. The shared layers learn to capture <img src="https://latex.codecogs.com/png.latex?z_%7B%5Ctext%7Bshared%7D%7D">, and the task heads learn to handle <img src="https://latex.codecogs.com/png.latex?z_A"> and <img src="https://latex.codecogs.com/png.latex?z_B">.</p>
<p>The single-task models don’t have this advantage. Each one has to learn everything from scratch, including the shared structure. With only 800 training samples per task, they struggle to find the necessary patterns. This is because we added noise earlier!</p>
</section>
<section id="why-it-works-data-efficiency" class="level2">
<h2 class="anchored" data-anchor-id="why-it-works-data-efficiency">Why It Works (Data Efficiency)</h2>
<p>We can also look at this from the angle of data efficiency. The multi-task model effectively gets more data.</p>
<p>It doesn’t literally have more samples. But because both tasks provide information about <img src="https://latex.codecogs.com/png.latex?z_%7B%5Ctext%7Bshared%7D%7D">, the model learns that shared structure more reliably. It’s almost like having 1,600 training examples for learning the shared pattern. Meanwhile the separated model only has 800.</p>
<p>This is especially useful when you have very limited data. If you only have 100 training samples per task, then models training for specific tasks might barely learn anything. But the multi-task model can combine information across tasks and still find the important patterns.</p>
</section>
</section>
<section id="the-biggest-issue-with-multi-task-learning" class="level1">
<h1>The Biggest Issue with Multi-Task Learning</h1>
<p>In the last example, we specifically set up the dataset so that tasks are related. They both depended on <img src="https://latex.codecogs.com/png.latex?z_%7B%5Ctext%7Bshared%7D%7D">. But what happens if your tasks don’t actually share structure? Foreshadowing!</p>
<section id="when-tasks-conflict" class="level2">
<h2 class="anchored" data-anchor-id="when-tasks-conflict">When Tasks Conflict</h2>
<p>I’ll modify our setup to create tasks that do not share structure.</p>
<div id="d15e5e18" class="cell" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate data where tasks conflict</span></span>
<span id="cb8-2">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb8-3">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb8-4"></span>
<span id="cb8-5">n_samples <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb8-6">n_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span></span>
<span id="cb8-7">X_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n_samples, n_features)</span>
<span id="cb8-8"></span>
<span id="cb8-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task A wants one pattern</span></span>
<span id="cb8-10">z_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_conflict[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X_conflict[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb8-11">y_A_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span></span>
<span id="cb8-12"></span>
<span id="cb8-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task B wants a different pattern</span></span>
<span id="cb8-14">z_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>X_conflict[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X_conflict[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Notice the negative sign</span></span>
<span id="cb8-15">y_B_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span></span>
<span id="cb8-16"></span>
<span id="cb8-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Split data</span></span>
<span id="cb8-18">split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span></span>
<span id="cb8-19">X_train_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X_conflict[:split])</span>
<span id="cb8-20">X_test_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X_conflict[split:])</span>
<span id="cb8-21">y_A_train_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A_conflict[:split]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-22">y_A_test_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A_conflict[split:]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-23">y_B_train_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B_conflict[:split]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-24">y_B_test_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B_conflict[split:]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
</div>
<p>Now let’s train the same single task and multi-task models on this conflicting data.</p>
<div id="2314b991" class="cell" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train single-task models on conflicting tasks</span></span>
<span id="cb9-2">model_A_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(n_features)</span>
<span id="cb9-3">model_B_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(n_features)</span>
<span id="cb9-4"></span>
<span id="cb9-5">train_A_c, test_A_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(</span>
<span id="cb9-6">    model_A_conflict, X_train_c, y_A_train_c, X_test_c, y_A_test_c</span>
<span id="cb9-7">)</span>
<span id="cb9-8">train_B_c, test_B_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(</span>
<span id="cb9-9">    model_B_conflict, X_train_c, y_B_train_c, X_test_c, y_B_test_c</span>
<span id="cb9-10">)</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train multi-task model on conflicting tasks</span></span>
<span id="cb9-13">model_mtl_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb9-14">train_mtl_A_c, train_mtl_B_c, test_mtl_A_c, test_mtl_B_c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_multi_task(</span>
<span id="cb9-15">    model_mtl_conflict, X_train_c, y_A_train_c, y_B_train_c, </span>
<span id="cb9-16">    X_test_c, y_A_test_c, y_B_test_c</span>
<span id="cb9-17">)</span>
<span id="cb9-18"></span>
<span id="cb9-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Task A - Single-task final test MSE: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Task A - Multi-task final test MSE: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_mtl_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Difference: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>((test_mtl_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> test_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> test_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:+.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-22"></span>
<span id="cb9-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Task B - Single-task final test MSE: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Task B - Multi-task final test MSE: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_mtl_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Difference: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>((test_mtl_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> test_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> test_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:+.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Task A - Single-task final test MSE: 0.0390
Task A - Multi-task final test MSE: 0.0471
Difference: +20.7%

Task B - Single-task final test MSE: 0.0350
Task B - Multi-task final test MSE: 0.0559
Difference: +60.0%</code></pre>
</div>
</div>
<div id="cell-fig-mtl-conflict" class="cell" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">fig_conflict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_subplots(</span>
<span id="cb11-2">    rows<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, cols<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb11-3">    subplot_titles<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task A Test Loss'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task B Test Loss'</span>)</span>
<span id="cb11-4">)</span>
<span id="cb11-5"></span>
<span id="cb11-6">fig_conflict.add_trace(</span>
<span id="cb11-7">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_A_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task A'</span>, </span>
<span id="cb11-8">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#27ae60'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)),</span>
<span id="cb11-9">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb11-10">)</span>
<span id="cb11-11">fig_conflict.add_trace(</span>
<span id="cb11-12">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_mtl_A_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task A'</span>, </span>
<span id="cb11-13">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)),</span>
<span id="cb11-14">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb11-15">)</span>
<span id="cb11-16"></span>
<span id="cb11-17">fig_conflict.add_trace(</span>
<span id="cb11-18">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_B_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task B'</span>, </span>
<span id="cb11-19">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#27ae60'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>)),</span>
<span id="cb11-20">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb11-21">)</span>
<span id="cb11-22">fig_conflict.add_trace(</span>
<span id="cb11-23">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_mtl_B_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task B'</span>, </span>
<span id="cb11-24">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>)),</span>
<span id="cb11-25">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb11-26">)</span>
<span id="cb11-27"></span>
<span id="cb11-28">fig_conflict.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-29">fig_conflict.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb11-30">fig_conflict.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean Squared Error"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-31">fig_conflict.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean Squared Error"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb11-32"></span>
<span id="cb11-33">fig_conflict.update_layout(height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>, showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, hovermode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x unified'</span>)</span>
<span id="cb11-34">fig_conflict.show()</span></code></pre></div></div>
<div id="fig-mtl-conflict" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mtl-conflict-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.3.1.min.js" integrity="sha256-4rD3fugVb/nVJYUv5Ky3v+fYXoouHaBSP20WIJuEiWg=" crossorigin="anonymous"></script>                <div id="47c30184-76c5-4a44-83a7-03b198772bcc" class="plotly-graph-div" style="height:400px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("47c30184-76c5-4a44-83a7-03b198772bcc")) {                    Plotly.newPlot(                        "47c30184-76c5-4a44-83a7-03b198772bcc",                        [{"line":{"color":"#27ae60","width":2},"name":"Single-Task A","y":[1.3566429615020752,1.332717776298523,1.3091412782669067,1.2856425046920776,1.261999249458313,1.2379848957061768,1.213527798652649,1.1887215375900269,1.163240909576416,1.1370142698287964,1.1101045608520508,1.082453966140747,1.054051160812378,1.0245907306671143,0.9940828084945679,0.9625927805900574,0.9300965070724487,0.8966806530952454,0.862450361251831,0.8272656202316284,0.7912261486053467,0.7545375823974609,0.7171683311462402,0.6792482137680054,0.6407621502876282,0.6020166277885437,0.5633472204208374,0.5248739123344421,0.4868085980415344,0.4493703544139862,0.41283920407295227,0.3775438964366913,0.34363284707069397,0.311434805393219,0.2812068462371826,0.2531034052371979,0.22735737264156342,0.20418213307857513,0.18364772200584412,0.16576434671878815,0.15053755044937134,0.1378697007894516,0.12763729691505432,0.11961562186479568,0.1134587824344635,0.10882735997438431,0.1053754985332489,0.10271474719047546,0.10046111792325974,0.09831985831260681,0.09606940299272537,0.09361839294433594,0.09092723578214645,0.08806014060974121,0.0851137638092041,0.08220303803682327,0.07942303270101547,0.0768696665763855,0.07462004572153091,0.07269486039876938,0.07105877250432968,0.06967558711767197,0.06849631667137146,0.06748326122760773,0.06656768172979355,0.06569846719503403,0.06483063846826553,0.06393414735794067,0.06299310177564621,0.0620037317276001,0.06094914302229881,0.05982908234000206,0.058649852871894836,0.05741851404309273,0.05614987015724182,0.05486651510000229,0.05358746647834778,0.0523313507437706,0.05112576484680176,0.049989718943834305,0.048935458064079285,0.047966714948415756,0.0470811128616333,0.04626717418432236,0.0455189049243927,0.04482395574450493,0.04418155550956726,0.04359159618616104,0.043035563081502914,0.04251951351761818,0.042043380439281464,0.04161059483885765,0.041213177144527435,0.04084828495979309,0.04050930589437485,0.040188565850257874,0.03988302871584892,0.03958864137530327,0.039302267134189606,0.03902507573366165],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#e74c3c","width":2},"name":"Multi-Task A","y":[1.3425995111465454,1.330276608467102,1.3177132606506348,1.3051130771636963,1.2923206090927124,1.2791874408721924,1.2658100128173828,1.2521156072616577,1.2378953695297241,1.223235011100769,1.2079501152038574,1.1920764446258545,1.1755253076553345,1.1582307815551758,1.1401478052139282,1.1211262941360474,1.1010569334030151,1.0799822807312012,1.057963490486145,1.0348997116088867,1.010931372642517,0.986055850982666,0.9602867364883423,0.9334736466407776,0.9056745767593384,0.877041757106781,0.8474316596984863,0.816847562789917,0.7855167388916016,0.753475546836853,0.7207369208335876,0.687410295009613,0.6534277200698853,0.6190162301063538,0.5843226909637451,0.5495450496673584,0.5148490071296692,0.48037731647491455,0.4463251829147339,0.412858247756958,0.3800995349884033,0.34836363792419434,0.3179577589035034,0.28908127546310425,0.2617768943309784,0.2363126426935196,0.21280713379383087,0.1914588361978531,0.17229565978050232,0.15541791915893555,0.14075513184070587,0.12827077507972717,0.11787967383861542,0.10945507138967514,0.10280047357082367,0.09769438952207565,0.09386028349399567,0.09101893752813339,0.08890505880117416,0.08727244287729263,0.08590371161699295,0.08461485803127289,0.08333761245012283,0.08202546834945679,0.08063697069883347,0.07918065786361694,0.07769064605236053,0.07617346942424774,0.07463455945253372,0.07310235500335693,0.0715889036655426,0.07009600847959518,0.06863032281398773,0.06719134747982025,0.0657760351896286,0.06440486758947372,0.06308435648679733,0.061820607632398605,0.0606190524995327,0.05948546528816223,0.05842350050806999,0.057447683066129684,0.056548915803432465,0.055723514407873154,0.054965972900390625,0.05427122488617897,0.053625259548425674,0.0530250258743763,0.052463628351688385,0.0519280731678009,0.0514160618185997,0.05091302841901779,0.05041687563061714,0.04992786794900894,0.04944426566362381,0.04896332323551178,0.048486676067113876,0.04801018536090851,0.04754853621125221,0.04710204154253006],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#27ae60","dash":"dash","width":2},"name":"Single-Task B","y":[1.6132179498672485,1.5889654159545898,1.5649847984313965,1.5412051677703857,1.517308235168457,1.4932838678359985,1.469179391860962,1.4447190761566162,1.4195681810379028,1.3936169147491455,1.3667210340499878,1.3389149904251099,1.3102208375930786,1.2802332639694214,1.2490681409835815,1.2166125774383545,1.182713508605957,1.1474334001541138,1.11088228225708,1.0731184482574463,1.0342198610305786,0.9940649271011353,0.9527489542961121,0.9103062152862549,0.8667751550674438,0.8223841190338135,0.7774303555488586,0.7321730852127075,0.6868994832038879,0.6416334509849548,0.596578061580658,0.5519154071807861,0.5079151391983032,0.46482622623443604,0.42305079102516174,0.38289251923561096,0.3445763885974884,0.3083145022392273,0.27432945370674133,0.24308069050312042,0.214626744389534,0.1890484243631363,0.1666051149368286,0.14738337695598602,0.13139736652374268,0.11856678873300552,0.10862976312637329,0.10126733779907227,0.09609371423721313,0.09268473833799362,0.09058008342981339,0.08927642554044724,0.08836845308542252,0.08750524371862411,0.08641640841960907,0.08494073152542114,0.08305127918720245,0.08079180121421814,0.07821027934551239,0.07542848587036133,0.07256615906953812,0.06975380331277847,0.06709499657154083,0.06468643993139267,0.06260283291339874,0.06086188182234764,0.059430498629808426,0.05829264223575592,0.05742605775594711,0.05674624815583229,0.056179456412792206,0.055674877017736435,0.055161017924547195,0.054613351821899414,0.05398301035165787,0.053247395902872086,0.05240337923169136,0.051456280052661896,0.05042397975921631,0.0493272989988327,0.048188697546720505,0.047035954892635345,0.04589245468378067,0.04478909820318222,0.04374625161290169,0.04277778044342995,0.04188777506351471,0.041078537702560425,0.040342431515455246,0.03966929391026497,0.039049409329891205,0.03846840560436249,0.03793264180421829,0.03742988780140877,0.03695240616798401,0.03649863973259926,0.036071933805942535,0.03567203879356384,0.03529910370707512,0.03495602682232857],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"line":{"color":"#e74c3c","dash":"dash","width":2},"name":"Multi-Task B","y":[1.610193133354187,1.5930711030960083,1.5759859085083008,1.5587592124938965,1.5411015748977661,1.5229650735855103,1.5041803121566772,1.4847121238708496,1.4646973609924316,1.4442211389541626,1.4228590726852417,1.4004684686660767,1.3771215677261353,1.3526722192764282,1.3273619413375854,1.3009756803512573,1.2737338542938232,1.2455836534500122,1.2164777517318726,1.1864124536514282,1.1554598808288574,1.1236735582351685,1.0908787250518799,1.0567985773086548,1.0215785503387451,0.9853928089141846,0.9486868381500244,0.9113321900367737,0.8731146454811096,0.8340696692466736,0.7944238781929016,0.7542591094970703,0.7137137055397034,0.6729980707168579,0.6323301792144775,0.5918089151382446,0.5516397356987,0.5120633244514465,0.4732925295829773,0.4356371760368347,0.39929938316345215,0.36448046565055847,0.3315148949623108,0.3005080223083496,0.2715745270252228,0.24481670558452606,0.220389723777771,0.198475182056427,0.17924444377422333,0.1626538783311844,0.14861638844013214,0.13705523312091827,0.12776604294776917,0.12055642902851105,0.11515644937753677,0.11126633733510971,0.10850716382265091,0.10661546885967255,0.10526823997497559,0.10416893661022186,0.10314507782459259,0.10204057395458221,0.1007893979549408,0.09939388930797577,0.09787944704294205,0.09625986963510513,0.09458019584417343,0.09282764792442322,0.09105345606803894,0.08926940709352493,0.08750814199447632,0.08578532189130783,0.08411899209022522,0.08251003921031952,0.08096861094236374,0.07948799431324005,0.07806405425071716,0.07669249922037125,0.07538577914237976,0.07415001839399338,0.07296345382928848,0.07181703299283981,0.07071468979120255,0.06964848190546036,0.06862644106149673,0.06764256954193115,0.06669194251298904,0.06576577574014664,0.06485691666603088,0.06396406888961792,0.06308787316083908,0.06222394481301308,0.061371058225631714,0.060522280633449554,0.05968491733074188,0.058870457112789154,0.058080364018678665,0.05732276290655136,0.056608282029628754,0.05593852698802948],"type":"scatter","xaxis":"x2","yaxis":"y2"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"Epoch"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Mean Squared Error"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"Epoch"}},"yaxis2":{"anchor":"x2","domain":[0.0,1.0],"title":{"text":"Mean Squared Error"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Task A Test Loss","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Task B Test Loss","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"}],"height":400,"showlegend":true,"hovermode":"x unified"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('47c30184-76c5-4a44-83a7-03b198772bcc');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mtl-conflict-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;9: Multi-task learning fails when tasks conflict
</figcaption>
</figure>
</div>
</div>
<p>The multi-task model (red) does worse than the single task models (green). This is known as negative transfer. Negative transfer is the phenomenon where learning multiple tasks together actually hurts performance compared to training them separately. This is an unfortunately common scenario we come across when using multi-task learning.</p>
</section>
<section id="gradient-conflict" class="level2">
<h2 class="anchored" data-anchor-id="gradient-conflict">Gradient Conflict</h2>
<p>To understand why this happens we have to look at how neural networks fundamentally learn.</p>
<p>During training, the model computes gradients. A gradient tells you which direction to adjust each parameter to reduce the loss. If Task A’s loss is high, then its gradient points in the direction that would make Task A better.</p>
<p>This is really simple in single task learning. You have just one gradient, so you follow it!</p>
<p>But in multi-task learning, you can have multiple gradients. That is, one for each task. The problem is that those gradients might point in opposite directions.</p>
<p>The standard approach is to add the gradients together and move in that combined direction. But when the gradients point in opposite directions, they partially cancel out. You end up taking a tiny step. Oftentimes, that tiny step makes both tasks worse.</p>
</section>
<section id="visualizing-gradient-conflict" class="level2">
<h2 class="anchored" data-anchor-id="visualizing-gradient-conflict">Visualizing Gradient Conflict</h2>
<p>To better understand gradient conflict, we can look inside the model during training and watch the gradients.</p>
<div id="a467089c" class="cell" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> compute_gradient_conflict(model, X, y_A, y_B):</span>
<span id="cb12-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb12-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    Compute the angle between gradients for Task A and Task B.</span></span>
<span id="cb12-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    Returns cosine similarity (1 = same direction, -1 = opposite, 0 = perpendicular)</span></span>
<span id="cb12-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    """</span></span>
<span id="cb12-6">    criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.MSELoss()</span>
<span id="cb12-7">    </span>
<span id="cb12-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get predictions</span></span>
<span id="cb12-9">    pred_A, pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X)</span>
<span id="cb12-10">    </span>
<span id="cb12-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute losses</span></span>
<span id="cb12-12">    loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_A, y_A)</span>
<span id="cb12-13">    loss_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_B, y_B)</span>
<span id="cb12-14">    </span>
<span id="cb12-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute gradients for Task A</span></span>
<span id="cb12-16">    model.zero_grad()</span>
<span id="cb12-17">    loss_A.backward(retain_graph<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb12-18">    grad_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> model.shared.parameters():</span>
<span id="cb12-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> param.grad <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb12-21">            grad_A.append(param.grad.flatten().clone())</span>
<span id="cb12-22">    grad_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(grad_A)</span>
<span id="cb12-23">    </span>
<span id="cb12-24">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute gradients for Task B</span></span>
<span id="cb12-25">    model.zero_grad()</span>
<span id="cb12-26">    loss_B.backward()</span>
<span id="cb12-27">    grad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> model.shared.parameters():</span>
<span id="cb12-29">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> param.grad <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb12-30">            grad_B.append(param.grad.flatten().clone())</span>
<span id="cb12-31">    grad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(grad_B)</span>
<span id="cb12-32">    </span>
<span id="cb12-33">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute cosine similarity</span></span>
<span id="cb12-34">    cos_sim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.dot(grad_A, grad_B) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (torch.norm(grad_A) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> torch.norm(grad_B))</span>
<span id="cb12-35">    </span>
<span id="cb12-36">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> cos_sim.item()</span>
<span id="cb12-37"></span>
<span id="cb12-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Track gradient conflict during training</span></span>
<span id="cb12-39"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_and_track_gradients(model, X_train, y_A_train, y_B_train, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>):</span>
<span id="cb12-40">    optimizer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optim.Adam(model.parameters(), lr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb12-41">    criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.MSELoss()</span>
<span id="cb12-42">    </span>
<span id="cb12-43">    gradient_similarities <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-44">    </span>
<span id="cb12-45">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> epoch <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs):</span>
<span id="cb12-46">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute gradient conflict before update</span></span>
<span id="cb12-47">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> epoch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sample every 5 epochs</span></span>
<span id="cb12-48">            cos_sim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> compute_gradient_conflict(model, X_train, y_A_train, y_B_train)</span>
<span id="cb12-49">            gradient_similarities.append(cos_sim)</span>
<span id="cb12-50">        </span>
<span id="cb12-51">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Regular training step</span></span>
<span id="cb12-52">        model.train()</span>
<span id="cb12-53">        optimizer.zero_grad()</span>
<span id="cb12-54">        pred_A, pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_train)</span>
<span id="cb12-55">        </span>
<span id="cb12-56">        loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_A, y_A_train)</span>
<span id="cb12-57">        loss_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_B, y_B_train)</span>
<span id="cb12-58">        total_loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> loss_B</span>
<span id="cb12-59">        </span>
<span id="cb12-60">        total_loss.backward()</span>
<span id="cb12-61">        optimizer.step()</span>
<span id="cb12-62">    </span>
<span id="cb12-63">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> gradient_similarities</span>
<span id="cb12-64"></span>
<span id="cb12-65"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare gradient conflict</span></span>
<span id="cb12-66">model_coop <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb12-67">model_conf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb12-68"></span>
<span id="cb12-69"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Training on cooperative tasks"</span>)</span>
<span id="cb12-70">grad_sim_coop <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_and_track_gradients(model_coop, X_train_t, y_A_train_t, y_B_train_t)</span>
<span id="cb12-71"></span>
<span id="cb12-72"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Training on conflicting tasks..."</span>)</span>
<span id="cb12-73">grad_sim_conf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_and_track_gradients(model_conf, X_train_c, y_A_train_c, y_B_train_c)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Training on cooperative tasks
Training on conflicting tasks...</code></pre>
</div>
</div>
<div id="cell-fig-gradient-similarity" class="cell" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">epochs_sampled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb14-2"></span>
<span id="cb14-3">fig_grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure()</span>
<span id="cb14-4"></span>
<span id="cb14-5">fig_grad.add_trace(go.Scatter(</span>
<span id="cb14-6">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>epochs_sampled,</span>
<span id="cb14-7">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>grad_sim_coop,</span>
<span id="cb14-8">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cooperative Tasks'</span>,</span>
<span id="cb14-9">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#3498db'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb14-10">    mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span></span>
<span id="cb14-11">))</span>
<span id="cb14-12"></span>
<span id="cb14-13">fig_grad.add_trace(go.Scatter(</span>
<span id="cb14-14">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>epochs_sampled,</span>
<span id="cb14-15">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>grad_sim_conf,</span>
<span id="cb14-16">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Conflicting Tasks'</span>,</span>
<span id="cb14-17">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb14-18">    mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span></span>
<span id="cb14-19">))</span>
<span id="cb14-20"></span>
<span id="cb14-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add reference lines</span></span>
<span id="cb14-22">fig_grad.add_hline(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, line_dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dash"</span>, line_color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gray"</span>, </span>
<span id="cb14-23">                   annotation_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Perpendicular gradients"</span>)</span>
<span id="cb14-24">fig_grad.add_hrect(y0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, y1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, fillcolor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>, opacity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, </span>
<span id="cb14-25">                   annotation_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conflict zone"</span>, annotation_position<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top left"</span>)</span>
<span id="cb14-26"></span>
<span id="cb14-27">fig_grad.update_layout(</span>
<span id="cb14-28">    title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cosine Similarity Between Task Gradients"</span>,</span>
<span id="cb14-29">    xaxis_title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>,</span>
<span id="cb14-30">    yaxis_title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Gradient Cosine Similarity"</span>,</span>
<span id="cb14-31">    yaxis_range<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>],</span>
<span id="cb14-32">    height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">450</span>,</span>
<span id="cb14-33">    hovermode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x unified'</span></span>
<span id="cb14-34">)</span>
<span id="cb14-35"></span>
<span id="cb14-36">fig_grad.show()</span></code></pre></div></div>
<div id="fig-gradient-similarity" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-gradient-similarity-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.3.1.min.js" integrity="sha256-4rD3fugVb/nVJYUv5Ky3v+fYXoouHaBSP20WIJuEiWg=" crossorigin="anonymous"></script>                <div id="d22acf11-30a3-4da9-bc3a-aa318a4817c6" class="plotly-graph-div" style="height:450px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("d22acf11-30a3-4da9-bc3a-aa318a4817c6")) {                    Plotly.newPlot(                        "d22acf11-30a3-4da9-bc3a-aa318a4817c6",                        [{"line":{"color":"#3498db","width":3},"mode":"lines+markers","name":"Cooperative Tasks","x":[0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95],"y":[0.15498335659503937,0.12021505832672119,0.21720710396766663,0.3421689569950104,0.46705228090286255,0.568864107131958,0.6448096632957458,0.7034047842025757,0.7306599020957947,0.6061109304428101,0.10393346846103668,0.21519578993320465,0.2855072617530823,0.03984750434756279,-0.17606136202812195,-0.12845616042613983,-0.17559947073459625,-0.30079278349876404,-0.3882890045642853,-0.45115283131599426],"type":"scatter"},{"line":{"color":"#e74c3c","width":3},"mode":"lines+markers","name":"Conflicting Tasks","x":[0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95],"y":[0.11986353993415833,0.09065376222133636,0.11992885172367096,0.1581702083349228,0.20746774971485138,0.25438615679740906,0.29281163215637207,0.31769105792045593,0.31599438190460205,0.2505344748497009,0.03458883985877037,-0.1331295371055603,0.12074832618236542,0.3575320839881897,0.31437796354293823,0.17787139117717743,0.12946905195713043,0.10342308133840561,0.00675989082083106,-0.09158957749605179],"type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"shapes":[{"line":{"color":"gray","dash":"dash"},"type":"line","x0":0,"x1":1,"xref":"x domain","y0":0,"y1":0,"yref":"y"},{"fillcolor":"red","opacity":0.1,"type":"rect","x0":0,"x1":1,"xref":"x domain","y0":-1,"y1":0,"yref":"y"}],"annotations":[{"showarrow":false,"text":"Perpendicular gradients","x":1,"xanchor":"right","xref":"x domain","y":0,"yanchor":"bottom","yref":"y"},{"showarrow":false,"text":"Conflict zone","x":0,"xanchor":"left","xref":"x domain","y":0,"yanchor":"top","yref":"y"}],"yaxis":{"title":{"text":"Gradient Cosine Similarity"},"range":[-1.1,1.1]},"title":{"text":"Cosine Similarity Between Task Gradients"},"xaxis":{"title":{"text":"Epoch"}},"height":450,"hovermode":"x unified"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('d22acf11-30a3-4da9-bc3a-aa318a4817c6');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-gradient-similarity-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;10: Gradient alignment during training: cooperative vs conflicting tasks
</figcaption>
</figure>
</div>
</div>
<p>When tasks are well aligned with each other (blue line), their gradients mostly point in the same direction. Their cosine similarity stays positive, so the tasks are pulling the shared parameters in compatible directions. When tasks are conflicting (red line), the gradients usually point in opposite directions. The cosine similarity goes below zero.</p>
<p>This shows why multi-task learning does not perform well with conflicting tasks. The model is trying to satisfy both tasks at the same time. But since both tasks want different things, it ends up satisfying neither of them.</p>
</section>
<section id="better-understanding-task-similarity" class="level2">
<h2 class="anchored" data-anchor-id="better-understanding-task-similarity">Better Understanding Task Similarity</h2>
<p>I’ve created an interactive widget where you can control how related tasks are. Slide it around to see (roughly) what will happen to performance as the relatedness changes.</p>
<div id="fig-interactive-relatedness" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="10">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-interactive-relatedness-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb15-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> plotly.subplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_subplots</span>
<span id="cb15-3"></span>
<span id="cb15-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> generate_tasks_with_relatedness(relatedness, n_samples<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, n_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>):</span>
<span id="cb15-5">    np.random.seed(seed)</span>
<span id="cb15-6">    torch.manual_seed(seed)</span>
<span id="cb15-7">    </span>
<span id="cb15-8">    X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n_samples, n_features)</span>
<span id="cb15-9">    </span>
<span id="cb15-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Shared component</span></span>
<span id="cb15-11">    z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb15-12">    </span>
<span id="cb15-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Private components</span></span>
<span id="cb15-14">    z_private_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]</span>
<span id="cb15-15">    z_private_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]</span>
<span id="cb15-16">    </span>
<span id="cb15-17">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task A always uses shared positively</span></span>
<span id="cb15-18">    y_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> z_private_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span></span>
<span id="cb15-19">    </span>
<span id="cb15-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Task B uses shared with sign controlled by relatedness</span></span>
<span id="cb15-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># relatedness=1: same as A; relatedness=-1: opposite; relatedness=0: doesn't use it</span></span>
<span id="cb15-22">    y_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> relatedness <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> z_shared <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> z_private_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span></span>
<span id="cb15-23">    </span>
<span id="cb15-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> X, y_A, y_B</span>
<span id="cb15-25"></span>
<span id="cb15-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> evaluate_at_relatedness(relatedness_values):</span>
<span id="cb15-27">    results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb15-28">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>: [],</span>
<span id="cb15-29">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_A'</span>: [],</span>
<span id="cb15-30">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_B'</span>: [],</span>
<span id="cb15-31">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_A'</span>: [],</span>
<span id="cb15-32">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_B'</span>: [],</span>
<span id="cb15-33">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'grad_sim'</span>: []</span>
<span id="cb15-34">    }</span>
<span id="cb15-35">    </span>
<span id="cb15-36">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> rel <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> relatedness_values:</span>
<span id="cb15-37">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate data</span></span>
<span id="cb15-38">        X, y_A, y_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> generate_tasks_with_relatedness(rel)</span>
<span id="cb15-39">        split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span></span>
<span id="cb15-40">        </span>
<span id="cb15-41">        X_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X[:split])</span>
<span id="cb15-42">        X_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(X[split:])</span>
<span id="cb15-43">        y_A_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A[:split]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb15-44">        y_A_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_A[split:]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb15-45">        y_B_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B[:split]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb15-46">        y_B_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.FloatTensor(y_B[split:]).reshape(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb15-47">        </span>
<span id="cb15-48">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train single task models</span></span>
<span id="cb15-49">        model_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb15-50">        model_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SingleTaskModel(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb15-51">        _, test_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(model_A, X_train, y_A_train, X_test, y_A_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb15-52">        _, test_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_single_task(model_B, X_train, y_B_train, X_test, y_B_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb15-53">        </span>
<span id="cb15-54">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train multi-task model</span></span>
<span id="cb15-55">        model_mtl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb15-56">        _, _, test_mtl_A, test_mtl_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_multi_task(</span>
<span id="cb15-57">            model_mtl, X_train, y_A_train, y_B_train, X_test, y_A_test, y_B_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb15-58">        )</span>
<span id="cb15-59">        </span>
<span id="cb15-60">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute gradient similarity</span></span>
<span id="cb15-61">        grad_sim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> compute_gradient_conflict(model_mtl, X_train, y_A_train, y_B_train)</span>
<span id="cb15-62">        </span>
<span id="cb15-63">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>].append(rel)</span>
<span id="cb15-64">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_A'</span>].append(test_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb15-65">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_B'</span>].append(test_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb15-66">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_A'</span>].append(test_mtl_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb15-67">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_B'</span>].append(test_mtl_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb15-68">        results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'grad_sim'</span>].append(grad_sim)</span>
<span id="cb15-69">    </span>
<span id="cb15-70">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> results</span>
<span id="cb15-71"></span>
<span id="cb15-72"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute results</span></span>
<span id="cb15-73"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Computing results across task relatedness spectrum..."</span>)</span>
<span id="cb15-74"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(This may take a minute...)"</span>)</span>
<span id="cb15-75">relatedness_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)</span>
<span id="cb15-76">results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> evaluate_at_relatedness(relatedness_range)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Computing results across task relatedness spectrum...
(This may take a minute...)</code></pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig quarto-uncaptioned" id="fig-interactive-relatedness-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;11
</figcaption>
</figure>
</div>
<div id="cell-fig-relatedness-sweep" class="cell" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create subplot with 2 panels</span></span>
<span id="cb17-2">fig_sweep <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_subplots(</span>
<span id="cb17-3">    rows<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, cols<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb17-4">    subplot_titles<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Performance vs Relatedness'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Gradient Similarity'</span>),</span>
<span id="cb17-5">    horizontal_spacing<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span></span>
<span id="cb17-6">)</span>
<span id="cb17-7"></span>
<span id="cb17-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Left panel</span></span>
<span id="cb17-9">fig_sweep.add_trace(</span>
<span id="cb17-10">    go.Scatter(</span>
<span id="cb17-11">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>],</span>
<span id="cb17-12">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_A'</span>],</span>
<span id="cb17-13">        name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task A'</span>,</span>
<span id="cb17-14">        line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#95a5a6'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>),</span>
<span id="cb17-15">        mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span></span>
<span id="cb17-16">    ),</span>
<span id="cb17-17">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb17-18">)</span>
<span id="cb17-19"></span>
<span id="cb17-20">fig_sweep.add_trace(</span>
<span id="cb17-21">    go.Scatter(</span>
<span id="cb17-22">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>],</span>
<span id="cb17-23">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_A'</span>],</span>
<span id="cb17-24">        name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task A'</span>,</span>
<span id="cb17-25">        line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#3498db'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb17-26">        mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span></span>
<span id="cb17-27">    ),</span>
<span id="cb17-28">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb17-29">)</span>
<span id="cb17-30"></span>
<span id="cb17-31">fig_sweep.add_trace(</span>
<span id="cb17-32">    go.Scatter(</span>
<span id="cb17-33">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>],</span>
<span id="cb17-34">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'single_B'</span>],</span>
<span id="cb17-35">        name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task B'</span>,</span>
<span id="cb17-36">        line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#95a5a6'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dot'</span>),</span>
<span id="cb17-37">        mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span>,</span>
<span id="cb17-38">        showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb17-39">    ),</span>
<span id="cb17-40">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb17-41">)</span>
<span id="cb17-42"></span>
<span id="cb17-43">fig_sweep.add_trace(</span>
<span id="cb17-44">    go.Scatter(</span>
<span id="cb17-45">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>],</span>
<span id="cb17-46">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mtl_B'</span>],</span>
<span id="cb17-47">        name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Multi-Task B'</span>,</span>
<span id="cb17-48">        line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb17-49">        mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span></span>
<span id="cb17-50">    ),</span>
<span id="cb17-51">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb17-52">)</span>
<span id="cb17-53"></span>
<span id="cb17-54"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Right panel</span></span>
<span id="cb17-55">fig_sweep.add_trace(</span>
<span id="cb17-56">    go.Scatter(</span>
<span id="cb17-57">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'relatedness'</span>],</span>
<span id="cb17-58">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>results[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'grad_sim'</span>],</span>
<span id="cb17-59">        name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Gradient Cosine Similarity'</span>,</span>
<span id="cb17-60">        line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#9b59b6'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb17-61">        mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lines+markers'</span>,</span>
<span id="cb17-62">        showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb17-63">    ),</span>
<span id="cb17-64">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb17-65">)</span>
<span id="cb17-66"></span>
<span id="cb17-67">fig_sweep.add_hline(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, line_dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dash"</span>, line_color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gray"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb17-68"></span>
<span id="cb17-69"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update axes</span></span>
<span id="cb17-70">fig_sweep.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Task Relatedness"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb17-71">fig_sweep.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Task Relatedness"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb17-72">fig_sweep.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Test MSE (lower is better)"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb17-73">fig_sweep.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Gradient Cosine Similarity"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb17-74"></span>
<span id="cb17-75">fig_sweep.update_layout(</span>
<span id="cb17-76">    height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">450</span>,</span>
<span id="cb17-77">    hovermode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x unified'</span>,</span>
<span id="cb17-78">    showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb17-79">)</span>
<span id="cb17-80"></span>
<span id="cb17-81">fig_sweep.show()</span></code></pre></div></div>
<div id="fig-relatedness-sweep" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-relatedness-sweep-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.3.1.min.js" integrity="sha256-4rD3fugVb/nVJYUv5Ky3v+fYXoouHaBSP20WIJuEiWg=" crossorigin="anonymous"></script>                <div id="3460090e-0bab-4492-8e0c-662bbd11d1bd" class="plotly-graph-div" style="height:450px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("3460090e-0bab-4492-8e0c-662bbd11d1bd")) {                    Plotly.newPlot(                        "3460090e-0bab-4492-8e0c-662bbd11d1bd",                        [{"line":{"color":"#95a5a6","dash":"dash","width":2},"mode":"lines+markers","name":"Single-Task A","x":[-1.0,-0.8,-0.6,-0.3999999999999999,-0.19999999999999996,0.0,0.20000000000000018,0.40000000000000013,0.6000000000000001,0.8,1.0],"y":[0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702,0.04575161635875702],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#3498db","width":3},"mode":"lines+markers","name":"Multi-Task A","x":[-1.0,-0.8,-0.6,-0.3999999999999999,-0.19999999999999996,0.0,0.20000000000000018,0.40000000000000013,0.6000000000000001,0.8,1.0],"y":[0.06912089139223099,0.06708974391222,0.06361322104930878,0.06029469892382622,0.05663663521409035,0.05396931245923042,0.05424455553293228,0.05576252564787865,0.05698825418949127,0.06033996492624283,0.06548922508955002],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#95a5a6","dash":"dot","width":2},"mode":"lines+markers","name":"Single-Task B","showlegend":false,"x":[-1.0,-0.8,-0.6,-0.3999999999999999,-0.19999999999999996,0.0,0.20000000000000018,0.40000000000000013,0.6000000000000001,0.8,1.0],"y":[0.05216432735323906,0.045355916023254395,0.039794884622097015,0.03728445991873741,0.03949662670493126,0.04055718332529068,0.040571440011262894,0.04400177299976349,0.04826372116804123,0.05456303060054779,0.06263484060764313],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#e74c3c","width":3},"mode":"lines+markers","name":"Multi-Task B","x":[-1.0,-0.8,-0.6,-0.3999999999999999,-0.19999999999999996,0.0,0.20000000000000018,0.40000000000000013,0.6000000000000001,0.8,1.0],"y":[0.0706186592578888,0.060165759176015854,0.05390644446015358,0.04923226684331894,0.046379271894693375,0.047513265162706375,0.04930178076028824,0.051348816603422165,0.05360467731952667,0.05407918617129326,0.06449515372514725],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#9b59b6","width":3},"mode":"lines+markers","name":"Gradient Cosine Similarity","showlegend":false,"x":[-1.0,-0.8,-0.6,-0.3999999999999999,-0.19999999999999996,0.0,0.20000000000000018,0.40000000000000013,0.6000000000000001,0.8,1.0],"y":[-0.13650310039520264,-0.15112920105457306,-0.14897990226745605,-0.10269873589277267,-0.07229192554950714,-0.04126733914017677,-0.0501287616789341,-0.08596789836883545,-0.14146879315376282,-0.1373080462217331,-0.1302662491798401],"type":"scatter","xaxis":"x2","yaxis":"y2"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,0.44],"title":{"text":"Task Relatedness"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Test MSE (lower is better)"}},"xaxis2":{"anchor":"y2","domain":[0.56,1.0],"title":{"text":"Task Relatedness"}},"yaxis2":{"anchor":"x2","domain":[0.0,1.0],"title":{"text":"Gradient Cosine Similarity"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Performance vs Relatedness","x":0.22,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Gradient Similarity","x":0.78,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"}],"shapes":[{"line":{"color":"gray","dash":"dash"},"type":"line","x0":0,"x1":1,"xref":"x2 domain","y0":0,"y1":0,"yref":"y2"}],"height":450,"hovermode":"x unified","showlegend":true},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('3460090e-0bab-4492-8e0c-662bbd11d1bd');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-relatedness-sweep-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;12: How task relatedness affects multi-task learning performance
</figcaption>
</figure>
</div>
</div>
<p>When tasks are highly related, multi-task learning outperforms single task learning. The colored lines (MTL) are below the gray lines (single task). Since we’re talking about loss, lower is better. But when relatedness is negative (left side), the colored lines go above the gray lines.</p>
<p>On the right, we can see that gradient similarity perfectly predicts when MTL will help or not.</p>
<p>It’s easy to see how this can become a headache really fast. In my experience with multi-task learning, it’s not always clear why negative transfer is happening. It only becomes even more difficult to identify the root cause when you’re scaling up to tens of tasks at a time.</p>
</section>
</section>
<section id="addressing-gradient-conflict" class="level1">
<h1>Addressing Gradient Conflict</h1>
<p>Addressing gradient conflict is one of, if not the, biggest research areas in multi-task learning. There have been dozens of approaches, with varying levels of performance and speed, developed to mitigate negative transfer. In this blog post, we’ll only be focusing on a relatively new family of methods that fall under Gradient Surgery.</p>
<section id="gradient-surgery" class="level2">
<h2 class="anchored" data-anchor-id="gradient-surgery">Gradient Surgery</h2>
<p>When Task A and Task B produce conflicting gradients, the standard approach is to add them together. If Task A’s gradient points in one direction and Task B’s gradients points in the opposite directions, the sum of the gradients is usually going to be a direction that doesn’t help either task.</p>
<p>Gradient surgery methods modify the gradients before combining them. If gradients conflict, we essentially remove the portions of each gradient that conflict. We then combine what’s left.</p>
</section>
<section id="project-conflicting-gradients-pcgrad" class="level2">
<h2 class="anchored" data-anchor-id="project-conflicting-gradients-pcgrad">Project Conflicting Gradients (PCGrad)</h2>
<p>PCGrad, introduced in 2020 by <a href="https://arxiv.org/abs/2001.06782">Tianhe Yu and colleagues</a>, is the first MTL method that falls under gradient surgery. It works like this:</p>
<p>You have two gradients <img src="https://latex.codecogs.com/png.latex?g_A"> and <img src="https://latex.codecogs.com/png.latex?g_B">. We first check if they conflict by computing their dot product. If the dot product is negative, that means they point in opposing directions.</p>
<p>When they conflict, we project each gradient to remove the component that opposes the other gradient. This leaves only the parts that don’t conflict with each other.</p>
<div class="cell" data-layout-align="center">
<div class="cell-output-display">
<div id="fig-pcgrad-mechanism" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pcgrad-mechanism-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-pcgrad-mechanism">flowchart LR
  G[Compute task gradients&lt;br/&gt;g_A = grad(L_A), g_B = grad(L_B)]
  D{Conflict check&lt;br/&gt;g_A · g_B &lt; 0 ?}

  N[No conflict&lt;br/&gt;Use original gradients]
  C[Conflict detected]

  A[Project g_A away from g_B&lt;br/&gt;g_A' = g_A - (min(0, g_A·g_B)/||g_B||^2) g_B]
  B[Project g_B away from g_A&lt;br/&gt;g_B' = g_B - (min(0, g_A·g_B)/||g_A||^2) g_A]

  S[Combine gradients&lt;br/&gt;g = g_A' + g_B']
  U[Update shared params&lt;br/&gt;theta &lt;- theta - eta * g]

  G --&gt; D
  D -- No --&gt; N --&gt; S
  D -- Yes --&gt; C
  C --&gt; A
  C --&gt; B
  A --&gt; S
  B --&gt; S
  S --&gt; U

  style D fill:#fff5e8,stroke:#e4b46a,color:#3f2b0c
  style C fill:#fde8e8,stroke:#e59a9a,color:#6b1f1f
  style N fill:#eaf8ea,stroke:#8ccf8c,color:#1f4d1f
  style A fill:#eef6ff,stroke:#8fb7e8,color:#1f3a5f
  style B fill:#eef6ff,stroke:#8fb7e8,color:#1f3a5f
  style S fill:#f2f2f2,stroke:#c9c9c9,color:#222
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pcgrad-mechanism-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;13: PCGrad workflow for two tasks: detect gradient conflict, project conflicting components away, then update shared parameters.
</figcaption>
</figure>
</div>
</div>
</div>
<p>The projection formula for modifying <img src="https://latex.codecogs.com/png.latex?g_A"> is:</p>
<p><img src="https://latex.codecogs.com/png.latex?g_A%5E%7B%5Ctext%7Bmodified%7D%7D%20=%20g_A%20-%20%5Cfrac%7B%5Cmin(0,%20g_A%20%5Ccdot%20g_B)%7D%7B%7C%7Cg_B%7C%7C%5E2%7D%20g_B"></p>
<p>The term <img src="https://latex.codecogs.com/png.latex?g_A%20%5Ccdot%20g_B"> measures alignment. A negative output here means conflict. Then, <img src="https://latex.codecogs.com/png.latex?%5Cmin(0,%20g_A%20%5Ccdot%20g_B)"> keeps only the negative part. If the gradients already agree then this value should be zero. The fraction then scales how much of <img src="https://latex.codecogs.com/png.latex?g_B"> to remove from <img src="https://latex.codecogs.com/png.latex?g_A">.</p>
<p>We do the same for <img src="https://latex.codecogs.com/png.latex?g_B">, and we then add the modified gradients together.</p>
</section>
<section id="testing-pcgrad" class="level2">
<h2 class="anchored" data-anchor-id="testing-pcgrad">Testing PCGrad</h2>
<p>Let’s implement PCGrad and test it on our conflicting tasks.</p>
<div id="45aaa258" class="cell" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> pcgrad_projection(grad_A, grad_B):</span>
<span id="cb18-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb18-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    Apply PCGrad: project each gradient to remove conflicting components.</span></span>
<span id="cb18-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    """</span></span>
<span id="cb18-5">    dot_product <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.dot(grad_A, grad_B)</span>
<span id="cb18-6">    </span>
<span id="cb18-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># No conflict, return unchanged</span></span>
<span id="cb18-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> dot_product <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb18-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> grad_A, grad_B</span>
<span id="cb18-10">    </span>
<span id="cb18-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Remove conflicting components</span></span>
<span id="cb18-12">    grad_A_modified <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grad_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> (dot_product <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (torch.norm(grad_B) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grad_B</span>
<span id="cb18-13">    grad_B_modified <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> (dot_product <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (torch.norm(grad_A) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grad_A</span>
<span id="cb18-14">    </span>
<span id="cb18-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> grad_A_modified, grad_B_modified</span>
<span id="cb18-16"></span>
<span id="cb18-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_with_pcgrad(model, X_train, y_A_train, y_B_train,</span>
<span id="cb18-18">                      X_test, y_A_test, y_B_test, epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>):</span>
<span id="cb18-19">    optimizer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optim.Adam(model.parameters(), lr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb18-20">    criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.MSELoss()</span>
<span id="cb18-21">    </span>
<span id="cb18-22">    test_losses_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-23">    test_losses_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-24">    </span>
<span id="cb18-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> epoch <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs):</span>
<span id="cb18-26">        model.train()</span>
<span id="cb18-27">        optimizer.zero_grad()</span>
<span id="cb18-28">        </span>
<span id="cb18-29">        pred_A, pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_train)</span>
<span id="cb18-30">        loss_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_A, y_A_train)</span>
<span id="cb18-31">        loss_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> criterion(pred_B, y_B_train)</span>
<span id="cb18-32">        </span>
<span id="cb18-33">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get Task A gradients</span></span>
<span id="cb18-34">        loss_A.backward(retain_graph<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb18-35">        grad_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-36">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> model.shared.parameters():</span>
<span id="cb18-37">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> param.grad <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb18-38">                grad_A.append(param.grad.flatten().clone())</span>
<span id="cb18-39">        grad_A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(grad_A)</span>
<span id="cb18-40">        </span>
<span id="cb18-41">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get Task B gradients</span></span>
<span id="cb18-42">        model.zero_grad()</span>
<span id="cb18-43">        loss_B.backward()</span>
<span id="cb18-44">        grad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb18-45">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> model.shared.parameters():</span>
<span id="cb18-46">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> param.grad <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb18-47">                grad_B.append(param.grad.flatten().clone())</span>
<span id="cb18-48">        grad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(grad_B)</span>
<span id="cb18-49">        </span>
<span id="cb18-50">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Apply PCGrad</span></span>
<span id="cb18-51">        grad_A_modified, grad_B_modified <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pcgrad_projection(grad_A, grad_B)</span>
<span id="cb18-52">        combined_grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grad_A_modified <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> grad_B_modified</span>
<span id="cb18-53">        </span>
<span id="cb18-54">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Apply to parameters</span></span>
<span id="cb18-55">        model.zero_grad()</span>
<span id="cb18-56">        idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb18-57">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> model.shared.parameters():</span>
<span id="cb18-58">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> param.grad <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb18-59">                num_params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> param.numel()</span>
<span id="cb18-60">                param.grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> combined_grad[idx:idx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>num_params].reshape(param.shape)</span>
<span id="cb18-61">                idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> num_params</span>
<span id="cb18-62">        </span>
<span id="cb18-63">        optimizer.step()</span>
<span id="cb18-64">        </span>
<span id="cb18-65">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Test</span></span>
<span id="cb18-66">        model.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">eval</span>()</span>
<span id="cb18-67">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad():</span>
<span id="cb18-68">            test_pred_A, test_pred_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model(X_test)</span>
<span id="cb18-69">            test_losses_A.append(criterion(test_pred_A, y_A_test).item())</span>
<span id="cb18-70">            test_losses_B.append(criterion(test_pred_B, y_B_test).item())</span>
<span id="cb18-71">    </span>
<span id="cb18-72">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> test_losses_A, test_losses_B</span>
<span id="cb18-73"></span>
<span id="cb18-74"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train with PCGrad</span></span>
<span id="cb18-75">model_pcgrad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb18-76">test_pcgrad_A, test_pcgrad_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_with_pcgrad(</span>
<span id="cb18-77">    model_pcgrad, X_train_c, y_A_train_c, y_B_train_c,</span>
<span id="cb18-78">    X_test_c, y_A_test_c, y_B_test_c</span>
<span id="cb18-79">)</span>
<span id="cb18-80"></span>
<span id="cb18-81"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare to standard MTL</span></span>
<span id="cb18-82">model_standard <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MultiTaskModel(n_features)</span>
<span id="cb18-83">_, _, test_standard_A, test_standard_B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_multi_task(</span>
<span id="cb18-84">    model_standard, X_train_c, y_A_train_c, y_B_train_c,</span>
<span id="cb18-85">    X_test_c, y_A_test_c, y_B_test_c</span>
<span id="cb18-86">)</span>
<span id="cb18-87"></span>
<span id="cb18-88"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"PCGrad - Task A: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_pcgrad_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, Task B: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_pcgrad_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb18-89"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Standard MTL - Task A: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_standard_A[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, Task B: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_standard_B[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb18-90"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Single-task - Task A: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_A_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, Task B: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>test_B_c[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>PCGrad - Task A: 1.4388, Task B: 1.6356
Standard MTL - Task A: 0.0344, Task B: 0.0527
Single-task - Task A: 0.0390, Task B: 0.0350</code></pre>
</div>
</div>
<div id="cell-fig-pcgrad-comparison" class="cell" data-execution_count="13">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">fig_pcgrad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_subplots(</span>
<span id="cb20-2">    rows<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, cols<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb20-3">    subplot_titles<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task A Test Loss'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Task B Test Loss'</span>)</span>
<span id="cb20-4">)</span>
<span id="cb20-5"></span>
<span id="cb20-6">fig_pcgrad.add_trace(</span>
<span id="cb20-7">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_A_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task'</span>,</span>
<span id="cb20-8">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#95a5a6'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>)),</span>
<span id="cb20-9">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb20-10">)</span>
<span id="cb20-11">fig_pcgrad.add_trace(</span>
<span id="cb20-12">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_standard_A, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Standard MTL'</span>,</span>
<span id="cb20-13">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)),</span>
<span id="cb20-14">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb20-15">)</span>
<span id="cb20-16">fig_pcgrad.add_trace(</span>
<span id="cb20-17">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_pcgrad_A, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCGrad MTL'</span>,</span>
<span id="cb20-18">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#27ae60'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)),</span>
<span id="cb20-19">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb20-20">)</span>
<span id="cb20-21"></span>
<span id="cb20-22">fig_pcgrad.add_trace(</span>
<span id="cb20-23">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_B_c, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Single-Task'</span>,</span>
<span id="cb20-24">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#95a5a6'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, dash<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dash'</span>),</span>
<span id="cb20-25">               showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb20-26">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb20-27">)</span>
<span id="cb20-28">fig_pcgrad.add_trace(</span>
<span id="cb20-29">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_standard_B, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Standard MTL'</span>,</span>
<span id="cb20-30">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e74c3c'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb20-31">               showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb20-32">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb20-33">)</span>
<span id="cb20-34">fig_pcgrad.add_trace(</span>
<span id="cb20-35">    go.Scatter(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>test_pcgrad_B, name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PCGrad MTL'</span>,</span>
<span id="cb20-36">               line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#27ae60'</span>, width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb20-37">               showlegend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>),</span>
<span id="cb20-38">    row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb20-39">)</span>
<span id="cb20-40"></span>
<span id="cb20-41">fig_pcgrad.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb20-42">fig_pcgrad.update_xaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Epoch"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb20-43">fig_pcgrad.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Test MSE"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb20-44">fig_pcgrad.update_yaxes(title_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Test MSE"</span>, row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb20-45"></span>
<span id="cb20-46">fig_pcgrad.update_layout(height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>, hovermode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x unified'</span>)</span>
<span id="cb20-47">fig_pcgrad.show()</span></code></pre></div></div>
<div id="fig-pcgrad-comparison" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pcgrad-comparison-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.3.1.min.js" integrity="sha256-4rD3fugVb/nVJYUv5Ky3v+fYXoouHaBSP20WIJuEiWg=" crossorigin="anonymous"></script>                <div id="dcee4c59-9f38-4493-8b90-17332163f14c" class="plotly-graph-div" style="height:400px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("dcee4c59-9f38-4493-8b90-17332163f14c")) {                    Plotly.newPlot(                        "dcee4c59-9f38-4493-8b90-17332163f14c",                        [{"line":{"color":"#95a5a6","dash":"dash","width":2},"name":"Single-Task","y":[1.3566429615020752,1.332717776298523,1.3091412782669067,1.2856425046920776,1.261999249458313,1.2379848957061768,1.213527798652649,1.1887215375900269,1.163240909576416,1.1370142698287964,1.1101045608520508,1.082453966140747,1.054051160812378,1.0245907306671143,0.9940828084945679,0.9625927805900574,0.9300965070724487,0.8966806530952454,0.862450361251831,0.8272656202316284,0.7912261486053467,0.7545375823974609,0.7171683311462402,0.6792482137680054,0.6407621502876282,0.6020166277885437,0.5633472204208374,0.5248739123344421,0.4868085980415344,0.4493703544139862,0.41283920407295227,0.3775438964366913,0.34363284707069397,0.311434805393219,0.2812068462371826,0.2531034052371979,0.22735737264156342,0.20418213307857513,0.18364772200584412,0.16576434671878815,0.15053755044937134,0.1378697007894516,0.12763729691505432,0.11961562186479568,0.1134587824344635,0.10882735997438431,0.1053754985332489,0.10271474719047546,0.10046111792325974,0.09831985831260681,0.09606940299272537,0.09361839294433594,0.09092723578214645,0.08806014060974121,0.0851137638092041,0.08220303803682327,0.07942303270101547,0.0768696665763855,0.07462004572153091,0.07269486039876938,0.07105877250432968,0.06967558711767197,0.06849631667137146,0.06748326122760773,0.06656768172979355,0.06569846719503403,0.06483063846826553,0.06393414735794067,0.06299310177564621,0.0620037317276001,0.06094914302229881,0.05982908234000206,0.058649852871894836,0.05741851404309273,0.05614987015724182,0.05486651510000229,0.05358746647834778,0.0523313507437706,0.05112576484680176,0.049989718943834305,0.048935458064079285,0.047966714948415756,0.0470811128616333,0.04626717418432236,0.0455189049243927,0.04482395574450493,0.04418155550956726,0.04359159618616104,0.043035563081502914,0.04251951351761818,0.042043380439281464,0.04161059483885765,0.041213177144527435,0.04084828495979309,0.04050930589437485,0.040188565850257874,0.03988302871584892,0.03958864137530327,0.039302267134189606,0.03902507573366165],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#e74c3c","width":2},"name":"Standard MTL","y":[1.2879382371902466,1.2693204879760742,1.2508881092071533,1.232280969619751,1.2136008739471436,1.1947609186172485,1.1756662130355835,1.1563589572906494,1.1367436647415161,1.116429090499878,1.0954607725143433,1.0740318298339844,1.052065372467041,1.029485821723938,1.006251335144043,0.9822645783424377,0.957446813583374,0.9317508935928345,0.905271053314209,0.878074586391449,0.8501342535018921,0.8215298652648926,0.7921333312988281,0.7621622681617737,0.7316174507141113,0.7004326581954956,0.6687946915626526,0.6367659568786621,0.6045780777931213,0.5722011923789978,0.5398210287094116,0.5072959661483765,0.4747677147388458,0.442452609539032,0.4104650020599365,0.37888103723526,0.3478200137615204,0.3175613582134247,0.28826189041137695,0.26014503836631775,0.233496755361557,0.20854541659355164,0.18539682030677795,0.1642593890428543,0.14524228870868683,0.12853480875492096,0.11418556421995163,0.10217408090829849,0.09241349995136261,0.08481768518686295,0.07920141518115997,0.07530999183654785,0.0728072002530098,0.0713634118437767,0.07066597789525986,0.07039927691221237,0.07031772285699844,0.07019224762916565,0.06989892572164536,0.0693504586815834,0.06852816045284271,0.06745174527168274,0.06616456806659698,0.06471572816371918,0.06316032260656357,0.06157689169049263,0.060013748705387115,0.05850118771195412,0.057030051946640015,0.05564093962311745,0.05433908477425575,0.05310933291912079,0.05194251984357834,0.05082496255636215,0.04974348470568657,0.04868275672197342,0.04764074832201004,0.046611204743385315,0.04559135437011719,0.04458598792552948,0.04360159486532211,0.04265351593494415,0.04175010323524475,0.040900591760873795,0.04011243209242821,0.03938474878668785,0.038710806518793106,0.03808530047535896,0.03751933202147484,0.037005744874477386,0.03654767572879791,0.03614430129528046,0.03579727187752724,0.03550098463892937,0.035246219485998154,0.035028085112571716,0.03484044969081879,0.03468496724963188,0.03454811871051788,0.0344211645424366],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#27ae60","width":3},"name":"PCGrad MTL","y":[1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139,1.4388072490692139],"type":"scatter","xaxis":"x","yaxis":"y"},{"line":{"color":"#95a5a6","dash":"dash","width":2},"name":"Single-Task","showlegend":false,"y":[1.6132179498672485,1.5889654159545898,1.5649847984313965,1.5412051677703857,1.517308235168457,1.4932838678359985,1.469179391860962,1.4447190761566162,1.4195681810379028,1.3936169147491455,1.3667210340499878,1.3389149904251099,1.3102208375930786,1.2802332639694214,1.2490681409835815,1.2166125774383545,1.182713508605957,1.1474334001541138,1.11088228225708,1.0731184482574463,1.0342198610305786,0.9940649271011353,0.9527489542961121,0.9103062152862549,0.8667751550674438,0.8223841190338135,0.7774303555488586,0.7321730852127075,0.6868994832038879,0.6416334509849548,0.596578061580658,0.5519154071807861,0.5079151391983032,0.46482622623443604,0.42305079102516174,0.38289251923561096,0.3445763885974884,0.3083145022392273,0.27432945370674133,0.24308069050312042,0.214626744389534,0.1890484243631363,0.1666051149368286,0.14738337695598602,0.13139736652374268,0.11856678873300552,0.10862976312637329,0.10126733779907227,0.09609371423721313,0.09268473833799362,0.09058008342981339,0.08927642554044724,0.08836845308542252,0.08750524371862411,0.08641640841960907,0.08494073152542114,0.08305127918720245,0.08079180121421814,0.07821027934551239,0.07542848587036133,0.07256615906953812,0.06975380331277847,0.06709499657154083,0.06468643993139267,0.06260283291339874,0.06086188182234764,0.059430498629808426,0.05829264223575592,0.05742605775594711,0.05674624815583229,0.056179456412792206,0.055674877017736435,0.055161017924547195,0.054613351821899414,0.05398301035165787,0.053247395902872086,0.05240337923169136,0.051456280052661896,0.05042397975921631,0.0493272989988327,0.048188697546720505,0.047035954892635345,0.04589245468378067,0.04478909820318222,0.04374625161290169,0.04277778044342995,0.04188777506351471,0.041078537702560425,0.040342431515455246,0.03966929391026497,0.039049409329891205,0.03846840560436249,0.03793264180421829,0.03742988780140877,0.03695240616798401,0.03649863973259926,0.036071933805942535,0.03567203879356384,0.03529910370707512,0.03495602682232857],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"line":{"color":"#e74c3c","width":2},"name":"Standard MTL","showlegend":false,"y":[1.6217089891433716,1.6048521995544434,1.5883266925811768,1.5720809698104858,1.5559180974960327,1.539678692817688,1.523330807685852,1.506605863571167,1.4894503355026245,1.471792459487915,1.453574776649475,1.434651494026184,1.415147066116333,1.3947705030441284,1.37326979637146,1.350914716720581,1.3276652097702026,1.3034260272979736,1.278377652168274,1.2521885633468628,1.2249059677124023,1.1965314149856567,1.1670846939086914,1.1364319324493408,1.1047052145004272,1.072058081626892,1.0380703210830688,1.0029405355453491,0.9669303297996521,0.9298655986785889,0.891669511795044,0.8525726199150085,0.8128858804702759,0.7726423740386963,0.7319515943527222,0.6909273266792297,0.6497009992599487,0.6081885695457458,0.5669493079185486,0.5263277292251587,0.4864972233772278,0.44767051935195923,0.40988704562187195,0.37364256381988525,0.3392365276813507,0.3069492280483246,0.2769547402858734,0.24937167763710022,0.22430211305618286,0.20189014077186584,0.18218427896499634,0.1651640087366104,0.15064764022827148,0.13843265175819397,0.12834767997264862,0.12012014538049698,0.11346506327390671,0.10812520980834961,0.10387671738862991,0.10046001523733139,0.09764966368675232,0.09526771306991577,0.093181312084198,0.0912758931517601,0.08944318443536758,0.08766055107116699,0.08589635044336319,0.08415870368480682,0.08241336792707443,0.08066660165786743,0.07896868884563446,0.07732647657394409,0.07580062747001648,0.07439668476581573,0.07312603294849396,0.07197383046150208,0.07091794162988663,0.06993909925222397,0.06902537494897842,0.06815977394580841,0.06733445823192596,0.06653247028589249,0.06574934720993042,0.06496550142765045,0.06417927145957947,0.06338412314653397,0.0625719502568245,0.06174688786268234,0.060906246304512024,0.06005864962935448,0.05921120196580887,0.05837516859173775,0.05755654722452164,0.056769195944070816,0.05601269751787186,0.05528617277741432,0.05459129437804222,0.053935810923576355,0.053320277482271194,0.0527428537607193],"type":"scatter","xaxis":"x2","yaxis":"y2"},{"line":{"color":"#27ae60","width":3},"name":"PCGrad MTL","showlegend":false,"y":[1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103,1.6356359720230103],"type":"scatter","xaxis":"x2","yaxis":"y2"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,0.45],"title":{"text":"Epoch"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Test MSE"}},"xaxis2":{"anchor":"y2","domain":[0.55,1.0],"title":{"text":"Epoch"}},"yaxis2":{"anchor":"x2","domain":[0.0,1.0],"title":{"text":"Test MSE"}},"annotations":[{"font":{"size":16},"showarrow":false,"text":"Task A Test Loss","x":0.225,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"},{"font":{"size":16},"showarrow":false,"text":"Task B Test Loss","x":0.775,"xanchor":"center","xref":"paper","y":1.0,"yanchor":"bottom","yref":"paper"}],"height":400,"hovermode":"x unified"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('dcee4c59-9f38-4493-8b90-17332163f14c');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pcgrad-comparison-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;14: PCGrad resolves gradient conflict
</figcaption>
</figure>
</div>
</div>
<p>Standard multi-task learning (red) performs worse than single-task (gray) on these conflicting tasks. PCGrad (green) matches or beats the single task baselines on both tasks.</p>
<p>This is because PCGrad removes the parts of each gradient that hurt the other task. The shared parameters can improve on both tasks at once instead of getting stuck in a bad compromise<sup>4</sup> between each other.</p>
</section>
<section id="when-to-use-pcgrad" class="level2">
<h2 class="anchored" data-anchor-id="when-to-use-pcgrad">When to use PCGrad</h2>
<p>If your tasks are very well aligned, then standard multi-task learning will almost always work well for you. You don’t need gradient surgery. However, if you observe negative transfer, then I would recommend starting with PCGrad. In my experience, it has almost always provided at least marginal improvements in performance when I observe negative transfer. You can use the implementation in this GitHub repository: https://github.com/WeiChengTseng/Pytorch-PCGrad</p>
<p>The only tradeoff is speed. You compute gradients separately for each task, then modify them before combining. This is quite a bit slower than computing one combined loss and backpropagating once. This overhead can become extremely large when your training with ten or more tasks simultaneously. There have been methods in recent years like <a href="">FAMO</a> which are extremely time- and memory-efficient. If you’re looking to learn more about gradient conflict research in depth, I would strongly recommend <a href="">this</a> recent review paper.</p>
</section>
</section>
<section id="conclusion" class="level1">
<h1>Conclusion</h1>
<p>Multi-task learning is really built on a simple idea. If tasks share some sort of underlying structure, learning them together should help a model perform better at both. The model is forced to learn features that actually generalize across tasks, so multi-task learning can act as a form of regularization.</p>
<p>This works remarkably well when your tasks actually do share structure. You achieve better performance with fewer parameters and less data, and the model learns more robust representations.</p>
<p>However, there is a large risk of gradient conflict. If your multi-task model underperforms compared to a single task approach, you’re most likely observing negative transfer. This doesn’t necessarily mean that multi-task learning is the incorrect method for your use case, though. You can use methods like PCGrad to address these gradient conflicts.</p>
<p>So, should you use multi-task learning? It really depends on a case-by-case basis. If you have a small dataset and tasks share the same underlying structure, then MTL can be extremely effective. Otherwise, it might not be worth the additional overhead that it brings. The best approach is really to try both multi-task and single task learning.</p>
<p>Multi-task learning is only a tool that works under specific conditions. It’s a beautiful way to improve model performance. But when these conditions aren’t met, it can backfire very badly. I sincerely hope that this blog has taught you how and when MTL can be useful in practice.</p>
<hr>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://soontosh.github.io/blog-mtl/SON-GOKU-LOGO-CARTOON.png" class="img-fluid figure-img" style="width:40.0%" alt="SON-GOKU logo"></p>
<figcaption>SON-GOKU Logo</figcaption>
</figure>
</div>
<p>P.S. If you’re interested in learning more about mitigating gradient conflict, you might find my <a href="https://arxiv.org/abs/2509.16959">recent paper</a> interesting. I introduce SON-GOKU, a novel approach based on graph coloring. It’s completely different from PCGrad and it is also highly efficient. I make some interesting theoretical and experimental contributions; I hope you check it out! <a href="https://arxiv.org/abs/2509.16959">https://arxiv.org/abs/2509.16959</a></p>
<hr>


<!-- -->

</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Regularization is any technique that prevents a model from overfitting to its training data. Common examples include dropout, weight decay, and early stopping.↩︎</p></li>
<li id="fn2"><p>An inductive bias is any assumption a learning algorithm makes that lets it generalize beyond its training data. For example, the assumption that nearby pixels in an image are related is an inductive bias.↩︎</p></li>
<li id="fn3"><p>Overfitting is when a model learns patterns that are too specific to the training data, including noise or random changes. It may perform great on training examples but perform poorly on unseen data↩︎</p></li>
<li id="fn4"><p>A “bad compromise” means the shared layers choose an update direction that is only mediocre for each task. Instead of strongly helping either task, the model ends up making weak progress on both (or no progress at all). We call this a “compromise” because it is between what Task A wants and what task B wants.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>algorithms</category>
  <category>machine learning</category>
  <category>theory</category>
  <guid>https://soontosh.github.io/blog-mtl/</guid>
  <pubDate>Sat, 31 Jan 2026 06:00:00 GMT</pubDate>
  <media:content url="https://soontosh.github.io/blog-mtl/image.jpg" medium="image" type="image/jpeg"/>
</item>
</channel>
</rss>
