| import argparse
|
|
|
| import hydra
|
| import pytorch_lightning as pl
|
| from typing import Iterator, Tuple, List, Optional
|
|
|
| import torch
|
| from torch.cuda.amp import autocast
|
| from torch.utils.data import DataLoader
|
| from tqdm import tqdm
|
|
|
| from src.consec_dataset import ConsecDataset, ConsecSample, ConsecDefinition
|
| from src.disambiguation_corpora import DisambiguationInstance
|
| from src.pl_modules import ConsecPLModule
|
| from src.consec_tokenizer import DeBERTaTokenizer, ConsecTokenizer
|
|
|
|
|
| def predict(
|
| module: pl.LightningModule,
|
| tokenizer: ConsecTokenizer,
|
| samples: Iterator[ConsecSample],
|
| text_encoding_strategy: str,
|
| token_batch_size: int = 1024,
|
| progress_bar: bool = False,
|
| ) -> Iterator[Tuple[ConsecSample, List[float]]]:
|
|
|
|
|
| device = next(module.parameters()).device
|
|
|
|
|
| dataset = ConsecDataset.from_samples(
|
| samples,
|
| tokenizer=tokenizer,
|
| use_definition_start=True,
|
| text_encoding_strategy=text_encoding_strategy,
|
| tokens_per_batch=token_batch_size,
|
| max_batch_size=128,
|
| section_size=2_000,
|
| prebatch=True,
|
| shuffle=False,
|
| max_length=tokenizer.model_max_length,
|
| )
|
| dataloader = DataLoader(dataset, batch_size=None, num_workers=0)
|
|
|
|
|
|
|
| iterator = dataloader
|
| progress_bar = tqdm() if progress_bar else None
|
|
|
| for batch in iterator:
|
|
|
| batch_samples = batch["original_sample"]
|
| batch_definitions_positions = batch["definitions_positions"]
|
|
|
| with autocast(enabled=True):
|
| with torch.no_grad():
|
| batch_out = module(**{k: (v.to(device) if torch.is_tensor(v) else v) for k, v in batch.items()})
|
| batch_predictions = batch_out["pred_probs"]
|
|
|
| for sample, dp, probs in zip(batch_samples, batch_definitions_positions, batch_predictions):
|
| definition_probs = []
|
| for start in dp:
|
| definition_probs.append(probs[start].item())
|
| yield sample, definition_probs
|
| if progress_bar is not None:
|
| progress_bar.update()
|
|
|
| if progress_bar is not None:
|
| progress_bar.close()
|
|
|
|
|
| def interactive_main(
|
| model_checkpoint_path: str,
|
| device: int,
|
| ):
|
| def read_ld_pairs() -> List[Tuple[str, str, Optional[str]]]:
|
| pairs = []
|
| while True:
|
| line = input(" * ").strip()
|
| if line == "":
|
| break
|
| parts = line.split(" --- ")
|
| if len(parts) == 3:
|
| l, d, p = parts
|
| p = int(p)
|
| elif len(parts) == 2:
|
| l, d = parts
|
| p = None
|
| else:
|
| raise ValueError
|
| pairs.append((l, d, p))
|
| return pairs
|
|
|
|
|
|
|
| module = ConsecPLModule.load_from_checkpoint(model_checkpoint_path)
|
| module.to(torch.device(device if device != -1 else "cpu"))
|
| module.freeze()
|
| module.sense_extractor.evaluation_mode = True
|
|
|
|
|
| tokenizer = hydra.utils.instantiate(module.hparams.tokenizer.consec_tokenizer)
|
|
|
| while True:
|
|
|
|
|
| text = input("Enter space-separated text: ").strip()
|
| tokens = text.split(" ")
|
| target_position = int(input("Target position: ").strip())
|
|
|
|
|
| print('Enter candidate lemma-def pairs. " --- " separated. Enter to stop')
|
| candidate_definitions = read_ld_pairs()
|
| candidate_definitions = [ConsecDefinition(d, l) for l, d, _ in candidate_definitions]
|
|
|
|
|
| print(
|
| 'Enter context lemma-def-position tuples. " --- " separated. Position should be token position in space-separated input. Enter to stop'
|
| )
|
| context_definitions = read_ld_pairs()
|
| context_definitions = [(ConsecDefinition(d, l), p) for l, d, p in context_definitions]
|
|
|
|
|
| _, probs = next(
|
| predict(
|
| module,
|
| tokenizer,
|
| [
|
| ConsecSample(
|
| sample_id="interactive-d0",
|
| position=target_position,
|
| disambiguation_context=[
|
| DisambiguationInstance("d0", "s0", "i0", t, None, None, None) for t in tokens
|
| ],
|
| candidate_definitions=candidate_definitions,
|
| gold_definitions=None,
|
| context_definitions=context_definitions,
|
| in_context_sample_id2position={'interactive-d0': target_position},
|
| disambiguation_instance=None,
|
| kwargs={},
|
| )
|
| ],
|
| text_encoding_strategy="simple-with-linker",
|
| )
|
| )
|
|
|
| idxs = torch.tensor(probs).argsort(descending=True)
|
| print(f"\t# predictions")
|
| for idx in idxs:
|
| idx = idx.item()
|
| print(
|
| f"\t\t * {probs[idx]:.4f} \t {candidate_definitions[idx].linker} \t {candidate_definitions[idx].text} "
|
| )
|
|
|
|
|
| def file_main(
|
| model_checkpoint_path: str,
|
| input_path: str,
|
| output_path: str,
|
| device: int,
|
| token_batch_size: int,
|
| ):
|
| raise NotImplementedError
|
|
|
|
|
| def main():
|
| args = parse_args()
|
| if args.t:
|
| interactive_main(
|
| args.model_checkpoint,
|
| device=args.device,
|
| )
|
| else:
|
| file_main(
|
| args.model_checkpoint,
|
| args.f,
|
| args.o,
|
| device=args.device,
|
| token_batch_size=args.token_batch_size,
|
| )
|
|
|
|
|
| def parse_args():
|
| parser = argparse.ArgumentParser()
|
| parser.add_argument("model_checkpoint", type=str, help="Path to pl_modules checkpoint")
|
| parser.add_argument("--device", type=int, default=-1, help="Device")
|
|
|
| parser.add_argument("-t", action="store_true", help="Interactive mode")
|
|
|
| parser.add_argument("-f", type=str, default=None, help="Input file")
|
| parser.add_argument("-o", type=str, default=None, help="Output file")
|
| parser.add_argument("--token-batch-size", type=int, default=128, help="Token batch size")
|
|
|
| return parser.parse_args()
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|