Project the tokenized prediction back to the original text.
(pred_text, orig_text, do_lower_case)
| 223 | |
| 224 | |
| 225 | def get_final_text(pred_text, orig_text, do_lower_case): |
| 226 | """Project the tokenized prediction back to the original text.""" |
| 227 | |
| 228 | # When we created the data, we kept track of the alignment between original |
| 229 | # (whitespace tokenized) tokens and our WordPiece tokenized tokens. So |
| 230 | # now `orig_text` contains the span of our original text corresponding to the |
| 231 | # span that we predicted. |
| 232 | # |
| 233 | # However, `orig_text` may contain extra characters that we don't want in |
| 234 | # our prediction. |
| 235 | # |
| 236 | # For example, let's say: |
| 237 | # pred_text = steve smith |
| 238 | # orig_text = Steve Smith's |
| 239 | # |
| 240 | # We don't want to return `orig_text` because it contains the extra "'s". |
| 241 | # |
| 242 | # We don't want to return `pred_text` because it's already been normalized |
| 243 | # (the SQuAD eval script also does punctuation stripping/lower casing but |
| 244 | # our tokenizer does additional normalization like stripping accent |
| 245 | # characters). |
| 246 | # |
| 247 | # What we really want to return is "Steve Smith". |
| 248 | # |
| 249 | # Therefore, we have to apply a semi-complicated alignment heruistic between |
| 250 | # `pred_text` and `orig_text` to get a character-to-charcter alignment. This |
| 251 | # can fail in certain cases in which case we just return `orig_text`. |
| 252 | |
| 253 | def _strip_spaces(text): |
| 254 | ns_chars = [] |
| 255 | ns_to_s_map = collections.OrderedDict() |
| 256 | for (i, c) in enumerate(text): |
| 257 | if c == " ": |
| 258 | continue |
| 259 | ns_to_s_map[len(ns_chars)] = i |
| 260 | ns_chars.append(c) |
| 261 | ns_text = "".join(ns_chars) |
| 262 | return (ns_text, ns_to_s_map) |
| 263 | |
| 264 | # We first tokenize `orig_text`, strip whitespace from the result |
| 265 | # and `pred_text`, and check if they are the same length. If they are |
| 266 | # NOT the same length, the heuristic has failed. If they are the same |
| 267 | # length, we assume the characters are one-to-one aligned. |
| 268 | tokenizer = tokenization.BasicTokenizer(do_lower_case=do_lower_case) |
| 269 | |
| 270 | tok_text = " ".join(tokenizer.tokenize(orig_text)) |
| 271 | |
| 272 | start_position = tok_text.find(pred_text) |
| 273 | if start_position == -1: |
| 274 | return orig_text |
| 275 | end_position = start_position + len(pred_text) - 1 |
| 276 | |
| 277 | (orig_ns_text, orig_ns_to_s_map) = _strip_spaces(orig_text) |
| 278 | (tok_ns_text, tok_ns_to_s_map) = _strip_spaces(tok_text) |
| 279 | |
| 280 | if len(orig_ns_text) != len(tok_ns_text): |
| 281 | return orig_text |
| 282 |
no test coverage detected