wikillm

Paper · 2018-06-10 · cs.CL

All-in-one: Multi-task Learning for Rumour Verification

Trains one LSTM with stance and rumour-detection heads alongside a veracity head, sharing the recurrent layers, on Twitter reply branches (PHEME, RumourEval). On PHEME with 5 events the three-task model reaches macro-F 0.396 against 0.339 for the NileTMRG* baseline; on RumourEval the veracity-plus-stance model reaches 0.558 against 0.539 for NileTMRG*. Author-reported.

Multi-task learningRecurrent neural network (RNN)Text classificationrumour-verificationmulti-task-learninglstmstance-classificationmisinformationtwitter

arXivPDFCodeMarkdown14 min read

AI-compiled by claude-haiku-5-5 on 2026-10-18, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.

In plain words

A rumour is a claim that spreads on social media before anyone has checked it. Deciding whether a rumour is true, false or still unknown is hard. People usually split the job into steps: notice that a post is a rumour, follow the replies, and work out whether each reply backs the claim, questions it or denies it. The last step, the final verdict, depends on the others.

Most earlier systems solved each step separately, and the output of one fed the next. This paper trains one neural network for the verdict and for the helper steps at the same time. Both kinds of task share the same core of the network, so the side tasks can give the verdict useful hints. This idea is called multi-task learning.

The authors compare several combinations of tasks against a single-task model and a strong earlier system. The best model uses all three tasks, and on PHEME with five events it scores higher on the verdict than the single-task model and the earlier system on the PHEME dataset with five events. They also look at how the results relate to the statistics of each dataset.

TL;DR

  • Rumour verification is the final step of a four-step pipeline. The paper treats veracity (true, false, unverified) as the main task and stance and rumour detection as auxiliary tasks §1 §2.1.
  • A shared LSTM stack reads each reply branch, with separate dense and output layers per task. Training uses the sum of task losses §4.1 §4.2.
  • Author-reported macro-F on veracity: PHEME 5 events 0.396 (three tasks) against 0.339 (NileTMRG*); PHEME 9 events 0.405 against 0.297; RumourEval 0.558 (veracity + stance) against 0.539 for NileTMRG* tab. 3.
  • Official code (MIT) is public. It shows the two-task and three-task models but not the single-task or NileTMRG* baselines, and it differs from the paper in loss weights, activations and the search space outer.py.
  • Read "Paper vs code" and "Pitfalls" before reimplementing.

Problem

Rumour resolution is a pipeline of four sub-tasks: rumour detection, rumour tracking, stance classification and rumour verification. Earlier work studied each sub-task separately, and the authors state that they know of no earlier work covering the whole pipeline §1 §2.1.

Earlier models that use stance as a feature assume stance and veracity labels for the same data. The authors state that this does not apply to their setting, because not every thread has stance labels §2.2.

Verification is hard for people too. For the PHEME rumours, a non-expert annotator agreed with the journalist labels on 60 to 65 percent of the stories from the five largest events §3.2. The veracity classes are imbalanced, so a majority-class baseline already scores well on accuracy §6.

Method

Data. The paper uses two Twitter datasets. RumourEval (SemEval-2017 Task 8) has 325 threads, with stance labels and veracity labels only, since every thread is a rumour §3.1 tab. 1. PHEME has nine events with rumour detection, veracity and, for a subset, stance labels §3.2 tab. 2. A conversation is split into linear branches, each running from a leaf reply up to the source tweet. Each branch is one training instance §3 fig. 2.

Features. Text is lower-cased, non-alphabetic characters are removed and tokens are split with NLTK. Each word gets a 300-dimensional word2vec vector trained on Google News, and a tweet is the average of its word vectors §4.4. The official repository does not compute these features. It loads preprocessed arrays from a figshare archive README.md MTL3_CV_VeracityStanceDetection.py.

