prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Typo in docs? multi-label text classification
  The docs give an example of text classification on IMDB [here](https://spacy.io/usage/training#example-textcat). It says it's "multi-label", but this dataset is binary. So I'm not sure what you mean here.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `examples/training/train_textcat.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 # coding: utf8
  3 """Train a multi-label convolutional neural network text classifier on the
  4 IMDB dataset, using the TextCategorizer component. The dataset will be loaded
  5 automatically via Thinc's built-in dataset loader. The model is added to
  6 spacy.pipeline, and predictions are available via `doc.cats`. For more details,
  7 see the documentation:
  8 * Training: https://spacy.io/usage/training
  9 
  10 Compatible with: spaCy v2.0.0+
  11 """
  12 from __future__ import unicode_literals, print_function
  13 import plac
  14 import random
  15 from pathlib import Path
  16 import thinc.extra.datasets
  17 
  18 import spacy
  19 from spacy.util import minibatch, compounding
  20 
  21 
  22 @plac.annotations(
  23     model=("Model name. Defaults to blank 'en' model.", "option", "m", str),
  24     output_dir=("Optional output directory", "option", "o", Path),
  25     n_texts=("Number of texts to train from", "option", "t", int),
  26     n_iter=("Number of training iterations", "option", "n", int))
  27 def main(model=None, output_dir=None, n_iter=20, n_texts=2000):
  28     if model is not None:
  29         nlp = spacy.load(model)  # load existing spaCy model
  30         print("Loaded model '%s'" % model)
  31     else:
  32         nlp = spacy.blank('en')  # create blank Language class
  33         print("Created blank 'en' model")
  34 
  35     # add the text classifier to the pipeline if it doesn't exist
  36     # nlp.create_pipe works for built-ins that are registered with spaCy
  37     if 'textcat' not in nlp.pipe_names:
  38         textcat = nlp.create_pipe('textcat')
  39         nlp.add_pipe(textcat, last=True)
  40     # otherwise, get it, so we can add labels to it
  41     else:
  42         textcat = nlp.get_pipe('textcat')
  43 
  44     # add label to text classifier
  45     textcat.add_label('POSITIVE')
  46 
  47     # load the IMDB dataset
  48     print("Loading IMDB data...")
  49     (train_texts, train_cats), (dev_texts, dev_cats) = load_data(limit=n_texts)
  50     print("Using {} examples ({} training, {} evaluation)"
  51           .format(n_texts, len(train_texts), len(dev_texts)))
  52     train_data = list(zip(train_texts,
  53                           [{'cats': cats} for cats in train_cats]))
  54 
  55     # get names of other pipes to disable them during training
  56     other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'textcat']
  57     with nlp.disable_pipes(*other_pipes):  # only train textcat
  58         optimizer = nlp.begin_training()
  59         print("Training the model...")
  60         print('{:^5}\t{:^5}\t{:^5}\t{:^5}'.format('LOSS', 'P', 'R', 'F'))
  61         for i in range(n_iter):
  62             losses = {}
  63             # batch up the examples using spaCy's minibatch
  64             batches = minibatch(train_data, size=compounding(4., 32., 1.001))
  65             for batch in batches:
  66                 texts, annotations = zip(*batch)
  67                 nlp.update(texts, annotations, sgd=optimizer, drop=0.2,
  68                            losses=losses)
  69             with textcat.model.use_params(optimizer.averages):
  70                 # evaluate on the dev data split off in load_data()
  71                 scores = evaluate(nlp.tokenizer, textcat, dev_texts, dev_cats)
  72             print('{0:.3f}\t{1:.3f}\t{2:.3f}\t{3:.3f}'  # print a simple table
  73                   .format(losses['textcat'], scores['textcat_p'],
  74                           scores['textcat_r'], scores['textcat_f']))
  75 
  76     # test the trained model
  77     test_text = "This movie sucked"
  78     doc = nlp(test_text)
  79     print(test_text, doc.cats)
  80 
  81     if output_dir is not None:
  82         output_dir = Path(output_dir)
  83         if not output_dir.exists():
  84             output_dir.mkdir()
  85         nlp.to_disk(output_dir)
  86         print("Saved model to", output_dir)
  87 
  88         # test the saved model
  89         print("Loading from", output_dir)
  90         nlp2 = spacy.load(output_dir)
  91         doc2 = nlp2(test_text)
  92         print(test_text, doc2.cats)
  93 
  94 
  95 def load_data(limit=0, split=0.8):
  96     """Load data from the IMDB dataset."""
  97     # Partition off part of the train data for evaluation
  98     train_data, _ = thinc.extra.datasets.imdb()
  99     random.shuffle(train_data)
  100     train_data = train_data[-limit:]
  101     texts, labels = zip(*train_data)
  102     cats = [{'POSITIVE': bool(y)} for y in labels]
  103     split = int(len(train_data) * split)
  104     return (texts[:split], cats[:split]), (texts[split:], cats[split:])
  105 
  106 
  107 def evaluate(tokenizer, textcat, texts, cats):
  108     docs = (tokenizer(text) for text in texts)
  109     tp = 1e-8  # True positives
  110     fp = 1e-8  # False positives
  111     fn = 1e-8  # False negatives
  112     tn = 1e-8  # True negatives
  113     for i, doc in enumerate(textcat.pipe(docs)):
  114         gold = cats[i]
  115         for label, score in doc.cats.items():
  116             if label not in gold:
  117                 continue
  118             if score >= 0.5 and gold[label] >= 0.5:
  119                 tp += 1.
  120             elif score >= 0.5 and gold[label] < 0.5:
  121                 fp += 1.
  122             elif score < 0.5 and gold[label] < 0.5:
  123                 tn += 1
  124             elif score < 0.5 and gold[label] >= 0.5:
  125                 fn += 1
  126     precision = tp / (tp + fp)
  127     recall = tp / (tp + fn)
  128     f_score = 2 * (precision * recall) / (precision + recall)
  129     return {'textcat_p': precision, 'textcat_r': recall, 'textcat_f': f_score}
  130 
  131 
  132 if __name__ == '__main__':
  133     plac.call(main)
  134
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/examples/training/train_textcat.py b/examples/training/train_textcat.py
  --- a/examples/training/train_textcat.py
  +++ b/examples/training/train_textcat.py
  @@ -1,6 +1,6 @@
   #!/usr/bin/env python
   # coding: utf8
  -"""Train a multi-label convolutional neural network text classifier on the
  +"""Train a convolutional neural network text classifier on the
   IMDB dataset, using the TextCategorizer component. The dataset will be loaded
   automatically via Thinc's built-in dataset loader. The model is added to
   spacy.pipeline, and predictions are available via `doc.cats`. For more details,
  
