Paper · 2017-02-27 · cs.CL
Identifying beneficial task relations for multi-task learning in deep neural networks
A hard-shared bi-LSTM tagger is trained on one of 10 sequence-labelling tasks per step, for all 90 main/auxiliary pairs. Logistic regression on learning-curve and dataset features of each task predicts whether the auxiliary task helps. Author-reported: 78.5% accuracy and 0.713 F1 for gain-or-loss prediction, against 55.5% accuracy for the majority baseline.
Multi-task learningSequence labelingMeta-learningRecurrent neural network (RNN)multi-task-learningtask-relatednesssequence-labelinglearning-curves
arXivPDFCodeMarkdown12 min read
AI-compiled by claude-haiku-5-5 on 2026-11-06, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Training one network on several language tasks at once, called multi-task learning, sometimes helps each task and sometimes hurts it. This paper asks which pairs of tasks help each other. Each pair has a main task, which is scored, and an extra task that is only used during training.
The authors train one shared recurrent network on ten tagging tasks, one task at a time, and then run it on all 90 ordered pairs. For each pair they record whether the main task got better or worse. The useful signal comes from how fast each task's training loss falls and where it levels off when the task is trained alone. A simple, readable classifier uses these curve features and some dataset statistics to predict gains. Its best reported result is right in about four cases out of five, well above the majority baseline. The study fixes every setting to the single-task values, so the result answers "does this pair help under these settings" and not "what is the best setting for this pair".
TL;DR
- One bi-directional LSTM with a shared, trainable 100-d embedding layer is trained on ten sequence-labelling datasets, with one dense output layer per task §3.1.
- Each training step draws one task at random and updates from one batch of 32 sentences of that task §3.1.
- For every ordered pair (main, auxiliary), the multi-task model is compared with the main task's single-task model. The label is whether main-task F1 went up §4 fig. 1.
- Logistic regression on 42 features per pair (main-task, auxiliary-task and ratio values of 14 features each) predicts the gain or loss. The authors report 0.785 accuracy and 0.713 F1 tab. 3.
- Settings are the same for single-task and multi-task runs, so the study only says whether a pair helps under those settings §3.1 §4.
Problem
Multi-task learning (MTL) in NLP gives mixed results, and there were no clear conditions under which it helps §1. Earlier work offers a few guesses: auxiliary data should not outweigh the target data §2, MTL may help most when target data is small §2, and success may depend on how evenly the auxiliary labels are spread §2 or on how similar the datasets are §2. The paper tests when MTL helps, not how to make it help, with single-task hyperparameters reused unchanged for the multi-task model, so the predictions are feasible §1.
Method
Shared model §3.1. Each task has its own output layer over a shared encoder. The encoder is a bi-directional LSTM with one hidden layer, shared across tasks. Its inputs are word vectors initialised from pretrained GloVe and updated during training. The embedding parameters are shared too. The model does not distinguish main from auxiliary tasks §3.1.
Training step §3.1. A training step draws one task uniformly at random. It samples a random batch of 32 examples from that task's training data and updates the shared parameters and that task's projection. Each step touches exactly one task. Adadelta is the optimizer §3.1.
# Multi-task training step [§3.1] [code: rnn_mtl/src/experiment.py#L76-L107]
# Input: task_list (10 tasks), batch_size (32)
# Output: updated shared weights and one task head
def train_step(task_list, batch_size):
# Draw one task uniformly; each step trains exactly one task [§3.1]
task = uniform_choice(task_list)
# Sample sentences from that task's training split [§3.1]
tokens, labels, lengths = sample_batch(task, batch_size)
# Forward pass: shared encoder, then the task's own output layer
states = shared_encoder(tokens, lengths) # (T, B, 200)
probs = task_head[task](states) # (T, B, n_labels)
# Masked loss: average per sentence, then over the batch
loss = sentence_mean_loss(probs, labels, lengths)
# Adadelta update, via this task's own optimizer instance
optimizer[task].update(loss)# Shared encoder [§3.1] [code: rnn_mtl/src/mtl_model.py#L40-L43, #L280-L285]
# Input: tokens (T, B) of word ids; lengths (B)
def shared_encoder(tokens, lengths):
# Trainable word vectors, initialised from 100-d GloVe [§3.1]
vectors = embedding[tokens] # (T, B, 100)
# One bi-directional LSTM with 100 units per direction [§3.1]
states = bilstm(vectors, lengths, units=100) # (T, B, 200)
# Dropout on the output, rate 0.1 [code: rnn_mtl/run.sh#L7]
return dropout(states, rate=0.1)# Loss used by the code [code: rnn_mtl/src/mtl_model.py#L123-L134]
# Not stated in the paper; this is what the code computes.
def sentence_mean_loss(probs, labels, lengths):
# Per-token cross-entropy, zeroed on padding positions
token_loss = cross_entropy(probs, labels) * (labels != PAD)
# Sum over the sentence, divide by its length, then average the batch
per_sentence = sum_over_tokens(token_loss) / lengths
return mean(per_sentence)Features for prediction §4. For each of the 10 tasks, the authors compute 14 features from its single-task model and its training data:
- Seven dataset features: number of training sentences, number of labels, type/token ratio, percentage of training words missing from GloVe, label entropy, Frobenius norm of the sentence-by-term count matrix, and Jensen-Shannon divergence between train and test bags of words §4 tab. 2.
- Five loss-curve gradients, taken at 10, 20, 30, 50 and 70 percent of the training log §4.
- Two parameters from a logarithmic fit to the loss curve, L(i) = a · ln(c · i + d) + b; the features are a and c §4.
For each ordered pair (main, auxiliary), the paper uses the main task's features, the auxiliary task's features and their ratio. That gives 3 × 14 = 42 values per pair §4. All features are rescaled to the interval [0, 1] §4.
# Pair row for predicting gain or loss [§4]
# Input: features[task] (14 values each), main, aux
# Output: 42 values for one ordered pair
def pair_row(features, main, aux):
row = {}
for name in features[main]:
# Main value, auxiliary value and their ratio for each feature
row["main_" + name] = features[main][name]
row["aux_" + name] = features[aux][name]
row["main/aux_" + name] = features[main][name] / features[aux][name]
return row# Curve features from the logged single-task training loss [§4]
# Code: experiments.ipynb#L195-L215 (grads at 10/20/30/50/70 % of the log)
def curve_features(losses):
# Finite-difference slope at each fraction of the log [§4]
grads = [slope_at(losses, p) for p in (0.1, 0.2, 0.3, 0.5, 0.7)]
# Fit loss = p0 + p1 * log(p2 * i + p3); the paper's a and c are p1, p2
p0, p1, p2, p3 = fit_log_curve(losses)
return grads + [p1, p2]Labels and classifier §4 fig. 1 tab. 3. For each ordered pair, the gain is the relative change in the main task's micro-averaged F1, from its MTL model against its single-task model, in percent. Pairs with a positive gain are the positive class (40 of 90 in the paper). A logistic regression is trained on the sign of the gain. The reported scores are the mean over 100 runs of randomised 5-fold cross-validation tab. 3.
Single-task and MTL runs §4 fig. 1. Single-task models are trained for 25,000 batches. Multi-task models get 50,000 batches, to offset the fact that each step touches one of the two tasks §4. The code reads F1 at 50,000 and 100,000 batches instead experiments.ipynb; see Paper vs code.
Tasks §3.2 tab. 1. The ten datasets are CCG supertagging, chunking, sentence compression, FrameNet frame and target labelling, POS tagging on tweets, hyperlink prediction, SemEval 2017 keyphrase detection, multiword expressions (STREUSLE), supersense tagging on SemCor, and joint bracket and supersense tagging on STREUSLE §3.2. Dataset statistics, as reported tab. 1:
| Task | Size | # Labels | Tok/typ | %OOV | H(y) | ||X||_F | JSD | F1 |
|---|---|---|---|---|---|---|---|---|
| CCG | 39,604 | 1,285 | 23.08 | 1.13 | 3.28 | 981.3 | 0.41 | 86.1 |
| CHU | 8,936 | 22 | 12.01 | 1.35 | 1.84 | 466.4 | 0.47 | 93.9 |
| COM | 9,600 | 2 | 9.47 | 0.99 | 0.47 | 519.3 | 0.44 | 51.9 |
| FNT | 3,711 | 2 | 8.44 | 1.79 | 0.51 | 286.8 | 0.30 | 58.0 |
| POS | 1,002 | 12 | 3.24 | 14.15 | 2.27 | 116.9 | 0.24 | 82.6 |
| HYP | 2,000 | 2 | 6.14 | 2.14 | 0.47 | 269.3 | 0.48 | 39.3 |
| KEY | 2,398 | 2 | 9.10 | 4.46 | 0.61 | 289.1 | 0.39 | 64.5 |
| MWE | 3,312 | 3 | 9.07 | 0.73 | 0.53 | 217.3 | 0.18 | 43.3 |
| SEM | 15,465 | 73 | 11.16 | 4.72 | 2.19 | 614.6 | 0.35 | 70.8 |
| STR | 3,312 | 118 | 9.07 | 0.73 | 2.43 | 217.3 | 0.26 | 61.5 |
The last column is single-task micro-averaged test F1 tab. 1.
Hyperparameters
Values marked "paper" are stated in the paper. Values marked "code" are not stated in the paper and come from the released scripts, which the paper does not mention. The paper's full setup is given as "not stated" where neither source gives a value.
| Name | Value | Where | Notes |
|---|---|---|---|
| Word vectors | 100-d GloVe, trainable, shared | §3.1 run.sh | Paper says "GloVe" only; code uses glove.6B.100d |
| Hidden size | 100 units per direction | §3.1 experiment.py | Paper: "100 dimensions"; the output is 200 |
| Hidden layers | 1 bi-LSTM | §3.1 run_batch.sh | Task configs say layer 3 (see Pitfalls) |
| Batch size | 32 sentences per step | §3.1 experiment.py | |
| Optimizer | Adadelta | §3.1 run.sh | Only the learning rate is set; TensorFlow defaults apply |
| Learning rate | not stated | run.sh = 0.1 | Parser default is 0.01 experiment.py |
| Dropout on layer output | not stated | run.sh = 0.1 | Applied at evaluation too (see Pitfalls) |
| Timesteps (truncation) | not stated | run.sh = 30 | Longer sentences are cut (see Pitfalls) |
| Single-task training | 25,000 batches | §4 | Code runs 50,000 run_batch.sh |
| Multi-task training | 50,000 batches | §4 | Code and notebook use 100,000 experiments.ipynb |
| Curve points | 10, 20, 30, 50, 70 % | §4 | experiments.ipynb |
| Log-curve form | a · ln(c · i + d) + b | §4 | Code fits a + b · log(c · x + d) |
| Feature scaling | min-max to [0, 1] | §4 | Fitted on all 90 pairs experiments.ipynb |
| Classifier | logistic regression | §4 | Scikit-learn defaults; no settings given experiments.ipynb |
| Evaluation | 100 runs of 5-fold CV | tab. 3 | Splits unseeded experiments.ipynb |
| Gain label | sign of relative F1 change | §4 fig. 1 | experiments.ipynb |
| Regularisation, init, warmup | not stated | — | Init is Glorot uniform in code mtl_model.py |
Results
Author-reported. Setup: ten sequence-labelling tasks; a shared 100-unit bi-LSTM; 90 ordered pairs; 100 repeats of 5-fold cross-validation of the gain-prediction classifier §4 tab. 3.
| Setting | Metric | Baseline | This paper | Source |
|---|---|---|---|---|
| Predict MTL gain/loss, majority baseline | Accuracy / F1 (gain) | — | 0.555 / 0.615 | tab. 3 |
| All 42 features | Accuracy / F1 (gain) | 0.555 / 0.615 | 0.749 / 0.669 | tab. 3 |
| Best data-only features | Accuracy / F1 (gain) | 0.555 / 0.615 | 0.665 / 0.542 | tab. 3 |
| Best combination | Accuracy / F1 (gain) | 0.555 / 0.615 | 0.785 / 0.713 | tab. 3 |
| Pairs that gain from MTL | Count of 90 | — | 40 | §4 fig. 1 |
Pair-level effects: the paper says chunking and the two supersense tasks contribute most as auxiliaries, and hyperlink prediction does not significantly improve any other task §4 fig. 1. Across the 90 pairs, 40 show a gain §4. In the notebook's own output the largest gains are main hyperlink prediction with auxiliary SemCor (about 23 %) and with auxiliary POS (about 22 %) experiments.ipynb.
Averaged logistic coefficients with the largest magnitudes tab. 4: the main task's curve gradient at 30 % (−1.566), the main task's curve gradient at 20 % (−1.164), the main task's log-curve parameter c (1.007), the main task's number of labels (0.828), and the auxiliary task's label entropy (0.798). Table 4 covers all 42 features §4.2 tab. 4.
The authors' main reading is that multi-task gains are more likely when the main task's loss has flattened early, while the auxiliary task's loss is still falling §4.2.
Paper vs code
- Training length. Paper: single-task 25,000 batches, MTL 50,000 §4. Code:
run_batch.shruns single tasks for 50,000 run_batch.sh, and the logs end at 50,000 forccgloss_tr.log and at 100,000 for theccg_compair loss_tr.log. The notebook reads 50,000 and 100,000 experiments.ipynb. The code is twice the paper's length for both. - Hidden size. Paper: "a single hidden layer of 100 dimensions" §3.1. Code: 100 units in each direction, so the output is 200 mtl_model.py.
- Dropout. Not in the paper. Code applies dropout 0.1 to the layer output, with no training/evaluation switch run.sh mtl_model.py.
- Learning rate. Not in the paper.
run.shsets 0.1 run.sh; the parser default is 0.01 experiment.py. - Dropout flag.
run.shpasses--dropout, but the parser declares--dropout_raterun.sh experiment.py. Whether the 0.1 reached the model depends on docopt's prefix matching; I did not run it. - Evaluation split. Paper: F1 on test data tab. 1. Code: the "dev" entries in
data.cfgare the_test.conllfiles data.cfg. Consistent with the paper's table, but the gains and training curves use the test split, not a separate validation split. - Gain metric. The paper uses micro-averaged F1 fig. 1. The code reads the F1 column for gains experiments.ipynb, although
get_f1's docstring says accuracy. The F1 uses positive classes only, excluding the negative labeloand the special symbols experiment.py. - Jensen-Shannon divergence. Paper: between train and test bags of words tab. 2. Code: the test side is built from the label vectorizer, not the input vectorizer.
xs_devis overwritten with the output-vectorized dev data experiments.ipynb; the train side uses input ids experiments.ipynb. So the JSD feature does not compare what the paper describes. - Majority baseline. My arithmetic from the 40 gains and 50 losses in the notebook output experiments.ipynb, not a stated result: always predicting "loss" gives accuracy 50/90 ≈ 0.556 (the paper prints 0.555), and always predicting "gain" gives F1 = 2·40/(2·40 + 50) = 0.615. So the baseline row pairs the accuracy of one constant classifier with the F1 of the other.
- Ablation rows. The ablation sets features to zero in place on
X_abl = X, so each row includes the zeroing of all earlier rows experiments.ipynb. The "best combination" row is not identified in the notebook. - Undefined helper. The gain loop calls
get_performance, which is not defined in the notebook as saved experiments.ipynb. - Task names. The paper's POS is
gposin the code experiments.ipynb; KEY iskeysem17; STR isstreusle; SEM issemcor; the other names are the same.data.cfgalso listskeyaclandupos, which are not among the ten tasks data.cfg. - Layers. Task configs register each task at layer 3 task_ccg.cfg, while the model has one layer. The code then uses the top layer and prints a warning mtl_model.py.
- No discrepancy found in: 100-d GloVe, batch 32, 10 tasks, 90 ordered pairs, 14 features per task, 42 per pair, and the curve points at 10, 20, 30, 50, 70 % §3.1 §4 experiment.py experiments.ipynb.
Pitfalls
- Truncation to 30 tokens. Sentences are padded or cut to 30 positions, which include the GO and EOS markers dio.py dio.py. Words beyond that are dropped from both training and evaluation. Evaluation scores positions 1 to 28 of each row experiment.py, so the last words of long sentences are not scored. The paper does not mention a cap.
- Dropout at evaluation time. The dropout op sits in the graph with no mode switch, so the same dropout runs when evaluating and decoding mtl_model.py. The source comments this as a TODO.
- One optimizer per task. Each task gets its own Adadelta instance, so the shared weights carry a separate accumulator per task mtl_model.py mtl_model.py. The paper says only "using Adadelta" §3.1.
- Hidden size wording. "100 dimensions" is per direction in the code, so the layer output is 200, not 100 mtl_model.py.
- Loss is not in the paper. The per-sentence average and then batch average is only in the code mtl_model.py.
- No validation split and no early stopping. Gains are read at fixed iterations on the test split data.cfg experiments.ipynb.
- Randomness is not controlled. Task choice uses Python's
randomwithout a seed experiment.py; cross-validation splits usenp.random.randintwithout a seed experiments.ipynb. Training-seed variance is not reported. The "100 runs" is over CV splits only tab. 3. - Scaling before CV. Min-max scaling is fitted on all 90 rows before cross-validation experiments.ipynb, so the test folds influence the scaling.
- Learning-curve features use training loss. Each logged value is the mean of the task's batch losses since the previous log line experiment.py experiment.py. The gradients are finite differences between neighbouring log lines, not per-iteration values experiments.ipynb.
- Curve fit uses a fixed slice. The fit uses every tenth log line up to index 5,000 experiments.ipynb. For a 50,000-batch single-task log, that is 500 points covering the whole run, but not for other lengths.
- Data is not in the repository.
data/is absent from the clone, so the splits and the conversion from the original corpora cannot be checked here. - Code is GPL-3.0. The repository is GPL-3.0 LICENSE. Only the pseudocode above is ours, paraphrased; nothing is quoted.
- Sensitive coefficients. Many features are correlated, and the coefficients are averages over random splits experiments.ipynb. The paper's own discussion stresses the curve features, but the coefficient ranking can change with the split.
Lineage
- Builds on: hard parameter sharing in deep networks [Caruana, 1993, as cited in §3]; recurrent MTL for sequence labelling [Søgaard and Goldberg 2016; Klerke et al. 2016; Plank 2016; Alonso and Plank 2017; as cited in §3.1]. The paper reuses hyperparameters across tasks §3.1.
- Compared against: single-task models with the same settings §4. The paper discusses earlier findings from Luong et al. 2016, Hovy et al. 2017, Alonso and Plank 2017, and Mou et al. 2016 §2.
- Superseded by: not known from content in this wiki.
Source and license
Adapted from “Identifying beneficial task relations for multi-task learning in deep neural networks” by Joachim Bingel, Anders Søgaard (arXiv:1702.08303), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/jbingel/eacl2017_mtl at commit 57c9cbc53f5d (GPL-3.0). Any quoted code is shown under that license.