Sequential model (single task). An LSTM layer reads the tweets of a branch in order, followed by dense ReLU layers and a softmax §4.1. Stance uses the output at every tweet. Detection and veracity use only the output at the last tweet. Per-thread predictions are majority votes over the branches of the thread §4.1. The single-task baseline is named branchLSTM §4.1 tab. 3.

Multi-task models. All tasks share the LSTM layers (hard parameter sharing), and each task then has its own dense layers and output §2.2 §4.2 fig. 3. The paper tests three settings: veracity with stance (MTL2), veracity with detection (MTL2), and all three tasks (MTL3) §4.2. In the code, the veracity and detection heads each have their own LSTM layer on top of the shared stack, while the stance head reads the shared states directly MTL3_CV_VeracityStanceDetection.py. The paper does not describe these private LSTM layers.

Loss. The paper uses a sum of the task losses. When a branch has no label for a task, that task adds nothing to the loss §4.2. The code implements this with per-sample weights close to zero MTL3_CV_VeracityStanceDetection.py. For MTL3 the code uses fixed loss weights of 0.3 for stance, 0.4 for veracity and 0.3 for detection MTL3_CV_VeracityStanceDetection.py.

Training. Categorical cross-entropy is used for stance and veracity, and the code uses binary cross-entropy for detection §4.1 MTL3_CV_VeracityStanceDetection.py. Dropout of 0.5 is applied before each output layer §5.1 MTL3_CV_VeracityStanceDetection.py. Hyperparameters are chosen by Tree-structured Parzen Estimator search with hyperopt on the development set, minimising a loss built from macro-F §5.1 parameter_search.py.

Evaluation. RumourEval: tune on dev, retrain on train plus dev, test on the test split §5.2 MTL2_RumEval_VeracityStance.py. PHEME: leave-one-event-out cross-validation over five or nine events. Charlie Hebdo is the development event §5.2 MTL3_CV_VeracityStanceDetection.py.

Pseudocode
# Multi-task branch model, MTL3 variant  [§4.2] [fig. 3]
# Input:  one branch, zero-padded to 25 tweets
# [code: MTL3_CV_VeracityStanceDetection.py#L116]
# Output: stance per tweet, veracity and detection per branch

def forward(branch):
    # Shared LSTM stack; masked (padded) steps are skipped  [§4.2]
    shared_states = shared_lstm_stack(mask(branch))  # (T, H)

    # Stance head: dense layers applied to every tweet  [§4.2] [fig. 3]
    stance_hidden = dense_layers_per_tweet(shared_states)  # (T, D)
    stance = softmax(linear(dropout(stance_hidden)))       # (T, 4)

    # Veracity head: own LSTM, read at the last unmasked step  [§4.1]
    veracity_state = lstm_veracity(shared_states)  # (H,)
    veracity = softmax(linear(dropout(dense(veracity_state))))  # (3,)

    # Detection head: own LSTM, read at the last unmasked step  [§4.1]
    detection_state = lstm_detection(shared_states)  # (H,)
    detection = softmax(linear(dropout(dense(detection_state))))  # (2,)

    return stance, veracity, detection
Pseudocode
# Training loss for one batch of branches  [§4.2]
# [code: MTL3_CV_VeracityStanceDetection.py#L88-L104]
# Labels that are missing for a task contribute (almost) nothing

def training_loss(branches, labels):
    # Stance is labelled per tweet; padded or unlabelled tweets get weight
    # 1e-5 in the code, not exactly 0
    # [code: MTL3_CV_VeracityStanceDetection.py#L92]
    stance_weight = any_label_per_tweet(labels.stance) + 1e-5
    # Veracity weight is 1e-5 when a branch has no veracity label
    # [code: MTL3_CV_VeracityStanceDetection.py#L93]
    veracity_weight = any_label_per_branch(labels.veracity) + 1e-5
    # Per-task cross-entropy, weighted by the masks above
    stance_loss = weighted_cross_entropy(stance, labels.stance, stance_weight)
    veracity_loss = weighted_cross_entropy(
        veracity, labels.veracity, veracity_weight
    )
    detection_loss = cross_entropy(detection, labels.detection)
    # Code: fixed weights 0.3, 0.4, 0.3
    # [code: MTL3_CV_VeracityStanceDetection.py#L77-L79]
    # Paper text: a plain sum of the task losses  [§4.2]
    return 0.3 * stance_loss + 0.4 * veracity_loss + 0.3 * detection_loss