verification_info: {"golden_diff": "diff --git a/examples/training/train_textcat.py b/examples/training/train_textcat.py\n--- a/examples/training/train_textcat.py\n+++ b/examples/training/train_textcat.py\n@@ -1,6 +1,6 @@\n #!/usr/bin/env python\n # coding: utf8\n-\"\"\"Train a multi-label convolutional neural network text classifier on the\n+\"\"\"Train a convolutional neural network text classifier on the\n IMDB dataset, using the TextCategorizer component. The dataset will be loaded\n automatically via Thinc's built-in dataset loader. The model is added to\n spacy.pipeline, and predictions are available via `doc.cats`. For more details,\n", "issue": "Typo in docs? multi-label text classification\nThe docs give an example of text classification on IMDB [here](https://spacy.io/usage/training#example-textcat). It says it's \"multi-label\", but this dataset is binary. So I'm not sure what you mean here.\n", "before_files": [{"content": "#!/usr/bin/env python\n# coding: utf8\n\"\"\"Train a multi-label convolutional neural network text classifier on the\nIMDB dataset, using the TextCategorizer component. The dataset will be loaded\nautomatically via Thinc's built-in dataset loader. The model is added to\nspacy.pipeline, and predictions are available via `doc.cats`. For more details,\nsee the documentation:\n* Training: https://spacy.io/usage/training\n\nCompatible with: spaCy v2.0.0+\n\"\"\"\nfrom __future__ import unicode_literals, print_function\nimport plac\nimport random\nfrom pathlib import Path\nimport thinc.extra.datasets\n\nimport spacy\nfrom spacy.util import minibatch, compounding\n\n\n@plac.annotations(\n    model=(\"Model name. Defaults to blank 'en' model.\", \"option\", \"m\", str),\n    output_dir=(\"Optional output directory\", \"option\", \"o\", Path),\n    n_texts=(\"Number of texts to train from\", \"option\", \"t\", int),\n    n_iter=(\"Number of training iterations\", \"option\", \"n\", int))\ndef main(model=None, output_dir=None, n_iter=20, n_texts=2000):\n    if model is not None:\n        nlp = spacy.load(model)  # load existing spaCy model\n        print(\"Loaded model '%s'\" % model)\n    else:\n        nlp = spacy.blank('en')  # create blank Language class\n        print(\"Created blank 'en' model\")\n\n    # add the text classifier to the pipeline if it doesn't exist\n    # nlp.create_pipe works for built-ins that are registered with spaCy\n    if 'textcat' not in nlp.pipe_names:\n        textcat = nlp.create_pipe('textcat')\n        nlp.add_pipe(textcat, last=True)\n    # otherwise, get it, so we can add labels to it\n    else:\n        textcat = nlp.get_pipe('textcat')\n\n    # add label to text classifier\n    textcat.add_label('POSITIVE')\n\n    # load the IMDB dataset\n    print(\"Loading IMDB data...\")\n    (train_texts, train_cats), (dev_texts, dev_cats) = load_data(limit=n_texts)\n    print(\"Using {} examples ({} training, {} evaluation)\"\n          .format(n_texts, len(train_texts), len(dev_texts)))\n    train_data = list(zip(train_texts,\n                          [{'cats': cats} for cats in train_cats]))\n\n    # get names of other pipes to disable them during training\n    other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'textcat']\n    with nlp.disable_pipes(*other_pipes):  # only train textcat\n        optimizer = nlp.begin_training()\n        print(\"Training the model...\")\n        print('{:^5}\\t{:^5}\\t{:^5}\\t{:^5}'.format('LOSS', 'P', 'R', 'F'))\n        for i in range(n_iter):\n            losses = {}\n            # batch up the examples using spaCy's minibatch\n            batches = minibatch(train_data, size=compounding(4., 32., 1.001))\n            for batch in batches:\n                texts, annotations = zip(*batch)\n                nlp.update(texts, annotations, sgd=optimizer, drop=0.2,\n                           losses=losses)\n            with textcat.model.use_params(optimizer.averages):\n                # evaluate on the dev data split off in load_data()\n                scores = evaluate(nlp.tokenizer, textcat, dev_texts, dev_cats)\n            print('{0:.3f}\\t{1:.3f}\\t{2:.3f}\\t{3:.3f}'  # print a simple table\n                  .format(losses['textcat'], scores['textcat_p'],\n                          scores['textcat_r'], scores['textcat_f']))\n\n    # test the trained model\n    test_text = \"This movie sucked\"\n    doc = nlp(test_text)\n    print(test_text, doc.cats)\n\n    if output_dir is not None:\n        output_dir = Path(output_dir)\n        if not output_dir.exists():\n            output_dir.mkdir()\n        nlp.to_disk(output_dir)\n        print(\"Saved model to\", output_dir)\n\n        # test the saved model\n        print(\"Loading from\", output_dir)\n        nlp2 = spacy.load(output_dir)\n        doc2 = nlp2(test_text)\n        print(test_text, doc2.cats)\n\n\ndef load_data(limit=0, split=0.8):\n    \"\"\"Load data from the IMDB dataset.\"\"\"\n    # Partition off part of the train data for evaluation\n    train_data, _ = thinc.extra.datasets.imdb()\n    random.shuffle(train_data)\n    train_data = train_data[-limit:]\n    texts, labels = zip(*train_data)\n    cats = [{'POSITIVE': bool(y)} for y in labels]\n    split = int(len(train_data) * split)\n    return (texts[:split], cats[:split]), (texts[split:], cats[split:])\n\n\ndef evaluate(tokenizer, textcat, texts, cats):\n    docs = (tokenizer(text) for text in texts)\n    tp = 1e-8  # True positives\n    fp = 1e-8  # False positives\n    fn = 1e-8  # False negatives\n    tn = 1e-8  # True negatives\n    for i, doc in enumerate(textcat.pipe(docs)):\n        gold = cats[i]\n        for label, score in doc.cats.items():\n            if label not in gold:\n                continue\n            if score >= 0.5 and gold[label] >= 0.5:\n                tp += 1.\n            elif score >= 0.5 and gold[label] < 0.5:\n                fp += 1.\n            elif score < 0.5 and gold[label] < 0.5:\n                tn += 1\n            elif score < 0.5 and gold[label] >= 0.5:\n                fn += 1\n    precision = tp / (tp + fp)\n    recall = tp / (tp + fn)\n    f_score = 2 * (precision * recall) / (precision + recall)\n    return {'textcat_p': precision, 'textcat_r': recall, 'textcat_f': f_score}\n\n\nif __name__ == '__main__':\n    plac.call(main)\n", "path": "examples/training/train_textcat.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# coding: utf8\n\"\"\"Train a convolutional neural network text classifier on the\nIMDB dataset, using the TextCategorizer component. The dataset will be loaded\nautomatically via Thinc's built-in dataset loader. The model is added to\nspacy.pipeline, and predictions are available via `doc.cats`. For more details,\nsee the documentation:\n* Training: https://spacy.io/usage/training\n\nCompatible with: spaCy v2.0.0+\n\"\"\"\nfrom __future__ import unicode_literals, print_function\nimport plac\nimport random\nfrom pathlib import Path\nimport thinc.extra.datasets\n\nimport spacy\nfrom spacy.util import minibatch, compounding\n\n\n@plac.annotations(\n    model=(\"Model name. Defaults to blank 'en' model.\", \"option\", \"m\", str),\n    output_dir=(\"Optional output directory\", \"option\", \"o\", Path),\n    n_texts=(\"Number of texts to train from\", \"option\", \"t\", int),\n    n_iter=(\"Number of training iterations\", \"option\", \"n\", int))\ndef main(model=None, output_dir=None, n_iter=20, n_texts=2000):\n    if model is not None:\n        nlp = spacy.load(model)  # load existing spaCy model\n        print(\"Loaded model '%s'\" % model)\n    else:\n        nlp = spacy.blank('en')  # create blank Language class\n        print(\"Created blank 'en' model\")\n\n    # add the text classifier to the pipeline if it doesn't exist\n    # nlp.create_pipe works for built-ins that are registered with spaCy\n    if 'textcat' not in nlp.pipe_names:\n        textcat = nlp.create_pipe('textcat')\n        nlp.add_pipe(textcat, last=True)\n    # otherwise, get it, so we can add labels to it\n    else:\n        textcat = nlp.get_pipe('textcat')\n\n    # add label to text classifier\n    textcat.add_label('POSITIVE')\n\n    # load the IMDB dataset\n    print(\"Loading IMDB data...\")\n    (train_texts, train_cats), (dev_texts, dev_cats) = load_data(limit=n_texts)\n    print(\"Using {} examples ({} training, {} evaluation)\"\n          .format(n_texts, len(train_texts), len(dev_texts)))\n    train_data = list(zip(train_texts,\n                          [{'cats': cats} for cats in train_cats]))\n\n    # get names of other pipes to disable them during training\n    other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'textcat']\n    with nlp.disable_pipes(*other_pipes):  # only train textcat\n        optimizer = nlp.begin_training()\n        print(\"Training the model...\")\n        print('{:^5}\\t{:^5}\\t{:^5}\\t{:^5}'.format('LOSS', 'P', 'R', 'F'))\n        for i in range(n_iter):\n            losses = {}\n            # batch up the examples using spaCy's minibatch\n            batches = minibatch(train_data, size=compounding(4., 32., 1.001))\n            for batch in batches:\n                texts, annotations = zip(*batch)\n                nlp.update(texts, annotations, sgd=optimizer, drop=0.2,\n                           losses=losses)\n            with textcat.model.use_params(optimizer.averages):\n                # evaluate on the dev data split off in load_data()\n                scores = evaluate(nlp.tokenizer, textcat, dev_texts, dev_cats)\n            print('{0:.3f}\\t{1:.3f}\\t{2:.3f}\\t{3:.3f}'  # print a simple table\n                  .format(losses['textcat'], scores['textcat_p'],\n                          scores['textcat_r'], scores['textcat_f']))\n\n    # test the trained model\n    test_text = \"This movie sucked\"\n    doc = nlp(test_text)\n    print(test_text, doc.cats)\n\n    if output_dir is not None:\n        output_dir = Path(output_dir)\n        if not output_dir.exists():\n            output_dir.mkdir()\n        nlp.to_disk(output_dir)\n        print(\"Saved model to\", output_dir)\n\n        # test the saved model\n        print(\"Loading from\", output_dir)\n        nlp2 = spacy.load(output_dir)\n        doc2 = nlp2(test_text)\n        print(test_text, doc2.cats)\n\n\ndef load_data(limit=0, split=0.8):\n    \"\"\"Load data from the IMDB dataset.\"\"\"\n    # Partition off part of the train data for evaluation\n    train_data, _ = thinc.extra.datasets.imdb()\n    random.shuffle(train_data)\n    train_data = train_data[-limit:]\n    texts, labels = zip(*train_data)\n    cats = [{'POSITIVE': bool(y)} for y in labels]\n    split = int(len(train_data) * split)\n    return (texts[:split], cats[:split]), (texts[split:], cats[split:])\n\n\ndef evaluate(tokenizer, textcat, texts, cats):\n    docs = (tokenizer(text) for text in texts)\n    tp = 1e-8  # True positives\n    fp = 1e-8  # False positives\n    fn = 1e-8  # False negatives\n    tn = 1e-8  # True negatives\n    for i, doc in enumerate(textcat.pipe(docs)):\n        gold = cats[i]\n        for label, score in doc.cats.items():\n            if label not in gold:\n                continue\n            if score >= 0.5 and gold[label] >= 0.5:\n                tp += 1.\n            elif score >= 0.5 and gold[label] < 0.5:\n                fp += 1.\n            elif score < 0.5 and gold[label] < 0.5:\n                tn += 1\n            elif score < 0.5 and gold[label] >= 0.5:\n                fn += 1\n    precision = tp / (tp + fp)\n    recall = tp / (tp + fn)\n    f_score = 2 * (precision * recall) / (precision + recall)\n    return {'textcat_p': precision, 'textcat_r': recall, 'textcat_f': f_score}\n\n\nif __name__ == '__main__':\n    plac.call(main)\n", "path": "examples/training/train_textcat.py"}]}