Hierarchical classification implementation question

L_Z: <p>I have 2 super classes, let’s say A and B. And then I have 2 sub classes under class B, call them C and D.</p>
<ol>
<li>How should I train the model to appropriately classify the three leaf classes (A, C, and D)? Like how to combine the losses for both super and sub classes?</li>
<li>How to do the inference after? Like how to evaluate the probability distribution being used to do the classification?</li>
</ol>

KFrank: <p>Hi L!</p>
<aside class="quote no-group" data-username="L_Z" data-post="1" data-topic="207763" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/l_z/48/71230_2.png" class="avatar"> L_Z:</div>
<blockquote>
<p>I have 2 super classes, let’s say A and B. And then I have 2 sub classes under class B, call them C and D.</p>
</blockquote>
</aside>
<p>Let me assume that your actual use case has three “leaf” classes.</p>
<aside class="quote no-group">
<blockquote>
<ol>
<li>How should I train the model to appropriately classify the three leaf classes (A, C, and D)?</li>
</ol>
</blockquote>
</aside>
<p>Let’s say that A is “electro-sharks,” B is “mammals,” C is “cats,” and<br>
D is “dogs.”</p>
<p>Just train this as a three-class classifier (with <code>CrossEntropyLoss</code>)<br>
for just the leaf classes.  I don’t see any likely benefit in trying to<br>
account for the fact that “cats” and “dogs” are logically part of the<br>
“mammals” super-class.</p>
<aside class="quote no-group">
<blockquote>
<ol start="2">
<li>How to do the inference after? Like how to evaluate the probability distribution being used to do the classification?</li>
</ol>
</blockquote>
</aside>
<p>I’m not sure what you’re asking.  I would say for inference, take<br>
<code>argmax()</code> of the output of your model to get the predicted integer<br>
class label (of the three leaf classes) of the sample in question (or<br>
pass that output through <code>softmax()</code> to get predicted probabilities<br>
of the three classes).</p>
<p>Best.</p>
<p>K. Frank</p>

L_Z: <p>The reason why I want to apply the hierarchical classification is that I want to increase my overall accuracy. Like I want the model to classify between my two super classes first which are two classes that are pretty similar but only have one major difference visually. And then classify based on the sub classes under class B. So maybe I want to compare the conditional probability instead of evenly distributed probability around all three classes. Or let’s say I have more than 2 sub classes, how does that work?<br>
I will clarify my second question. So if I want to train based on both my super and sub classes, I will have 2 set of probability distribution, then how should I use them to find out which class I should pick?</p>

KFrank: <p>Hi L!</p>
<aside class="quote no-group" data-username="L_Z" data-post="3" data-topic="207763" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/l_z/48/71230_2.png" class="avatar"> L_Z:</div>
<blockquote>
<p>The reason why I want to apply the hierarchical classification is that I want to increase my overall accuracy.</p>
</blockquote>
</aside>
<p>In principle, the fact that two of your classes are grouped into a<br>
single super-class is information about the structure of your problem<br>
that could be provided directly to your model so that it wouldn’t have<br>
to “learn” that part of the structure.  And in principle, this could make<br>
your model work better.</p>
<p>But I think that in practice, training directly with the three leaf classes<br>
will work better than trying to introduce the super-class somehow.  I<br>
would say that the burden is on you to show that using the super-class<br>
actually helps.</p>
<p>But you haven’t told us anything about your actual use case, so it’s<br>
hard to say.</p>
<aside class="quote no-group">
<blockquote>
<p>I will have 2 set of probability distribution, then how should I use them to find out which class I should pick?</p>
</blockquote>
</aside>
<p>Let me assume that you are asking the following:</p>
<p>You predict the “electro-sharks” super-class (that only has one<br>
sub-class) with probability <code>p</code> and the “mammals” super-class with<br>
probability <code>1 - p</code>. Within the “mammals” super-class you predict<br>
“cats” with probability <code>q</code> and “dogs” with probability <code>1 - q</code>.  Then<br>
you have predicted “electro-sharks” with probability <code>p</code>, “cats” with<br>
probability <code>(1 - p) * q</code>, and “dogs” with probability <code>(1 - p) * (1 - q)</code>.<br>
To get the prediction for a single specific class, just take the class that<br>
has the largest predicted probability.</p>
<p>Best.</p>
<p>K. Frank</p>

L_Z: <p>Hi Frank,<br>
How should I train the model to properly get the probability distribution for the two subclasses as q and (1-q) respectively?<br>
Like should the end of the model has 2 nn.Linear layers? Each with output channel set as 2? For example, features = self.cnnBlock(input_sequence), and then I return super_class_output = self.fc_super(features) and sub_class_out = self.fc_sub(features) in my forward function, where self.fc_super = nn.Linear(input_channels, num_superclasses) and self.fc_sub = nn.Linear(input_channles, num_subclasses).<br>
Then, if this is the case, how should I combine the losses? Should I pass in super class and sub class labels separately to the model to evaluate the loss? And then combine the two? But then how should I label each data file as? Like should I label electro-sharks’ sub class ask as electro-sharks?<br>
Also, because inside each batch, there might be cases of electro-sharks, how should I pass that and differentiate between cats and dogs? Like should I get rid of the cases which are labeled as electro-sharks first and then evaluate the loss and then combine with the super class loss?</p>

stillahill: <p>A simple approach would be to encode your class hierarchy as a multilabel problem. So, your three label combinations would be:</p>
<pre><code class="lang-auto">from sklearn.preprocessing import MultiLabelBinarizer
import pandas as pd

mlb = MultiLabelBinarizer()
labels = mlb.fit_transform([["A"], ["B", "C"], ["B", "D"]])
df = pd.DataFrame(labels, columns=mlb.classes_)
print(df)
</code></pre>
<div class="md-table">
<table>
<thead>
<tr>
<th style="text-align:right">A</th>
<th style="text-align:right">B</th>
<th style="text-align:right">C</th>
<th style="text-align:right">D</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right">1</td>
<td style="text-align:right">0</td>
<td style="text-align:right">0</td>
<td style="text-align:right">0</td>
</tr>
<tr>
<td style="text-align:right">0</td>
<td style="text-align:right">1</td>
<td style="text-align:right">1</td>
<td style="text-align:right">0</td>
</tr>
<tr>
<td style="text-align:right">0</td>
<td style="text-align:right">1</td>
<td style="text-align:right">0</td>
<td style="text-align:right">1</td>
</tr>
</tbody>
</table>
</div><p>This approach allows you to calculate evaluation metrics for individual labels or aggregate metrics across different hierarchy levels.</p>