"""T5 span corruption + BART denoising noise functions. Pure stdlib. Shows how encoder-decoder models turn any input into a supervised (corrupted_input -> clean_spans) training pair. """ import random def sentinel(i): return f"" def corrupt_spans(tokens, mask_rate=0.15, mean_span=3.0, rng=None): """T5-style span corruption. Returns (corrupted_source, decoder_target) as lists of tokens (strings). """ if rng is None: rng = random.Random() n = len(tokens) n_mask = max(1, int(round(n * mask_rate))) n_spans = max(1, int(round(n_mask / mean_span))) # Pick span start positions with no overlap. positions = list(range(n)) rng.shuffle(positions) starts = [] used = [False] * n span_lengths = [] remaining = n_mask for _ in range(n_spans): if remaining <= 0: break # pick a random starting point not yet used and with room random_order = list(range(n)) rng.shuffle(random_order) chosen_start = None for start in random_order: if used[start]: continue # span length length = max(1, int(rng.gauss(mean_span, 1.0))) length = min(length, remaining, n - start) if length < 1: continue if any(used[i] for i in range(start, start + length)): continue chosen_start = start for i in range(start, start + length): used[i] = True starts.append(start) span_lengths.append(length) remaining -= length break if chosen_start is None: break ordered = sorted(zip(starts, span_lengths), key=lambda x: x[0]) source = [] target = [] prev_end = 0 for idx, (start, length) in enumerate(ordered): source.extend(tokens[prev_end:start]) source.append(sentinel(idx)) target.append(sentinel(idx)) target.extend(tokens[start:start + length]) prev_end = start + length source.extend(tokens[prev_end:]) target.append(sentinel(len(ordered))) # closing sentinel return source, target def round_trip(source, target): """Reconstruct original by replacing sentinels in source with corresponding target spans.""" # Parse target into sentinel->span map spans = {} current_key = None current_span = [] for tok in target: if tok.startswith("= rate] def text_infill(tokens, rate=0.15, mean_span=3.0, rng=None, mask_token=""): """BART text infill: mask spans with a SINGLE mask; decoder infers length.""" if rng is None: rng = random.Random() out = [] i = 0 n = len(tokens) budget = int(n * rate) while i < n: if budget > 0 and rng.random() < 0.3: span_len = max(1, min(int(rng.gauss(mean_span, 1.0)), budget, n - i)) out.append(mask_token) budget -= span_len i += span_len else: out.append(tokens[i]) i += 1 return out def sentence_permute(sentences, rng=None): if rng is None: rng = random.Random() sents = list(sentences) rng.shuffle(sents) return sents def document_rotate(tokens, rng=None): if rng is None: rng = random.Random() if len(tokens) <= 1: return tokens pivot = rng.randrange(1, len(tokens)) return tokens[pivot:] + tokens[:pivot] def main(): rng = random.Random(42) sentence = ( "the quick brown fox jumps over the lazy dog a stitch in time saves nine " "language models learn statistical patterns subword tokenization helps rare words" ).split() print("=== T5 span corruption ===") source, target = corrupt_spans(sentence, mask_rate=0.20, mean_span=3.0, rng=rng) print("corrupted source:") print(" " + " ".join(source)) print() print("decoder target:") print(" " + " ".join(target)) print() reconstructed = round_trip(source, target) print("reconstruction matches original:", "YES" if reconstructed == sentence else "NO") if reconstructed != sentence: print(" reconstructed: " + " ".join(reconstructed)) print() print("=== BART noise functions ===") print("original: " + " ".join(sentence[:14])) print() print("token mask: " + " ".join(token_mask(sentence[:14], rate=0.2, rng=random.Random(1)))) print("token delete: " + " ".join(token_delete(sentence[:14], rate=0.2, rng=random.Random(2)))) print("text infill: " + " ".join(text_infill(sentence[:14], rate=0.3, rng=random.Random(3)))) sentences = [ ["the", "quick", "brown", "fox"], ["a", "stitch", "in", "time"], ["language", "models", "learn", "patterns"], ] perm = sentence_permute(sentences, rng=random.Random(4)) print("sentence permute:") for s in perm: print(" " + " ".join(s)) print() print("document rotate: " + " ".join(document_rotate(sentence[:14], rng=random.Random(5)))) if __name__ == "__main__": main()