Download runtime/jevlike/data/sources_choice.py from Cem13/kodama-core: direct link, hf CLI and curl.
- Browser
- Download file 43.2 kB
-
https://huggingface.co/Cem13/kodama-core/resolve/main/runtime/jevlike/data/sources_choice.py
- Command line
-
hf download hf://Cem13/kodama-core/runtime/jevlike/data/sources_choice.py
-
curl -L -o sources_choice.py https://huggingface.co/Cem13/kodama-core/resolve/main/runtime/jevlike/data/sources_choice.py
43.2 kB
| """Converters for classification datasets (primary type: choice). | |
| Each converter yields `Example`s: a choice question over a sampled option subset | |
| (varied keys / descriptions / instructions), often a derived true/false statement, and | |
| occasionally a second choice question with a different option set. | |
| """ | |
| from __future__ import annotations | |
| import random | |
| import re | |
| from dataclasses import dataclass | |
| from typing import Callable, Iterator, Optional, Sequence | |
| from jevlike.data.common import ( | |
| Example, Label, balanced_order, clean, dedupe_rows, derived_noul, intent_label, make_choice, | |
| make_mcq, noul, pick_instr, readable, weighted, | |
| ) | |
| from jevlike.data.hub import read_many, read_rows | |
| GENERIC_CHOICE = [ | |
| "Which option best describes the text?", "Choose the best matching option.", | |
| "Pick the most appropriate label.", "Classify the text.", "Select one.", | |
| "Which category does this belong to?", "Assign the correct category.", | |
| "What is the best label for this input?", "Which of these applies?", | |
| "Pick one of the options below.", "Label this.", "Categorize the input.", | |
| "Decide which option fits best.", "Which option matches the input best?", | |
| "Choose one label for the text above.", | |
| ] | |
| TOPIC_POS = [ | |
| "This {thing} is about {x}.", "The main topic of this {thing} is {x}.", | |
| "The {thing} discusses {x}.", "Is this {thing} about {x}?", "This {thing} mainly concerns {x}.", | |
| "The subject of the {thing} is {x}.", "Topic: {x}.", | |
| ] | |
| TOPIC_NEG = ["This {thing} is not about {x}.", "The {thing} has nothing to do with {x}.", | |
| "This {thing} is unrelated to {x}."] | |
| class Ctx: | |
| rng: random.Random | |
| name: str | |
| # ---------------------------------------------------------------- generic classification loop | |
| def classify(ctx: Ctx, rows: list, text_fn: Callable, label_fn: Callable, labels: list[Label], *, | |
| instr: Sequence[str], noul_pos: Sequence[str], noul_neg: Sequence[str] = (), | |
| thing: str = "text", alpha: float = 0.5, full_prob: float = 0.08, | |
| other_prob: float = 0.03, p_choice: float = 0.85, p_noul: float = 0.45, | |
| p_second: float = 0.12, p_other_group: float = 0.6, p_generic: float = 0.2, | |
| extra: Optional[Callable] = None) -> Iterator[Example]: | |
| """Shared loop: balanced row order -> choice (+ derived noul, + second choice).""" | |
| rng = ctx.rng | |
| rows = dedupe_rows(rows, text_fn, label_fn) | |
| for row in balanced_order(rng, rows, label_fn, alpha): | |
| state = text_fn(row) | |
| if len(state) < 3: | |
| continue | |
| gold = label_fn(row) | |
| qs = [] | |
| if rng.random() < p_choice: | |
| qs.append(make_choice(rng, labels, gold, pick_instr(rng, instr, GENERIC_CHOICE, p_generic, thing=thing), | |
| full_prob=full_prob, other_prob=other_prob)) | |
| if not qs or rng.random() < p_noul: | |
| qs.append(derived_noul(rng, labels, gold, noul_pos, noul_neg, p_other_group=p_other_group, | |
| thing=thing)) | |
| if rng.random() < p_second: | |
| qs.append(make_choice(rng, labels, gold, pick_instr(rng, instr, GENERIC_CHOICE, 0.5, thing=thing), | |
| full_prob=full_prob, other_prob=other_prob)) | |
| if extra is not None: | |
| qs.extend(extra(row, rng)) | |
| yield Example(state, qs[:3]) | |
| # ---------------------------------------------------------------- topic datasets | |
| AG_LABELS = [ | |
| Label("world", ["world news and international affairs", "international politics, conflicts and diplomacy", | |
| "global news"], "world news or international affairs"), | |
| Label("sports", ["sports news: games, teams and athletes", "sport events and results"], "sports"), | |
| Label("business", ["business, companies and the economy", "markets, finance and corporate news"], | |
| "business or the economy"), | |
| Label("science and technology", ["science and technology news", "computers, internet, space and research", | |
| "the tech industry and scientific discoveries"], | |
| "science or technology", key="sci_tech"), | |
| ] | |
| NEWS_INSTR = [ | |
| "What is this {thing} mainly about?", "Which section of the newspaper does this {thing} belong in?", | |
| "Topic?", "Classify the news {thing} by topic.", "Which category best fits this {thing}?", | |
| "What kind of news is this?", "Assign a news category to the {thing}.", | |
| "Pick the topic of the {thing} from the list.", "Which desk should cover this story?", | |
| ] | |
| def ag_news(ctx: Ctx): | |
| rows = read_many("fancyzhx/ag_news", ["data/test-00000-of-00001.parquet", "data/train-00000-of-00001.parquet"]) | |
| yield from classify(ctx, rows, lambda r: clean(r["text"]), lambda r: int(r["label"]), AG_LABELS, | |
| instr=NEWS_INSTR, noul_pos=TOPIC_POS, noul_neg=TOPIC_NEG, thing="article", | |
| alpha=1.0, p_other_group=0.0) | |
| DBP = [ | |
| ("Company", "a company", ["a company or business", "a business organization"], "org"), | |
| ("Educational institution", "an educational institution", ["a school, college or university"], "org"), | |
| ("Artist", "an artist", ["an artist such as a musician, painter, actor or writer"], "person"), | |
| ("Athlete", "an athlete", ["an athlete or sports player"], "person"), | |
| ("Office holder", "a politician or office holder", ["a politician or public office holder"], "person"), | |
| ("Means of transportation", "a vehicle or other means of transportation", | |
| ["a vehicle, ship, aircraft or train"], "thing"), | |
| ("Building", "a building", ["a building or man-made structure"], "place"), | |
| ("Natural place", "a natural place", ["a natural place such as a mountain, river or lake"], "place"), | |
| ("Village", "a village", ["a village or small settlement"], "place"), | |
| ("Animal", "an animal", ["an animal species"], "nature"), | |
| ("Plant", "a plant", ["a plant species"], "nature"), | |
| ("Album", "a music album", ["a music album or record"], "work"), | |
| ("Film", "a film", ["a film or movie"], "work"), | |
| ("Written work", "a written work", ["a book, novel, journal or other written work"], "work"), | |
| ] | |
| DBP_LABELS = [Label(n.lower(), d, p, group=g) for n, p, d, g in DBP] | |
| def dbpedia(ctx: Ctx): | |
| rows = read_rows("fancyzhx/dbpedia_14", "dbpedia_14/test-00000-of-00001.parquet") | |
| rng = ctx.rng | |
| def text(r): | |
| c = clean(r["content"]) | |
| return c if rng.random() < 0.6 else f"{clean(r['title'])}\n{c}" | |
| instr = ["What kind of entity does this text describe?", "What is the subject of this encyclopedia entry?", | |
| "Which ontology class fits this article?", "Classify the entity described.", | |
| "What type of thing is this passage about?", "Which category does the described entity belong to?"] | |
| pos = ["This text describes {x}.", "The subject of this passage is {x}.", | |
| "This is an encyclopedia entry about {x}.", "Is this about {x}?", "The passage is about {x}."] | |
| neg = ["This text does not describe {x}.", "The subject of this passage is not {x}."] | |
| rows = [dict(r, _t=text(r)) for r in rows] | |
| yield from classify(ctx, rows, lambda r: r["_t"], lambda r: int(r["label"]), DBP_LABELS, | |
| instr=instr, noul_pos=pos, noul_neg=neg, thing="entry", alpha=1.0, | |
| p_other_group=0.3) | |
| YAHOO = [ | |
| ("society and culture", ["society, culture, religion and traditions"], "society or culture"), | |
| ("science and mathematics", ["science and math questions"], "science or mathematics"), | |
| ("health", ["health, medicine and fitness"], "health"), | |
| ("education and reference", ["education, school, language and reference questions"], "education"), | |
| ("computers and internet", ["computers, software and the internet"], "computers or the internet"), | |
| ("sports", ["sports and athletes"], "sports"), | |
| ("business and finance", ["business, money, jobs and finance"], "business or finance"), | |
| ("entertainment and music", ["movies, TV, music and celebrities"], "entertainment or music"), | |
| ("family and relationships", ["family, dating, friendship and relationships"], "family or relationships"), | |
| ("politics and government", ["politics, government and law"], "politics or government"), | |
| ] | |
| YAHOO_LABELS = [Label(n, d, p) for n, d, p in YAHOO] | |
| def yahoo(ctx: Ctx): | |
| rows = read_rows("community-datasets/yahoo_answers_topics", "yahoo_answers_topics/test-00000-of-00001.parquet") | |
| rng = ctx.rng | |
| def text(r): | |
| t, c, a = clean(r["question_title"]), clean(r["question_content"]), clean(r["best_answer"]) | |
| s = t + (f"\n{c}" if c else "") | |
| u = rng.random() | |
| if a and u < 0.35: | |
| s = f"Question: {s}\nBest answer: {a}" | |
| elif a and u < 0.5: | |
| s = f"{s}\n\n{a}" | |
| return s | |
| rows = [dict(r, _t=text(r)) for r in rows] | |
| instr = ["Which category of the Q&A site does this question belong to?", "What is this question about?", | |
| "Choose the forum section for this post.", "Topic of the question?", | |
| "In which category should this question be posted?"] | |
| yield from classify(ctx, rows, lambda r: r["_t"], lambda r: int(r["topic"]), YAHOO_LABELS, | |
| instr=instr, noul_pos=TOPIC_POS, noul_neg=TOPIC_NEG, thing="question", | |
| alpha=1.0, p_other_group=0.0) | |
| NG = { | |
| "alt.atheism": ("atheism", "discussion of atheism and religious skepticism", "religion"), | |
| "comp.graphics": ("computer graphics", "computer graphics, images and rendering software", "comp"), | |
| "comp.os.ms-windows.misc": ("Microsoft Windows", "the Microsoft Windows operating system", "comp"), | |
| "comp.sys.ibm.pc.hardware": ("PC hardware", "IBM PC compatible hardware", "comp"), | |
| "comp.sys.mac.hardware": ("Mac hardware", "Apple Macintosh hardware", "comp"), | |
| "comp.windows.x": ("X Window System", "the X Window System (X11) on Unix", "comp"), | |
| "misc.forsale": ("for sale", "items for sale and classified ads", "misc"), | |
| "rec.autos": ("cars", "automobiles and driving", "rec"), | |
| "rec.motorcycles": ("motorcycles", "motorcycles and riding", "rec"), | |
| "rec.sport.baseball": ("baseball", "baseball games, teams and players", "rec"), | |
| "rec.sport.hockey": ("hockey", "ice hockey games, teams and players", "rec"), | |
| "sci.crypt": ("cryptography", "cryptography, encryption and privacy", "sci"), | |
| "sci.electronics": ("electronics", "electronic circuits and components", "sci"), | |
| "sci.med": ("medicine", "medicine and health", "sci"), | |
| "sci.space": ("space", "space exploration and astronomy", "sci"), | |
| "soc.religion.christian": ("Christianity", "Christian religion and faith", "religion"), | |
| "talk.politics.guns": ("gun politics", "gun control and firearms politics", "politics"), | |
| "talk.politics.mideast": ("Middle East politics", "politics of the Middle East", "politics"), | |
| "talk.politics.misc": ("politics", "general political discussion", "politics"), | |
| "talk.religion.misc": ("religion", "general religious discussion", "religion"), | |
| } | |
| def newsgroups(ctx: Ctx): | |
| rows = read_many("SetFit/20_newsgroups", ["train.jsonl", "test.jsonl"]) | |
| names = list(NG) | |
| labels = [Label(NG[n][0], [NG[n][1], n], NG[n][1], key=n, group=NG[n][2]) for n in names] | |
| rows = [dict(r, _t=clean(r["text"])) for r in rows if len(clean(r["text"])) >= 60] | |
| instr = ["Which newsgroup was this post published in?", "What is this forum post about?", | |
| "Route this message to the right discussion group.", "Which group does this post belong to?", | |
| "Classify the post by topic."] | |
| yield from classify(ctx, rows, lambda r: r["_t"], lambda r: names.index(r["label_text"]), labels, | |
| instr=instr, noul_pos=TOPIC_POS, noul_neg=TOPIC_NEG, thing="post", | |
| alpha=1.0, p_other_group=0.5) | |
| TT = { | |
| "arts_&_culture": ("arts and culture", "arts, books, museums and culture"), | |
| "business_&_entrepreneurs": ("business", "business and entrepreneurship"), | |
| "pop_culture": ("pop culture", "celebrities, music, movies and TV"), | |
| "daily_life": ("daily life", "everyday personal life, family and feelings"), | |
| "sports_&_gaming": ("sports and gaming", "sports, athletes and video games"), | |
| "science_&_technology": ("science and technology", "science, tech and gadgets"), | |
| } | |
| def _tweet_clean(t: str) -> str: | |
| t = re.sub(r"\{@([^@}]*)@\}", r"@\1", t) | |
| t = t.replace("{{URL}}", "http://t.co/link").replace("{{USERNAME}}", "@user") | |
| return clean(t) | |
| def tweet_topic(ctx: Ctx): | |
| rows = read_many("cardiffnlp/tweet_topic_single", [ | |
| "dataset/split_coling2022_random/train_random.single.json", | |
| "dataset/split_coling2022_random/test_random.single.json"]) | |
| names = list(TT) | |
| labels = [Label(TT[n][0], [TT[n][1]], TT[n][1], key=n.replace("_&_", "_")) for n in names] | |
| instr = ["What is this tweet about?", "Which topic does the tweet belong to?", "Topic of this tweet?", | |
| "Classify the tweet by topic.", "Which feed should this tweet appear in?"] | |
| yield from classify(ctx, rows, lambda r: _tweet_clean(r["text"]), lambda r: names.index(r["label_name"]), | |
| labels, instr=instr, noul_pos=TOPIC_POS, noul_neg=TOPIC_NEG, thing="tweet", | |
| alpha=0.5, p_other_group=0.0) | |
| FIN_TOPICS = [ | |
| ("analyst update", "analyst ratings, upgrades, downgrades and price targets"), | |
| ("central banks", "the Fed and central bank policy"), | |
| ("company or product news", "news about a company or its products"), | |
| ("treasuries and corporate debt", "bonds, treasuries and corporate debt"), | |
| ("dividends", "dividend announcements"), | |
| ("earnings", "earnings reports and results"), | |
| ("energy and oil", "oil, gas and energy markets"), | |
| ("financials", "banks and the financial sector"), | |
| ("currencies", "currencies and foreign exchange"), | |
| ("general news or opinion", "general news and opinion pieces"), | |
| ("gold, metals and materials", "gold, metals and raw materials"), | |
| ("IPO", "initial public offerings"), | |
| ("legal and regulation", "lawsuits, regulation and legal matters"), | |
| ("M&A and investments", "mergers, acquisitions and investments"), | |
| ("macro", "the macroeconomy: inflation, jobs, GDP"), | |
| ("markets", "overall market moves and indexes"), | |
| ("politics", "politics and government"), | |
| ("personnel change", "executive appointments and departures"), | |
| ("stock commentary", "commentary and opinions about stocks"), | |
| ("stock movement", "individual stock price moves"), | |
| ] | |
| def fin_topic(ctx: Ctx): | |
| rows = read_many("zeroshot/twitter-financial-news-topic", ["topic_train.csv", "topic_valid.csv"]) | |
| labels = [Label(n, [d], d) for n, d in FIN_TOPICS] | |
| instr = ["What is this financial tweet about?", "Which finance topic does this headline cover?", | |
| "Classify the financial news tweet.", "Tag this market news item with a topic.", | |
| "Which newsletter section should this item go in?"] | |
| yield from classify(ctx, rows, lambda r: clean(r["text"]), lambda r: int(r["label"]), labels, | |
| instr=instr, noul_pos=TOPIC_POS, noul_neg=TOPIC_NEG, thing="tweet", | |
| alpha=0.5, p_other_group=0.0) | |
| # ---------------------------------------------------------------- intent / routing datasets | |
| INTENT_INSTR = [ | |
| "What does the customer want?", "Which intent best matches this {thing}?", | |
| "Route this {thing} to the right intent.", "What is the user asking for?", | |
| "Classify the customer's request.", "Which issue is the customer raising?", | |
| "Identify the intent of the {thing}.", "Which workflow should handle this {thing}?", | |
| "Pick the intent.", "What is this {thing} about?", | |
| ] | |
| INTENT_POS = ["The customer is asking about {x}.", "This {thing} is about {x}.", | |
| "The user's request concerns {x}.", "Intent: {x}.", "Is the user asking about {x}?", | |
| "The {thing} relates to {x}."] | |
| INTENT_NEG = ["The customer is not asking about {x}.", "This {thing} has nothing to do with {x}."] | |
| _BANK_GROUPS = [("card", "card"), ("transfer", "transfer"), ("top_up", "topup"), ("topping", "topup"), | |
| ("exchange", "fx"), ("currenc", "fx"), ("cash", "cash"), ("atm", "cash"), | |
| ("pin", "security"), ("passcode", "security"), ("verify", "identity"), | |
| ("identity", "identity"), ("refund", "refund"), ("payment", "payment")] | |
| def _bank_group(n: str) -> str: | |
| for k, g in _BANK_GROUPS: | |
| if k in n.lower(): | |
| return g | |
| return "other" | |
| BANKING77 = [ | |
| "activate_my_card", "age_limit", "apple_pay_or_google_pay", "atm_support", "automatic_top_up", | |
| "balance_not_updated_after_bank_transfer", "balance_not_updated_after_cheque_or_cash_deposit", | |
| "beneficiary_not_allowed", "cancel_transfer", "card_about_to_expire", "card_acceptance", "card_arrival", | |
| "card_delivery_estimate", "card_linking", "card_not_working", "card_payment_fee_charged", | |
| "card_payment_not_recognised", "card_payment_wrong_exchange_rate", "card_swallowed", | |
| "cash_withdrawal_charge", "cash_withdrawal_not_recognised", "change_pin", "compromised_card", | |
| "contactless_not_working", "country_support", "declined_card_payment", "declined_cash_withdrawal", | |
| "declined_transfer", "direct_debit_payment_not_recognised", "disposable_card_limits", | |
| "edit_personal_details", "exchange_charge", "exchange_rate", "exchange_via_app", | |
| "extra_charge_on_statement", "failed_transfer", "fiat_currency_support", "get_disposable_virtual_card", | |
| "get_physical_card", "getting_spare_card", "getting_virtual_card", "lost_or_stolen_card", | |
| "lost_or_stolen_phone", "order_physical_card", "passcode_forgotten", "pending_card_payment", | |
| "pending_cash_withdrawal", "pending_top_up", "pending_transfer", "pin_blocked", "receiving_money", | |
| "Refund_not_showing_up", "request_refund", "reverted_card_payment?", "supported_cards_and_currencies", | |
| "terminate_account", "top_up_by_bank_transfer_charge", "top_up_by_card_charge", | |
| "top_up_by_cash_or_cheque", "top_up_failed", "top_up_limits", "top_up_reverted", "topping_up_by_card", | |
| "transaction_charged_twice", "transfer_fee_charged", "transfer_into_account", | |
| "transfer_not_received_by_recipient", "transfer_timing", "unable_to_verify_identity", | |
| "verify_my_identity", "verify_source_of_funds", "verify_top_up", "virtual_card_not_working", | |
| "visa_or_mastercard", "why_verify_identity", "wrong_amount_of_cash_received", | |
| "wrong_exchange_rate_for_cash_withdrawal", | |
| ] | |
| def banking77(ctx: Ctx): | |
| rows = read_many("legacy-datasets/banking77", ["data/train-00000-of-00001.parquet", | |
| "data/test-00000-of-00001.parquet"]) | |
| labels = [] | |
| for n in BANKING77: | |
| r = readable(n) | |
| labels.append(Label(r, [r, f"customer asks about {r}", f"banking query: {r}"], r, | |
| key=re.sub(r"[^a-z_]", "", n.lower()), group=_bank_group(n))) | |
| yield from classify(ctx, rows, lambda r: clean(r["text"]), lambda r: int(r["label"]), labels, | |
| instr=INTENT_INSTR, noul_pos=INTENT_POS, noul_neg=INTENT_NEG, thing="banking query", | |
| alpha=1.0, full_prob=0.08, other_prob=0.05, p_other_group=0.5) | |
| def clinc(ctx: Ctx): | |
| rows = read_many("clinc/clinc_oos", [f"plus/{s}-00000-of-00001.parquet" for s in ("train", "validation", "test")]) | |
| from jevlike.data.label_names import CLINC150 | |
| labels = [] | |
| for n in CLINC150: | |
| if n == "oos": | |
| labels.append(Label("out of scope", ["request not covered by any listed intent", | |
| "unsupported request"], "something outside the supported requests", | |
| key="out_of_scope")) | |
| else: | |
| labels.append(intent_label(n)) | |
| oos = CLINC150.index("oos") | |
| rng = ctx.rng | |
| # keep ~5% out-of-scope examples; never make "out of scope" a negative-only filler | |
| rows = [r for r in rows if int(r["intent"]) != oos or rng.random() < 0.3] | |
| instr = ["What does the user want the assistant to do?", "Which intent does this request express?", | |
| "Classify the user's request.", "Which skill should handle this command?", | |
| "Map this utterance to an intent.", "What is the user trying to do?"] | |
| pos = ["The user wants help with {x}.", "This request is about {x}.", "Intent: {x}.", | |
| "Is the user asking about {x}?"] | |
| neg = ["The user is not asking about {x}."] | |
| yield from classify(ctx, rows, lambda r: clean(r["text"]), lambda r: int(r["intent"]), labels, | |
| instr=instr, noul_pos=pos, noul_neg=neg, thing="request", alpha=1.0, | |
| full_prob=0.05, other_prob=0.04, p_other_group=0.0) | |
| MASSIVE_SCEN = { | |
| "alarm": "alarms and wake-up times", "audio": "audio and volume controls", | |
| "calendar": "calendar events, meetings and reminders", "cooking": "recipes and cooking", | |
| "datetime": "dates, times and time zones", "email": "reading and sending email", | |
| "general": "chit-chat, jokes and general questions to the assistant", | |
| "iot": "smart home devices such as lights, plugs and vacuums", "lists": "to-do and shopping lists", | |
| "music": "music settings and preferences", "news": "news updates", | |
| "play": "playing music, podcasts, radio, audiobooks or games", | |
| "qa": "factual questions, definitions, math and currency", "recommendation": "recommendations for places, " | |
| "movies and events", "social": "social media posts and complaints to companies", | |
| "takeaway": "takeaway food orders", "transport": "trains, taxis, tickets and traffic", | |
| "weather": "weather forecasts", | |
| } | |
| def massive(ctx: Ctx): | |
| files = ["train.jsonl", "validation.jsonl", "test.jsonl"] | |
| irows = read_many("SetFit/amazon_massive_intent_en-US", files) | |
| srows = read_many("SetFit/amazon_massive_scenario_en-US", files) | |
| scen_by_text = {} | |
| for r in srows: | |
| scen_by_text.setdefault(r["text"], r["label_text"]) | |
| intents = sorted({r["label_text"] for r in irows}) | |
| scens = sorted(MASSIVE_SCEN) | |
| ilabels = [] | |
| for n in intents: | |
| sc = n.split("_")[0] | |
| rest = readable(n[len(sc) + 1:]) if n.startswith(sc + "_") else readable(n) | |
| ilabels.append(Label(readable(n), [f"{sc}: {rest}", readable(n)], readable(n), key=n, group=sc)) | |
| slabels = [Label(s, [MASSIVE_SCEN[s]], MASSIVE_SCEN[s], group=s) for s in scens] | |
| rng = ctx.rng | |
| rows = [r for r in irows if r["text"] in scen_by_text] | |
| rows = dedupe_rows(rows, lambda r: r["text"], lambda r: r["label_text"]) | |
| s_instr = ["Which domain does this voice command belong to?", "Which app should handle this request?", | |
| "What area is the user's request in?", "Route this command to the right domain.", | |
| "Which assistant skill is needed?"] | |
| i_instr = ["What does the user want the assistant to do?", "Which intent does this command express?", | |
| "Classify the voice command.", "What action is requested?", "Map this utterance to an intent."] | |
| for r in balanced_order(rng, rows, lambda r: r["label_text"], 0.7): | |
| text = clean(r["text"]) | |
| gi = intents.index(r["label_text"]) | |
| gs = scens.index(scen_by_text[r["text"]]) if scen_by_text[r["text"]] in scens else None | |
| qs = [] | |
| u = rng.random() | |
| if u < 0.55 or gs is None: | |
| qs.append(make_choice(rng, ilabels, gi, pick_instr(rng, i_instr, GENERIC_CHOICE), full_prob=0.06, | |
| other_prob=0.04)) | |
| else: | |
| qs.append(make_choice(rng, slabels, gs, pick_instr(rng, s_instr, GENERIC_CHOICE), full_prob=0.15, | |
| other_prob=0.04)) | |
| if rng.random() < 0.3 and gs is not None: | |
| qs.append(make_choice(rng, slabels, gs, pick_instr(rng, s_instr, GENERIC_CHOICE))) | |
| if rng.random() < 0.45: | |
| if rng.random() < 0.5 and gs is not None: | |
| qs.append(derived_noul(rng, slabels, gs, ["This request is about {x}.", "The user needs help with {x}.", | |
| "Is this command about {x}?"], | |
| ["This request is not about {x}."], p_other_group=0.0)) | |
| else: | |
| qs.append(derived_noul(rng, ilabels, gi, ["The user's intent is: {x}.", "Intent: {x}.", | |
| "The command asks for {x}."], | |
| ["The user's intent is not {x}."], p_other_group=0.7)) | |
| yield Example(text, qs[:3]) | |
| BITEXT_CAT = { | |
| "ACCOUNT": ("accounts", ["account team: sign-up, login, profile changes, deleting accounts", | |
| "account creation, editing, deletion and passwords"]), | |
| "CANCEL": ("cancellations", ["cancellation fees and policies"]), | |
| "CONTACT": ("contact", ["requests to reach customer service or a human agent"]), | |
| "DELIVERY": ("delivery", ["delivery options and delivery times"]), | |
| "FEEDBACK": ("feedback", ["complaints and reviews"]), | |
| "INVOICE": ("billing", ["invoices and billing documents", "invoices, bills"]), | |
| "ORDER": ("orders", ["placing, changing, cancelling or tracking orders"]), | |
| "PAYMENT": ("payments", ["payment methods and payment problems"]), | |
| "REFUND": ("refunds", ["refund policy, refund requests and refund status"]), | |
| "SHIPPING": ("shipping", ["shipping addresses"]), | |
| "SUBSCRIPTION": ("subscriptions", ["newsletter subscriptions"]), | |
| } | |
| _FILL = { | |
| "Order Number": lambda r: "#" + str(r.randint(10000, 99999999)), | |
| "Invoice Number": lambda r: "INV-" + str(r.randint(1000, 999999)), | |
| "Person Name": lambda r: r.choice(["Anna", "John Smith", "Maria", "Ahmed", "Li Wei", "Carlos", "Emma"]), | |
| "Client First Name": lambda r: r.choice(["Anna", "John", "Maria", "Ahmed", "Wei", "Carlos"]), | |
| "Client Last Name": lambda r: r.choice(["Smith", "Garcia", "Chen", "Yilmaz", "Novak"]), | |
| "Account Type": lambda r: r.choice(["premium", "business", "standard", "free", "pro"]), | |
| "Account Category": lambda r: r.choice(["premium", "business", "standard", "gold", "platinum"]), | |
| "Delivery City": lambda r: r.choice(["Berlin", "Chicago", "Istanbul", "Lyon", "Osaka", "Leeds"]), | |
| "Delivery Country": lambda r: r.choice(["Germany", "Canada", "Spain", "Brazil", "Japan", "Turkey"]), | |
| "Refund Amount": lambda r: "$" + str(r.randint(5, 900)), | |
| "Currency Symbol": lambda r: r.choice(["$", "EUR ", "GBP "]), | |
| "Money Amount": lambda r: "$" + str(r.randint(5, 900)), | |
| } | |
| def _bitext_fill(rng: random.Random, text: str) -> str: | |
| def sub(m): | |
| k = m.group(1).strip() | |
| f = _FILL.get(k) | |
| return f(rng) if f else k.lower() | |
| return re.sub(r"\{\{([^}]*)\}\}", sub, text) | |
| def bitext(ctx: Ctx): | |
| rows = read_rows("bitext/Bitext-customer-support-llm-chatbot-training-dataset", | |
| "Bitext_Sample_Customer_Support_Training_Dataset_27K_responses-v11.csv") | |
| rng = ctx.rng | |
| cats = sorted(BITEXT_CAT) | |
| intents = sorted({r["intent"] for r in rows}) | |
| int_cat = {r["intent"]: r["category"] for r in rows} | |
| clabels = [Label(BITEXT_CAT[c][0], BITEXT_CAT[c][1], BITEXT_CAT[c][1][0].split(":")[0], key=BITEXT_CAT[c][0], | |
| group=c) for c in cats] | |
| ilabels = [intent_label(i, group=int_cat[i]) for i in intents] | |
| rows = [dict(r, _t=_bitext_fill(rng, clean(r["instruction"]))) for r in rows] | |
| rows = dedupe_rows(rows, lambda r: r["_t"], lambda r: r["intent"]) | |
| c_instr = ["Which team should handle this request?", "Route this ticket to the right department.", | |
| "Which support queue does this message belong to?", "Assign this customer message to a team.", | |
| "Which department is responsible for this?", "Who should pick up this ticket?"] | |
| i_instr = INTENT_INSTR | |
| for r in balanced_order(rng, rows, lambda r: r["intent"], 0.5): | |
| text = r["_t"] | |
| gi, gc = intents.index(r["intent"]), cats.index(r["category"]) | |
| qs = [] | |
| if rng.random() < 0.5: | |
| qs.append(make_choice(rng, clabels, gc, pick_instr(rng, c_instr, GENERIC_CHOICE), full_prob=0.3, | |
| other_prob=0.04)) | |
| else: | |
| qs.append(make_choice(rng, ilabels, gi, pick_instr(rng, i_instr, GENERIC_CHOICE, thing="message"), | |
| full_prob=0.15, other_prob=0.04)) | |
| if rng.random() < 0.45: | |
| qs.append(derived_noul(rng, ilabels, gi, INTENT_POS, INTENT_NEG, p_other_group=0.7, thing="message")) | |
| if rng.random() < 0.2: | |
| qs.append(derived_noul(rng, clabels, gc, ["This ticket should go to the {x} team.", | |
| "The {x} team should handle this.", | |
| "Is this a matter for {x}?"], | |
| ["The {x} team is not responsible for this."], p_other_group=0.0)) | |
| yield Example(text, qs[:3]) | |
| # ---------------------------------------------------------------- emotion / stance / abuse | |
| EMO_INSTR = ["Which emotion does the writer express?", "How does the author feel?", | |
| "What is the dominant emotion in this {thing}?", "Detect the emotion.", | |
| "Pick the emotion that best matches the {thing}.", "What mood is the writer in?"] | |
| EMO_POS = ["The writer is {x}.", "The author of this {thing} is {x}.", "In this {thing}, the writer seems {x}.", | |
| "Is the writer {x}?", "The {thing} shows that the author is {x}."] | |
| EMO_NEG = ["The writer is not {x}.", "The author does not seem {x}."] | |
| def emotion(ctx: Ctx): | |
| rows = read_many("dair-ai/emotion", [f"split/{s}-00000-of-00001.parquet" for s in ("train", "validation", "test")]) | |
| E = [("sadness", "sad", "feeling sad, down or hurt", "neg"), ("joy", "happy", "feeling happy or content", "pos"), | |
| ("love", "affectionate", "feeling love, affection or tenderness", "pos"), | |
| ("anger", "angry", "feeling angry, annoyed or irritated", "neg"), | |
| ("fear", "afraid", "feeling scared, anxious or nervous", "neg"), | |
| ("surprise", "surprised", "feeling surprised or amazed", "amb")] | |
| labels = [Label(n, [d], p, group=g) for n, p, d, g in E] | |
| yield from classify(ctx, rows, lambda r: clean(r["text"]), lambda r: int(r["label"]), labels, | |
| instr=EMO_INSTR, noul_pos=EMO_POS, noul_neg=EMO_NEG, thing="text", alpha=0.5, | |
| other_prob=0.0, p_other_group=0.85) | |
| def tweet_emotion(ctx: Ctx): | |
| rows = read_many("cardiffnlp/tweet_eval", [f"emotion/{s}-00000-of-00001.parquet" for s in ("train", "validation", "test")]) | |
| E = [("anger", "angry", "anger or rage", "neg"), ("joy", "joyful", "joy or happiness", "pos"), | |
| ("optimism", "optimistic", "optimism or hope", "pos"), ("sadness", "sad", "sadness or grief", "neg")] | |
| labels = [Label(n, [d], p, group=g) for n, p, d, g in E] | |
| yield from classify(ctx, rows, lambda r: _tweet_clean(r["text"]), lambda r: int(r["label"]), labels, | |
| instr=EMO_INSTR, noul_pos=EMO_POS, noul_neg=EMO_NEG, thing="tweet", alpha=0.5, | |
| other_prob=0.0, p_other_group=0.9) | |
| GO = [("admiration", "admiring", "pos"), ("amusement", "amused", "pos"), ("anger", "angry", "neg"), | |
| ("annoyance", "annoyed", "neg"), ("approval", "approving", "pos"), ("caring", "caring", "pos"), | |
| ("confusion", "confused", "amb"), ("curiosity", "curious", "amb"), ("desire", "full of desire", "pos"), | |
| ("disappointment", "disappointed", "neg"), ("disapproval", "disapproving", "neg"), | |
| ("disgust", "disgusted", "neg"), ("embarrassment", "embarrassed", "neg"), ("excitement", "excited", "pos"), | |
| ("fear", "afraid", "neg"), ("gratitude", "grateful", "pos"), ("grief", "grieving", "neg"), | |
| ("joy", "joyful", "pos"), ("love", "loving", "pos"), ("nervousness", "nervous", "neg"), | |
| ("optimism", "optimistic", "pos"), ("pride", "proud", "pos"), ("realization", "having a realization", "amb"), | |
| ("relief", "relieved", "pos"), ("remorse", "remorseful", "neg"), ("sadness", "sad", "neg"), | |
| ("surprise", "surprised", "amb"), ("neutral", "emotionally neutral", "neutral")] | |
| def go_emotions(ctx: Ctx): | |
| rows = read_many("google-research-datasets/go_emotions", | |
| [f"simplified/{s}-00000-of-00001.parquet" for s in ("train", "validation", "test")]) | |
| labels = [Label(n, [f"the writer is {p}"] if n != "neutral" else ["no particular emotion"], p, group=g) | |
| for n, p, g in GO] | |
| rng = ctx.rng | |
| for r in rows: | |
| r["_l"] = sorted(int(x) for x in r["labels"]) | |
| r["_t"] = clean(r["text"]).replace("[NAME]", rng.choice(["Alex", "Sam", "Jordan", "Chris", "Taylor"])) | |
| rows = dedupe_rows(rows, lambda r: r["_t"], lambda r: tuple(r["_l"])) | |
| for r in balanced_order(rng, rows, lambda r: r["_l"][0], 0.4): | |
| gold = r["_l"] | |
| qs = [] | |
| if len(gold) == 1 and rng.random() < 0.7: | |
| qs.append(make_choice(rng, labels, gold[0], pick_instr(rng, EMO_INSTR, GENERIC_CHOICE, thing="comment"), | |
| full_prob=0.1, other_prob=0.0)) | |
| n_noul = 1 if qs else rng.choice([1, 1, 2]) | |
| for _ in range(n_noul): | |
| # multi-label rows give real negatives: any emotion not annotated (prefer other valence) | |
| qs.append(derived_noul(rng, labels, gold, EMO_POS, EMO_NEG, p_other_group=0.85, thing="comment")) | |
| yield Example(r["_t"], qs[:3]) | |
| STANCE = {"abortion": "the legalization of abortion", "atheism": "atheism", | |
| "climate": "the view that climate change is a serious concern", "feminist": "feminism", | |
| "hillary": "Hillary Clinton"} | |
| def tweet_stance(ctx: Ctx): | |
| rng = ctx.rng | |
| rows = [] | |
| for t in STANCE: | |
| for s in ("train", "validation", "test"): | |
| for r in read_rows("cardiffnlp/tweet_eval", f"stance_{t}/{s}-00000-of-00001.parquet"): | |
| rows.append(dict(r, _target=t)) | |
| rows = dedupe_rows(rows, lambda r: r["text"] + r["_target"], lambda r: r["label"]) | |
| instr = ["What is the author's stance toward {target}?", "Does this tweet support or oppose {target}?", | |
| "How does the writer feel about {target}?", "Stance on {target}?", | |
| "Classify the tweet's position on {target}."] | |
| for r in balanced_order(rng, rows, lambda r: (r["_target"], r["label"]), 0.7): | |
| tgt = STANCE[r["_target"]] | |
| labels = [Label("none", [f"neutral or unrelated to {tgt}", "no clear stance"], f"no position on {tgt}", | |
| key=rng.choice(["none", "neutral", "neither"])), | |
| Label("against", [f"opposes {tgt}", "is against it"], f"is against {tgt}"), | |
| Label("favor", [f"supports {tgt}", "is in favor of it"], f"supports {tgt}", | |
| key=rng.choice(["favor", "support", "for"]))] | |
| gold = int(r["label"]) | |
| qs = [] | |
| if rng.random() < 0.8: | |
| qs.append(make_choice(rng, labels, gold, pick_instr(rng, instr, (), target=tgt), n=3)) | |
| if not qs or rng.random() < 0.4: | |
| qs.append(derived_noul(rng, labels, gold, ["The author {x}.", "This tweet {x}.", | |
| "The writer's position: {x}."], | |
| p_other_group=0.0, use_desc=0.0)) | |
| yield Example(_tweet_clean(r["text"]), qs) | |
| def hate_offensive(ctx: Ctx): | |
| rows = read_many("SetFit/hate_speech_offensive", ["train.jsonl", "test.jsonl"]) | |
| labels = [Label("hate speech", ["attacks or demeans a group based on identity"], "hate speech", key="hate"), | |
| Label("offensive language", ["offensive or vulgar but not hate speech"], "offensive language", | |
| key="offensive"), | |
| Label("neither", ["neither hateful nor offensive", "harmless"], "harmless content", | |
| key=None)] | |
| rng = ctx.rng | |
| instr = ["Is this tweet hate speech, offensive, or neither?", "Moderate this tweet.", | |
| "How should this tweet be classified for moderation?", "Classify the tweet's content.", | |
| "Which moderation label applies?"] | |
| def extra(r, rng): | |
| g = int(r["label"]) | |
| if rng.random() < 0.35: | |
| s, truth = weighted(rng, [("This tweet contains offensive or abusive language.", g in (0, 1)), | |
| ("This tweet is harmless.", g == 2), | |
| ("This tweet contains hate speech targeting a group.", g == 0)], | |
| [0.45, 0.3, 0.25]) | |
| return [noul(s, truth)] | |
| return [] | |
| rows = [dict(r, _t=_tweet_clean(r["text"])) for r in rows] | |
| yield from classify(ctx, rows, lambda r: r["_t"], lambda r: int(r["label"]), labels, instr=instr, | |
| noul_pos=["This tweet is best described as {x}."], thing="tweet", alpha=0.3, | |
| other_prob=0.0, p_noul=0.0, p_second=0.0, extra=extra) | |
| # ---------------------------------------------------------------- multiple-choice QA (option texts vary) | |
| def _ans_noul(rng: random.Random, q: str, answers: list[str], gold: int) -> tuple: | |
| truth = rng.random() < 0.5 | |
| a = answers[gold] if truth else rng.choice([x for i, x in enumerate(answers) if i != gold]) | |
| q = q.strip() | |
| t = weighted(rng, [f"The correct answer to \"{q}\" is \"{a}\".", f"\"{a}\" answers the question: {q}", | |
| f"Question: {q} Answer: {a}. This answer is correct.", | |
| f"{q} -> {a}"], [0.35, 0.25, 0.25, 0.15]) | |
| return noul(t, truth) | |
| def commonsense_qa(ctx: Ctx): | |
| rows = read_many("tau/commonsense_qa", ["data/train-00000-of-00001.parquet", | |
| "data/validation-00000-of-00001.parquet"]) | |
| rng = ctx.rng | |
| rng.shuffle(rows) | |
| instr = ["Which answer is correct?", "Pick the best answer.", "Answer the question.", | |
| "Choose the most sensible answer.", "What is the right answer?"] | |
| for r in rows: | |
| ch = r["choices"] | |
| answers = [clean(t) for t in ch["text"]] | |
| labs = list(ch["label"]) | |
| if r["answerKey"] not in labs: | |
| continue | |
| g = labs.index(r["answerKey"]) | |
| q = clean(r["question"]) | |
| qs = [make_mcq(rng, answers, g, pick_instr(rng, instr))] | |
| if rng.random() < 0.3: | |
| qs.append(_ans_noul(rng, q, answers, g)) | |
| yield Example(q, qs) | |
| def social_iqa(ctx: Ctx): | |
| rows = read_many("allenai/social_i_qa", ["default/train/0000.parquet", "default/validation/0000.parquet"], | |
| revision="refs/convert/parquet") | |
| rng = ctx.rng | |
| rng.shuffle(rows) | |
| for r in rows: | |
| answers = [clean(r["answerA"]), clean(r["answerB"]), clean(r["answerC"])] | |
| g = int(r["label"]) - 1 | |
| q = clean(r["question"]) | |
| instr = q if rng.random() < 0.8 else f"Based on the situation: {q[:1].lower() + q[1:]}" | |
| qs = [make_mcq(rng, answers, g, instr)] | |
| if rng.random() < 0.3: | |
| qs.append(_ans_noul(rng, q, answers, g)) | |
| yield Example(clean(r["context"]), qs, key=clean(r["context"])) | |
| def race(ctx: Ctx): | |
| rows = read_many("ehovy/race", ["middle/train-00000-of-00001.parquet", "middle/validation-00000-of-00001.parquet", | |
| "middle/test-00000-of-00001.parquet", "high/validation-00000-of-00001.parquet", | |
| "high/test-00000-of-00001.parquet"]) | |
| rng = ctx.rng | |
| by_art: dict[str, list] = {} | |
| for r in rows: | |
| by_art.setdefault(r["article"], []).append(r) | |
| arts = list(by_art) | |
| rng.shuffle(arts) | |
| for art in arts: | |
| state = clean(art) | |
| if len(state) > 2000: # truncation could cut the evidence | |
| continue | |
| qrows = by_art[art] | |
| rng.shuffle(qrows) | |
| qs = [] | |
| for r in qrows[:rng.choice([1, 2, 2, 3])]: | |
| answers = [clean(o) for o in r["options"]] | |
| g = "ABCD".index(r["answer"]) | |
| q = clean(r["question"]) | |
| if "_" in q: | |
| instr = weighted(rng, [f"Fill in the blank: {q}", f"Complete the statement: {q}", q], [0.4, 0.3, 0.3]) | |
| else: | |
| instr = q | |
| qs.append(make_mcq(rng, answers, g, instr)) | |
| if qs: | |
| yield Example(state, qs) | |
| def hellaswag(ctx: Ctx): | |
| rows = read_rows("Rowan/hellaswag", "data/validation-00000-of-00001.parquet") | |
| rng = ctx.rng | |
| rng.shuffle(rows) | |
| def hs(t): | |
| return clean(re.sub(r"\[(header|title|step|substeps)\]", " ", t)) | |
| instr = ["How does the text most likely continue?", "Which ending is most plausible?", | |
| "Pick the most likely continuation.", "What happens next?", "Choose the sentence that best completes the passage."] | |
| for r in rows: | |
| ends = [hs(e) for e in r["endings"]] | |
| state = hs(r["ctx"]) | |
| if rng.random() < 0.4: | |
| state = f"{r['activity_label']}: {state}" | |
| yield Example(state, [make_mcq(rng, ends, int(r["label"]), pick_instr(rng, instr))]) | |
| def sciq(ctx: Ctx): | |
| rows = read_many("allenai/sciq", [f"data/{s}-00000-of-00001.parquet" for s in ("train", "validation", "test")]) | |
| rng = ctx.rng | |
| rng.shuffle(rows) | |
| for r in rows: | |
| answers = [clean(r["correct_answer"]), clean(r["distractor1"]), clean(r["distractor2"]), clean(r["distractor3"])] | |
| if len({a.lower() for a in answers}) < 4: | |
| continue | |
| q = clean(r["question"]) | |
| sup = clean(r["support"]) | |
| if sup and len(sup) <= 2000 and rng.random() < 0.8: | |
| state, instr = sup, q | |
| else: | |
| state, instr = q, weighted(rng, ["Which answer is correct?", "Answer the science question.", | |
| "Pick the correct answer."], [1, 1, 1]) | |
| qs = [make_mcq(rng, answers, 0, instr)] | |
| if rng.random() < 0.25: | |
| qs.append(_ans_noul(rng, q, answers, 0)) | |
| yield Example(state, qs) | |
| def copa(ctx: Ctx): | |
| rows = read_many("aps/super_glue", ["copa/train-00000-of-00001.parquet", "copa/validation-00000-of-00001.parquet"]) | |
| rng = ctx.rng | |
| rng.shuffle(rows) | |
| for r in rows: | |
| instr = rng.choice(["What was the cause?", "Why did this happen?", "What is the more likely cause?"]) \ | |
| if r["question"] == "cause" else \ | |
| rng.choice(["What happened as a result?", "What is the most likely effect?", "What happened next?"]) | |
| yield Example(clean(r["premise"]), [make_mcq(rng, [clean(r["choice1"]), clean(r["choice2"])], | |
| int(r["label"]), instr)]) | |
| SOURCES = { | |
| "ag_news": ag_news, "dbpedia_14": dbpedia, "yahoo_answers_topics": yahoo, "20_newsgroups": newsgroups, | |
| "tweet_topic": tweet_topic, "fin_news_topic": fin_topic, "banking77": banking77, "clinc_oos": clinc, | |
| "massive": massive, "bitext_support": bitext, "emotion": emotion, "tweet_eval_emotion": tweet_emotion, | |
| "go_emotions": go_emotions, "tweet_eval_stance": tweet_stance, "hate_speech_offensive": hate_offensive, | |
| "commonsense_qa": commonsense_qa, "social_i_qa": social_iqa, "race": race, "hellaswag": hellaswag, | |
| "sciq": sciq, "copa": copa, | |
| } | |