Pseudocode
# Leave-one-event-out evaluation on PHEME  [§5.2]
# [code: MTL3_CV_VeracityStanceDetection.py#L336-L346]
# Thread-level veracity is a majority vote over branch predictions  [§4.1]

def evaluate_leave_one_event_out(events):
    # Hold out each event once; train on all the others
    for test_event in events:
        train_events = [e for e in events if e != test_event]
        model = train(train_events)  # Adam, 50 epochs, batch 32  [§5.1]
        branch_predictions = model.predict(test_event.branches)
        # Ties go to the smallest class index
        # [code: branch2treelabels.py#L22-L24]
        thread_predictions = majority_vote(branch_predictions)
    # Macro-F over the pooled predictions of all folds
    # [code: MTL3_CV_VeracityStanceDetection.py#L491-L526]
    return macro_f1(pooled_labels, pooled_predictions)

Key quantities, in the paper's notation (no numbered equations are given):

  • Macro-F on each task, computed on the test set §5.2.
  • Hyperparameter objective for multi-task models: the paper writes the product of (1 − macro-F) over the tasks, and the code uses the sum §5.1 MTL3.

Hyperparameters

NameValueWhereNotes
OptimizerAdam (Keras default settings)MTL3_CV_VeracityStanceDetection.pyNot stated in the paper
Learning ratenot stated in the paper; searched over {1e-4, 1e-3}parameter_search.pyThe value is searched but never passed to the model, so Adam's default applies (see Paper vs code)
Mini-batch size32§5.1 parameter_search.py
Epochs50§5.1 parameter_search.pyNo early stopping in the code
Shared LSTM layers{1, 2}§5.1 parameter_search.py
LSTM units{100, 200, 300}§5.1 parameter_search.py
Dense layerspaper: 1 to 4; code search: {1, 2}§5.1 parameter_search.pySee Paper vs code
Dense units{300, 400, 500, 600}§5.1 parameter_search.py
Dropout0.5, before the output layers§5.1 MTL3_CV_VeracityStanceDetection.py
L2 regularisationpaper: {1e-4, 1e-3}; code: {1e-3}§5.1 parameter_search.pyCode applies it as an activity regulariser on the outputs MTL3_CV_VeracityStanceDetection.py
Search methodTree-structured Parzen Estimator (hyperopt)§5.1 parameter_search.py
Search trials30§5.1Code default is 10 outer.py; the README uses 50
Loss weights (MTL3)Paper: plain sum; code: 0.3 stance, 0.4 veracity, 0.3 detection§4.2 MTL3_CV_VeracityStanceDetection.py
Max branch lengthnot stated in the paper; code uses 25 tweetsMTL3_CV_VeracityStanceDetection.pyLonger branches are truncated at the end
Word embeddings300-d word2vec, Google News, averaged per tweet§4.4Not computed in the repository
Dev setRumourEval: dev split; PHEME: Charlie Hebdo§5.2
Cross-validationRumourEval: fixed split; PHEME: leave-one-event-out, 5 or 9 events§3.2 §5.2

Results

Author-reported. Setup: RumourEval (train/dev/test split) and PHEME (leave-one-event-out, five or nine events), with word2vec features, LSTM models and macro-F and accuracy as metrics §5.2 §6. The paper gives one value per cell and no variance or seed information tab. 3. The MTL2 detection and MTL3 models were run only on PHEME, since RumourEval has no detection labels §6.

