def predict(self, docs: Iterable[Doc]) -> List[str]:
        """Apply the pipeline's model to a batch of docs, without modifying them.
        Returns the KB IDs for each entity in each doc, including NIL if there is
        no prediction.

        docs (Iterable[Doc]): The documents to predict.
        RETURNS (List[str]): The models prediction for each document.

        DOCS: https://spacy.io/api/entitylinker#predict
        """
        self.validate_kb()
        entity_count = 0
        final_kb_ids: List[str] = []
        xp = self.model.ops.xp
        if not docs:
            return final_kb_ids
        if isinstance(docs, Doc):
            docs = [docs]
        for i, doc in enumerate(docs):
            if len(doc) == 0:
                continue
            sentences = [s for s in doc.sents]

            # Loop over entities in batches.
            for ent_idx in range(0, len(doc.ents), self.candidates_batch_size):
                ent_batch = doc.ents[ent_idx : ent_idx + self.candidates_batch_size]

                # Look up candidate entities.
                valid_ent_idx = [
                    idx
                    for idx in range(len(ent_batch))
                    if ent_batch[idx].label_ not in self.labels_discard
                ]

                batch_candidates = list(
                    self.get_candidates_batch(
                        self.kb, [ent_batch[idx] for idx in valid_ent_idx]
                    )
                    if self.candidates_batch_size > 1
                    else [
                        self.get_candidates(self.kb, ent_batch[idx])
                        for idx in valid_ent_idx
                    ]
                )

                # Looping through each entity in batch (TODO: rewrite)
                for j, ent in enumerate(ent_batch):
                    assert hasattr(ent, "sents")
                    sents = list(ent.sents)
                    sent_indices = (
                        sentences.index(sents[0]),
                        sentences.index(sents[-1]),
                    )
                    assert sent_indices[1] >= sent_indices[0] >= 0

                    if self.incl_context:
                        # get n_neighbour sentences, clipped to the length of the document
                        start_sentence = max(0, sent_indices[0] - self.n_sents)
                        end_sentence = min(
                            len(sentences) - 1, sent_indices[1] + self.n_sents
                        )
                        start_token = sentences[start_sentence].start
                        end_token = sentences[end_sentence].end
                        sent_doc = doc[start_token:end_token].as_doc()

                        # currently, the context is the same for each entity in a sentence (should be refined)
                        sentence_encoding = self.model.predict([sent_doc])[0]
                        sentence_encoding_t = sentence_encoding.T
                        sentence_norm = xp.linalg.norm(sentence_encoding_t)
                    entity_count += 1
                    if ent.label_ in self.labels_discard:
                        # ignoring this entity - setting to NIL
                        final_kb_ids.append(self.NIL)
                    else:
                        candidates = list(batch_candidates[j])
                        if not candidates:
                            # no prediction possible for this entity - setting to NIL
                            final_kb_ids.append(self.NIL)
                        elif len(candidates) == 1 and self.threshold is None:
                            # shortcut for efficiency reasons: take the 1 candidate
                            final_kb_ids.append(candidates[0].entity_)
                        else:
                            random.shuffle(candidates)
                            # set all prior probabilities to 0 if incl_prior=False
                            prior_probs = xp.asarray([c.prior_prob for c in candidates])
                            if not self.incl_prior:
                                prior_probs = xp.asarray([0.0 for _ in candidates])
                            scores = prior_probs
                            # add in similarity from the context
                            if self.incl_context:
                                entity_encodings = xp.asarray(
                                    [c.entity_vector for c in candidates]
                                )
                                entity_norm = xp.linalg.norm(entity_encodings, axis=1)
                                if len(entity_encodings) != len(prior_probs):
                                    raise RuntimeError(
                                        Errors.E147.format(
                                            method="predict",
                                            msg="vectors not of equal length",
                                        )
                                    )
                                # cosine similarity
                                sims = xp.dot(entity_encodings, sentence_encoding_t) / (
                                    sentence_norm * entity_norm
                                )
                                if sims.shape != prior_probs.shape:
                                    raise ValueError(Errors.E161)
                                scores = prior_probs + sims - (prior_probs * sims)
                            final_kb_ids.append(
                                candidates[scores.argmax().item()].entity_
                                if self.threshold is None
                                or scores.max() >= self.threshold
                                else EntityLinker.NIL
                            )

        if not (len(final_kb_ids) == entity_count):
            err = Errors.E147.format(
                method="predict", msg="result variables not of equal length"
            )
            raise RuntimeError(err)
        return final_kb_ids
Apply the pipeline's model to a batch of docs, without modifying them.
        Returns the KB IDs for each entity in each doc, including NIL if there is
        no prediction.

        docs (Iterable[Doc]): The documents to predict.
        RETURNS (List[str]): The models prediction for each document.

        DOCS: https://spacy.io/api/entitylinker#predict
        
spacy/pipeline/entity_linker.py