DatasetMetricMajority (True)NileTMRG*branchLSTMMTL2 Veracity+StanceMTL2 Veracity+DetectionMTL3Source
RumourEvalMacro F0.1480.5390.4910.558not runnot runtab. 3
RumourEvalAccuracy0.2860.5700.5000.571not runnot runtab. 3
PHEME 5 eventsMacro F0.2260.3390.3360.3760.3730.396tab. 3
PHEME 5 eventsAccuracy0.5110.4380.4540.4410.4100.492tab. 3
PHEME 9 eventsMacro F0.2050.2970.2590.3180.3450.405tab. 3
PHEME 9 eventsAccuracy0.4440.3600.3140.3570.3970.405tab. 3

Per-event results for MTL3 on the five PHEME events tab. 4:

Held-out eventMacro FAccuracyTRUEFALSEUnverified
Charlie Hebdo0.3270.3690.5020.2270.251
Sydney siege0.3500.5750.7310.1530.168
Ferguson0.1890.3380.05800.508
Ottawa shooting0.3520.6450.7890.1680.100
Germanwings-crash0.4290.4200.5380.3580.364

The per-event figure for the single-task and two-task models is described in words only fig. 4 §6.1.

Dataset statistics for RumourEval tab. 1, for stance classes S, D, Q and C (support, deny, query, comment; the abbreviations are inferred from the text §3.1):

SplitThreadsBranchesTweetsTrueFalseUnverifiedSDQC
Development2521528110123691128173
Testing28772104981289471106778
Training2723030423812750958413333302734
Total325401755681457410610044154643685

Dataset statistics for PHEME tab. 2:

EventThreadsTweetsRumoursNon-rumoursTrueFalseUnverified
Charlie Hebdo2,07938,2684581,621193116149
Sydney siege1,22123,9965226993828654
Ferguson1,14324,175284859108266
Ottawa shooting89012,2844704203297269
Germanwings-crash4694,4892382319411133
Putin missing23883512611209117
Prince Toronto233902229402227
Gurlitt13817961775902
Ebola Essien142261400140
Total6,425105,3542,4024,0231,067638697

Label-distribution statistics per event for stance (S), veracity (V) and detection (D): kurtosis, entropy and token-type ratio (TTR). A dash means the paper reports no value tab. 5 §6.2:

EventKurt SKurt VKurt DEnt SEnt VEnt DTTR STTR VTTR D
charliehebdo-0.73-1.25-0.180.891.080.530.20.110.07
ottawashooting-0.830.33-1.991.040.820.690.190.110.09
germanwings-crash-1.11-0.86-1.990.990.990.690.260.160.13
sydneysiege-0.790.71-1.911.010.760.680.190.110.07
ferguson-0.517.44-0.640.990.280.560.170.090.06
ebola-essien-0.22-3-31.01000.380.270.27
putinmissing-1.559.08-1.981.120.260.690.490.260.24
prince-toronto-1.0527.7553.261.040.140.090.360.180.18
gurlitt-25.5-1.95-0.140.68-0.310.25

The authors report that multi-task models outperform single-task models for each of the five largest events §6.1, and that all models predict the majority class (true) best §6.1.

Paper vs code

Official repository: https://github.com/kochkinaelena/Multitask4Veracity at commit 56d9aed33d15d58fae5d6049db67622e6d07a4a4, MIT licence. The repository belongs to the first author, and the paper's footnote links to it §5.1. It contains the MTL2 (RumourEval, PHEME 5, PHEME 9) and MTL3 models, the hyperparameter search and the evaluation code. The single-task branchLSTM baseline, the NileTMRG* baseline and the majority baseline are not in the repository, and neither are the preprocessed data (figshare) or the saved_data/ folder that the code loads README.md.

Differences between paper and code:

No discrepancies were found in the RumourEval protocol: the code retrains on train plus dev before testing MTL2_RumEval_VeracityStance.py, as §5.2 describes.

Pitfalls

  • Objective and loss disagree. Tuning uses a product (paper) or sum (code) of (1 − F) terms, and training uses a weighted sum (code) or a plain sum (paper). Implement the code's choices if you want to match the reported numbers, and say so in your write-up.
  • Dense activations are unclear. The paper says ReLU, the code uses none. Whether the reported numbers came from a ReLU or a linear model cannot be verified from the repository, so test both before concluding.
  • Learning rate is effectively not searched. The searched value is never used, so the released code runs with Adam's default. Whether the paper's results used the searched value cannot be verified; the paper does not state an optimizer or learning rate.
  • Detection loss. The detection head has two softmax outputs but is trained with binary cross-entropy MTL3_CV_VeracityStanceDetection.py. Which class is "1" is not stated in the paper or the code; F1 is taken as binary with the default positive label MTL3_CV_VeracityStanceDetection.py.
  • Missing labels are down-weighted, not removed. The code uses 1e-5 for unlabelled tweets and branches MTL3_CV_VeracityStanceDetection.py. This is almost zero, not zero, and the paper says such instances "do not add anything" §4.2.
  • Branch truncation. Branches are padded to a fixed length of 25 tweets and truncated at the end MTL3_CV_VeracityStanceDetection.py MTL3_CV_VeracityStanceDetection.py. Long conversations keep only their first 25 tweets. The paper gives no length limit.
  • Duplicate and placeholder IDs. Stance evaluation keeps the first occurrence of each tweet ID and drops a placeholder ID b'a' MTL3_CV_VeracityStanceDetection.py. The paper does not mention deduplication.
  • Tie-breaking in majority vote. The branch vote uses np.unique and argmax over counts, so a tie goes to the smallest class index branch2treelabels.py. The paper gives no tie rule.
  • Thread label. A thread's label is taken from its first branch branch2treelabels.py. This is safe only if every branch of a thread carries the same label.
  • Search and final training differ in size. For five-event PHEME, the search trains on three events and tests on Charlie Hebdo MTL3_CV_VeracityStanceDetection.py. Final cross-validation trains on four events. The chosen hyperparameters therefore come from a different training set size than the final models.
  • Single run, no variance. Tables give one number per cell, with no seeds or standard deviations tab. 3 tab. 4. The paper gives no significance test, so small gaps between models cannot be judged from the card.
  • Results depend on the split. The paper argues that PHEME with nine events is harder, because the four added events are small and contain a single rumour story §6. The per-event scores vary widely tab. 4 tab. 5.
  • Baselines are not reproducible from this repository. NileTMRG* is the authors' own reimplementation, using a stance model from earlier work §4.3. The single-task branchLSTM is not in the code. Table 3 rows for these cannot be checked against the code.
  • Data prerequisites. The code needs preprocessed arrays with specific names (train_array.npy, fold_stance_labels.npy, labels.npy, rnr_labels.npy, tweet_ids.npy, ids.npy), which come from a separate figshare archive README.md MTL3_CV_VeracityStanceDetection.py. Word-embedding extraction is not in the repository.
  • Python 2 and 3. Some files are Python 2 scripts, so run them under the Python version the code targets, or port them with care around byte-string IDs MTL3_CV_VeracityStanceDetection.py.

Lineage

  • Builds on: the branchLSTM sequential approach of Zubiaga et al. §4.1, the stance classifier of Kochkina et al. 2017 used for NileTMRG* features §4.3, and the observation of Alonso and Plank that multi-task gains depend on label distributions, which this paper extends to rumour tasks §6.2.
  • Compared against: Majority (True), NileTMRG* (the best veracity system at SemEval-2017 Task 8) and the single-task branchLSTM §4.1 §4.3 tab. 3.
  • Superseded by: not stated in the wiki.

Source and license

Adapted from “All-in-one: Multi-task Learning for Rumour Verification” by Elena Kochkina, Maria Liakata, Arkaitz Zubiaga (arXiv:1806.03713), 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/kochkinaelena/Multitask4Veracity at commit 56d9aed33d15 (MIT). Any quoted code is shown under that license.