diff --git a/.github/workflows/gpu_tests.yml b/.github/workflows/gpu_tests.yml index d7d245049d..9d36919a9a 100644 --- a/.github/workflows/gpu_tests.yml +++ b/.github/workflows/gpu_tests.yml @@ -42,6 +42,11 @@ jobs: .github/workflows/gpu_tests.yml modelopt/** tests/gpu/** + tests/gpu_regression/** + examples/speculative_decoding/** + examples/dataset/** + modelopt_recipes/general/speculative_decoding/** + tools/launcher/** pyproject.toml tox.ini fail_on_initial_diff_error: true @@ -66,6 +71,9 @@ jobs: timeout: 45 container_image: pytorch:26.01-py3 # tests/gpu/_extensions/test_onnx_extensions.py fails for newer containers until https://github.com/tbenthompson/cppimport/pull/98 + - example: gpu-regression + timeout: 15 + container_image: pytorch:26.01-py3 - example: gpu-megatron timeout: 45 container_image: pytorch:26.01-py3 diff --git a/examples/dataset/README.md b/examples/dataset/README.md index 7774e7c34c..15cb21613c 100644 --- a/examples/dataset/README.md +++ b/examples/dataset/README.md @@ -219,3 +219,16 @@ python -m modelopt.torch.utils.plugins.megatron_preprocess_data \ --workers 32 \ --reasoning_content inline ``` + +## Synthetic Test Dataset + +`synthetic_conversations_1k.jsonl` is a 1,000-sample dataset in OpenAI messages format +(900 single-turn + 100 two-turn conversations) covering writing, reasoning, math, coding, +STEM, extraction, humanities, and roleplay categories. + +This dataset was synthesized by Claude (Anthropic) and is licensed under Apache-2.0. +It is intended for testing and CI regression — not for production training. + +```json +{"messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]} +``` diff --git a/examples/dataset/make_dataset.py b/examples/dataset/make_dataset.py index 716634902d..3cf1b98095 100644 --- a/examples/dataset/make_dataset.py +++ b/examples/dataset/make_dataset.py @@ -522,7 +522,10 @@ async def main(args: argparse.Namespace) -> None: ) if "conversation_id" not in entry: entry["conversation_id"] = id_for_conversation(entry["conversations"]) - f.write(json.dumps(entry, ensure_ascii=False) + "\n") + # Output in OpenAI messages format (rename conversations → messages) + output_entry = {k: v for k, v in entry.items() if k != "conversations"} + output_entry["messages"] = entry["conversations"] + f.write(json.dumps(output_entry, ensure_ascii=False) + "\n") if __name__ == "__main__": diff --git a/examples/dataset/synthetic_conversations_1k.jsonl b/examples/dataset/synthetic_conversations_1k.jsonl new file mode 100644 index 0000000000..740e0ec331 --- /dev/null +++ b/examples/dataset/synthetic_conversations_1k.jsonl @@ -0,0 +1,1000 @@ +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v776)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v507)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v895)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v22)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v33)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v483)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v85)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v750)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v354)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v523)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v184)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v809)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v418)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is an API? (v615)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v682)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v501)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v760)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v49)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v732)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v336)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v450)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v790)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v350)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v467)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v622)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v476)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v614)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v554)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v365)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v770)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v630)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v40)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "What is an API? (v797)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v496)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v24)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v369)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v596)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v720)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v53)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v426)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v56)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v264)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v772)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v185)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v466)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v789)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v174)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v150)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v741)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v113)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v428)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is an API? (v65)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance."}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v189)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v414)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is an API? (v589)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v666)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v763)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v221)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v586)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v581)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v299)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v638)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v386)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v364)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v879)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v334)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file."}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v202)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn."}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v38)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v290)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v493)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v247)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v506)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v896)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v713)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v891)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v76)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v11)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v792)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v508)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v177)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v842)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v200)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v765)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work?"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v293)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v538)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds."}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v694)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v210)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v424)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v528)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v34)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v28)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v398)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v607)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v298)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v848)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v668)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v282)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v39)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v44)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v606)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v59)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v34)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v731)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v287)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v527)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v807)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v229)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v436)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v28)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v374)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v819)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v316)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v560)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v241)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v149)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v516)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v417)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v660)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v198)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v585)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v325)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What is an API? (v823)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v702)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v49)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v515)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v864)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v836)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v877)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v359)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v594)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v788)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v188)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v66)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is an API? (v355)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v799)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis?"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v20)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v42)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v330)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v727)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v396)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v463)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v393)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v311)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v680)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v744)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v21)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v461)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v522)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v631)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v490)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v195)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v256)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is an API? (v693)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v740)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v577)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v157)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v612)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v392)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v69)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v688)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v361)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v816)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v401)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v92)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v17)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v489)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v451)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What is an API? (v251)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v653)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v769)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v670)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v129)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v637)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v91)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v342)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v308)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v136)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v88)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v327)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v475)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v81)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v850)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v892)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v375)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v178)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v26)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v349)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v499)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v474)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v617)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v697)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v50)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v211)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is an API? (v381)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v883)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is an API? (v173)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is an API? (v147)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v419)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v61)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v148)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is an API? (v75)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v79)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v775)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v302)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is an API? (v95)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v525)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v774)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v231)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v625)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v800)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v561)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v509)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v840)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v494)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v119)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v477)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v144)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v29)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v10)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "What is an API? (v121)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v605)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v61)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v871)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v572)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome."}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v26)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v639)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v439)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v729)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v193)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v752)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v626)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v571)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is an API?"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v742)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v14)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v510)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v573)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v138)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v191)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240?"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v443)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis?"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v213)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v64)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v411)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v301)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v333)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v192)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v664)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v262)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v647)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v810)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v232)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v795)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v681)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v804)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v482)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v360)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v838)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v236)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v627)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v57)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v582)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v272)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v201)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023."}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v427)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v239)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v84)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v532)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v172)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v289)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is an API? (v485)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is an API? (v329)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v683)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v318)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v454)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v249)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v846)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v279)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v455)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python?"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v761)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v547)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v180)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v557)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v628)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v423)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v843)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost?"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is an API? (v199)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v425)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v534)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v31)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v579)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v404)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is an API? (v277)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v444)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is an API? (v771)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v372)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v722)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v400)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v78)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is an API? (v537)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v575)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v548)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v710)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v41)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v885)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v632)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v858)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v139)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v385)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v456)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v32)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v813)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v140)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v624)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v320)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v708)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v457)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v873)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v326)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v126)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v132)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v817)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v397)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is an API? (v15)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v93)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v415)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v595)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v258)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v313)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v409)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v162)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v304)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v286)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v644)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v635)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v353)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v68)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v678)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v833)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is an API? (v35)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v679)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is an API? (v719)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v237)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v265)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v90)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v835)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v862)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v54)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v657)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v43)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v406)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v380)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v124)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v491)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v802)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula?"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v430)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is an API? (v45)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v703)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v294)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v878)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v212)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v18)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v37)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v860)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v898)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v125)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect?"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v839)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v76)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v101)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v115)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v435)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v50)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v120)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v384)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v47)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v171)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v317)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v324)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v880)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v263)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v145)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is an API? (v43)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v504)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v86)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v376)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v530)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v84)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v851)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v345)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v403)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v226)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v87)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v164)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v335)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v600)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v16)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v472)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v447)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v107)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v856)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v155)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v458)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v280)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v207)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v154)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v587)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v757)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is an API? (v85)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v383)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v801)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v648)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v806)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v536)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v503)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v737)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v559)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v544)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v356)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v206)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v888)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v611)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v711)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v531)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v259)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v153)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v852)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v63)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v434)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v339)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v513)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v748)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v487)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v524)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v893)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v52)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v186)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v673)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v343)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v377)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What caused World War I?"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v368)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v568)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v275)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v690)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v266)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v782)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v37)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v533)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research?"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v542)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v97)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v295)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v460)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v197)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v707)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v261)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v310)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v79)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v160)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v402)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v539)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v176)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v726)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v793)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v818)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v778)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v756)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v297)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v91)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v29)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v449)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v645)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply."}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v480)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v96)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v868)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v431)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v695)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v502)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v260)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v328)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v179)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v564)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v395)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v495)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v35)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v442)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v27)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v659)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v636)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v98)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v337)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner."}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v684)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v116)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v446)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What is an API? (v407)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v815)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v312)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v358)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v471)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v204)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v227)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v481)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v39)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v391)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v110)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v832)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v812)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v62)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v421)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v340)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v183)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v97)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v422)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v181)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work."}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v861)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v649)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is an API? (v745)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v700)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v105)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v19)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v651)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v366)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v619)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is an API?"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v315)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v42)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v130)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v440)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v151)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v588)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v36)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v152)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v676)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v60)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v601)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v437)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v452)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v785)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v268)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v133)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v341)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v803)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v45)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v283)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v652)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v48)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v52)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v821)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v779)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v77)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v599)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v208)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v351)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v215)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v288)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v278)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v53)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v820)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v109)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v118)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v41)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v137)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v106)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v306)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v72)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue?"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v822)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v309)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v556)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v743)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v634)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v291)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v378)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v889)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v629)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v357)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v712)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v620)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v518)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v662)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v550)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v75)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v102)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v576)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v857)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What caused tides?"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v74)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v51)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v468)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v307)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v134)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v859)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v884)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v244)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is an API? (v641)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v209)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v267)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v870)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v535)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v578)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v845)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v68)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v83)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v40)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v608)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v592)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v853)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v583)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v122)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v413)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v240)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v723)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v609)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v766)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v190)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v82)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v520)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v876)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v805)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v783)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v514)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v488)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v847)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v672)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v58)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v321)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v691)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v555)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v593)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v837)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v222)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is an API? (v303)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v716)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v158)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v498)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v569)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v897)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v292)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v465)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v88)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v399)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5?"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v886)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v168)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v725)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v869)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v218)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v492)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v715)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v751)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v170)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v242)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v80)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula?"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v553)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is an API? (v667)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v51)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v89)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "What is an API? (v563)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v453)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v77)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v255)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v12)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v717)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v187)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v829)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v143)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v66)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v814)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v705)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v23)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v254)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v111)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v347)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v412)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v62)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v100)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v661)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v669)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v689)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v55)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v478)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v420)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v755)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v362)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v441)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v674)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v46)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v96)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v194)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v416)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v709)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v248)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v484)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v590)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v584)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v135)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v753)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v219)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v767)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v685)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v285)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What caused tides? (v243)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v526)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v728)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v338)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v872)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is an API? (v69)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v874)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v60)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v646)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v724)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v72)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA?"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v67)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v734)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v235)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v567)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v602)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work?"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v346)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v827)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v230)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v253)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v123)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v462)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v529)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v448)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v831)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v71)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v687)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v844)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v319)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v730)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v205)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v706)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v38)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v784)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v866)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is an API? (v433)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v621)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v540)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v855)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v169)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v562)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v486)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v675)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v131)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v128)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v545)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v70)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v497)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v749)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v87)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v33)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v865)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v246)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v59)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v245)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v314)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v371)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v808)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7."}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v500)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v331)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v613)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation."}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v543)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v552)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v165)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v798)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v382)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v834)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v73)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v894)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v796)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v99)"}, {"role": "assistant", "content": "Refrigerant cycles: compress, release heat, expand, absorb heat from food."}, {"role": "user", "content": "Why does it make noise?"}, {"role": "assistant", "content": "Compressor motor cycling, refrigerant flowing, defrost heater, evaporator fan, ice dropping."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v305)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v640)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v108)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v519)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v182)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v780)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v512)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v30)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v736)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v739)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect?"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v161)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v445)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is a dictionary in Python? (v31)"}, {"role": "assistant", "content": "A collection of key-value pairs. d = {\"name\": \"Alice\", \"age\": 30}."}, {"role": "user", "content": "How to iterate over keys and values?"}, {"role": "assistant", "content": "for key, value in d.items(): print(f\"{key}: {value}\")"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v98)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "What is an API? (v55)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v656)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v787)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v899)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v768)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v36)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v698)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v117)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v738)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v830)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet?"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v566)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v257)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v541)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v479)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v63)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v390)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v394)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v65)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v610)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v56)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v696)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v811)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v58)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v642)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v156)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v112)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v48)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v773)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v93)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v505)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v521)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v141)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v881)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is an API? (v25)"}, {"role": "assistant", "content": "A set of rules for software communication. Like a waiter between you and the kitchen."}, {"role": "user", "content": "REST vs GraphQL?"}, {"role": "assistant", "content": "REST uses fixed endpoints, may need multiple requests. GraphQL uses one endpoint where client specifies exact data needed."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v408)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v597)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v438)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v598)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v764)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v269)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v551)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v74)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v762)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v252)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v92)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v271)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v146)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v469)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v658)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v405)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is an API? (v511)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v671)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v217)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v322)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v735)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v580)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "Why is the sky blue? (v216)"}, {"role": "assistant", "content": "Due to Rayleigh scattering. Shorter blue wavelengths scatter more than longer red wavelengths in the atmosphere."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v67)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v274)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v410)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v323)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v824)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v82)"}, {"role": "assistant", "content": "Plants convert sunlight, water, CO2 into glucose and oxygen."}, {"role": "user", "content": "What happens in light-dependent reactions?"}, {"role": "assistant", "content": "In thylakoid membranes, chlorophyll absorbs light, splits water, creates ATP and NADPH. Oxygen released."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v841)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v234)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v57)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v794)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v786)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v863)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v332)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v701)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v224)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v570)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v704)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v655)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v276)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v388)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v473)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v167)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v94)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v746)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v546)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v175)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the trolley problem?"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v623)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v73)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v663)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v699)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v70)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v273)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v686)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v214)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v363)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v379)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v166)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v373)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v854)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v650)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v464)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v54)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "What is the trolley problem? (v47)"}, {"role": "assistant", "content": "Moral dilemma: pull lever to divert trolley, saving 5 but killing 1."}, {"role": "user", "content": "What about the footbridge variant?"}, {"role": "assistant", "content": "Must physically push someone to stop trolley. Feels worse despite identical outcome. Reveals we distinguish side-effect harm from using someone as means."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v103)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v887)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v78)"}, {"role": "assistant", "content": "Affect = verb (influence). Effect = noun (result)."}, {"role": "user", "content": "Are there exceptions?"}, {"role": "assistant", "content": "Effect can be a verb meaning to bring about. Affect can be a psychology noun meaning emotional expression."}]} +{"messages": [{"role": "user", "content": "What is an API? (v875)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v81)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v296)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v791)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v233)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v677)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v46)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v71)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v721)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v196)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v591)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v370)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v882)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research?"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v633)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v643)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is an API? (v849)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v300)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v565)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v80)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v387)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v127)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v549)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v470)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v747)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v44)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v826)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v270)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v618)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Explain how a transistor works simply. (v352)"}, {"role": "assistant", "content": "A transistor is an electronic switch with three terminals. A small current at the base controls a larger current from collector to emitter, enabling amplification and switching."}]} +{"messages": [{"role": "user", "content": "What caused tides? (v867)"}, {"role": "assistant", "content": "Tides are caused by the gravitational pull of the Moon and Sun on Earth oceans, creating bulges of water."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v367)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v99)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42. (v389)"}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v94)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v90)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a)."}, {"role": "user", "content": "Use it to solve x^2 - 5x + 6 = 0."}, {"role": "assistant", "content": "a=1, b=-5, c=6. x = (5 +/- sqrt(25-24))/2 = (5 +/- 1)/2. x = 3 or x = 2."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v344)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v781)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v220)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "Solve: 2x + 5 = 17 (v159)"}, {"role": "assistant", "content": "2x + 5 = 17\n2x = 12\nx = 6"}]} +{"messages": [{"role": "user", "content": "Help me start a blog post about remote work. (v64)"}, {"role": "assistant", "content": "Three years ago, working from home was a perk. Today it reshapes productivity and work-life balance."}, {"role": "user", "content": "Add a paragraph about challenges."}, {"role": "assistant", "content": "Remote work brings isolation, communication gaps, missed mentorship, and difficulty separating work from personal life."}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v348)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v83)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v714)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is the difference between DNA and RNA? (v163)"}, {"role": "assistant", "content": "DNA is double-stranded with deoxyribose sugar and thymine. RNA is single-stranded with ribose sugar and uracil. DNA stores genetic info; RNA carries instructions for protein synthesis."}]} +{"messages": [{"role": "user", "content": "Calculate the area of a triangle with base 10 and height 7. (v825)"}, {"role": "assistant", "content": "Area = 0.5 x 10 x 7 = 35 square units"}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v777)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python."}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v890)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for medical research? (v828)"}, {"role": "assistant", "content": "Complex question. Supporters cite life-saving advances. Opponents cite animal rights. Modern frameworks advocate the 3Rs: Replace, Reduce, Refine."}]} +{"messages": [{"role": "user", "content": "Write a one-paragraph product description for wireless earbuds. (v284)"}, {"role": "assistant", "content": "Crystal-clear audio with active noise cancellation, 30-hour battery life, ergonomic design, IPX5 water resistance, and Bluetooth 5.3 connectivity."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v603)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "What is an API? (v459)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is an API? (v225)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "Extract the dates from: Founded March 15 2010, IPO September 22 2018, acquired January 3 2023. (v429)"}, {"role": "assistant", "content": "March 15 2010 - Founded\nSeptember 22 2018 - IPO\nJanuary 3 2023 - Acquired"}]} +{"messages": [{"role": "user", "content": "Is it ethical to use animals for research? (v86)"}, {"role": "assistant", "content": "Complex. Supporters cite life-saving advances. Opponents cite animal rights. 3Rs framework."}, {"role": "user", "content": "What are alternatives?"}, {"role": "assistant", "content": "Organ-on-chip, computer simulations, cell cultures, human microdosing, 3D bioprinting."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v718)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v665)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v733)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v203)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "What is the derivative of f(x) = 3x^2 + 2x - 5? (v574)"}, {"role": "assistant", "content": "Using the power rule: f prime(x) = 6x + 2"}]} +{"messages": [{"role": "user", "content": "Compose a haiku about autumn. (v27)"}, {"role": "assistant", "content": "Crimson leaves descend\nCrisp wind whispers through bare trees\nNature final bow"}]} +{"messages": [{"role": "user", "content": "Briefly explain the significance of the Renaissance. (v616)"}, {"role": "assistant", "content": "A cultural rebirth (14th-17th century) from Italy that transformed European art, science, and thought, shifting from medieval religious doctrine to humanism."}]} +{"messages": [{"role": "user", "content": "Difference between affect and effect? (v517)"}, {"role": "assistant", "content": "Affect is usually a verb (to influence). Effect is usually a noun (a result). Affect = Action, Effect = End result."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v238)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "What is the quadratic formula? (v223)"}, {"role": "assistant", "content": "x = (-b +/- sqrt(b^2 - 4ac)) / (2a), for solving ax^2 + bx + c = 0."}]} +{"messages": [{"role": "user", "content": "What is an API? (v95)"}, {"role": "assistant", "content": "An API is a set of rules allowing software applications to communicate. Like a waiter taking your order to the kitchen and bringing back food."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v30)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v32)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v432)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Explain the difference between a list and a tuple in Python. (v604)"}, {"role": "assistant", "content": "Lists are mutable and use []. Tuples are immutable and use (). Tuples are slightly faster and can be used as dictionary keys."}]} +{"messages": [{"role": "user", "content": "What are the main themes in Hamlet? (v89)"}, {"role": "assistant", "content": "Revenge, appearance vs reality, mortality, corruption, and the impossibility of certainty."}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v558)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What caused World War I? (v13)"}, {"role": "assistant", "content": "Alliance systems, militarism, imperialism, nationalism. Triggered by assassination of Archduke Franz Ferdinand."}, {"role": "user", "content": "How did alliances make it worse?"}, {"role": "assistant", "content": "Domino effect: Austria vs Serbia pulled in Russia, Germany, France, Britain. Regional conflict became global."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v758)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v692)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v104)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "Write a professional email declining a meeting invitation. (v754)"}, {"role": "assistant", "content": "Subject: Unable to Attend\n\nDear Team,\n\nThank you for the meeting invitation. Unfortunately, I have a scheduling conflict. Could you please share the meeting notes afterward?\n\nBest regards"}]} +{"messages": [{"role": "user", "content": "You are a chef. Recommend a quick weeknight dinner. (v142)"}, {"role": "assistant", "content": "Garlic shrimp pasta! Saute garlic in olive oil, add shrimp, toss with linguine, lemon, and parsley. 15 minutes total."}]} +{"messages": [{"role": "user", "content": "What is photosynthesis? (v228)"}, {"role": "assistant", "content": "Plants convert sunlight, water, and CO2 into glucose and oxygen using chlorophyll. 6CO2 + 6H2O + light -> C6H12O6 + 6O2."}]} +{"messages": [{"role": "user", "content": "Write a bash one-liner to count lines in a file. (v250)"}, {"role": "assistant", "content": "wc -l < filename.txt"}]} +{"messages": [{"role": "user", "content": "How does a refrigerator work? (v281)"}, {"role": "assistant", "content": "A refrigerant cycles through compression and expansion. Compressor pressurizes gas, condenser releases heat, expansion valve drops temperature, evaporator absorbs heat from food."}]} +{"messages": [{"role": "user", "content": "Write a Python function to check if a string is a palindrome. (v759)"}, {"role": "assistant", "content": "def is_palindrome(s):\n s = s.lower().replace(\" \", \"\")\n return s == s[::-1]"}]} +{"messages": [{"role": "user", "content": "Find the mean of 4, 8, 15, 16, 23, 42."}, {"role": "assistant", "content": "Mean = (4 + 8 + 15 + 16 + 23 + 42) / 6 = 108 / 6 = 18"}]} +{"messages": [{"role": "user", "content": "A bat and ball cost 1.10 together. The bat costs 1.00 more than the ball. How much does the ball cost? (v114)"}, {"role": "assistant", "content": "The ball costs 0.05. If ball = x, bat = x + 1.00. x + x + 1.00 = 1.10, so x = 0.05."}]} +{"messages": [{"role": "user", "content": "What is 15% of 240? (v654)"}, {"role": "assistant", "content": "15% of 240 = 0.15 x 240 = 36"}]} diff --git a/examples/speculative_decoding/README.md b/examples/speculative_decoding/README.md index 820b587b91..86a874e659 100644 --- a/examples/speculative_decoding/README.md +++ b/examples/speculative_decoding/README.md @@ -217,8 +217,7 @@ To use your own datasets, please preprocess your data into a `.jsonl` file with ```json { - "conversation_id": , - "conversations": [{"role":, "content":}] + "messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}] } ``` @@ -350,3 +349,46 @@ More models coming soon! - 💡 [Release Notes](https://nvidia.github.io/Model-Optimizer/reference/0_changelog.html) - 🐛 [File a bug](https://github.com/NVIDIA/Model-Optimizer/issues/new?template=1_bug_report.md) - ✨ [File a Feature Request](https://github.com/NVIDIA/Model-Optimizer/issues/new?template=2_feature_request.md) + +## DFlash (Block Diffusion for Speculative Decoding) + +DFlash is a parallel speculative decoding method based on [Block Diffusion](https://arxiv.org/abs/2602.06036). +Unlike autoregressive draft models (EAGLE3), DFlash predicts an entire block of tokens in a single forward pass +using masked parallel prediction with KV injection from the target model's hidden states. + +### Quick Start + +For a complete end-to-end example (training + evaluation), see the +[launcher example](../../tools/launcher/examples/Qwen/Qwen3-8B/hf_online_dflash.yaml): + +```bash +uv run launch.py --yaml examples/Qwen/Qwen3-8B/hf_online_dflash.yaml --yes +``` + +### Key Configuration ([dflash.yaml](../../modelopt_recipes/general/speculative_decoding/dflash.yaml)) + +| Field | Default | Description | +|-------|---------|-------------| +| `dflash.dflash_block_size` | 8 | Block size for parallel prediction | +| `dflash.dflash_num_anchors` | 512 | Number of anchor positions per sample | +| `dflash.dflash_loss_decay_factor` | 4.0 | Exponential decay gamma (0 disables) | +| `dflash.dflash_self_logit_distillation` | true | Use logit distillation from target | +| `dflash.dflash_architecture_config.num_hidden_layers` | 5 | Draft decoder layers | +| `dflash.dflash_architecture_config.mask_token_id` | auto | Token ID for masked positions | +| `training.answer_only_loss` | false | Mask loss on non-assistant tokens | + +Qwen3 sliding window attention is automatically supported — draft layers inherit +`layer_types` and `sliding_window` from the config, matching the target model's +attention pattern. + +### Export + +```bash +python scripts/export_hf_checkpoint.py \ + --model_path /path/to/training/output \ + --export_path /path/to/exported/model +``` + +### Results + +See [doc/dflash.md](doc/dflash.md) for design details, benchmark results, and open items. diff --git a/examples/speculative_decoding/collect_hidden_states/compute_hidden_states_hf.py b/examples/speculative_decoding/collect_hidden_states/compute_hidden_states_hf.py index 7a76ec4d8f..906784aeea 100644 --- a/examples/speculative_decoding/collect_hidden_states/compute_hidden_states_hf.py +++ b/examples/speculative_decoding/collect_hidden_states/compute_hidden_states_hf.py @@ -201,7 +201,7 @@ async def submit_generates(): for entry in dataset: conversation_id = entry.get("conversation_id", entry.get("uuid")) - conversations = entry["conversations"] + conversations = entry.get("messages") or entry["conversations"] if not conversations or not isinstance(conversations, list): num_invalid += 1 continue diff --git a/examples/speculative_decoding/doc/dflash.md b/examples/speculative_decoding/doc/dflash.md new file mode 100644 index 0000000000..44db5d39e7 --- /dev/null +++ b/examples/speculative_decoding/doc/dflash.md @@ -0,0 +1,387 @@ +# DFlash — Block Diffusion for Speculative Decoding + +DFlash predicts an entire block of tokens in a single forward pass using masked parallel +prediction with KV injection from the target model's hidden states. + +Reference: [arXiv:2602.06036](https://arxiv.org/abs/2602.06036) | +[SpecForge](https://github.com/sgl-project/SpecForge) | +[z-lab](https://github.com/z-lab/dflash) + +## Architecture + +```text +Target Model (frozen) + │ + ├─ hidden_states[layer 1, 9, 17, 25, 33] ──► concat ──► FC + RMSNorm ──► target_hidden + │ │ + │ K/V injection + │ │ + └─ embed([anchor, mask, mask, ...]) ──► noise_embedding ──► DFlash Decoder (5 layers) + │ + lm_head ──► draft tokens +``` + +**Key components:** +- **Parallel Drafting**: Position 0 is the anchor (the last accepted token — known and correct), + positions 1..B-1 are filled with a special mask token (similar to BERT's `[MASK]`). The draft + model predicts all B-1 unknown positions in a single forward pass, unlike autoregressive drafters + (EAGLE3) which predict one token at a time. Benefit: one forward pass produces B-1 draft tokens. +- **Feature Fusion**: Multi-layer hidden states → Linear(num_layers × hidden_size, hidden_size) + RMSNorm. + Concatenates hidden states from multiple target layers (e.g., layers 1, 9, 17, 25, 33) to give + the draft model richer context. Similar to EAGLE3's fused feature approach. +- **KV Injection**: A design choice for how the draft model conditions on the target model's + context. In each draft decoder layer, K and V are projected from the concatenation of target + hidden states and the block's own embeddings, while Q is projected from the block embeddings + only. This is one approach to parallel prediction — alternatives include cross-attention or + prefix conditioning. +- **Random Anchor Sampling**: During training, anchors are sampled randomly from assistant response + positions (where `loss_mask=1`), not placed at fixed intervals. The anchor is the starting token + of each training block — it's always correct (from the ground truth) and the model learns to + predict the next B-1 tokens given this anchor and the target's hidden states. See the + [illustrated example](#random-anchor-sampling-num_anchors) below for why this improves efficiency. + +**KV Injection (token-level example):** + +Given context `"The answer is"` and block_size=4 with anchor `"is"`: + +```text +Target model hidden states (from frozen base model): + h["The"] h["answer"] h["is"] ← target_hidden (ctx_len=3) + │ │ │ + └──── FC + RMSNorm ────┘ + │ + fused context features + +Block input (draft token embeddings): + embed("is") embed(MASK) embed(MASK) embed(MASK) ← noise_embedding (block_size=4) + pos=3 pos=4 pos=5 pos=6 + +In each DFlash decoder layer: + Q = q_proj(noise_embedding) ← shape [4, head_dim] + only the block tokens generate queries + + K = concat( ← shape [7, head_dim] + k_proj(fused_context), ← from target hidden [3 positions: "The","answer","is"] + k_proj(noise_embedding) ← from block tokens [4 positions: "is",MASK,MASK,MASK] + ) + + V = concat(v_proj(fused_context), v_proj(noise_embedding)) ← same shape as K + + Attention: Q (4 tokens) attends to K/V (7 tokens) + + K/V: "The" "answer" "is" │ "is" MASK MASK MASK + pos0 pos1 pos2 │ pos3 pos4 pos5 pos6 + ───────────────────────────┼────────────────────────── + Q pos=3 "is" : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + Q pos=4 MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + Q pos=5 MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + Q pos=6 MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + ─── context ─── │ ──── block ──────────── + (bidirectional within block, no attention mask at inference) + + Output → lm_head → predictions: + pos=3: skip (anchor, already known) + pos=4: predict token after "is" → "5" + pos=5: predict token after "is 5" → "." + pos=6: predict token after "is 5." → "[EOS]" +``` + +**Training vs Inference:** + +```text +TRAINING (2 anchors, block_size=4): + + Context tokens: "The" "answer" "is" "5" "." + Block 0 (anchor="The"): [The, MASK, MASK, MASK] + Block 1 (anchor="is"): [is, MASK, MASK, MASK] + + All blocks processed in ONE forward pass. Attention mask controls visibility: + + K/V (context) K/V (block 0) K/V (block 1) + "The" "ans" "is" "5" "." The M M M is M M M + c0 c1 c2 c3 c4 b0 b1 b2 b3 b4 b5 b6 b7 + Q ───────────────────────────────────────────────────────────────────────── + b0 "The" : ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ + b1 MASK : ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ + b2 MASK : ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ + b3 MASK : ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✗ ✗ ✗ ✗ + b4 "is" : ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ + b5 MASK : ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ + b6 MASK : ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ + b7 MASK : ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ + ── context ────── ── block 0 ────── ── block 1 ────── + + Block 0: first block sees NO context (✗), only its own block (bidirectional ✓) + Block 1: sees context before anchor "is" (c0,c1 ✓), NOT its own anchor or later + plus its own block (bidirectional ✓) + + Loss: computed on all non-anchor positions simultaneously. + No verification — ground truth labels known from training data. + +INFERENCE (one block at a time, NO attention mask): + + Step 1: target forward("The answer is") → base_token = "5" + block = [5, MASK, MASK, MASK] + + K/V: "The" "ans" "is" │ "5" MASK MASK MASK + Q ─────────────────────────────────┼────────────────────────── + "5" : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + MASK : ✓ ✓ ✓ │ ✓ ✓ ✓ ✓ + + All ✓ — no mask at inference. Block sees full context freely. + Target verifies → accept 3 → sequence: "The answer is 5 . [EOS]" + + Step 2: next block with grown context (5 tokens) ... +``` + +The draft model sees the target's internal representation of the context (via KV injection) +without re-running the target model for drafting. The expensive target forward pass is +only needed for verification — the lightweight draft model reuses the target's hidden states. + +**Draft model components** (Qwen3-based): +- `Qwen3MLP`, `Qwen3RMSNorm`, `Qwen3RotaryEmbedding` from transformers +- Sliding window attention supported via `config.layer_types` *(implemented, not yet validated end-to-end)* +- Independent of target model architecture + +## Training + +### Quick Start + +```bash +uv run launch.py --yaml examples/Qwen/Qwen3-8B/hf_online_dflash.yaml --yes +``` + +### Recipe + +See [`modelopt_recipes/general/speculative_decoding/dflash.yaml`](../../../modelopt_recipes/general/speculative_decoding/dflash.yaml) + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `dflash.dflash_block_size` | 8 | Block size for parallel prediction | +| `dflash.dflash_num_anchors` | 512 | Random anchor positions per sample (see below) | +| `dflash.dflash_loss_decay_factor` | 4.0 | Exponential decay gamma (0 disables, see below) | +| `dflash.dflash_self_logit_distillation` | true | Use target model logits as soft labels (vs hard CE) | +| `dflash.dflash_architecture_config.num_hidden_layers` | 5 | Draft decoder layers | +| `dflash.dflash_architecture_config.mask_token_id` | auto | Token ID for masked positions | +| `training.answer_only_loss` | false | Mask loss on non-assistant tokens | + +> **Note on `answer_only_loss` and chat templates:** When `answer_only_loss=true`, the +> tokenizer's chat template must include `{% generation %}` / `{% endgeneration %}` tags +> around assistant content. HuggingFace uses these tags to produce `assistant_masks` via +> `return_assistant_tokens_mask=True` in `apply_chat_template()`. +> +> Most model tokenizers (Qwen3, Llama3, etc.) do **not** ship with these tags by default. +> You must provide a custom template via `data.chat_template=path/to/template.jinja` in +> the training config. A Qwen3 template is provided at +> `tools/launcher/examples/Qwen/Qwen3-8B/chat_template_train.jinja`. +> +> To create a template for other models: +> 1. Copy the model's original `chat_template` from `tokenizer_config.json` +> 2. Add `{% generation %}` before and `{% endgeneration %}` after assistant content +> 3. Test that tokenization matches the original template (no extra/missing tokens) +> +> See the [HuggingFace guide on train-on-completions-only](https://huggingface.co/docs/transformers/en/chat_templating#train-on-completions-only) +> for details on generation tags. + +### Random Anchor Sampling (`num_anchors`) + +During training, anchor positions are sampled randomly from valid (assistant response) +tokens in each batch, rather than dividing the sequence into fixed blocks. Each anchor +starts a block of `block_size` tokens where the draft model predicts positions 1..B-1. + +```text +Sequence: [SYS] You helpful [USR] What 2+3? [AST] The answer is 5 +Position: 0 1 2 3 4 5 6 7 8 9 10 +loss_mask: 0 0 0 0 0 0 0 1 1 1 1 + ^^^^^^^^^^^^^^^^ + assistant response + +Fixed blocks (block_size=4): +Block 0: pos [0,1,2,3] anchor=0 → predict 1,2,3 → loss_mask=0,0,0 → ZERO LOSS +Block 1: pos [4,5,6,7] anchor=4 → predict 5,6,7 → loss_mask=0,0,1 → 1/3 useful +Block 2: pos [8,9,10,—] anchor=8 → predict 9,10,— → loss_mask=1,1,— → 2/2 useful + +Efficiency: 3/8 = 38% + +Random anchors (num_anchors=3, sampled from loss_mask=1): +Anchor 7: pos [7,8,9,10] → predict 8,9,10 → loss_mask=1,1,1 → 3/3 useful +Anchor 9: pos [9,10,—,—] → predict 10,—,— → loss_mask=1,—,— → 1/1 useful +Anchor 8: pos [8,9,10,—] → predict 9,10,— → loss_mask=1,1,— → 2/2 useful + +Efficiency: 6/6 = 100% +``` + +Random anchors guarantee every prediction is on assistant tokens. +Fixed blocks waste compute on prompt tokens where loss_mask=0. + +**Tradeoff:** Higher `num_anchors` = more training signal per sample but more compute. +Lower = faster iteration but less data efficiency. With `seq_len=4096` and `block_size=8`, +`num_anchors=512` means the model sees ~512 blocks per sample (covering ~4096 positions). +Scale proportionally: `num_anchors ≈ seq_len / block_size` gives full coverage. + +### Loss Decay + +The exponential decay factor (gamma) weights early block positions higher than later ones. +If position 1 in a block is wrong, all subsequent positions are rejected in speculative +decoding. Decay aligns the training loss with what matters for acceptance rate. + +```text +weight[k] = exp(-(k-1).clamp(min=0) / gamma) for k = 0..B-1 +``` + +Positions 0 (anchor, excluded by loss mask) and 1 get full weight (1.0). Later positions +decay: e.g., with `gamma=4` and `block_size=8`, position 7 contributes only 22% as +much as position 1. Paper recommendation: gamma=7 for block_size=16, gamma=4 for block_size=8. + +Note: this is different from EAGLE3's `eagle_loss_decay_factor` which multiplies loss by +`alpha^step` across TTT steps. DFlash decay operates within a single block, weighting +early positions higher because they gate acceptance of all later positions. + +### Checkpoint Resume + +DFlash supports checkpoint resume transparently. Rotary embeddings are lazily +initialized on first forward (matching EAGLE3's `_maybe_init_rope` pattern), +avoiding meta-tensor issues during `from_pretrained` model construction. + +### Export + +```bash +python scripts/export_hf_checkpoint.py \ + --model_path /path/to/training/output \ + --export_path /path/to/exported/model +``` + +Exports to z-lab compatible HF format (`config.json` + `model.safetensors`). + +## Results (Qwen3-8B) + +Trained on nvidia/Nemotron-Post-Training-Dataset-v2 (2M samples), 64 GPUs, 10 epochs. + +### Training Configuration + +| Parameter | Value | +|-----------|-------| +| Block Size | 8 | +| Sequence Length | 4096 | +| Anchors | 512 | +| Loss | KD + decay (gamma=4) | +| Total Steps | 306,620 | +| Final Per-Token Acc | 67.0% | + +### HuggingFace AR Evaluation + +AR is evaluated using `ar_validate.py` which calls `pseudo_speculative_generate` +with online (context-dependent) ground truth: + +1. Run base model on `input_ids` → get base token + hidden states +2. Build draft block: `[base_token, MASK, MASK, ...]` +3. Run DFlash draft forward → get `block_size-1` draft tokens +4. Verify each draft token against the base model's prediction **given the + accepted sequence so far** (not a pre-computed fixed reference) +5. Accept consecutive matches, append target's correction on first mismatch +6. AR = total accepted tokens / number of speculative steps + +```bash +python scripts/ar_validate.py --model_path /path/to/checkpoint --per_category --osl 512 --steps 7 +``` + +### vLLM Deployment Results + +vLLM nightly (v0.19.1+), H100, MT-Bench 80 prompts, 1024 max tokens: + +| | Baseline | z-lab (bs16) | **ModelOpt (bs8)** | +|---|---------|-------------|-------------------| +| TP=1 tok/s | 145 | 422 | **443** | +| TP=8 tok/s | 377 | 919 | **1053** | +| Speedup (TP=1) | 1.0x | 2.9x | **3.1x** | + +**Per-Category (TP=8):** + +| Category | ModelOpt Accept | z-lab Accept | ModelOpt TPS | z-lab TPS | +|----------|----------------|-------------|-------------|-----------| +| math | **5.14** | 4.24 | **1238** | 1098 | +| coding | **4.03** | 3.52 | **1299** | 1269 | +| writing | **3.99** | 3.97 | **1002** | 903 | +| reasoning | **3.89** | 3.49 | **1188** | 1020 | +| roleplay | **3.88** | 3.37 | **1069** | 923 | +| extraction | **3.60** | 3.02 | **1002** | 789 | +| stem | 3.55 | **3.63** | **1027** | 914 | +| humanities | **3.05** | 2.68 | **786** | 672 | +| **ALL** | | | **1053** | 919 | + +ModelOpt wins acceptance length on 7/8 categories and TPS on 8/8 categories. + +### Key Findings + +| Finding | Evidence | +|---------|----------| +| 3.1x speedup over baseline (TP=1) | 443 vs 145 tok/s on vLLM | +| 15% faster than z-lab | TP=1: 443 vs 422; TP=8: 1053 vs 919 | +| More efficient drafting | 44% vs 16.5% draft acceptance; fewer tokens drafted, more accepted | +| Loss decay boosts AR | +0.12 AR at 55K (gamma=7, bs16); consistent across checkpoints | +| Longer sequences help | seq=4096 vs 512: +0.49 AR on AA-Synthetic | + +## Open Items + +### Not Yet Implemented + +- **Offline training**: DFlash needs multi-layer hidden states at all positions for KV + injection (5x storage vs EAGLE3's single-layer approach). Possible approaches: store + fused hidden states, pre-sample anchors, or hybrid CPU base + GPU draft. +- **Qwen3MoE draft**: Replace `Qwen3MLP` with `Qwen3MoeMLP` via config flag. See + `hf_dflash.py` module docstring for instructions. +- **MLA support (DeepseekV3/Kimi-K2)**: Requires MLA-aware KV injection with compressed K/V. +- **Docker local testing**: Launcher example requires Slurm. Need a local Docker example + with `hf_local=` path mapping. + +### Implemented but Not Yet Validated End-to-End + +- **Sliding window attention**: Code reads `config.layer_types` and sets `sliding_window` + per layer. Unit tested but not validated in a full training run with sliding window models. +- **FP8 / NVFP4 quantization**: Export pipeline supports quantized checkpoints via + `hf_ptq.py` (PTQ succeeded in testing). AR impact of quantization not yet measured. + The flow: train (bf16) → `mtq.quantize(model, quant_cfg)` → `export_hf_checkpoint.py`. +- **Checkpoint resume**: Lazy rotary embedding init (matching EAGLE3 pattern). + Validated in train+resume E2E tests on DDP and FSDP2. + +### Validated + +- **Online training**: E2E pipeline (train → export → eval) on sample-1K and sample-10K. +- **Multi-node DDP**: 8-node (64 GPU) training on full dataset, 10 epochs. +- **AR evaluation**: `ar_validate.py` with online GT, per-category MT-Bench. +- **vLLM deployment**: Speculative decoding with `vllm/vllm-openai:nightly` (v0.19.1+). + 3.1x speedup over baseline. Per-category benchmarks on MT-Bench. + + ```bash + vllm serve Qwen/Qwen3-8B \ + --speculative-config '{"method": "dflash", "model": "path/to/checkpoint", "num_speculative_tokens": 7}' \ + --max-num-batched-tokens 32768 + ``` + +- **FSDP2 training**: `dp_shard_size=8` with checkpoint resume validated. +- **Export**: z-lab compatible HF format, loadable by vLLM and z-lab benchmark. +- **Loss decay**: Validated +0.12 AR improvement with gamma=7 (bs16). +- **Qwen3.5-4B**: E2E pipeline validated (train → export → vLLM serve). + +### vLLM Deployment Notes for Qwen3.5 + +Qwen3.5 models have non-standard architecture dimensions (`head_dim=160`, `num_attention_heads=16`) +that cause vLLM KV cache page size errors when inherited by the DFlash draft model. Key findings: + +1. **M-RoPE incompatibility**: Qwen3.5 uses M-RoPE (multimodal RoPE with `mrope_section`). + DFlash draft models use standard Qwen3 RoPE. Inheriting `rope_scaling` from the base model + causes `NotImplementedError: Speculative Decoding does not support M-RoPE yet` in vLLM. + **Fix**: `rope_scaling` is not inherited from base model; the draft uses standard RoPE. + +2. **Head dimension mismatch**: Qwen3.5-4B has `head_dim=160` (2560/16 heads) which is + non-standard and causes `page size not divisible` errors in vLLM's KV cache. + **Fix**: Override draft architecture to use z-lab's dimensions: `num_attention_heads=32`, + `num_key_value_heads=8`, `head_dim=128`, `intermediate_size=9728`, `rope_theta=10000000`. + See `tools/launcher/examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml`. + +3. **MTP alternative**: Qwen3.5 has built-in MTP (Multi-Token Prediction) heads that work + with vLLM natively (no draft model needed): `--speculative-config '{"method": "mtp", "num_speculative_tokens": 1}'`. + MTP-1 achieves 91% acceptance rate on Qwen3.5-4B. DFlash provides higher speedup when + trained sufficiently (z-lab's checkpoint: 3.84 mean acceptance length). diff --git a/examples/speculative_decoding/eagle_utils.py b/examples/speculative_decoding/eagle_utils.py index 191478f1ab..5db21168af 100644 --- a/examples/speculative_decoding/eagle_utils.py +++ b/examples/speculative_decoding/eagle_utils.py @@ -53,11 +53,27 @@ __all__ = ["EagleOfflineDataCollator", "OfflineSupervisedDataset"] -def make_eagle_supervised_data_module( +def make_speculative_data_module( tokenizer: transformers.PreTrainedTokenizer, data_args, train_len=None, + answer_only_loss=False, + shift_labels=True, ) -> dict: + """Create data module for speculative decoding training. + + Args: + shift_labels: If True, labels are shifted by 1 for autoregressive training (EAGLE3). + If False, labels are unshifted for diffusion-style training (DFlash). + """ + # Load chat template from file if provided + chat_template = None + if getattr(data_args, "chat_template", None): + template_path = data_args.chat_template + with open(template_path) as f: + chat_template = f.read() + print_rank_0(f"Loaded chat template from {template_path}") + if data_args.offline_data_path is None: train_dataset = ShardedDataset("json", data_files=data_args.data_path) @@ -66,6 +82,9 @@ def make_eagle_supervised_data_module( tokenizer=tokenizer, train_len=train_len, return_labels=True, + answer_only_loss=answer_only_loss, + shift_labels=shift_labels, + chat_template=chat_template, ) else: data_collator = VisionLanguageDataCollator( @@ -117,7 +136,7 @@ class EagleTrainingPlot(TrainerCallback): def __init__(self, ar_validate_steps: int = 1000, estimate_ar: bool = False): self.ar_validate_steps = ar_validate_steps - if hasattr(wandb, "init") and is_master(): + if wandb is not None and wandb.run is not None and is_master(): wandb.init() self.estimate_ar = estimate_ar @@ -126,6 +145,17 @@ def on_log(self, args, state, control, **kwargs): if not hasattr(state, "training_accs") or len(state.training_accs) == 0: return control average_acc = np.mean(state.training_accs, axis=0) + # Always print accuracy to console + try: + acc_str = ", ".join(f"{a:.4f}" for a in np.array(average_acc).flatten()) + print_rank_0(f"Step {state.global_step} Training Acc: [{acc_str}]") + except Exception: + print_rank_0(f"Step {state.global_step} Training Acc: {average_acc}") + # Log accuracy to HF Trainer's logs dict (picked up by TensorBoard) + logs = kwargs.get("logs") or {} + for i, draft_acc in enumerate(average_acc): + for j, step_acc in enumerate(draft_acc): + logs[f"train_acc/parallel_{i}_step_{j}"] = float(step_acc) if self.estimate_ar: # Calculate mean training AR since last log # NOTE: This is only an estimate of the real AR. @@ -139,19 +169,12 @@ def on_log(self, args, state, control, **kwargs): acc_cumprod *= draft_acc[-1] est_ar += acc_cumprod print_rank_0(f"Step {state.global_step} Estimated Training AR: {est_ar:.4f}") + logs["estimated_training_ar"] = est_ar # log to wandb - if wandb and is_master(): - logs = kwargs.get("logs") or {} + if wandb is not None and wandb.run is not None and is_master(): if logs: wandb.log({k: v for k, v in logs.items() if v is not None}, step=state.global_step) - for i, draft_acc in enumerate(average_acc): - for j, step_acc in enumerate(draft_acc): - wandb.log( - {f"parallel_{i}_step_{j}_train_acc": step_acc}, step=state.global_step - ) - if self.estimate_ar: - wandb.log({"estimated_training_ar": est_ar}, step=state.global_step) # reset training_accs state.training_accs = [] @@ -171,7 +194,7 @@ def on_step_end(self, args, state, control, **kwargs): device=kwargs["model"].device, ) print_rank_0(f"Step {state.global_step} AR: {sum(ars) / len(ars):.4f}") - if wandb and is_master(): + if wandb is not None and wandb.run is not None and is_master(): wandb.log({"validate_ar": sum(ars) / len(ars)}, step=state.global_step) except Exception: print_rank_0("AR validation not available.") diff --git a/examples/speculative_decoding/main.py b/examples/speculative_decoding/main.py index 171a8b0129..a5f12d7dcf 100644 --- a/examples/speculative_decoding/main.py +++ b/examples/speculative_decoding/main.py @@ -40,7 +40,7 @@ from eagle_utils import ( EagleTrainerWithAccLog, EagleTrainingPlot, - make_eagle_supervised_data_module, + make_speculative_data_module, patch_ring_attention_for_ttt, ) from omegaconf import OmegaConf @@ -90,6 +90,13 @@ class DataArguments: default=None, metadata={"help": "Path to draft vocabulary cache file."}, ) + chat_template: str = field( + default=None, + metadata={ + "help": "Jinja chat template with {% generation %} tags for answer_only_loss. " + "If not set, the tokenizer's built-in template is used (must already have generation tags)." + }, + ) vlm_img_dir: str = field(default=None, metadata={"help": "Path to the VLM image directory."}) vlm_processor: str = field(default=None, metadata={"help": "Path to the VLM processor."}) sample_size: int = field( @@ -112,11 +119,17 @@ class TrainingArguments(transformers.TrainingArguments): ) }, ) - mode: Literal["eagle3", "medusa"] = "eagle3" + mode: Literal["eagle3", "medusa", "dflash"] = "eagle3" estimate_ar: bool = field( default=False, metadata={"help": "Whether to estimate AR using training accuracy to log."} ) ar_validate_steps: int = field(default=1000, metadata={"help": "AR validation interval."}) + answer_only_loss: bool = field( + default=False, + metadata={ + "help": "Mask loss on non-assistant tokens. Requires a chat_template with generation tags." + }, + ) cp_size: int = field(default=1, metadata={"help": "Context parallelism size."}) dp_shard_size: int | None = field( default=None, @@ -142,8 +155,8 @@ def _parse_cli() -> tuple[str, list[str]]: return args.config, overrides -def _load_config(config_path: str, overrides: list[str] = ()) -> tuple[dict, dict]: - """Load training config from a YAML file with sections: model, data, training, eagle. +def _load_config(config_path: str, overrides: list[str] = ()) -> tuple[dict, dict, dict]: + """Load training config from a YAML file with sections: model, data, training, eagle/dflash. *overrides* are OmegaConf dotlist entries (e.g. ``["model.model_name_or_path=xxx"]``) applied on top of the YAML. @@ -151,15 +164,16 @@ def _load_config(config_path: str, overrides: list[str] = ()) -> tuple[dict, dic Returns: hf_cfg: Flat dict from model/data/training sections, for HfArgumentParser.parse_dict() eagle_cfg: Eagle section dict (EagleConfig fields), passed directly to mtsp.convert() + dflash_cfg: DFlash section dict (DFlashConfig fields), passed directly to mtsp.convert() """ merged = OmegaConf.load(config_path) if overrides: merged = OmegaConf.merge(merged, OmegaConf.from_dotlist(list(overrides))) cfg = OmegaConf.to_container(merged, resolve=True) - # Eagle section maps directly to EagleConfig fields — no field enumeration needed. - # eagle_architecture_config is a nested dict and is included as-is. + # Eagle/DFlash sections map directly to config fields — no field enumeration needed. eagle_cfg = cfg.get("eagle", {}) + dflash_cfg = cfg.get("dflash", {}) hf_cfg = { **cfg.get("model", {}), @@ -171,12 +185,12 @@ def _load_config(config_path: str, overrides: list[str] = ()) -> tuple[dict, dic cp_size = hf_cfg.get("cp_size", 1) hf_cfg["dp_shard_size"] = torch.cuda.device_count() // cp_size - return hf_cfg, eagle_cfg + return hf_cfg, eagle_cfg, dflash_cfg def train(): config_path, overrides = _parse_cli() - hf_cfg, eagle_cfg = _load_config(config_path, overrides) + hf_cfg, eagle_cfg, dflash_cfg = _load_config(config_path, overrides) parser = transformers.HfArgumentParser( ( @@ -202,7 +216,10 @@ def train(): patch_ring_attention_for_ttt() # Specific patch to accelerate 1.12.0. Removable after move to 1.13.0 training_args.parallelism_config.sp_backend = None - print_rank_0(f"arguments: {model_args}, {training_args}, {medusa_args}, eagle_cfg={eagle_cfg}") + print_rank_0( + f"arguments: {model_args}, {training_args}, {medusa_args}, " + f"eagle_cfg={eagle_cfg}, dflash_cfg={dflash_cfg}" + ) # Detect checkpoint to resume from last_checkpoint = ( @@ -282,13 +299,32 @@ def train(): ) model.eagle_module.d2t = torch.load(data_args.draft_vocab_cache, weights_only=True) print_rank_0(f"Loaded draft vocab cache from {data_args.draft_vocab_cache}.") + elif training_args.mode == "dflash": + # Auto-detect mask_token_id from tokenizer if not set + if not dflash_cfg.get("dflash_mask_token_id"): + if tokenizer.mask_token_id is not None: + dflash_cfg["dflash_mask_token_id"] = tokenizer.mask_token_id + print_rank_0( + f"Auto-detected mask_token_id={tokenizer.mask_token_id} from tokenizer" + ) + else: + raise ValueError( + "mask_token_id not found in tokenizer and not set in config. " + "Set dflash.dflash_mask_token_id in the training YAML." + ) + mtsp.convert(model, [("dflash", dflash_cfg)]) else: raise Exception(f"{training_args.mode} is not supported!") print_rank_0("Loading dataset...") - if training_args.mode == "eagle3": - data_module = make_eagle_supervised_data_module( - tokenizer, data_args, train_len=training_args.training_seq_len + is_dflash = training_args.mode == "dflash" + if training_args.mode in ("eagle3", "dflash"): + data_module = make_speculative_data_module( + tokenizer, + data_args, + train_len=training_args.training_seq_len, + answer_only_loss=training_args.answer_only_loss, + shift_labels=not is_dflash, ) trainer = EagleTrainerWithAccLog( diff --git a/examples/speculative_decoding/requirements.txt b/examples/speculative_decoding/requirements.txt index 409c35f0ed..4ded40502b 100644 --- a/examples/speculative_decoding/requirements.txt +++ b/examples/speculative_decoding/requirements.txt @@ -1 +1 @@ -transformers<5.4 +transformers>=5.0,<5.4 diff --git a/examples/speculative_decoding/scripts/ar_validate.py b/examples/speculative_decoding/scripts/ar_validate.py index 1ad7bec409..8fcae87652 100644 --- a/examples/speculative_decoding/scripts/ar_validate.py +++ b/examples/speculative_decoding/scripts/ar_validate.py @@ -13,7 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""AR validation for speculative decoding models (EAGLE3, DFlash, Medusa). + +Supports per-category MT-Bench evaluation and online (context-dependent) validation. +""" + import argparse +from collections import defaultdict from accelerate import Accelerator from datasets import load_dataset @@ -27,52 +33,76 @@ mto.enable_huggingface_checkpointing() -def validate_ar(model, tokenizer, ds, steps=3, osl=20, num_samples=80, device=None): +def validate_ar( + model, + tokenizer, + ds, + steps=3, + osl=20, + num_samples=80, + device=None, +): + """Validate acceptance rate on MT-Bench prompts using online validation. + + Online validation recomputes ground truth after each accepted draft token + (context-dependent), matching actual speculative decoding behavior. + + Args: + model: Speculative decoding model (EAGLE3, DFlash, etc.) + tokenizer: Tokenizer for the model. + ds: MT-Bench dataset (HuggingFace dataset with 'prompt' and optional 'category'). + steps: Number of draft tokens per speculative step. + osl: Output sequence length. + num_samples: Max number of samples to evaluate. + device: Device to run on. + + Returns: + List of (category, ar) tuples. + """ validator = HFARValidation(model, tokenizer) num_samples = min(num_samples, len(ds)) - ars = [] + results = [] + failures = 0 for i in tqdm(range(num_samples), desc="Validating AR"): prompt = ds[i]["prompt"][0] - input_ids = tokenizer(prompt, return_tensors="pt").input_ids - # Apply chat template to the prompt, continuing with assistant response + category = ds[i].get("category", "unknown") if hasattr(tokenizer, "apply_chat_template"): - chat_messages = [ - {"role": "user", "content": prompt}, - ] + chat_messages = [{"role": "user", "content": prompt}] prompt = tokenizer.apply_chat_template( chat_messages, tokenize=False, add_generation_prompt=True ) - input_ids = tokenizer(prompt, return_tensors="pt").input_ids + input_ids = tokenizer(prompt, return_tensors="pt").input_ids if device: input_ids = input_ids.to(device) - # validate AR - _, ar = validator.validate(osl, input_ids=input_ids, steps=steps) - ars.append(ar) - return ars + try: + _, ar = validator.validate_online(osl, input_ids=input_ids, steps=steps) + results.append((category, ar)) + except Exception as e: + failures += 1 + print(f" WARNING: sample {i} ({category}) failed: {e}") + if failures: + print(f"WARNING: {failures}/{num_samples} samples failed during AR validation") + return results def main(): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser(description="AR validation for speculative decoding models.") parser.add_argument("--model_path", type=str, required=True, help="Path to model directory") parser.add_argument("--trust_remote_code", action="store_true", help="Trust remote code") - parser.add_argument("--steps", type=int, default=3, help="Steps for AR validation") - parser.add_argument( - "--osl", type=int, default=32, help="Output sequence length for AR validation" - ) - parser.add_argument( - "--num_samples", type=int, default=80, help="Number of MT-Bench samples to use" - ) + parser.add_argument("--steps", type=int, default=3, help="Draft tokens per step") + parser.add_argument("--osl", type=int, default=32, help="Output sequence length") + parser.add_argument("--num_samples", type=int, default=80, help="Number of samples") + parser.add_argument("--per_category", action="store_true", help="Report per-category AR") parser.add_argument( "--ar_lower_bound", type=float, default=None, - help="AR lower bound for validation. If provided, will throw error if AR is below threshold.", + help="Error if AR is below this threshold.", ) args = parser.parse_args() accelerator = Accelerator() - # Load model and tokenizer model = load_vlm_or_llm( args.model_path, device_map="auto", trust_remote_code=args.trust_remote_code ) @@ -82,26 +112,35 @@ def main(): model.eval() model = accelerator.prepare(model) - # Load MT-Bench prompts from HuggingFace ds = load_dataset("HuggingFaceH4/mt_bench_prompts")["train"] - ars = validate_ar( - model, tokenizer, ds, args.steps, args.osl, args.num_samples, accelerator.device + results = validate_ar( + model, + tokenizer, + ds, + args.steps, + args.osl, + args.num_samples, + accelerator.device, ) - # Optionally, throw error if AR is below lower bound - if args.ar_lower_bound: - mean_ar = sum(ars) / len(ars) - if mean_ar < args.ar_lower_bound: - raise ValueError( - f"AR is below lower bound {args.ar_lower_bound}. Mean AR: {mean_ar:.4f}" - ) - # Print results - if ars and accelerator.is_main_process: - avg_ar = sum(ars) / len(ars) - print("\n==== AR Validation Results on MT-Bench ====") - print(f"Number of samples: {len(ars)}") - print(f"Output Sequence Length: {args.osl}") - print(f"Steps: {args.steps}") - print(f"Average AR: {avg_ar:.4f}") + + if results and accelerator.is_main_process: + all_ars = [ar for _, ar in results] + avg_ar = sum(all_ars) / len(all_ars) + print(f"\n==== AR Validation Results (osl={args.osl}, steps={args.steps}) ====") + + if args.per_category: + cat_ars = defaultdict(list) + for cat, ar in results: + cat_ars[cat].append(ar) + for cat in sorted(cat_ars): + cat_avg = sum(cat_ars[cat]) / len(cat_ars[cat]) + print(f" {cat:>12}: {cat_avg:.4f}") + + print(f" {'ALL':>12}: {avg_ar:.4f}") + print(f" Samples: {len(results)}") + + if args.ar_lower_bound and avg_ar < args.ar_lower_bound: + raise ValueError(f"AR {avg_ar:.4f} is below lower bound {args.ar_lower_bound}.") if __name__ == "__main__": diff --git a/examples/speculative_decoding/scripts/calibrate_draft_vocab.py b/examples/speculative_decoding/scripts/calibrate_draft_vocab.py index 16e6b2d0ee..19f387a654 100644 --- a/examples/speculative_decoding/scripts/calibrate_draft_vocab.py +++ b/examples/speculative_decoding/scripts/calibrate_draft_vocab.py @@ -49,7 +49,9 @@ def main(): tokenizer = AutoTokenizer.from_pretrained(args.model) with open(args.data) as f: lines = islice(f, args.calibrate_size) if args.calibrate_size else f - conversations = [json.loads(line)["conversations"] for line in lines] + conversations = [ + (d := json.loads(line)).get("messages") or d["conversations"] for line in lines + ] conversations = [item for sublist in conversations for item in sublist] d2t = calibrate_frequent_vocab(tokenizer, conversations, args.draft_vocab_size) diff --git a/examples/speculative_decoding/scripts/export_hf_checkpoint.py b/examples/speculative_decoding/scripts/export_hf_checkpoint.py index 98ea438f1b..cee2e45d0e 100644 --- a/examples/speculative_decoding/scripts/export_hf_checkpoint.py +++ b/examples/speculative_decoding/scripts/export_hf_checkpoint.py @@ -42,5 +42,8 @@ def parse_args(): model = load_vlm_or_llm(args.model_path, dtype="auto", trust_remote_code=args.trust_remote_code) model.eval() with torch.inference_mode(): - export_speculative_decoding(model, export_dir=args.export_path) + export_speculative_decoding( + model, + export_dir=args.export_path, + ) print(f"Exported checkpoint to {args.export_path}") diff --git a/modelopt/torch/export/plugins/hf_spec_export.py b/modelopt/torch/export/plugins/hf_spec_export.py index 67a64e831b..b1232f8f6a 100644 --- a/modelopt/torch/export/plugins/hf_spec_export.py +++ b/modelopt/torch/export/plugins/hf_spec_export.py @@ -27,7 +27,7 @@ from .hf_spec_configs import kimik2_eagle_template_config, llama_eagle_template_config -ALL_SPEC_MODES = ["eagle"] +ALL_SPEC_MODES = ["eagle", "dflash"] LLAMA_EAGLE_SINGLE_LAYER = { "required": { @@ -263,3 +263,129 @@ def _extract_state_dict(self, full_state_dict: dict): export_sd.pop(f"parallel_draft_heads.medusa_heads.{i}.{j}.linear.bias") ) return export_sd + + +class DFlashExporter(SpeculativeDecodingExporter): + """Draft model exporter for DFlash. + + Exports in z-lab compatible format: + - model.safetensors: draft module weights (no prefix) + - config.json: Qwen3-style config with dflash_config field + """ + + def _extract_state_dict(self, full_state_dict: dict): + """Extract DFlash module weights, stripping the dflash_module prefix.""" + export_sd = {} + for key, value in full_state_dict.items(): + if "dflash_module." in key: + export_key = key.split("dflash_module.", 1)[1] + # Skip rotary embedding buffers (not needed, recomputed) + if "rotary_emb" in export_key: + continue + export_sd[export_key] = value.clone() + return export_sd + + def _export_config(self): + """Build config.json matching z-lab DFlash format.""" + model = self.model + base_config = ( + getattr(model.config, "text_config", None) + or getattr(model.config, "llm_config", None) + or model.config + ) + draft_config = model.dflash_config + + config = { + "architectures": ["DFlashDraftModel"], + # DFlash draft uses Qwen3 architecture regardless of base model type. + # Use "qwen3" as default; base model types like "qwen3_5_text" are not + # recognized by vLLM for draft model loading. + "model_type": "qwen3", + "block_size": model.dflash_block_size, + "dflash_config": { + "mask_token_id": model.mask_token_id, + "target_layer_ids": list(model.target_layer_ids), + }, + # Architecture dimensions + "hidden_size": getattr(draft_config, "hidden_size", base_config.hidden_size), + "num_hidden_layers": draft_config.num_hidden_layers, + "num_attention_heads": getattr( + draft_config, "num_attention_heads", base_config.num_attention_heads + ), + "num_key_value_heads": getattr( + draft_config, "num_key_value_heads", base_config.num_key_value_heads + ), + "head_dim": getattr( + draft_config, + "head_dim", + base_config.hidden_size // base_config.num_attention_heads, + ), + "intermediate_size": getattr( + draft_config, "intermediate_size", base_config.intermediate_size + ), + "hidden_act": getattr(draft_config, "hidden_act", "silu"), + "rms_norm_eps": getattr(draft_config, "rms_norm_eps", 1e-6), + "vocab_size": base_config.vocab_size, + "max_position_embeddings": getattr(base_config, "max_position_embeddings", 32768), + "initializer_range": getattr(base_config, "initializer_range", 0.02), + "attention_bias": getattr(draft_config, "attention_bias", False), + "attention_dropout": getattr(draft_config, "attention_dropout", 0.0), + "rope_theta": getattr( + draft_config, "rope_theta", getattr(base_config, "rope_theta", 1000000.0) + ), + # DFlash draft uses standard Qwen3 RoPE, not M-RoPE from multimodal models. + # z-lab uses null; vLLM handles null rope_scaling correctly. + "rope_scaling": None, + "tie_word_embeddings": False, + "torch_dtype": str(getattr(base_config, "torch_dtype", torch.bfloat16)).replace( + "torch.", "" + ), + "num_target_layers": base_config.num_hidden_layers, + } + + # Add layer_types if present (Qwen3-style) + if hasattr(draft_config, "layer_types"): + config["layer_types"] = draft_config.layer_types + else: + config["layer_types"] = ["full_attention"] * draft_config.num_hidden_layers + + return config + + def export(self, export_dir: Path | str, dtype: torch.dtype | None = None): + """Export the DFlash draft model to deployment format.""" + export_dir = Path(export_dir) + export_dir.mkdir(parents=True, exist_ok=True) + + # Export quantized modules if applicable + if has_quant_opt(self.model): + from ..unified_export_hf import _export_transformers_checkpoint + + full_sd, hf_quant_config = _export_transformers_checkpoint(self.model, dtype) + else: + full_sd, hf_quant_config = self.model.state_dict(), None + + # Export state dict + drafter_sd = self._extract_state_dict(full_sd) + assert drafter_sd, "No dflash_module weights found in state dict" + if dtype is not None and hf_quant_config is None: + drafter_sd = {k: v.to(dtype) for k, v in drafter_sd.items()} + save_file(drafter_sd, f"{export_dir}/model.safetensors") + + # Export config + drafter_config = self._export_config() + # Update torch_dtype to match actual exported weights + if dtype is not None: + drafter_config["torch_dtype"] = str(dtype).replace("torch.", "") + if hf_quant_config is not None: + drafter_config["quantization_config"] = hf_quant_config + with open(f"{export_dir}/config.json", "w") as f: + json.dump(drafter_config, f, indent=2) + + if hf_quant_config is not None: + with open(f"{export_dir}/hf_quant_config.json", "w") as f: + json.dump(hf_quant_config, f, indent=2) + + print( + f"Exported DFlash draft model: {len(drafter_sd)} tensors, " + f"config keys: {list(drafter_config.keys())[:5]}..." + ) diff --git a/modelopt/torch/speculative/config.py b/modelopt/torch/speculative/config.py index 16439e76ad..6fd6fc38c8 100644 --- a/modelopt/torch/speculative/config.py +++ b/modelopt/torch/speculative/config.py @@ -50,6 +50,67 @@ } +def _get_dflash_default_config(): + from .dflash.default_config import default_dflash_config + + return default_dflash_config + + +DFLASH_DEFAULT_CFG = { + "algorithm": "dflash", + "config": { + "dflash_architecture_config": {}, # merged with default at convert time + }, +} + + +class DFlashConfig(ModeloptBaseConfig): + """DFlash config for block-wise parallel speculative decoding.""" + + dflash_block_size: int = ModeloptField( + default=8, + description="Block size for parallel prediction. Draft predicts this many tokens per block.", + ) + + dflash_freeze_base_model: bool = ModeloptField( + default=True, description="Whether to freeze base model during DFlash module training." + ) + + dflash_self_logit_distillation: bool = ModeloptField( + default=True, description="Whether to use logit distillation from base model." + ) + + dflash_loss_decay_factor: float = ModeloptField( + default=0.0, + description="Gamma for exponential loss decay weighting (paper Eq.4). " + "Suggested: 7 for block_size=16, 5 for 10, 4 for 8. 0 disables.", + ) + + dflash_num_anchors: int = ModeloptField( + default=512, + description="Number of random anchor positions sampled per sequence during training.", + ) + + dflash_report_acc: bool = ModeloptField( + default=True, description="Whether to report eval accuracy." + ) + + dflash_mask_token_id: int = ModeloptField( + default=None, + description="Token ID used for masked (unknown) positions. " + "Set explicitly or auto-detected from tokenizer.mask_token_id in main.py.", + ) + + dflash_architecture_config: dict = ModeloptField( + default={}, description="Config for the DFlash draft module architecture." + ) + + dflash_use_torch_compile: bool = ModeloptField( + default=True, + description="Whether to use torch.compile on DFlash forward/loss methods.", + ) + + class MedusaConfig(ModeloptBaseConfig): """Medusa config.""" diff --git a/modelopt/torch/speculative/dflash/__init__.py b/modelopt/torch/speculative/dflash/__init__.py new file mode 100644 index 0000000000..912b8d47a2 --- /dev/null +++ b/modelopt/torch/speculative/dflash/__init__.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""DFlash Optimization Method.""" + +from .conversion import * +from .default_config import * +from .dflash_model import * diff --git a/modelopt/torch/speculative/dflash/conversion.py b/modelopt/torch/speculative/dflash/conversion.py new file mode 100644 index 0000000000..943be90ca0 --- /dev/null +++ b/modelopt/torch/speculative/dflash/conversion.py @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""DFlash conversion/restore utilities.""" + +from torch import nn + +from modelopt.torch.opt.conversion import ModelLikeModule +from modelopt.torch.opt.dynamic import _DMRegistryCls +from modelopt.torch.opt.mode import ConvertReturnType, MetadataDict + +from ..config import DFlashConfig + +DFlashDMRegistry = _DMRegistryCls(prefix="DFlash") # global instance for the registry + + +def convert_to_dflash_model(model: nn.Module, config: DFlashConfig) -> ConvertReturnType: + """Convert the model to a DFlash model as per `config`.""" + model = model.init_modellike() if isinstance(model, ModelLikeModule) else model + + original_cls = type(model) + if original_cls not in DFlashDMRegistry: + for cls in DFlashDMRegistry._registry: + if issubclass(original_cls, cls): + DFlashDMRegistry.register({original_cls: "base_model_class"})(DFlashDMRegistry[cls]) + break + + # merge custom config with default config (lazy import to avoid circular) + from .default_config import default_dflash_config + + custom_config = config.dflash_architecture_config + config.dflash_architecture_config = {**default_dflash_config, **custom_config} + + dflash_model = DFlashDMRegistry.convert(model) + dflash_model.modify(config) + + metadata = {} + return dflash_model, metadata + + +def restore_dflash_model( + model: nn.Module, config: DFlashConfig, metadata: MetadataDict +) -> nn.Module: + """Function for restoring a previously converted model to a DFlash model.""" + assert not metadata, "No metadata expected!" + return convert_to_dflash_model(model, config)[0] diff --git a/modelopt/torch/speculative/dflash/default_config.py b/modelopt/torch/speculative/dflash/default_config.py new file mode 100644 index 0000000000..1777de3f29 --- /dev/null +++ b/modelopt/torch/speculative/dflash/default_config.py @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Default DFlash architecture config. + +Model-specific settings (hidden_size, num_attention_heads, rope_*, etc.) +are inherited from the base model in HFDFlashModel.modify(). Static +defaults that don't depend on the base model are set here, similar to +``eagle/default_config.py``. +""" + +default_dflash_config = { + # DFlash-specific + "num_hidden_layers": 5, + # Architecture defaults (overridable by user config) + "hidden_act": "silu", + "rms_norm_eps": 1e-06, + "initializer_range": 0.02, + "attention_bias": False, + "attention_dropout": 0.0, + "tie_word_embeddings": False, + "_attn_implementation": "sdpa", +} diff --git a/modelopt/torch/speculative/dflash/dflash_model.py b/modelopt/torch/speculative/dflash/dflash_model.py new file mode 100644 index 0000000000..0a10f065eb --- /dev/null +++ b/modelopt/torch/speculative/dflash/dflash_model.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""DFlash model to support block-wise parallel speculative decoding.""" + +from modelopt.torch.opt.dynamic import DynamicModule + + +class DFlashModel(DynamicModule): + """Base DFlash Model.""" + + def _setup(self): + """Register temporary attributes for the DFlash module.""" + self._register_temp_attribute("dflash_module", None) + + def modify(self, config): + """Base DFlash Model modify function. Child class should implement the details.""" + self.dflash_block_size = config.dflash_block_size + self.dflash_freeze_base_model = config.dflash_freeze_base_model + self.dflash_loss_decay_factor = config.dflash_loss_decay_factor + self.dflash_self_logit_distillation = config.dflash_self_logit_distillation + self.dflash_num_anchors = config.dflash_num_anchors + self.dflash_report_acc = config.dflash_report_acc + self.dflash_use_torch_compile = config.dflash_use_torch_compile diff --git a/modelopt/torch/speculative/mode.py b/modelopt/torch/speculative/mode.py index 866449e155..ae965354a9 100644 --- a/modelopt/torch/speculative/mode.py +++ b/modelopt/torch/speculative/mode.py @@ -23,7 +23,8 @@ _ModeRegistryCls, ) -from .config import EagleConfig, MedusaConfig +from .config import DFlashConfig, EagleConfig, MedusaConfig +from .dflash.conversion import convert_to_dflash_model, restore_dflash_model from .eagle.conversion import convert_to_eagle_model, restore_eagle_model from .medusa.conversion import convert_to_medusa_model, restore_medusa_model @@ -58,6 +59,34 @@ def restore(self) -> RestoreEntrypoint: return restore_medusa_model +@SpeculativeDecodingModeRegistry.register_mode +class DFlashModeDescriptor(ModeDescriptor): + """Class to describe the ``"dflash"`` mode. + + The properties of this mode can be inspected via the source code. + """ + + @property + def name(self) -> str: + """Returns the value (str representation) of the mode.""" + return "dflash" + + @property + def config_class(self) -> type[ModeloptBaseConfig]: + """Specifies the config class for the mode.""" + return DFlashConfig + + @property + def convert(self) -> ConvertEntrypoint: + """The mode's entrypoint for converting a model.""" + return convert_to_dflash_model + + @property + def restore(self) -> RestoreEntrypoint: + """The mode's entrypoint for restoring a model.""" + return restore_dflash_model + + @SpeculativeDecodingModeRegistry.register_mode class EagleModeDescriptor(ModeDescriptor): """Class to describe the ``"eagle"`` mode. diff --git a/modelopt/torch/speculative/plugins/__init__.py b/modelopt/torch/speculative/plugins/__init__.py index 5e3f4bff2f..9b55db3af0 100644 --- a/modelopt/torch/speculative/plugins/__init__.py +++ b/modelopt/torch/speculative/plugins/__init__.py @@ -30,4 +30,5 @@ from .megatron_medusa import * with import_plugin("transformers"): + from .hf_dflash import * from .transformers import * diff --git a/modelopt/torch/speculative/plugins/hf_dflash.py b/modelopt/torch/speculative/plugins/hf_dflash.py new file mode 100644 index 0000000000..c2079038a2 --- /dev/null +++ b/modelopt/torch/speculative/plugins/hf_dflash.py @@ -0,0 +1,825 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""DFlash speculative decoding plugin for HuggingFace models. + +Architecture: +- Feature Fusion: multi-layer target hidden states → FC + RMSNorm +- KV Injection: fused features as K/V in every draft layer with QK-norm +- Parallel Drafting: mask_token_id for unknown positions, bidirectional within blocks +- Random anchor sampling with exponential loss decay +- Logit distillation from target model + +Reference: "DFlash: Block Diffusion for Flash Speculative Decoding" (arXiv:2602.06036) + +Draft model components: + The draft model currently uses Qwen3 components (MLP, RMSNorm, RotaryEmbedding) + from ``transformers.models.qwen3``, matching z-lab's reference checkpoint format. + Qwen3 sliding window attention is supported via ``config.layer_types``. + The draft architecture is independent of the target model — any target model can + be used as long as it provides hidden states. + + To add support for other draft architectures: + + Qwen3MoE (MoE MLP): + 1. Import ``Qwen3MoeMLP`` from ``transformers.models.qwen3_moe`` + 2. Add a config flag (e.g., ``use_moe``) in ``dflash_architecture_config`` + 3. In ``DFlashDecoderLayer.__init__``, select MLP based on the flag + RMSNorm, RotaryEmbedding, and attention are shared across Qwen3 variants. + + MLA (Multi-head Latent Attention, e.g., DeepseekV3/Kimi-K2): + MLA compresses K/V into a low-rank latent space. To support MLA in DFlash: + 1. Replace ``DFlashAttention`` with an MLA-aware variant that handles + compressed KV injection (project target_hidden through MLA's down/up + projections before concatenating with noise K/V) + 2. Handle lazy rope initialization (see ``_setup_kimi_k2_decoder`` in + ``modelopt.torch.speculative.utils`` for the EAGLE3 approach) + 3. The ``_apply`` meta buffer fix in ``DFlashModule`` already handles the + lazy rope pattern needed for MLA models. +""" + +import logging + +import torch +import torch.nn.functional as F +from torch import nn +from transformers import PreTrainedModel +from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS +from transformers.models.qwen3.configuration_qwen3 import Qwen3Config as _Qwen3Config +from transformers.models.qwen3.modeling_qwen3 import Qwen3MLP as _MLP_CLS # noqa: N814 +from transformers.models.qwen3.modeling_qwen3 import Qwen3RMSNorm as _NORM_CLS # noqa: N814 +from transformers.models.qwen3.modeling_qwen3 import ( + Qwen3RotaryEmbedding as _ROTARY_CLS, # noqa: N814 +) +from transformers.models.qwen3.modeling_qwen3 import rotate_half as _rotate_half +from transformers.trainer_pt_utils import LabelSmoother +from transformers.utils import ModelOutput + +from ..dflash.conversion import DFlashDMRegistry +from ..dflash.dflash_model import DFlashModel +from .modeling_fakebase import _BASE_MODEL_PATHS, _EMBED_TOKENS_PATHS, _LM_HEAD_PATHS + +logger = logging.getLogger(__name__) + +__all__ = ["HFDFlashModel"] + + +def build_target_layer_ids(num_target_layers, num_draft_layers): + """Select layers uniformly from the target model for feature extraction.""" + if num_target_layers < num_draft_layers: + raise ValueError( + f"num_target_layers ({num_target_layers}) must be >= num_draft_layers ({num_draft_layers})" + ) + if num_draft_layers == 1: + return [num_target_layers // 2] + start = min(1, num_target_layers - 1) + end = max(start, num_target_layers - 3) + span = end - start + return [round(start + (i * span) / (num_draft_layers - 1)) for i in range(num_draft_layers)] + + +def apply_rotary_pos_emb(q, k, cos, sin): + """Apply RoPE. Q uses last q_len positions, K uses all positions.""" + cos = cos.unsqueeze(1) # [B, 1, seq, dim] + sin = sin.unsqueeze(1) + q_len = q.size(2) + q_embed = (q * cos[:, :, -q_len:, :]) + (_rotate_half(q) * sin[:, :, -q_len:, :]) + k_embed = (k * cos) + (_rotate_half(k) * sin) + return q_embed, k_embed + + +class DFlashAttention(nn.Module): + """Attention with KV injection, using HF's attention dispatch.""" + + def __init__(self, config, layer_idx): + """Initialize DFlash attention with KV injection projections and QK-norm.""" + super().__init__() + self.config = config + self.layer_idx = layer_idx + self.head_dim = getattr( + config, "head_dim", config.hidden_size // config.num_attention_heads + ) + self.num_heads = config.num_attention_heads + self.num_kv_heads = config.num_key_value_heads + self.num_key_value_groups = self.num_heads // self.num_kv_heads + self.scaling = self.head_dim**-0.5 + self.attention_dropout = getattr(config, "attention_dropout", 0.0) + self.is_causal = False + + attn_bias = getattr(config, "attention_bias", False) + self.q_proj = nn.Linear(config.hidden_size, self.num_heads * self.head_dim, bias=attn_bias) + self.k_proj = nn.Linear( + config.hidden_size, self.num_kv_heads * self.head_dim, bias=attn_bias + ) + self.v_proj = nn.Linear( + config.hidden_size, self.num_kv_heads * self.head_dim, bias=attn_bias + ) + self.o_proj = nn.Linear(self.num_heads * self.head_dim, config.hidden_size, bias=attn_bias) + + self.q_norm = _NORM_CLS(self.head_dim, eps=config.rms_norm_eps) + self.k_norm = _NORM_CLS(self.head_dim, eps=config.rms_norm_eps) + + # Resolve HF attention function + self._attn_fn = None + # Qwen3 uses sliding window attention on some layers (config.layer_types) + if hasattr(config, "layer_types") and hasattr(config, "sliding_window"): + is_sliding = config.layer_types[layer_idx] == "sliding_attention" + self.sliding_window = config.sliding_window if is_sliding else None + else: + self.sliding_window = None + + def _get_attn_fn(self): + """Lazily resolve the HF attention function (default: sdpa).""" + if self._attn_fn is not None: + return self._attn_fn + impl = self.config._attn_implementation # default set in dflash/default_config.py + self._attn_fn = ALL_ATTENTION_FUNCTIONS.get(impl, ALL_ATTENTION_FUNCTIONS["sdpa"]) + return self._attn_fn + + def forward(self, hidden_states, target_hidden, position_embeddings, attention_mask=None): + """Forward with KV injection. + + Q is projected from the noise block (draft token embeddings: [anchor, mask, mask, ...]). + K and V are projected from the concatenation of target hidden states (context from the + base model) and noise block, so the draft can attend to both context and its own block. + """ + bsz, q_len, _ = hidden_states.shape + ctx_len = target_hidden.shape[1] + + # Q from noise block only (the draft tokens being predicted), with QK-norm + q = self.q_proj(hidden_states).view(bsz, q_len, -1, self.head_dim) + q = self.q_norm(q).transpose(1, 2) + + # K from context + noise, with QK-norm + k_ctx = self.k_proj(target_hidden) + k_noise = self.k_proj(hidden_states) + k = torch.cat([k_ctx, k_noise], dim=1).view(bsz, ctx_len + q_len, -1, self.head_dim) + k = self.k_norm(k).transpose(1, 2) + + # V from context + noise (no norm) + v_ctx = self.v_proj(target_hidden) + v_noise = self.v_proj(hidden_states) + v = ( + torch.cat([v_ctx, v_noise], dim=1) + .view(bsz, ctx_len + q_len, -1, self.head_dim) + .transpose(1, 2) + ) + + # RoPE + cos, sin = position_embeddings + q, k = apply_rotary_pos_emb(q, k, cos, sin) + + # Use HF's attention dispatch (handles GQA internally) + attn_fn = self._get_attn_fn() + attn_output, _ = attn_fn( + self, + q, + k, + v, + attention_mask, + dropout=0.0 if not self.training else self.attention_dropout, + scaling=self.scaling, + sliding_window=self.sliding_window, + ) + attn_output = attn_output.reshape(bsz, q_len, -1) + return self.o_proj(attn_output) + + +class DFlashDecoderLayer(nn.Module): + """Draft decoder layer with KV injection.""" + + def __init__(self, config, layer_idx): + """Initialize decoder layer with attention, MLP, and layer norms.""" + super().__init__() + self.self_attn = DFlashAttention(config, layer_idx) + self.mlp = _MLP_CLS(config) + self.input_layernorm = _NORM_CLS(config.hidden_size, eps=config.rms_norm_eps) + self.post_attention_layernorm = _NORM_CLS(config.hidden_size, eps=config.rms_norm_eps) + + def forward(self, hidden_states, target_hidden, position_embeddings, attention_mask=None): + """Forward pass with residual connections.""" + residual = hidden_states + hidden_states = self.input_layernorm(hidden_states) + hidden_states = self.self_attn( + hidden_states, target_hidden, position_embeddings, attention_mask + ) + hidden_states = residual + hidden_states + + residual = hidden_states + hidden_states = self.post_attention_layernorm(hidden_states) + hidden_states = self.mlp(hidden_states) + hidden_states = residual + hidden_states + return hidden_states + + +class DFlashModule(nn.Module): + """DFlash draft module using Qwen3 components (MLP, RMSNorm, RotaryEmbedding).""" + + def __init__(self, config): + """Initialize DFlash module with feature fusion, decoder layers, and rotary embeddings.""" + super().__init__() + self.config = config + self.block_size = config.block_size + + # Feature fusion + num_fused_layers = len(config.target_layer_ids) + self.fc = nn.Linear(num_fused_layers * config.hidden_size, config.hidden_size, bias=False) + self.hidden_norm = _NORM_CLS(config.hidden_size, eps=config.rms_norm_eps) + + # Decoder layers + self.layers = nn.ModuleList( + [DFlashDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)] + ) + self.norm = _NORM_CLS(config.hidden_size, eps=config.rms_norm_eps) + self._rotary_config = config # Used by _maybe_init_rotary_emb + + # Explicit weight init is needed because DFlashModule is instantiated via + # mtsp.convert() AFTER the base model's post_init() has already run, so HF's + # automatic _init_weights walk doesn't reach these new layers. + self._init_weights(config) + + def _maybe_init_rotary_emb(self, device=None): + """Lazily initialize rotary embeddings on first forward call. + + Same pattern as EAGLE3's _maybe_init_rope. Avoids creating rotary_emb + during __init__ (which runs on meta device during from_pretrained), + preventing the meta-tensor inv_freq issue on checkpoint resume. + """ + if not hasattr(self, "rotary_emb"): + self.rotary_emb = _ROTARY_CLS(config=self._rotary_config, device=device) + + def _init_weights(self, config): + """Initialize weights matching HF PreTrainedModel._init_weights.""" + std = getattr(config, "initializer_range", 0.02) + for module in self.modules(): + if isinstance(module, nn.Linear): + nn.init.normal_(module.weight, mean=0.0, std=std) + if module.bias is not None: + nn.init.zeros_(module.bias) + + def forward(self, noise_embedding, target_hidden, position_ids, attention_mask=None): + """Forward with feature fusion, KV injection, and position embeddings.""" + hidden_states = noise_embedding + target_hidden = self.hidden_norm(self.fc(target_hidden)) + self._maybe_init_rotary_emb(device=hidden_states.device) + position_embeddings = self.rotary_emb(hidden_states, position_ids) + + for layer in self.layers: + hidden_states = layer(hidden_states, target_hidden, position_embeddings, attention_mask) + + return self.norm(hidden_states) + + +@DFlashDMRegistry.register({PreTrainedModel: "hf.PreTrainedModel"}) +class HFDFlashModel(DFlashModel): + """DFlash Model for HuggingFace transformers.""" + + @property + def _base_model(self): + return self.get_submodule(self.base_model_path) + + @property + def _base_model_embeddings(self): + return self.get_submodule(self.base_model_embeddings_path) + + @property + def _base_model_lm_head(self): + return self.get_submodule(self.base_model_lm_head_path) + + @property + def _base_llm_config(self): + return ( + getattr(self.config, "text_config", None) + or getattr(self.config, "llm_config", None) + or self.config + ) + + def _find_base_model_parts(self): + """Locate base model submodules (backbone, embeddings, lm_head) by probing known paths. + + Reuses the shared path constants from modeling_fakebase (same as EAGLE). + """ + for name, paths in { + "base_model_path": _BASE_MODEL_PATHS, + "base_model_embeddings_path": _EMBED_TOKENS_PATHS, + "base_model_lm_head_path": _LM_HEAD_PATHS, + }.items(): + for path in paths: + try: + submodule = self.get_submodule(path) + assert isinstance(submodule, torch.nn.Module) + setattr(self, name, path) + break + except Exception: + continue + else: + raise ValueError(f"Part {name} not found in model") + + def modify(self, config): + """Initialize DFlash draft module.""" + super().modify(config) + + base_config = self._base_llm_config + # Use Qwen3Config (not generic PretrainedConfig) so rope_parameters is + # auto-populated from rope_theta. DFlash draft uses Qwen3 components. + self.dflash_config = _Qwen3Config(**config.dflash_architecture_config) + + # hidden_size and vocab_size MUST match the base model. + self.dflash_config.hidden_size = base_config.hidden_size + self.dflash_config.vocab_size = base_config.vocab_size + + # Inherit architecture settings from base model when not specified by user. + # Static defaults (hidden_act, attention_bias, etc.) are in dflash/default_config.py. + # NOTE: rope_scaling is intentionally excluded. DFlash draft uses Qwen3 + # RotaryEmbedding which only supports standard RoPE. Inheriting M-RoPE + # config from multimodal models (e.g. Qwen3.5) would be incorrect. + _base_model_attrs = [ + "max_position_embeddings", + "intermediate_size", + "num_attention_heads", + "num_key_value_heads", + "rope_theta", + "rope_type", + "rope_interleaved", + "rms_norm_eps", + ] + for attr in _base_model_attrs: + if not hasattr(self.dflash_config, attr) or getattr(self.dflash_config, attr) is None: + if hasattr(base_config, attr): + setattr(self.dflash_config, attr, getattr(base_config, attr)) + + self.dflash_config.head_dim = getattr( + self.dflash_config, + "head_dim", + self.dflash_config.hidden_size // self.dflash_config.num_attention_heads, + ) + self.dflash_config.block_size = self.dflash_block_size + + # Target layer IDs + num_target_layers = base_config.num_hidden_layers + num_draft_layers = self.dflash_config.num_hidden_layers + self.target_layer_ids = build_target_layer_ids(num_target_layers, num_draft_layers) + self.dflash_config.target_layer_ids = self.target_layer_ids + + # mask_token_id: set in DFlashConfig (or auto-detected by main.py from tokenizer) + mask_id = config.dflash_mask_token_id + if mask_id is None: + raise ValueError( + "dflash_mask_token_id is required. Set it in the config YAML " + "(dflash.dflash_mask_token_id=TOKEN_ID) or let main.py auto-detect " + "from tokenizer.mask_token_id." + ) + self.mask_token_id = mask_id + logger.info("DFlash mask_token_id: %s", self.mask_token_id) + + # Freeze base model + if self.dflash_freeze_base_model: + for param in self.parameters(): + param.requires_grad = False + + self._find_base_model_parts() + + self.dflash_module = DFlashModule(self.dflash_config) + # Match base model dtype/device. Skip if base is on meta (during from_pretrained + # restore — the model will be moved to the correct device after weight loading). + base_device = next(self._base_model.layers[-1].parameters()).device + if base_device.type != "meta": + self.dflash_module.to(self._base_model.dtype).to(base_device) + + self.is_quantized = False + self._num_anchors = self.dflash_num_anchors + + def get_exporter(self): + """Get the exporter for the DFlash draft model.""" + from modelopt.torch.export.plugins.hf_spec_export import DFlashExporter + + return DFlashExporter(self) + + def _sample_anchor_positions(self, seq_len, loss_mask, device): + """Randomly sample anchor positions per sample. + + Returns (anchor_positions [B, N], block_keep_mask [B, N]). + + TODO: Fix the random seed per epoch (change between epochs) so that anchor + positions are deterministic within an epoch. This would allow caching the derived + masks and position IDs across steps while preserving the same data augmentation + effect. Currently, anchors are re-sampled every forward pass. + """ + bs = self.dflash_block_size + bsz = loss_mask.shape[0] + max_anchor = max(seq_len - bs, 0) + num_anchors = getattr(self, "_num_anchors", 512) + + valid = loss_mask[:, : max_anchor + 1] > 0.5 + valid_counts = valid.sum(dim=1) + max_n = min(num_anchors, int(valid_counts.max().item()) - 1) + + if max_n <= 0: + # No valid anchors — return empty + anchors = torch.zeros(bsz, 1, dtype=torch.long, device=device) + keep = torch.zeros(bsz, 1, dtype=torch.bool, device=device) + return anchors, keep + + indices = torch.arange(max_anchor + 1, device=device).unsqueeze(0).expand(bsz, -1) + masked_indices = torch.where(valid, indices, torch.tensor(seq_len + 1, device=device)) + + random_vals = torch.rand(bsz, max_anchor + 1, device=device) + random_vals = torch.where(valid, random_vals, torch.tensor(2.0, device=device)) + + _, sorted_idx = random_vals.sort(dim=1) + gathered = torch.gather(masked_indices, 1, sorted_idx) + anchors = gathered[:, :max_n].sort(dim=1).values + + keep = torch.arange(max_n, device=device).unsqueeze(0) < valid_counts.unsqueeze(1).clamp( + max=max_n + ) + anchors = torch.where(keep, anchors, torch.tensor(0, dtype=torch.long, device=device)) + return anchors, keep + + def _build_noise_embedding(self, input_ids, anchor_positions, block_keep_mask, n_blocks): + """Build noise embeddings: anchor token at block start, mask_token elsewhere.""" + bsz, seq_len = input_ids.shape + block_size = self.dflash_block_size + device = input_ids.device + + noise_ids = torch.full( + (bsz, n_blocks * block_size), self.mask_token_id, dtype=torch.long, device=device + ) + block_starts = torch.arange(n_blocks, device=device) * block_size + block_starts_exp = block_starts.unsqueeze(0).expand(bsz, -1) + valid_anchors = anchor_positions.clamp(0, seq_len - 1) + anchor_tokens = torch.gather(input_ids, 1, valid_anchors) + batch_idx = torch.arange(bsz, device=device).unsqueeze(1).expand(bsz, n_blocks) + noise_ids[batch_idx, block_starts_exp] = torch.where( + block_keep_mask, + anchor_tokens, + torch.tensor(self.mask_token_id, dtype=torch.long, device=device), + ) + return self._base_model_embeddings(noise_ids) + + def _build_position_ids(self, seq_len, anchor_positions, device): + """Build position IDs: context [0..S-1], draft blocks [anchor+0..anchor+B-1].""" + bsz = anchor_positions.shape[0] + block_size = self.dflash_block_size + + ctx_pos = torch.arange(seq_len, device=device).unsqueeze(0).expand(bsz, -1) + offsets = torch.arange(block_size, device=device).view(1, 1, -1) + draft_pos = (anchor_positions.unsqueeze(-1) + offsets).view(bsz, -1) + return torch.cat([ctx_pos, draft_pos], dim=1) + + def _build_draft_attention_mask( + self, seq_len, anchor_positions, block_keep_mask, n_blocks, dtype, device + ): + """Build SDPA attention mask: context (causal) + draft (bidirectional within block).""" + bsz = anchor_positions.shape[0] + block_size = self.dflash_block_size + q_len = n_blocks * block_size + kv_len = seq_len + q_len + + q_indices = torch.arange(q_len, device=device).view(1, 1, -1, 1) + kv_indices = torch.arange(kv_len, device=device).view(1, 1, 1, -1) + q_block_ids = q_indices // block_size + + anchor_exp = anchor_positions.view(bsz, 1, n_blocks, 1).repeat_interleave(block_size, dim=2) + + # Context: kv < S and kv < anchor + mask_ctx = (kv_indices < seq_len) & (kv_indices < anchor_exp) + # Draft: kv >= S and same block + is_draft = kv_indices >= seq_len + kv_block_ids = (kv_indices - seq_len) // block_size + mask_draft = is_draft & (q_block_ids == kv_block_ids) + # Valid block + valid_block = block_keep_mask.view(bsz, 1, n_blocks, 1).repeat_interleave(block_size, dim=2) + + final_mask = (mask_ctx | mask_draft) & valid_block # [B, 1, Q, KV] + + # Convert bool mask to float additive mask for SDPA + attn_mask = torch.zeros(bsz, 1, q_len, kv_len, device=device, dtype=dtype) + attn_mask.masked_fill_(~final_mask, torch.finfo(dtype).min) + return attn_mask + + def _compute_loss( + self, logits, input_ids, anchor_positions, block_keep_mask, loss_mask, base_logits=None + ): + """Compute weighted cross-entropy (or KD) loss and accuracy. + + Args: + logits: Draft model output [B, N*block_size, vocab]. + input_ids: Original input token IDs [B, seq_len]. + anchor_positions: Anchor positions per block [B, N]. + block_keep_mask: Valid block mask [B, N]. + loss_mask: Token-level loss mask [B, seq_len]. + base_logits: Base model logits for KD loss [B, seq_len, vocab], or None for CE. + + Returns: + (loss, accuracy) tuple. + """ + bsz, seq_len = input_ids.shape + block_size = self.dflash_block_size + n_blocks = anchor_positions.shape[1] + device = input_ids.device + + label_offsets = torch.arange(0, block_size, device=device).view(1, 1, -1) + label_indices = anchor_positions.unsqueeze(-1) + label_offsets + valid_label = label_indices < seq_len + safe_label_indices = label_indices.clamp(max=seq_len - 1) + + target_ids = torch.gather( + input_ids.unsqueeze(1).expand(-1, n_blocks, -1), 2, safe_label_indices + ) + + # Weight mask: valid block * in bounds * exclude anchor (pos 0) * loss_mask + weight_mask = block_keep_mask.unsqueeze(-1).expand(-1, -1, block_size).float() + weight_mask = weight_mask * valid_label.float() + pos_in_block = torch.arange(block_size, device=device).view(1, 1, -1) + weight_mask = weight_mask * (pos_in_block > 0).float() + + orig_loss_mask = torch.gather( + loss_mask.unsqueeze(1).expand(-1, n_blocks, -1), 2, safe_label_indices + ) + weight_mask = weight_mask * orig_loss_mask + + binary_eval_mask = weight_mask.view(-1) + + # Optional loss decay + if self.dflash_loss_decay_factor > 0: + k = torch.arange(block_size, device=device).view(1, 1, -1) + decay = torch.exp(-(k - 1).clamp(min=0).float() / self.dflash_loss_decay_factor) + weight_mask = weight_mask * decay + + flat_logits = logits.view(-1, logits.size(-1)) + flat_targets = target_ids.view(-1) + flat_weights = weight_mask.view(-1) + valid_count = flat_weights.sum() + 1e-6 + + if valid_count > 1.0: + if base_logits is not None: + # KD loss: teacher logits for token anchor+k are at position anchor+k-1 + teacher_indices = (safe_label_indices - 1).clamp(min=0) + teacher_logits = torch.gather( + base_logits.unsqueeze(1).expand(-1, n_blocks, -1, -1), + 2, + teacher_indices.unsqueeze(-1).expand(-1, -1, -1, base_logits.size(-1)), + ) + flat_teacher = teacher_logits.reshape(-1, base_logits.size(-1)).detach() + target_soft = torch.softmax(flat_teacher, dim=-1) + draft_logsoft = torch.log_softmax(flat_logits, dim=-1) + kd_loss = -(target_soft * draft_logsoft).sum(dim=-1) + loss = (kd_loss * flat_weights).sum() / valid_count + else: + loss_per_token = F.cross_entropy(flat_logits, flat_targets, reduction="none") + loss = (loss_per_token * flat_weights).sum() / valid_count + + with torch.no_grad(): + preds = flat_logits.argmax(dim=-1) + correct = (preds == flat_targets) & (binary_eval_mask > 0.5) + accuracy = correct.sum().float() / (binary_eval_mask.sum() + 1e-6) + accuracy = accuracy.item() + else: + loss = flat_logits.sum() * 0.0 + accuracy = 0.0 + + return loss, accuracy + + def forward( + self, + input_ids=None, + attention_mask=None, + position_ids=None, + past_key_values=None, + inputs_embeds=None, + labels=None, + use_cache=None, + output_attentions=None, + output_hidden_states=None, + cache_position=None, + **kwargs, + ): + """Training forward with random anchor sampling. + + - Random anchor sampling instead of uniform block division + - Bidirectional intra-block attention (no causal constraint) + - Context sees strictly before anchor position + - Label alignment: position k predicts token at anchor+k + - Optional loss decay weighting + """ + if not self.training: + # Don't pass labels to base model — DFlash uses unshifted labels + # which are incompatible with the base model's shifted loss. + return super().forward( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + cache_position=cache_position, + **kwargs, + ) + + bsz, seq_len = input_ids.shape + block_size = self.dflash_block_size + device = input_ids.device + + if seq_len % block_size != 0: + raise ValueError( + f"seq_len ({seq_len}) must be divisible by block_size ({block_size}). " + f"Adjust training_seq_len or use padding." + ) + + # 1. Run base model → hidden states + # TODO: For co-training the base model, remove no_grad and eval() switch. + with torch.no_grad(): + base_outputs = super().forward( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + ) + + offset = 1 + selected = [base_outputs.hidden_states[lid + offset] for lid in self.target_layer_ids] + target_hidden = torch.cat(selected, dim=-1) # [B, seq, num_layers * H] + + # 2. Build loss mask. + # When labels are provided (answer_only_loss), they already encode both + # assistant masking and padding (-100 for both). When labels are not + # provided, fall back to attention_mask for padding only. + if labels is not None: + loss_mask = (labels != LabelSmoother.ignore_index).float() + elif attention_mask is not None: + loss_mask = attention_mask.float() + else: + loss_mask = torch.ones(bsz, seq_len, device=device) + + # 3. Random anchor sampling + anchor_positions, block_keep_mask = self._sample_anchor_positions( + seq_len, loss_mask, device + ) + n_blocks = anchor_positions.shape[1] + + if n_blocks == 0 or not block_keep_mask.any(): + # Zero loss that still flows through dflash_module for DDP gradient sync + dummy = self.dflash_module.fc.weight.sum() * 0.0 + return ModelOutput(loss=dummy, logits=base_outputs.logits, train_acc=[[0.0]]) + + # 4. Build draft inputs + noise_embedding = self._build_noise_embedding( + input_ids, anchor_positions, block_keep_mask, n_blocks + ) + full_pos = self._build_position_ids(seq_len, anchor_positions, device) + attn_mask = self._build_draft_attention_mask( + seq_len, anchor_positions, block_keep_mask, n_blocks, target_hidden.dtype, device + ) + + # 5. Draft forward + hidden = self.dflash_module( + noise_embedding=noise_embedding, + target_hidden=target_hidden, + position_ids=full_pos, + attention_mask=attn_mask, + ) + + # 6. Compute loss and accuracy + logits = self._base_model_lm_head(hidden) + loss, accuracy = self._compute_loss( + logits, + input_ids, + anchor_positions, + block_keep_mask, + loss_mask, + base_outputs.logits if self.dflash_self_logit_distillation else None, + ) + + return ModelOutput( + loss=loss, + logits=base_outputs.logits, + train_acc=[[accuracy]], + ) + + @torch.no_grad() + def pseudo_speculative_generate(self, input_ids, steps=1): + """Generate draft tokens using one DFlash block for AR validation. + + This method implements a single speculative decoding step: + + 1. **Base model forward**: Run the full target model on ``input_ids`` to get: + - ``base_token``: greedy next token (argmax of last position logits) + - ``hidden_states``: intermediate hidden states from target layers + + 2. **Extract target hidden states**: Concatenate hidden states from + ``target_layer_ids`` (e.g., layers [1, 9, 17, 25, 33] for 5-layer draft). + Shape: ``[B, seq_len, num_layers * hidden_size]``. + + 3. **Build block input**: Create a block of ``block_size`` tokens where: + - Position 0 = ``base_token`` (the anchor/known token) + - Positions 1..block_size-1 = ``mask_token_id`` (unknown, to be predicted) + Embed this block via the base model's embedding layer. + + 4. **Position IDs**: Context positions ``[0..seq_len-1]`` followed by block + positions ``[seq_len..seq_len+block_size-1]``. The draft model's attention + uses RoPE on these positions so Q (block only) attends to K (context + block) + with correct relative position encoding. + + 5. **Draft forward**: Run ``DFlashModule`` with: + - ``noise_embedding``: embedded block tokens + - ``target_hidden``: extracted hidden states from step 2 + - ``position_ids``: context + block positions + - ``attention_mask=None``: no mask at inference (all positions attend freely) + The draft model's KV injection concatenates projected target_hidden as K/V + with the block's own K/V, enabling the draft to "see" the target's context. + + 6. **Decode**: Apply ``lm_head`` to draft hidden states at positions 1..block_size-1 + (skip position 0 which is the known anchor). Argmax gives draft tokens. + + 7. **Return**: ``(base_token, draft_tokens[:steps])`` — base token is always + returned; draft tokens are truncated to ``steps`` (default: block_size-1). + + Note: + This method re-runs the full target model from scratch on each call + (no KV cache). For AR validation, it is called repeatedly with growing + ``input_ids`` by ``AcceptanceRateValidation.validate()``. The ``steps`` + parameter should be set to ``block_size - 1`` for full block evaluation. + + Args: + input_ids: Input token IDs [B, seq_len]. + steps: Number of draft tokens to return (capped at block_size-1). + + Returns: + base_token: Next token from base model [B, 1]. + draft_tokens: Draft tokens [B, min(steps, block_size-1)] or None if steps < 1. + """ + # Call the base model's inner model directly (avoids DynamicModule dispatch) + model_output = self._base_model( + input_ids=input_ids, + output_hidden_states=True, + ) + # Compute logits via lm_head + base_logits = self._base_model_lm_head(model_output.last_hidden_state) + # Build output with hidden_states + base_outputs = ModelOutput( + logits=base_logits, + hidden_states=model_output.hidden_states, + ) + base_logits = base_outputs.logits + base_token = base_logits[:, -1:, :].argmax(dim=-1).to(input_ids.device) + + if steps < 1: + return base_token, None + + # Extract target hidden states (raw, before FC projection) + hid_offset = 1 + selected = [base_outputs.hidden_states[lid + hid_offset] for lid in self.target_layer_ids] + target_hidden = torch.cat(selected, dim=-1) + + block_size = self.dflash_block_size + bsz = input_ids.shape[0] + device = input_ids.device + + # Block: first token is base_token (anchor), rest are mask + block_ids = torch.full( + (bsz, block_size), self.mask_token_id, dtype=torch.long, device=device + ) + block_ids[:, 0] = base_token.squeeze(-1) + noise_embedding = self._base_model_embeddings(block_ids) + + # Position IDs: training uses [0..L-1, 0..L-1] where noise positions + # mirror context positions. At inference, block predicts tokens at + # seq_len..seq_len+B-1, so noise positions continue from ctx_len. + ctx_len = target_hidden.shape[1] + ctx_positions = torch.arange(ctx_len, device=device) + block_positions = torch.arange(ctx_len, ctx_len + block_size, device=device) + pos_ids = torch.cat([ctx_positions, block_positions]).unsqueeze(0).expand(bsz, -1) + + # No attention mask at inference + # which uses KV cache with no mask. All positions attend freely to + # context and each other within the block. + + # Draft forward + draft_hidden = self.dflash_module( + noise_embedding=noise_embedding, + target_hidden=target_hidden, + position_ids=pos_ids, + attention_mask=None, + ) + + # Logits on positions 1..block_size-1 (skip anchor at position 0) + draft_logits = self._base_model_lm_head(draft_hidden[:, 1:, :]) + draft_tokens = draft_logits.argmax(dim=-1) # [B, block_size-1] + + # Return up to `steps` tokens + num_tokens = min(steps, block_size - 1) + return base_token, draft_tokens[:, :num_tokens] diff --git a/modelopt/torch/speculative/utils.py b/modelopt/torch/speculative/utils.py index 7bc6e2be0a..93871f6044 100644 --- a/modelopt/torch/speculative/utils.py +++ b/modelopt/torch/speculative/utils.py @@ -376,6 +376,86 @@ def validate( return ground_truth, ar + def validate_online( + self, + osl, + prompt=None, + input_ids=None, + steps=1, + ): + """Validate AR with online (context-dependent) ground truth. + + Instead of pre-computing a fixed ground truth, this method verifies + draft tokens against the target model's response to the current + sequence (including previously accepted draft tokens). This matches + the actual speculative decoding verification loop. + + Args: + osl: output sequence length + prompt: text prompt (alternative to input_ids) + input_ids: tokenized input + steps: number of draft tokens per step + """ + if input_ids is None: + input_ids = self.tokenize(prompt) + + if input_ids.shape[0] != 1: + raise ValueError("validate_online only supports batch_size=1") + + isl = input_ids.shape[1] + max_len = isl + osl + total_accepted = 0 + cnt = 0 + + while input_ids.shape[1] < max_len: + cnt += 1 + + # Generate base token + draft tokens + input_id, draft_tokens = self.model.pseudo_speculative_generate(input_ids, steps=steps) + draft_tokens = self.check_data_consistency_across_ranks(draft_tokens) + input_id = self.check_data_consistency_across_ranks(input_id) + + # Append base token + input_ids = torch.cat((input_ids, input_id), dim=-1) + + if draft_tokens is None or input_ids.shape[1] >= max_len: + total_accepted += 1 # base token + continue + + # Build candidate sequence with draft tokens appended + candidate = torch.cat((input_ids, draft_tokens), dim=-1) + + # Get target model's response to the candidate sequence + with torch.no_grad(): + target_output = self.model._base_model(candidate) + target_logits = self.model._base_model_lm_head(target_output.last_hidden_state) + # posterior[i] = target's prediction given candidate[:i+1] + # For positions where we placed draft tokens, compare + # target's prediction at position i-1 with draft token at i + posterior = target_logits.argmax(dim=-1) + + # Check acceptance: compare draft[i] with posterior at input_ids_len-1+i + accepted = 0 + pos = input_ids.shape[1] - 1 # position of base token in candidate + for i in range(draft_tokens.shape[-1]): + if pos + i >= candidate.shape[1] - 1: + break + if posterior[:, pos + i] == draft_tokens[:, i]: + accepted += 1 + input_ids = torch.cat((input_ids, draft_tokens[:, i : i + 1]), dim=-1) + else: + # Rejected — append target's correction token (not counted as accepted) + input_ids = torch.cat((input_ids, posterior[:, pos + i : pos + i + 1]), dim=-1) + break + + if input_ids.shape[1] >= max_len: + break + + total_accepted += 1 + accepted # base token + accepted drafts + + ar = total_accepted / cnt if cnt > 0 else 0.0 + return input_ids, ar + @contextlib.contextmanager def temporary_set_config_value(config, field, value): @@ -512,7 +592,8 @@ def load_vlm_or_llm( return FakeBaseModel.from_source(model_name_or_path, trust_remote_code=trust_remote_code) model_config = transformers.AutoConfig.from_pretrained( - model_name_or_path, trust_remote_code=trust_remote_code + model_name_or_path, + trust_remote_code=trust_remote_code, ) if "vl" in model_config.model_type.lower(): model_cls = transformers.AutoModelForVision2Seq diff --git a/modelopt/torch/utils/plugins/transformers_dataset.py b/modelopt/torch/utils/plugins/transformers_dataset.py index e147ebf2c2..547c0ae06d 100644 --- a/modelopt/torch/utils/plugins/transformers_dataset.py +++ b/modelopt/torch/utils/plugins/transformers_dataset.py @@ -33,26 +33,6 @@ IGNORE_TOKEN_ID = LabelSmoother.ignore_index -def _sharegpt_to_openai_messages(conversations: list[dict]): - """Optionally align sharedgpt format to openai format.""" - role_mapping = { - "user": "user", - "User": "user", - "human": "user", - "assistant": "assistant", - "Assistant": "assistant", - "gpt": "assistant", - "system": "system", - "System": "system", - } - messages = [] - for msg in conversations: - role = role_mapping[msg["role"]] - content = msg["content"] - messages.append({"role": role, "content": content}) - return messages - - class ShardedDataset(torch.utils.data.Dataset): """Subclass of torch.utils.data.Dataset to load data from HuggingFace dataset.""" @@ -127,10 +107,29 @@ def __init__( chat_template: str | None = None, add_generation_prompt: bool = False, answer_only_loss: bool = False, + shift_labels: bool = True, json_key: str = "text", return_labels: bool = False, ): - """Initialize the LanguageDataset.""" + """Initialize the LanguageDataset. + + Args: + tokenizer: HuggingFace tokenizer. + train_len: Maximum sequence length for training. + chat_template: Optional custom chat template override. + add_generation_prompt: Whether to add generation prompt to chat template. + answer_only_loss: If True, mask loss on non-assistant tokens using + ``{% generation %}`` tags in the chat template. + shift_labels: Label alignment mode. + If True (default), labels are shifted by 1 for autoregressive training + (label[i] = input[i+1], used by EAGLE3). The answer_only_loss mask is + also shifted to align with the target tokens. + If False, labels are unshifted for diffusion-style training + (label[i] = input[i], used by DFlash). The answer_only_loss mask is + applied directly without shifting. + json_key: Key for plain text samples (non-chat format). + return_labels: Whether to include labels in the output. + """ if not isinstance(tokenizer, transformers.PreTrainedTokenizerBase): raise ValueError( "The tokenizer must be a transformers.PreTrainedTokenizerBase but got {}".format( @@ -141,8 +140,10 @@ def __init__( self.train_len = train_len self.add_generation_prompt = add_generation_prompt self.answer_only_loss = answer_only_loss + self.shift_labels = shift_labels self.json_key = json_key self.return_labels = return_labels + self._conversations_warned = False if chat_template is not None: self.tokenizer.chat_template = chat_template @@ -153,6 +154,9 @@ def __init__( if self.tokenizer.chat_template is None: raise ValueError("No valid chat template!") + if self.answer_only_loss: + self._verify_generation_tags() + def _post_process_tokenizer(self): if self.tokenizer.pad_token_id is None: print_rank_0("The tokenizer has no pad_token_id, using eos_token_id instead.") @@ -171,6 +175,37 @@ def _post_process_chat_template(self): REMOVE_THINK_CHAT_TEMPLATE, "" ) + def _verify_generation_tags(self): + """Verify the chat template supports answer_only_loss via {% generation %} tags. + + answer_only_loss requires the tokenizer's chat template to include + {% generation %} / {% endgeneration %} tags around assistant content. + These tags tell HuggingFace's apply_chat_template() which tokens are + assistant responses, enabling return_assistant_tokens_mask. + + If the template lacks these tags, this method raises an error with + instructions for the user to provide a compatible template. + + Per-model chat templates with generation tags should be maintained + alongside model recipes (e.g., in modelopt_recipes/) where correctness + can be tested. + """ + template = self.tokenizer.chat_template + if template and ("generation" in template and "endgeneration" in template): + return + + raise ValueError( + "answer_only_loss requires {% generation %} / {% endgeneration %} tags in the " + "chat template, but the current template does not have them.\n\n" + "To fix, provide a chat_template with generation tags:\n" + " 1. Copy your model's chat_template from tokenizer_config.json\n" + " 2. Wrap assistant content with {% generation %} / {% endgeneration %}\n" + " 3. Pass via LanguageDataCollator(chat_template=...) or the training config\n\n" + "See https://huggingface.co/docs/transformers/en/chat_templating" + "#train-on-completions-only for the official HuggingFace guide.\n\n" + "Per-model templates are maintained in modelopt_recipes/ alongside training recipes." + ) + def _process_chat_sample(self, examples: list): tokenized_examples = self.tokenizer.apply_chat_template( examples, @@ -185,7 +220,33 @@ def _process_chat_sample(self, examples: list): if self.return_labels: input_ids = tokenized_examples["input_ids"] labels = input_ids.new_full(input_ids.shape, IGNORE_TOKEN_ID) - labels[..., :-1] = input_ids[..., 1:] + if self.shift_labels: + # Autoregressive: label[i] = input[i+1] + labels[..., :-1] = input_ids[..., 1:] + else: + # Diffusion: label[i] = input[i] + labels[:] = input_ids + if self.answer_only_loss: + if "assistant_masks" in tokenized_examples: + assistant_mask = tokenized_examples["assistant_masks"] + if isinstance(assistant_mask, torch.Tensor) and assistant_mask.any(): + if self.shift_labels: + # Shifted labels: mask based on whether the *target* token + # (input[i+1]) is assistant content. + shifted_mask = assistant_mask[..., 1:] + labels[..., :-1][shifted_mask == 0] = IGNORE_TOKEN_ID + else: + # Unshifted labels: mask based on the input token directly. + labels[assistant_mask == 0] = IGNORE_TOKEN_ID + else: + # All assistant content truncated or no assistant in batch — mask all + labels[:] = IGNORE_TOKEN_ID + else: + raise ValueError( + "answer_only_loss requires {% generation %} tags in the chat " + "template but assistant_masks was not returned by the tokenizer. " + "Ensure _ensure_generation_tags() ran successfully." + ) tokenized_examples["labels"] = labels return tokenized_examples @@ -211,16 +272,31 @@ def __call__(self, examples): batch.append(text) else: messages = example.get("messages", None) - if messages is None: - conversations = example.get("conversations", None) - if conversations is None: - raise ValueError( - "The sample must in either OpenAI messages format or ShareGPT conversations format." + if not messages and example.get("conversations", None): + messages = example["conversations"] + if not self._conversations_warned: + print_rank_0( + "=== DEPRECATION WARNING === 'conversations' field is deprecated. " + "Use 'messages' (OpenAI format) instead." ) - else: - messages = _sharegpt_to_openai_messages(conversations) + self._conversations_warned = True + if not messages: + raise ValueError( + "Sample must have a 'messages' field in OpenAI format " + "(list of {role, content} dicts)." + ) + if not any(m.get("role") == "assistant" for m in messages): + print_rank_0( + "=== WARNING === Skipping sample with no assistant turn in messages." + ) + continue batch.append(messages) + if not batch: + # All samples skipped — create a dummy batch with all-masked labels + # so the training step produces zero loss without crashing DDP + batch = [[{"role": "user", "content": ""}, {"role": "assistant", "content": ""}]] # type: ignore[list-item] + return self._process_chat_sample(batch) @@ -241,6 +317,7 @@ def __init__( self.processor = transformers.AutoProcessor.from_pretrained(processor) self.chat_template = chat_template self.local_image_path = local_image_path + self._conversations_warned = False super().__init__( tokenizer=self.processor.tokenizer, @@ -272,14 +349,19 @@ def __call__(self, examples): for example in examples: messages = example.get("messages", None) - if messages is None: - conversations = example.get("conversations", None) - if conversations is None: - raise ValueError( - "The sample must in either OpenAI messages format or ShareGPT conversations format." + if not messages and example.get("conversations", None): + messages = example["conversations"] + if not self._conversations_warned: + print_rank_0( + "=== DEPRECATION WARNING === 'conversations' field is deprecated. " + "Use 'messages' (OpenAI format) instead." ) - else: - messages = _sharegpt_to_openai_messages(conversations) + self._conversations_warned = True + if messages is None: + raise ValueError( + "Sample must have a 'messages' field in OpenAI format " + "(list of {role, content} dicts)." + ) copy_messages = copy.deepcopy(messages) diff --git a/modelopt_recipes/general/speculative_decoding/dflash.yaml b/modelopt_recipes/general/speculative_decoding/dflash.yaml new file mode 100644 index 0000000000..3d43e0fe1d --- /dev/null +++ b/modelopt_recipes/general/speculative_decoding/dflash.yaml @@ -0,0 +1,60 @@ +# Base config for DFlash training. Override fields via OmegaConf dotlist on the CLI. + +# maps to ModelArguments (main.py) +model: + model_name_or_path: + trust_remote_code: false + use_fake_base_for_offline: false + +# maps to DataArguments (main.py) +data: + data_path: + offline_data_path: + # Jinja chat template with {% generation %} tags for answer_only_loss. + # Required when answer_only_loss=true. Set in per-model launcher YAML. + # Templates are in modelopt_recipes/general/speculative_decoding/chat_templates/ + chat_template: + +# maps to TrainingArguments (main.py) +training: + # --- commonly modified --- + mode: dflash + output_dir: + num_train_epochs: 10 + per_device_train_batch_size: 1 + learning_rate: 6.0e-4 + warmup_steps: 100 + training_seq_len: 4096 + logging_steps: 100 + save_steps: 5000 + cp_size: 1 + dp_shard_size: 1 + disable_tqdm: true + estimate_ar: false + ar_validate_steps: 0 + answer_only_loss: true + + # --- rarely modified --- + do_eval: false + lr_scheduler_type: linear + save_strategy: steps + weight_decay: 0.0 + dataloader_drop_last: true + bf16: true + tf32: true + remove_unused_columns: false + ddp_find_unused_parameters: true + ddp_timeout: 1800 + report_to: tensorboard + +# maps to DFlashConfig (modelopt/torch/speculative/config.py). +dflash: + dflash_block_size: 8 + dflash_num_anchors: 512 + dflash_use_torch_compile: false + dflash_self_logit_distillation: true + dflash_loss_decay_factor: 4.0 + dflash_architecture_config: + num_hidden_layers: 5 + # mask_token_id: auto-detected from model vocab (override for specific models) + # sliding_window and layer_types are inherited from base model config automatically diff --git a/modelopt_recipes/general/speculative_decoding/eagle3.yaml b/modelopt_recipes/general/speculative_decoding/eagle3.yaml index 9dd578a632..a1b7ff7770 100644 --- a/modelopt_recipes/general/speculative_decoding/eagle3.yaml +++ b/modelopt_recipes/general/speculative_decoding/eagle3.yaml @@ -30,6 +30,7 @@ training: disable_tqdm: false estimate_ar: false ar_validate_steps: -1 + answer_only_loss: false # --- rarely modified --- do_eval: false diff --git a/tests/examples/speculative_decoding/conftest.py b/tests/examples/speculative_decoding/conftest.py index 4ea2bc1f29..3b487805be 100644 --- a/tests/examples/speculative_decoding/conftest.py +++ b/tests/examples/speculative_decoding/conftest.py @@ -14,10 +14,9 @@ # limitations under the License. import json +from pathlib import Path import pytest -import yaml -from _test_utils.examples.run_command import run_example_command @pytest.fixture(scope="session") @@ -46,24 +45,11 @@ def tiny_conversations_path(tmp_path_factory): @pytest.fixture(scope="session", autouse=True) -def tiny_daring_anteater_path(tmp_path_factory): - tmp_dir = tmp_path_factory.mktemp("daring_anteater") - output_file = tmp_dir / "train.jsonl" - - config = { - "outputs": [ - { - "filename": str(output_file), - "global_limit": 100, - "sources": [{"name": "daring-anteater", "splits": {"all": 100}}], - } - ] - } - config_path = tmp_dir / "data_config.yaml" - config_path.write_text(yaml.dump(config)) - - run_example_command( - ["python", "make_dataset.py", "-f", str(config_path), "--full-conversations"], "dataset" - ) +def tiny_daring_anteater_path(): + """Return path to synthetic test data in OpenAI messages format. - return output_file + Uses examples/dataset/synthetic_conversations_1k.jsonl (1000 samples, + 900 single-turn + 100 two-turn). Synthesized by Claude (Anthropic), + Apache-2.0 licensed. + """ + return Path(__file__).parents[3] / "examples" / "dataset" / "synthetic_conversations_1k.jsonl" diff --git a/tests/gpu/torch/speculative/plugins/test_hf_dflash.py b/tests/gpu/torch/speculative/plugins/test_hf_dflash.py new file mode 100644 index 0000000000..6777973ce8 --- /dev/null +++ b/tests/gpu/torch/speculative/plugins/test_hf_dflash.py @@ -0,0 +1,196 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""GPU tests for DFlash speculative decoding plugin. + +These tests require a CUDA GPU. CPU-only tests are in tests/unit/. +""" + +from copy import deepcopy + +import pytest +import torch +from _test_utils.torch.transformers_models import get_tiny_llama + +import modelopt.torch.speculative as mtsp +from modelopt.torch.speculative.config import DFLASH_DEFAULT_CFG + +BLOCK_SIZE = 4 +NUM_DRAFT_LAYERS = 2 +SEQ_LEN = 16 # must be multiple of BLOCK_SIZE + + +def _get_dflash_config(block_size=BLOCK_SIZE, num_layers=NUM_DRAFT_LAYERS): + """Create a DFlash config for testing.""" + config = deepcopy(DFLASH_DEFAULT_CFG["config"]) + config["dflash_block_size"] = block_size + config["dflash_use_torch_compile"] = False + config["dflash_mask_token_id"] = 0 + config["dflash_architecture_config"] = { + "num_hidden_layers": num_layers, + } + return config + + +@pytest.fixture +def dflash_model(): + """Create a tiny DFlash model on GPU.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + model = model.cuda() + return model + + +class TestDFlashModuleGPU: + """Test DFlash draft module forward pass on GPU.""" + + def test_dflash_module_forward_shape(self, dflash_model): + """Test that draft module produces correct output shape.""" + model = dflash_model + bsz = 2 + hidden_size = model.config.hidden_size + num_layers = len(model.target_layer_ids) + + dtype = next(model.dflash_module.parameters()).dtype + target_hidden = torch.randn( + bsz, SEQ_LEN, num_layers * hidden_size, device="cuda", dtype=dtype + ) + noise_emb = torch.randn(bsz, SEQ_LEN, hidden_size, device="cuda", dtype=dtype) + pos_ids = ( + torch.cat([torch.arange(SEQ_LEN), torch.arange(SEQ_LEN)]) + .unsqueeze(0) + .expand(bsz, -1) + .cuda() + ) + + output = model.dflash_module( + noise_embedding=noise_emb, + target_hidden=target_hidden, + position_ids=pos_ids, + attention_mask=None, + ) + assert output.shape == (bsz, SEQ_LEN, hidden_size) + + def test_dflash_module_deterministic(self, dflash_model): + """Test that draft module produces identical outputs for same input.""" + model = dflash_model + model.eval() + bsz = 1 + hidden_size = model.config.hidden_size + num_layers = len(model.target_layer_ids) + + dtype = next(model.dflash_module.parameters()).dtype + target_hidden = torch.randn( + bsz, SEQ_LEN, num_layers * hidden_size, device="cuda", dtype=dtype + ) + noise_emb = torch.randn(bsz, SEQ_LEN, hidden_size, device="cuda", dtype=dtype) + pos_ids = torch.cat([torch.arange(SEQ_LEN), torch.arange(SEQ_LEN)]).unsqueeze(0).cuda() + + with torch.no_grad(): + out1 = model.dflash_module( + noise_embedding=noise_emb, + target_hidden=target_hidden, + position_ids=pos_ids, + ) + out2 = model.dflash_module( + noise_embedding=noise_emb, + target_hidden=target_hidden, + position_ids=pos_ids, + ) + assert torch.allclose(out1, out2) + + +class TestDFlashTrainingForwardGPU: + """Test DFlash training forward pass end-to-end on GPU.""" + + @pytest.fixture + def model(self): + """Create a tiny DFlash model in training mode on GPU.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + model = model.cuda() + model.train() + return model + + def test_training_forward_returns_loss(self, model): + """Test that training forward returns a differentiable loss.""" + bsz = 2 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + attention_mask = torch.ones(bsz, SEQ_LEN, dtype=torch.long, device="cuda") + + output = model(input_ids=input_ids, attention_mask=attention_mask) + assert hasattr(output, "loss") + assert output.loss.requires_grad + + def test_training_forward_returns_accuracy(self, model): + """Test that training forward returns train_acc.""" + bsz = 2 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + attention_mask = torch.ones(bsz, SEQ_LEN, dtype=torch.long, device="cuda") + + output = model(input_ids=input_ids, attention_mask=attention_mask) + assert hasattr(output, "train_acc") + + def test_training_forward_with_labels(self, model): + """Test that labels are used for response-only loss masking.""" + bsz = 2 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + attention_mask = torch.ones(bsz, SEQ_LEN, dtype=torch.long, device="cuda") + + # Labels with -100 for first half (masked), real labels for second half + labels = torch.full((bsz, SEQ_LEN), -100, dtype=torch.long, device="cuda") + labels[:, SEQ_LEN // 2 :] = input_ids[:, SEQ_LEN // 2 :] + + output = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels) + assert hasattr(output, "loss") + assert output.loss.requires_grad + + def test_training_forward_all_masked_labels(self, model): + """Test that all-masked labels produce zero loss without crashing.""" + bsz = 2 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + attention_mask = torch.ones(bsz, SEQ_LEN, dtype=torch.long, device="cuda") + labels = torch.full((bsz, SEQ_LEN), -100, dtype=torch.long, device="cuda") + + output = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels) + assert output.loss.item() == 0.0 + + def test_training_backward(self, model): + """Test that gradients flow to dflash_module.""" + bsz = 2 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + attention_mask = torch.ones(bsz, SEQ_LEN, dtype=torch.long, device="cuda") + + output = model(input_ids=input_ids, attention_mask=attention_mask) + output.loss.backward() + + has_grad = False + for name, param in model.dflash_module.named_parameters(): + if param.grad is not None and param.grad.abs().sum() > 0: + has_grad = True + break + assert has_grad, "DFlash module should receive gradients" + + def test_eval_forward_uses_base_model(self, model): + """In eval mode, forward should use base model (not DFlash training).""" + model.eval() + bsz = 1 + input_ids = torch.randint(0, model.config.vocab_size, (bsz, SEQ_LEN), device="cuda") + + with torch.no_grad(): + output = model(input_ids=input_ids) + assert output.logits.shape == (bsz, SEQ_LEN, model.config.vocab_size) diff --git a/tests/gpu_regression/torch/speculative/test_dflash.py b/tests/gpu_regression/torch/speculative/test_dflash.py new file mode 100644 index 0000000000..2e8092d62f --- /dev/null +++ b/tests/gpu_regression/torch/speculative/test_dflash.py @@ -0,0 +1,177 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""DFlash E2E regression tests. + +Tests the full DFlash pipeline using Qwen3-0.6B and the synthetic dataset +(examples/dataset/synthetic_conversations_1k.jsonl). Matches the configuration +in tools/launcher/examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml. + +Convergence baseline (from L40 run): + Step 100 (epoch 0.2): loss=6.59 acc=0.079 + Step 500 (epoch 1.0): loss=1.78 acc=0.525 + Step 1500 (epoch 3.0): loss=1.11 acc=0.595 +""" + +import json +import os + +import pytest +from _test_utils.examples.run_command import MODELOPT_ROOT, run_example_command + +DFLASH_YAML = str( + MODELOPT_ROOT / "modelopt_recipes" / "general" / "speculative_decoding" / "dflash.yaml" +) + +CHAT_TEMPLATE = str( + MODELOPT_ROOT + / "tools" + / "launcher" + / "examples" + / "Qwen" + / "Qwen3-0.6B" + / "chat_template_train.jinja" +) + +SYNTH_DATA = str(MODELOPT_ROOT / "examples" / "dataset" / "synthetic_conversations_1k.jsonl") + +# Match tools/launcher/examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml +_DFLASH_OVERRIDES = [ + f"data.data_path={SYNTH_DATA}", + f"data.chat_template={CHAT_TEMPLATE}", + "training.training_seq_len=512", + "training.per_device_train_batch_size=2", + "training.logging_steps=100", + "training.answer_only_loss=true", + "dflash.dflash_block_size=8", + "dflash.dflash_mask_token_id=151669", + "dflash.dflash_use_torch_compile=False", + "dflash.dflash_architecture_config.num_hidden_layers=2", +] + + +@pytest.fixture(scope="session") +def qwen3_model_name(): + """Qwen3-0.6B model name (downloaded from HF on first use).""" + return "Qwen/Qwen3-0.6B" + + +@pytest.fixture(scope="session") +def dflash_output_dir(tmp_path_factory): + return tmp_path_factory.mktemp("dflash_output") + + +def test_dflash_training(qwen3_model_name, dflash_output_dir): + """Train DFlash on Qwen3-0.6B and validate loss convergence.""" + output_dir = str(dflash_output_dir / "dflash-qwen3-0.6b") + overrides = [ + f"model.model_name_or_path={qwen3_model_name}", + f"training.output_dir={output_dir}", + "training.num_train_epochs=3", + "training.save_steps=500", + *_DFLASH_OVERRIDES, + ] + + run_example_command( + ["./launch_train.sh", "--config", DFLASH_YAML, *overrides], + "speculative_decoding", + ) + + # Verify checkpoint was saved + assert os.path.exists(os.path.join(output_dir, "modelopt_state.pth")) or any( + "checkpoint-" in d + for d in os.listdir(output_dir) + if os.path.isdir(os.path.join(output_dir, d)) + ) + + # Regression: verify loss decreased + trainer_state = os.path.join(output_dir, "trainer_state.json") + assert os.path.exists(trainer_state), "trainer_state.json not found" + with open(trainer_state) as f: + state = json.load(f) + logs = [h for h in state.get("log_history", []) if "loss" in h] + assert len(logs) >= 2, f"Expected at least 2 log entries, got {len(logs)}" + + first_loss = float(logs[0]["loss"]) + final_loss = float(logs[-1]["loss"]) + assert final_loss < first_loss, f"Loss did not decrease: {first_loss:.3f} -> {final_loss:.3f}" + # Sanity: final loss should be reasonable (baseline: ~1.1 on L40) + assert final_loss < 3.0, f"Final loss {final_loss:.3f} too high (expected < 3.0)" + + +def test_dflash_resume(qwen3_model_name, dflash_output_dir): + """Resume DFlash training from checkpoint.""" + output_dir = str(dflash_output_dir / "dflash-qwen3-0.6b") + overrides = [ + f"model.model_name_or_path={qwen3_model_name}", + f"training.output_dir={output_dir}", + "training.num_train_epochs=4", + "training.save_steps=5000", + *_DFLASH_OVERRIDES, + ] + + run_example_command( + ["./launch_train.sh", "--config", DFLASH_YAML, *overrides], + "speculative_decoding", + ) + + +def test_dflash_export(dflash_output_dir): + """Export DFlash checkpoint to deployment format.""" + output_dir = str(dflash_output_dir / "dflash-qwen3-0.6b") + export_dir = str(dflash_output_dir / "dflash-export") + + run_example_command( + [ + "python", + "./scripts/export_hf_checkpoint.py", + "--model_path", + output_dir, + "--export_path", + export_dir, + ], + "speculative_decoding", + ) + + assert os.path.exists(os.path.join(export_dir, "model.safetensors")) + assert os.path.exists(os.path.join(export_dir, "config.json")) + + with open(os.path.join(export_dir, "config.json")) as f: + config = json.load(f) + assert config["architectures"] == ["DFlashDraftModel"] + assert config["model_type"] == "qwen3" + assert "dflash_config" in config + assert "block_size" in config + + +def test_dflash_ar_validate(dflash_output_dir): + """AR validation on trained DFlash checkpoint.""" + output_dir = str(dflash_output_dir / "dflash-qwen3-0.6b") + + run_example_command( + [ + "python", + "./scripts/ar_validate.py", + "--model_path", + output_dir, + "--osl", + "10", + "--num_samples", + "3", + "--steps", + "7", + ], + "speculative_decoding", + ) diff --git a/tests/unit/torch/speculative/plugins/test_hf_dflash.py b/tests/unit/torch/speculative/plugins/test_hf_dflash.py new file mode 100644 index 0000000000..560c571212 --- /dev/null +++ b/tests/unit/torch/speculative/plugins/test_hf_dflash.py @@ -0,0 +1,502 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""CPU unit tests for DFlash speculative decoding plugin. + +GPU-dependent tests (training forward, module forward) are in tests/gpu/. +""" + +import os +from copy import deepcopy +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest +import torch +from _test_utils.torch.transformers_models import ( + get_tiny_llama, + tf_modelopt_state_and_output_tester, +) +from transformers import AutoModelForCausalLM + +import modelopt.torch.opt as mto +import modelopt.torch.speculative as mtsp +from modelopt.torch.speculative.config import DFLASH_DEFAULT_CFG +from modelopt.torch.speculative.plugins.hf_dflash import ( + DFlashModule, + HFDFlashModel, + build_target_layer_ids, +) + +BLOCK_SIZE = 4 +NUM_DRAFT_LAYERS = 2 +SEQ_LEN = 16 # must be multiple of BLOCK_SIZE + + +def _get_dflash_config(block_size=BLOCK_SIZE, num_layers=NUM_DRAFT_LAYERS): + """Create a DFlash config for testing.""" + config = deepcopy(DFLASH_DEFAULT_CFG["config"]) + config["dflash_block_size"] = block_size + config["dflash_use_torch_compile"] = False + config["dflash_mask_token_id"] = 0 # use token 0 as mask for tiny model + config["dflash_architecture_config"] = { + "num_hidden_layers": num_layers, + } + return config + + +class TestDFlashConvert: + """Test DFlash model conversion.""" + + def test_convert_creates_dflash_model(self): + """Test that convert produces an HFDFlashModel.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + assert isinstance(model, HFDFlashModel) + + def test_convert_creates_dflash_module(self): + """Test that convert attaches a DFlashModule.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + assert hasattr(model, "dflash_module") + assert isinstance(model.dflash_module, DFlashModule) + + def test_convert_freezes_base_model(self): + """Test that base model parameters are frozen after convert.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + for name, param in model.named_parameters(): + if "dflash_module" not in name: + assert not param.requires_grad, f"Base param {name} should be frozen" + + def test_convert_dflash_module_trainable(self): + """Test that DFlash module parameters are trainable after convert.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + dflash_params = [(n, p) for n, p in model.named_parameters() if "dflash_module" in n] + assert len(dflash_params) > 0 + for name, param in dflash_params: + assert param.requires_grad, f"DFlash param {name} should be trainable" + + def test_convert_sets_target_layer_ids(self): + """Test that target layer IDs are set correctly.""" + model = get_tiny_llama(num_hidden_layers=8) + config = _get_dflash_config(num_layers=3) + mtsp.convert(model, [("dflash", config)]) + assert hasattr(model, "target_layer_ids") + assert len(model.target_layer_ids) == 3 + for lid in model.target_layer_ids: + assert 0 <= lid < 8 + + def test_convert_sets_mask_token_id(self): + """Test that mask_token_id is set from config.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + assert hasattr(model, "mask_token_id") + assert model.mask_token_id == 0 + + def test_convert_missing_mask_token_id_errors(self): + """Test that missing mask_token_id raises ValueError.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + del config["dflash_mask_token_id"] + with pytest.raises(ValueError, match="dflash_mask_token_id is required"): + mtsp.convert(model, [("dflash", config)]) + + +class TestDFlashSaveRestore: + """Test DFlash model save and restore.""" + + def test_save_and_restore(self, tmp_path): + """Test round-trip save/load preserves modelopt state and outputs.""" + mto.enable_huggingface_checkpointing() + model_ref = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model_ref, [("dflash", config)]) + + model_ref.save_pretrained(tmp_path / "modelopt_model") + assert os.path.exists(tmp_path / "modelopt_model/modelopt_state.pth") + + model_test = AutoModelForCausalLM.from_pretrained(tmp_path / "modelopt_model") + assert isinstance(model_test, HFDFlashModel) + tf_modelopt_state_and_output_tester(model_ref, model_test) + + +class TestDFlashLazyRotaryEmb: + """Test lazy rotary embedding initialization (matching EAGLE3 pattern). + + rotary_emb is not created in __init__ — it's lazily initialized on first + forward call to avoid meta-tensor issues during from_pretrained restore. + """ + + def test_rotary_emb_not_created_in_init(self): + """rotary_emb should not exist after convert (before forward).""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + assert not hasattr(model.dflash_module, "rotary_emb") + + def test_rotary_emb_created_on_forward(self): + """rotary_emb should be created on first forward call.""" + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + + dflash_mod = model.dflash_module + # Call _maybe_init_rotary_emb directly + dflash_mod._maybe_init_rotary_emb(device="cpu") + assert hasattr(dflash_mod, "rotary_emb") + assert not any(b.is_meta for b in dflash_mod.rotary_emb.buffers()) + + +class TestBuildTargetLayerIds: + """Test target layer selection.""" + + def test_single_draft_layer(self): + ids = build_target_layer_ids(32, 1) + assert len(ids) == 1 + assert ids[0] == 16 + + def test_multiple_draft_layers(self): + ids = build_target_layer_ids(36, 5) + assert len(ids) == 5 + assert ids == sorted(ids) + assert all(1 <= lid <= 33 for lid in ids) + + def test_layer_ids_no_duplicates(self): + ids = build_target_layer_ids(32, 5) + assert len(set(ids)) == 5 + + def test_layer_ids_match_zlab(self): + """Test layer IDs match z-lab reference for Qwen3-8B (36 layers, 5 draft).""" + ids = build_target_layer_ids(36, 5) + assert ids == [1, 9, 17, 25, 33] + + +class TestDFlashSlidingWindow: + """Test sliding window attention support.""" + + def test_sliding_window_from_config(self): + """Test DFlashAttention reads sliding_window from config.layer_types.""" + from transformers import PretrainedConfig + + from modelopt.torch.speculative.plugins.hf_dflash import DFlashAttention + + config = PretrainedConfig( + hidden_size=64, + num_attention_heads=4, + num_key_value_heads=4, + head_dim=16, + rms_norm_eps=1e-6, + attention_bias=False, + attention_dropout=0.0, + layer_types=["full_attention", "sliding_attention"], + sliding_window=256, + _attn_implementation="sdpa", + ) + attn_full = DFlashAttention(config, layer_idx=0) + attn_sliding = DFlashAttention(config, layer_idx=1) + assert attn_full.sliding_window is None + assert attn_sliding.sliding_window == 256 + + def test_no_sliding_window_without_config(self): + """Test DFlashAttention defaults to no sliding window.""" + from transformers import PretrainedConfig + + from modelopt.torch.speculative.plugins.hf_dflash import DFlashAttention + + config = PretrainedConfig( + hidden_size=64, + num_attention_heads=4, + num_key_value_heads=4, + head_dim=16, + rms_norm_eps=1e-6, + attention_bias=False, + attention_dropout=0.0, + _attn_implementation="sdpa", + ) + attn = DFlashAttention(config, layer_idx=0) + assert attn.sliding_window is None + + +class TestValidateOnline: + """Test validate_online acceptance counting logic.""" + + def test_all_accepted(self): + """When all draft tokens match posterior, AR = 1 + steps.""" + from modelopt.torch.speculative.utils import AcceptanceRateValidation + + validator = AcceptanceRateValidation.__new__(AcceptanceRateValidation) + validator.check_data_consistency_across_ranks = lambda x: x + + # Mock model: draft produces [10, 20], posterior agrees + mock_model = MagicMock() + # pseudo_speculative_generate returns (base_token, draft_tokens) + call_count = [0] + + def mock_psg(input_ids, steps=1): + call_count[0] += 1 + base = torch.tensor([[100]]) + drafts = torch.tensor([[10, 20]]) + return base, drafts + + mock_model.pseudo_speculative_generate = mock_psg + + # Base model returns logits where argmax matches draft tokens + def mock_base_model(candidate): + # posterior at pos i = candidate[i+1] (perfect prediction) + return SimpleNamespace(last_hidden_state=candidate.unsqueeze(-1).float()) + + def mock_lm_head(hidden): + # One-hot logits: argmax = candidate token at next position + bsz, seq_len, _ = hidden.shape + logits = torch.zeros(bsz, seq_len, 200) + for i in range(seq_len - 1): + token_id = int(hidden[0, i + 1, 0].item()) + if 0 <= token_id < 200: + logits[0, i, token_id] = 1.0 + return logits + + mock_model._base_model = mock_base_model + mock_model._base_model_lm_head = mock_lm_head + validator.model = mock_model + + input_ids = torch.tensor([[1, 2, 3]]) + # osl=3: need 3 new tokens. Step 1: base(1) + draft(2) = 3 tokens → done in 1 step + result_ids, ar = validator.validate_online(osl=3, input_ids=input_ids, steps=2) + assert ar == 3.0 # 1 step, 3 tokens accepted (1 base + 2 drafts) + + def test_all_rejected(self): + """When no draft tokens match, AR = 1 (base token only + correction).""" + from modelopt.torch.speculative.utils import AcceptanceRateValidation + + validator = AcceptanceRateValidation.__new__(AcceptanceRateValidation) + validator.check_data_consistency_across_ranks = lambda x: x + + mock_model = MagicMock() + + def mock_psg(input_ids, steps=1): + base = torch.tensor([[100]]) + drafts = torch.tensor([[10, 20]]) + return base, drafts + + mock_model.pseudo_speculative_generate = mock_psg + + # Base model disagrees with all drafts + def mock_base_model(candidate): + return SimpleNamespace(last_hidden_state=candidate.unsqueeze(-1).float()) + + def mock_lm_head(hidden): + bsz, seq_len, _ = hidden.shape + # All predictions are token 99 (won't match drafts 10, 20) + logits = torch.zeros(bsz, seq_len, 200) + logits[:, :, 99] = 1.0 + return logits + + mock_model._base_model = mock_base_model + mock_model._base_model_lm_head = mock_lm_head + validator.model = mock_model + + input_ids = torch.tensor([[1, 2, 3]]) + # osl=4: each step produces base(1) + correction(1) = 2 tokens, AR = 1 + # (correction token not counted as accepted) + result_ids, ar = validator.validate_online(osl=4, input_ids=input_ids, steps=2) + # 2 steps, each producing 1 base token + 0 accepted drafts = 2 total accepted + # But correction token still advances sequence, so 2 steps produce 4 tokens + assert ar == 1.0 # total_accepted=2, cnt=2 + + +class TestDFlashExporter: + """Test DFlash checkpoint export.""" + + def test_export_creates_files(self, tmp_path): + """Test that export produces model.safetensors and config.json.""" + + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + + exporter = model.get_exporter() + export_dir = tmp_path / "exported" + exporter.export(export_dir) + + assert (export_dir / "model.safetensors").exists() + assert (export_dir / "config.json").exists() + + def test_export_state_dict_has_no_prefix(self, tmp_path): + """Exported weights should not have dflash_module. or model. prefix.""" + from safetensors.torch import load_file + + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + + exporter = model.get_exporter() + export_dir = tmp_path / "exported" + exporter.export(export_dir) + + sd = load_file(str(export_dir / "model.safetensors")) + for key in sd: + assert "dflash_module." not in key, f"Key has prefix: {key}" + assert "model." not in key, f"Key has prefix: {key}" + assert "rotary_emb" not in key, f"Rotary buffer should be excluded: {key}" + + def test_export_config_fields(self, tmp_path): + """Exported config.json should have required DFlash fields.""" + import json + + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + + exporter = model.get_exporter() + export_dir = tmp_path / "exported" + exporter.export(export_dir) + + with open(export_dir / "config.json") as f: + cfg = json.load(f) + + assert cfg["architectures"] == ["DFlashDraftModel"] + assert cfg["block_size"] == BLOCK_SIZE + assert "dflash_config" in cfg + assert "mask_token_id" in cfg["dflash_config"] + assert "target_layer_ids" in cfg["dflash_config"] + assert cfg["num_hidden_layers"] == NUM_DRAFT_LAYERS + assert "hidden_size" in cfg + assert "vocab_size" in cfg + assert "layer_types" in cfg + assert len(cfg["layer_types"]) == NUM_DRAFT_LAYERS + + def test_export_tensor_count(self, tmp_path): + """Exported model should have the right number of tensors.""" + from safetensors.torch import load_file + + model = get_tiny_llama(num_hidden_layers=4) + config = _get_dflash_config() + mtsp.convert(model, [("dflash", config)]) + + exporter = model.get_exporter() + export_dir = tmp_path / "exported" + exporter.export(export_dir) + + sd = load_file(str(export_dir / "model.safetensors")) + # Should have: fc, hidden_norm, norm, + per-layer (q/k/v/o_proj, q/k_norm, + # gate/up/down_proj, input_layernorm, post_attention_layernorm) + assert len(sd) > 0 + assert any("fc.weight" in k for k in sd) + assert any("norm.weight" in k for k in sd) + assert any("layers.0" in k for k in sd) + + +class TestEnsureGenerationTags: + """Test _ensure_generation_tags with a real tokenizer (Qwen3-0.6B from HF).""" + + @pytest.fixture + def qwen3_tokenizer(self): + from transformers import AutoTokenizer + + return AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B") + + @pytest.fixture + def qwen3_chat_template(self): + template_path = ( + Path(__file__).parents[5] + / "tools/launcher/examples/Qwen/Qwen3-8B/chat_template_train.jinja" + ) + return template_path.read_text() + + def test_chatml_think_template_produces_assistant_mask( + self, qwen3_tokenizer, qwen3_chat_template + ): + """Verify generation-tagged chat template produces correct assistant masks.""" + from modelopt.torch.utils.plugins.transformers_dataset import LanguageDataCollator + + collator = LanguageDataCollator( + tokenizer=qwen3_tokenizer, + train_len=128, + return_labels=True, + answer_only_loss=True, + chat_template=qwen3_chat_template, + ) + + # Verify template was replaced with generation-tagged version + assert "generation" in collator.tokenizer.chat_template + + # Tokenize a sample conversation + samples = [ + { + "messages": [ + {"role": "user", "content": "What is 2+2?"}, + {"role": "assistant", "content": "The answer is 4."}, + ] + } + ] + result = collator(samples) + + labels = result["labels"] + input_ids = result["input_ids"] + + # Labels should NOT be all-masked (assistant content should have real labels) + assert (labels != -100).any(), "All labels masked — generation tags not working" + + # Labels should have SOME masked positions (user/system tokens) + assert (labels == -100).any(), "No labels masked — answer_only_loss not working" + + # Decode the non-masked positions to verify they're assistant content + non_masked = input_ids[labels != -100] + decoded = qwen3_tokenizer.decode(non_masked) + assert "The answer is 4" in decoded + + def test_multi_turn_masks_only_assistant(self, qwen3_tokenizer, qwen3_chat_template): + """Verify multi-turn: only assistant turns are unmasked.""" + from modelopt.torch.utils.plugins.transformers_dataset import LanguageDataCollator + + collator = LanguageDataCollator( + tokenizer=qwen3_tokenizer, + train_len=256, + return_labels=True, + answer_only_loss=True, + chat_template=qwen3_chat_template, + ) + + samples = [ + { + "messages": [ + {"role": "system", "content": "You are helpful."}, + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi there!"}, + {"role": "user", "content": "How are you?"}, + {"role": "assistant", "content": "I am fine."}, + ] + } + ] + result = collator(samples) + labels = result["labels"] + input_ids = result["input_ids"] + + non_masked = input_ids[labels != -100] + decoded = qwen3_tokenizer.decode(non_masked) + # Both assistant responses should appear in unmasked tokens + assert "Hi there" in decoded + assert "I am fine" in decoded + # User/system content should NOT appear in unmasked tokens + assert "You are helpful" not in decoded + assert "How are you?" not in decoded diff --git a/tests/unit/torch/speculative/plugins/test_hf_speculative_offline.py b/tests/unit/torch/speculative/plugins/test_hf_speculative_offline.py index 20a4d98340..bff8259137 100644 --- a/tests/unit/torch/speculative/plugins/test_hf_speculative_offline.py +++ b/tests/unit/torch/speculative/plugins/test_hf_speculative_offline.py @@ -54,7 +54,7 @@ assert _spec is not None and _spec.loader is not None _eagle_utils = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_eagle_utils) -make_eagle_supervised_data_module = _eagle_utils.make_eagle_supervised_data_module +make_speculative_data_module = _eagle_utils.make_speculative_data_module # --------------------------------------------------------------------------- @@ -79,7 +79,7 @@ def test_sample_size_positive_truncates(tmp_path): """sample_size > 0 should truncate the dataset to that many samples.""" data_args = _make_data_args(sample_size=3, tmp_path=tmp_path, n_files=5) tokenizer = MagicMock() - module = make_eagle_supervised_data_module(tokenizer, data_args, train_len=8) + module = make_speculative_data_module(tokenizer, data_args, train_len=8) assert len(module["train_dataset"]) == 3 @@ -87,7 +87,7 @@ def test_sample_size_minus_one_uses_all(tmp_path): """sample_size=-1 should use all samples.""" data_args = _make_data_args(sample_size=-1, tmp_path=tmp_path, n_files=5) tokenizer = MagicMock() - module = make_eagle_supervised_data_module(tokenizer, data_args, train_len=8) + module = make_speculative_data_module(tokenizer, data_args, train_len=8) assert len(module["train_dataset"]) == 5 @@ -96,14 +96,14 @@ def test_sample_size_zero_raises(tmp_path): data_args = _make_data_args(sample_size=0, tmp_path=tmp_path, n_files=5) tokenizer = MagicMock() with pytest.raises(ValueError, match="sample_size must be -1"): - make_eagle_supervised_data_module(tokenizer, data_args, train_len=8) + make_speculative_data_module(tokenizer, data_args, train_len=8) def test_sample_size_larger_than_dataset_uses_all(tmp_path): """sample_size > number of files should use all samples without error.""" data_args = _make_data_args(sample_size=100, tmp_path=tmp_path, n_files=5) tokenizer = MagicMock() - module = make_eagle_supervised_data_module(tokenizer, data_args, train_len=8) + module = make_speculative_data_module(tokenizer, data_args, train_len=8) assert len(module["train_dataset"]) == 5 @@ -118,7 +118,7 @@ def test_sample_size_no_pt_files_raises(tmp_path): ) tokenizer = MagicMock() with pytest.raises(ValueError, match="No .pt files found"): - make_eagle_supervised_data_module(tokenizer, data_args, train_len=8) + make_speculative_data_module(tokenizer, data_args, train_len=8) # --------------------------------------------------------------------------- diff --git a/tools/launcher/common/check_regression.py b/tools/launcher/common/check_regression.py new file mode 100644 index 0000000000..17ca7980f5 --- /dev/null +++ b/tools/launcher/common/check_regression.py @@ -0,0 +1,162 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Regression check for training jobs. + +Reads trainer_state.json from a HuggingFace Trainer checkpoint and validates +that final metrics meet specified thresholds. Used by training scripts to +catch regressions in CI. + +Environment variables (all optional — no check if unset): + MAX_FINAL_LOSS: Final loss must be below this value + MIN_FINAL_ACC: Final accuracy must be above this value (any key containing 'acc') + MAX_FINAL_PERPLEXITY: Final perplexity must be below this value + +Usage: + python check_regression.py /path/to/output_dir + + Or from a shell script: + python common/check_regression.py ${OUTPUT_DIR} + +Exit codes: + 0 — all checks pass (or no thresholds set) + 1 — regression detected +""" + +import json +import os +import sys +from glob import glob + + +def find_trainer_state(output_dir): + """Find the latest trainer_state.json in the output directory.""" + # Check checkpoint subdirs first (sorted by step number) + checkpoint_states = sorted(glob(os.path.join(output_dir, "checkpoint-*", "trainer_state.json"))) + if checkpoint_states: + return checkpoint_states[-1] + # Fall back to output_dir itself + direct = os.path.join(output_dir, "trainer_state.json") + if os.path.exists(direct): + return direct + return None + + +def get_final_metrics(trainer_state_path): + """Extract final loss and accuracy from trainer_state.json.""" + with open(trainer_state_path) as f: + state = json.load(f) + + logs = [h for h in state.get("log_history", []) if "loss" in h] + if not logs: + return {} + + last = logs[-1] + metrics = {"loss": float(last["loss"])} + + # Find any accuracy key (train_acc/parallel_0_step_0, eval_accuracy, etc.) + for key, value in last.items(): + if "acc" in key.lower(): + metrics["accuracy"] = float(value) + break + + # Perplexity if available + if "perplexity" in last: + metrics["perplexity"] = float(last["perplexity"]) + + return metrics + + +def check_regression(metrics): + """Check metrics against environment variable thresholds. Returns (passed, messages).""" + checks = [ + ( + "MAX_FINAL_LOSS", + "loss", + lambda val, thresh: val <= thresh, + "loss {val:.3f} > threshold {thresh}", + ), + ( + "MIN_FINAL_ACC", + "accuracy", + lambda val, thresh: val >= thresh, + "acc {val:.3f} < threshold {thresh}", + ), + ( + "MAX_FINAL_PERPLEXITY", + "perplexity", + lambda val, thresh: val <= thresh, + "perplexity {val:.3f} > threshold {thresh}", + ), + ] + + passed = True + messages = [] + + for env_var, metric_key, check_fn, fail_msg in checks: + thresh_str = os.environ.get(env_var) + if thresh_str is None: + continue + thresh = float(thresh_str) + val = metrics.get(metric_key) + if val is None: + messages.append(f"WARNING: {env_var} set but '{metric_key}' not found in metrics") + continue + if check_fn(val, thresh): + messages.append(f"PASS: {metric_key}={val:.3f} (threshold: {env_var}={thresh})") + else: + messages.append(f"REGRESSION: {fail_msg.format(val=val, thresh=thresh)}") + passed = False + + return passed, messages + + +def main(): + """Entry point for regression check CLI.""" + if len(sys.argv) < 2: + print("Usage: python check_regression.py ") + sys.exit(0) + + output_dir = sys.argv[1] + + # Skip if no thresholds set + if not any( + os.environ.get(v) for v in ["MAX_FINAL_LOSS", "MIN_FINAL_ACC", "MAX_FINAL_PERPLEXITY"] + ): + return + + trainer_state = find_trainer_state(output_dir) + if not trainer_state: + print(f"WARNING: No trainer_state.json found in {output_dir}, skipping regression check") + return + + print(f"=== Regression Check ({trainer_state}) ===") + metrics = get_final_metrics(trainer_state) + if not metrics: + print("No training logs found in trainer_state.json") + return + + print(f"Final metrics: {metrics}") + passed, messages = check_regression(metrics) + for msg in messages: + print(f" {msg}") + + if not passed: + sys.exit(1) + print("Regression check PASSED") + + +if __name__ == "__main__": + main() diff --git a/tools/launcher/common/query.py b/tools/launcher/common/query.py index 9b8973322f..866e147444 100644 --- a/tools/launcher/common/query.py +++ b/tools/launcher/common/query.py @@ -103,6 +103,13 @@ def generate(self, messages, verbose=False, **chat_template_kwargs): parser.add_argument( "--max-tokens", type=int, default=None, help="maximum tokens to generate per response." ) +parser.add_argument( + "--max-total-length", + type=int, + default=8192, + help="maximum total length (prompt + output). Stops synthesizing remaining turns " + "when context exceeds this limit.", +) args = parser.parse_args() llm = LLM(args) @@ -117,7 +124,7 @@ def disable_thinking_column(data): def synthesize(data): - messages = data.get("conversations") or data.get("messages") + messages = data.get("messages") or data.get("conversations") if messages is None: raise ValueError( "No conversations or messages in the data. Only OAI chat data is supported." @@ -128,6 +135,7 @@ def synthesize(data): current_messages = [] last_full_message = None # tracks the most recent generated response (unstripped) + max_total = args.max_total_length for msg in messages: role = msg["role"] @@ -140,6 +148,16 @@ def synthesize(data): msg["content"] = msg["content"] + " /no_think" current_messages.append(msg) + + # Estimate context length; stop if remaining budget is too small. + if max_total is not None and args.max_tokens is not None: + ctx_chars = sum(len(m.get("content", "")) for m in current_messages) + est_tokens = ctx_chars // 3 # rough char-to-token estimate + if est_tokens + args.max_tokens > max_total: + # Drop this user turn — context too long for another generation + current_messages.pop() + break + new_message = llm.generate(current_messages, verbose=False) if new_message is None: break @@ -178,7 +196,7 @@ def synthesize(data): current_messages[i] = last_full_message break - return {"conversations": current_messages} + return {"messages": current_messages} # Support both HF Hub repo IDs and local file paths (.jsonl, .json, .parquet, etc.) diff --git a/tools/launcher/common/specdec/ar_eval_mtbench.sh b/tools/launcher/common/specdec/ar_eval_mtbench.sh new file mode 100644 index 0000000000..4062e6b2fe --- /dev/null +++ b/tools/launcher/common/specdec/ar_eval_mtbench.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# MT-Bench AR evaluation using scripts/ar_validate.py. +# Finds the latest checkpoint and runs per-category AR validation. +# +# Args are passed directly to ar_validate.py (--model_path, --osl, --steps, etc.) +# If --model_path is not provided, auto-detects from --ckpt_dir. + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +source ${SCRIPT_DIR}/../service_utils.sh + +pip install -r modules/Model-Optimizer/examples/speculative_decoding/requirements.txt 2>&1 | tail -3 + +trap 'error_handler $0 $LINENO' ERR + +# Parse --ckpt_dir to find latest checkpoint (ar_validate.py expects --model_path) +ARGS=() +CKPT_DIR="" +while [ $# -gt 0 ]; do + case "$1" in + --ckpt_dir) shift; CKPT_DIR="$1" ;; + *) ARGS+=("$1") ;; + esac + shift +done + +# Auto-detect model_path from ckpt_dir if not explicitly provided +MODEL_PATH="" +if [ -n "$CKPT_DIR" ]; then + # Find latest checkpoint subdir + LAST_CKPT=$(ls -d ${CKPT_DIR}/checkpoint-* 2>/dev/null | sort -t- -k2 -n | tail -1) + if [ -f "${CKPT_DIR}/model.safetensors" ]; then + MODEL_PATH="${CKPT_DIR}" + elif [ -n "$LAST_CKPT" ]; then + MODEL_PATH="${LAST_CKPT}" + fi + echo "Auto-detected model_path: ${MODEL_PATH}" +fi + +if [ -z "$MODEL_PATH" ]; then + echo "ERROR: No checkpoint found. Provide --ckpt_dir or --model_path." + exit 1 +fi + +CUDA_VISIBLE_DEVICES=0 python3 modules/Model-Optimizer/examples/speculative_decoding/scripts/ar_validate.py \ + --model_path "${MODEL_PATH}" \ + --per_category \ + "${ARGS[@]}" + +report_result "PASS: MT-Bench AR evaluation" diff --git a/tools/launcher/common/specdec/dflash_online_training.sh b/tools/launcher/common/specdec/dflash_online_training.sh new file mode 100644 index 0000000000..bfa5fdcf03 --- /dev/null +++ b/tools/launcher/common/specdec/dflash_online_training.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# DFlash online training script for the ModelOpt Launcher. +# Trains a DFlash draft model using accelerate launch + main.py --config. +# +# All training config comes from the YAML recipe (--config) and OmegaConf overrides. +# All args are passed directly to main.py (--config + key=value overrides). +# +# Multi-node env vars (set by Slurm or user): +# NUM_NODES — number of nodes (default: 1) +# HEAD_NODE_IP — head node IP (auto-detected if not set) +# +# Usage from YAML: +# script: common/dflash/online_training.sh +# args: +# - --config modules/Model-Optimizer/modelopt_recipes/general/speculative_decoding/dflash.yaml +# - model.model_name_or_path=/hf-local/Qwen/Qwen3-8B +# - data.data_path=/path/to/data.jsonl +# - training.output_dir=/scratchspace/dflash +# environment: +# - NUM_NODES: "8" + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +source ${SCRIPT_DIR}/../service_utils.sh + +pip install -r modules/Model-Optimizer/examples/speculative_decoding/requirements.txt +pip install huggingface-hub>=1.2.1 +export PATH=$PATH:/workspace/.local/bin + +################################################################################################### + +trap 'error_handler $0 $LINENO' ERR + +# Auto-detect head node IP for multi-node training +NUM_NODES=${NUM_NODES:-1} +if [ -z "$HEAD_NODE_IP" ] && [[ "$NUM_NODES" != "1" ]]; then + HEAD_NODE_IP=$(scontrol show hostnames "$SLURM_JOB_NODELIST" 2>/dev/null | head -1) + HEAD_NODE_IP=${HEAD_NODE_IP:-$SLURM_LAUNCH_NODE_IPADDR} + if [ -z "$HEAD_NODE_IP" ] && [ -n "$SLURM_JOB_NODELIST" ]; then + HEAD_NODE_IP=$(python3 -c " +import socket, re, os +nl = os.environ.get('SLURM_JOB_NODELIST', '') +m = re.match(r'([a-zA-Z0-9-]+?)(?:\[(\d+))?', nl) +if m: + host = m.group(1) + (m.group(2) or '') + try: + print(socket.gethostbyname(host)) + except: + print(host) +" 2>/dev/null) + fi + if [ -z "$HEAD_NODE_IP" ] && [ "${SLURM_PROCID:-0}" = "0" ]; then + HEAD_NODE_IP=$(hostname -I 2>/dev/null | awk '{print $1}') + fi + export HEAD_NODE_IP + echo "Auto-detected HEAD_NODE_IP: ${HEAD_NODE_IP}" +fi + +# Build accelerate launch command +MAIN_PY=modules/Model-Optimizer/examples/speculative_decoding/main.py + +if [[ "$NUM_NODES" != "1" ]]; then + if [ -z "$HEAD_NODE_IP" ]; then + echo "ERROR: HEAD_NODE_IP is empty. Cannot launch multi-node training." + exit 1 + fi + GPU_PER_NODE=${GPU_PER_NODE:-$(nvidia-smi --query-gpu=name --format=csv,noheader | wc -l)} + TOTAL_GPU=$((NUM_NODES * GPU_PER_NODE)) + echo "Total GPUs: $TOTAL_GPU (NUM_NODES: $NUM_NODES, GPU_PER_NODE: $GPU_PER_NODE)" + MULTI_NODE_ARGS="--num_processes $TOTAL_GPU \ + --num_machines $NUM_NODES \ + --machine_rank $SLURM_PROCID \ + --rdzv_backend c10d \ + --main_process_ip $HEAD_NODE_IP \ + --main_process_port 29500" +else + TOTAL_GPU=$(python3 -c "import torch; print(torch.cuda.device_count())") + echo "Total GPUs: $TOTAL_GPU (single node)" + MULTI_NODE_ARGS="" +fi + +export TOKENIZERS_PARALLELISM=False + +set -x +start_time=$(date +%s) +accelerate launch --mixed_precision bf16 $MULTI_NODE_ARGS $MAIN_PY "$@" +echo "Training time: $(( $(date +%s) - start_time )) seconds" +set +x + +# Export last checkpoint to deployment format (rank 0 only, single GPU) +if [ "${SLURM_PROCID:-0}" = "0" ]; then + OUTPUT_DIR=$(python3 -c " +import sys +for arg in sys.argv[1:]: + if arg.startswith('training.output_dir='): + print(arg.split('=', 1)[1]) + break +" "$@") + + if [ -n "$OUTPUT_DIR" ]; then + # Export all checkpoints that don't already have an exported version + EXPORTED=0 + for CKPT in $(ls -d ${OUTPUT_DIR}/checkpoint-* 2>/dev/null | sort -t- -k2 -n); do + STEP=$(basename "$CKPT" | sed 's/checkpoint-//') + EXPORT_DIR="${OUTPUT_DIR}/exported-checkpoint-${STEP}" + if [ -d "$EXPORT_DIR" ]; then + echo "Already exported: ${EXPORT_DIR}" + continue + fi + echo "=== Exporting: ${CKPT} → ${EXPORT_DIR} ===" + CUDA_VISIBLE_DEVICES=0 python3 modules/Model-Optimizer/examples/speculative_decoding/scripts/export_hf_checkpoint.py \ + --model_path "${CKPT}" \ + --export_path "${EXPORT_DIR}" \ + --trust_remote_code + EXPORTED=$((EXPORTED + 1)) + done + # Also export final model if saved directly to output_dir + if [ -f "${OUTPUT_DIR}/modelopt_state.pth" ] && [ ! -d "${OUTPUT_DIR}/exported-checkpoint-final" ]; then + echo "=== Exporting: ${OUTPUT_DIR} → ${OUTPUT_DIR}/exported-checkpoint-final ===" + CUDA_VISIBLE_DEVICES=0 python3 modules/Model-Optimizer/examples/speculative_decoding/scripts/export_hf_checkpoint.py \ + --model_path "${OUTPUT_DIR}" \ + --export_path "${OUTPUT_DIR}/exported-checkpoint-final" \ + --trust_remote_code + EXPORTED=$((EXPORTED + 1)) + fi + if [ "$EXPORTED" -eq 0 ]; then + echo "No new checkpoints to export in ${OUTPUT_DIR}" + fi + fi + + # Regression check (uses env vars MAX_FINAL_LOSS, MIN_FINAL_ACC, etc.) + if [ -n "$OUTPUT_DIR" ]; then + python3 common/check_regression.py "${OUTPUT_DIR}" || true + fi +fi diff --git a/tools/launcher/common/specdec/vllm_smoke_test.sh b/tools/launcher/common/specdec/vllm_smoke_test.sh new file mode 100644 index 0000000000..1e508cb116 --- /dev/null +++ b/tools/launcher/common/specdec/vllm_smoke_test.sh @@ -0,0 +1,171 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Quick vLLM smoke test for speculative decoding (EAGLE3, DFlash, MTP, etc.). +# Launches server, sends a few test prompts, verifies responses, and shuts down. +# +# Required env vars: +# HF_MODEL_CKPT — target model path +# +# Optional env vars: +# DRAFT_MODEL — draft model path (not needed for MTP) +# SPEC_METHOD — speculative method: "eagle", "dflash", "mtp", etc. (default: "eagle") +# NUM_SPEC_TOKENS — number of speculative tokens (default: 15) +# TP_SIZE — tensor parallel size (default: 1) +# VLLM_PORT — server port (default: 8000) +# REASONING_PARSER — reasoning parser (e.g., "qwen3" for Qwen3.5) +# DISABLE_PREFIX_CACHING — set to "1" to disable prefix caching + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +source ${SCRIPT_DIR}/../service_utils.sh 2>/dev/null || true + +cleanup() { kill $SERVER_PID 2>/dev/null; sleep 2; kill -9 $SERVER_PID 2>/dev/null; } +trap cleanup EXIT + +MODEL=${HF_MODEL_CKPT} +DRAFT=${DRAFT_MODEL:-} +# Auto-detect exported checkpoint from training output dir +if [ -z "$DRAFT" ] && [ -n "${DRAFT_CKPT_DIR:-}" ]; then + DRAFT=$(ls -d ${DRAFT_CKPT_DIR}/exported-checkpoint-* 2>/dev/null | sort -t- -k3 -n | tail -1) + if [ -n "$DRAFT" ]; then + echo "Auto-detected draft model: ${DRAFT}" + fi +fi +METHOD=${SPEC_METHOD:-eagle} +NUM_SPEC=${NUM_SPEC_TOKENS:-15} +PORT=${VLLM_PORT:-8000} +TP=${TP_SIZE:-1} + +echo "=== vLLM Speculative Decoding Smoke Test ===" +echo "Method: ${METHOD}" +echo "Target: ${MODEL}" +echo "Draft: ${DRAFT:-none (self-draft)}" +echo "Spec tokens: ${NUM_SPEC}, TP: ${TP}" + +# Build speculative config: include "model" only if DRAFT_MODEL is set +if [ -n "$DRAFT" ] && [ "$DRAFT" != "none" ]; then + SPEC_CONFIG="{\"method\": \"${METHOD}\", \"model\": \"${DRAFT}\", \"num_speculative_tokens\": ${NUM_SPEC}}" +else + # Self-draft methods (MTP, Medusa) — no separate draft model + SPEC_CONFIG="{\"method\": \"${METHOD}\", \"num_speculative_tokens\": ${NUM_SPEC}}" +fi + +# Build optional args +OPTIONAL_ARGS="" +if [ -n "${REASONING_PARSER:-}" ]; then + OPTIONAL_ARGS="${OPTIONAL_ARGS} --reasoning-parser ${REASONING_PARSER}" +fi +if [ "${DISABLE_PREFIX_CACHING:-}" = "1" ]; then + OPTIONAL_ARGS="${OPTIONAL_ARGS} --no-enable-prefix-caching" +fi + +# Start vLLM server +if [ -n "$SPEC_CONFIG" ]; then + vllm serve ${MODEL} \ + --speculative-config "${SPEC_CONFIG}" \ + --max-num-batched-tokens 32768 \ + --tensor-parallel-size ${TP} \ + --port ${PORT} \ + ${OPTIONAL_ARGS} \ + & +else + vllm serve ${MODEL} \ + --max-num-batched-tokens 32768 \ + --tensor-parallel-size ${TP} \ + --port ${PORT} \ + ${OPTIONAL_ARGS} \ + & +fi +SERVER_PID=$! + +# Wait for server +echo "Waiting for vLLM server..." +for i in $(seq 1 180); do + if curl -s http://localhost:${PORT}/health > /dev/null 2>&1; then + echo "Server ready after ${i}s" + break + fi + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server died"; wait $SERVER_PID; exit 1 + fi + sleep 1 +done + +if ! curl -s http://localhost:${PORT}/health > /dev/null 2>&1; then + echo "ERROR: Server timeout"; exit 1 +fi + +# Run quick test prompts using chat completions API +MAX_TOKENS=${MAX_OUTPUT_TOKENS:-1024} +echo "" +echo "=== Test Prompts (max_tokens=${MAX_TOKENS}) ===" +PASS=0 +FAIL=0 +TOTAL_TOKENS=0 +TOTAL_TIME=0 +# 8 prompts mimicking MT-Bench categories: writing, roleplay, reasoning, +# math, coding, extraction, stem, humanities +for PROMPT in \ + "Write a persuasive email to your manager requesting a four-day work week. Include at least three supporting arguments." \ + "You are a medieval blacksmith. A traveler asks you to forge a sword. Describe your process and the qualities of your finest work." \ + "A farmer has 17 sheep. All but 9 run away. How many sheep does the farmer have left? Explain your reasoning carefully." \ + "Solve the equation 3x + 7 = 22. Show each step of your solution." \ + "Write a Python function that takes a list of integers and returns the second largest unique value. Include error handling." \ + "Extract all the dates, names, and locations from: On March 15 2024 Dr. Alice Chen presented her findings at the Berlin Conference on Climate Science." \ + "Explain the process of photosynthesis. What role does chlorophyll play and why are plants green?" \ + "Discuss the main themes in George Orwells 1984. How do they relate to modern society?"; do + START=$(date +%s%N) + RESULT=$(curl -s http://localhost:${PORT}/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d "{\"model\": \"${MODEL}\", \"messages\": [{\"role\": \"user\", \"content\": \"${PROMPT}\"}], \"max_tokens\": ${MAX_TOKENS}, \"temperature\": 0}" \ + 2>/dev/null) + END=$(date +%s%N) + ELAPSED=$(echo "scale=2; ($END - $START) / 1000000000" | bc 2>/dev/null || echo "0") + TOKENS=$(echo "$RESULT" | python3 -c "import json,sys; r=json.load(sys.stdin); print(r.get('usage',{}).get('completion_tokens',0))" 2>/dev/null) + if [ -n "$TOKENS" ] && [ "$TOKENS" -gt 0 ] 2>/dev/null; then + TPS=$(echo "scale=1; $TOKENS / $ELAPSED" | bc 2>/dev/null || echo "?") + echo " PASS: ${TOKENS} tokens in ${ELAPSED}s (${TPS} tok/s) — \"${PROMPT:0:50}...\"" + PASS=$((PASS + 1)) + TOTAL_TOKENS=$((TOTAL_TOKENS + TOKENS)) + TOTAL_TIME=$(echo "$TOTAL_TIME + $ELAPSED" | bc 2>/dev/null || echo "0") + else + echo " FAIL: \"${PROMPT}\"" + echo " Response: $(echo "$RESULT" | head -c 200)" + FAIL=$((FAIL + 1)) + fi +done + +echo "" +echo "Results: ${PASS} passed, ${FAIL} failed" +if [ "$TOTAL_TOKENS" -gt 0 ] 2>/dev/null; then + AVG_TPS=$(echo "scale=1; $TOTAL_TOKENS / $TOTAL_TIME" | bc 2>/dev/null || echo "?") + echo "Total: ${TOTAL_TOKENS} tokens in ${TOTAL_TIME}s (${AVG_TPS} tok/s avg)" +fi + +# Fetch speculative decoding metrics if available +echo "" +METRICS=$(curl -s http://localhost:${PORT}/metrics 2>/dev/null | grep -i "spec\|accept\|draft" | head -10) +if [ -n "$METRICS" ]; then + echo "=== Speculative Decoding Metrics ===" + echo "$METRICS" +fi + +if [ $FAIL -gt 0 ]; then + echo "ERROR: Some prompts failed" + exit 1 +fi + +echo "Done" diff --git a/tools/launcher/examples/Qwen/Qwen3-0.6B/chat_template_train.jinja b/tools/launcher/examples/Qwen/Qwen3-0.6B/chat_template_train.jinja new file mode 100644 index 0000000000..7c0393da27 --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3-0.6B/chat_template_train.jinja @@ -0,0 +1,30 @@ +{# Qwen3 chat template with {% generation %} tags for answer_only_loss training. + Based on the official Qwen3 template but simplified: + - Preserves system/user/assistant formatting and injection + - Adds {% generation %} tags around assistant content for loss masking + - Drops tool_call/tool_response formatting (not needed for SFT/spec-dec training) + + Usage in YAML: data.chat_template=path/to/chat_template_train.jinja + + See https://huggingface.co/docs/transformers/en/chat_templating#train-on-completions-only +#} +{%- if messages[0].role == 'system' -%} + {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' -}} +{%- endif -%} +{%- for message in messages -%} + {%- if message.role == 'user' -%} + {{- '<|im_start|>user\n' + message.content + '<|im_end|>\n' -}} + {%- elif message.role == 'assistant' -%} + {{- '<|im_start|>assistant\n' -}} + {%- generation -%} + {%- if loop.last and not message.content.startswith('') -%} + {{- '\n\n\n\n' -}} + {%- endif -%} + {{- message.content -}} + {%- endgeneration -%} + {{- '<|im_end|>\n' -}} + {%- endif -%} +{%- endfor -%} +{%- if add_generation_prompt -%} + {{- '<|im_start|>assistant\n' -}} +{%- endif -%} diff --git a/tools/launcher/examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml b/tools/launcher/examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml new file mode 100644 index 0000000000..c5534cf9ff --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml @@ -0,0 +1,55 @@ +# DFlash online speculative decoding training for Qwen3-0.6B. +# +# Lightweight single-GPU regression test. Uses synthetic_conversations_1k.jsonl +# (packaged with the code) — no external data dependencies. +# +# Trains for 3 epochs on 1K samples, logs loss every 100 steps. +# +# Convergence baseline (L40, batch_size=2, seq_len=512, 2-layer draft): +# Step 100 (epoch 0.2): loss=6.59 acc=0.079 +# Step 500 (epoch 1.0): loss=1.78 acc=0.525 +# Step 1000 (epoch 2.0): loss=1.13 acc=0.580 +# Step 1500 (epoch 3.0): loss=1.11 acc=0.595 +# +# Regression criteria (set via environment): +# MAX_FINAL_LOSS: final loss must be below this (default: 2.0) +# MIN_FINAL_ACC: final accuracy must be above this (default: 0.40) +# +# Reference: "DFlash: Block Diffusion for Flash Speculative Decoding" (arXiv:2602.06036) +# +# Usage: +# uv run launch.py --yaml examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml --yes +# uv run launch.py --yaml examples/Qwen/Qwen3-0.6B/hf_online_dflash.yaml hf_local=/mnt/hf-local --yes + +job_name: Qwen3-0.6B_DFlash_regression +pipeline: + global_vars: + hf_model: /hf-local/Qwen/Qwen3-0.6B + + task_0: + script: common/specdec/dflash_online_training.sh + args: + - --config modules/Model-Optimizer/modelopt_recipes/general/speculative_decoding/dflash.yaml + - model.model_name_or_path=<> + - data.data_path=modules/Model-Optimizer/examples/dataset/synthetic_conversations_1k.jsonl + - data.chat_template=examples/Qwen/Qwen3-0.6B/chat_template_train.jinja + - training.output_dir=/scratchspace/dflash_qwen3_0.6b + - training.num_train_epochs=3 + - training.training_seq_len=512 + - training.per_device_train_batch_size=2 + - training.save_steps=500 + - training.logging_steps=100 + - training.disable_tqdm=true + - training.answer_only_loss=true + - dflash.dflash_block_size=8 + - dflash.dflash_mask_token_id=151669 + - dflash.dflash_use_torch_compile=False + - dflash.dflash_architecture_config.num_hidden_layers=2 + environment: + - MAX_FINAL_LOSS: "2.0" + - MIN_FINAL_ACC: "0.40" + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 1 diff --git a/tools/launcher/examples/Qwen/Qwen3-8B/chat_template_train.jinja b/tools/launcher/examples/Qwen/Qwen3-8B/chat_template_train.jinja new file mode 100644 index 0000000000..7c0393da27 --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3-8B/chat_template_train.jinja @@ -0,0 +1,30 @@ +{# Qwen3 chat template with {% generation %} tags for answer_only_loss training. + Based on the official Qwen3 template but simplified: + - Preserves system/user/assistant formatting and injection + - Adds {% generation %} tags around assistant content for loss masking + - Drops tool_call/tool_response formatting (not needed for SFT/spec-dec training) + + Usage in YAML: data.chat_template=path/to/chat_template_train.jinja + + See https://huggingface.co/docs/transformers/en/chat_templating#train-on-completions-only +#} +{%- if messages[0].role == 'system' -%} + {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' -}} +{%- endif -%} +{%- for message in messages -%} + {%- if message.role == 'user' -%} + {{- '<|im_start|>user\n' + message.content + '<|im_end|>\n' -}} + {%- elif message.role == 'assistant' -%} + {{- '<|im_start|>assistant\n' -}} + {%- generation -%} + {%- if loop.last and not message.content.startswith('') -%} + {{- '\n\n\n\n' -}} + {%- endif -%} + {{- message.content -}} + {%- endgeneration -%} + {{- '<|im_end|>\n' -}} + {%- endif -%} +{%- endfor -%} +{%- if add_generation_prompt -%} + {{- '<|im_start|>assistant\n' -}} +{%- endif -%} diff --git a/tools/launcher/examples/Qwen/Qwen3-8B/hf_online_dflash.yaml b/tools/launcher/examples/Qwen/Qwen3-8B/hf_online_dflash.yaml new file mode 100644 index 0000000000..e255f51dc3 --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3-8B/hf_online_dflash.yaml @@ -0,0 +1,71 @@ +# DFlash online speculative decoding training for Qwen3-8B. +# +# 3-step pipeline: +# task_0: Online DFlash training +# task_1: vLLM smoke test with DFlash speculative decoding +# task_2: MT-Bench per-category HF AR evaluation (1 GPU) +# +# Reference: "DFlash: Block Diffusion for Flash Speculative Decoding" (arXiv:2602.06036) +# +# Usage: +# uv run launch.py --yaml examples/Qwen/Qwen3-8B/hf_online_dflash.yaml --yes +# uv run slurm.py --yaml modules/Model-Optimizer/tools/launcher/examples/Qwen/Qwen3-8B/hf_online_dflash.yaml --yes + +job_name: Qwen3-8B_DFlash_online +pipeline: + global_vars: + hf_model: /hf-local/Qwen/Qwen3-8B + + # Step 1: Online DFlash training + task_0: + script: common/specdec/dflash_online_training.sh + args: + - --config modules/Model-Optimizer/modelopt_recipes/general/speculative_decoding/dflash.yaml + - model.model_name_or_path=<> + - data.data_path=/hf-local/modelopt/Speculative-Decoding-Dataset-v1-Qwen3-8B/sample-1K-openai.jsonl + - data.chat_template=examples/Qwen/Qwen3-8B/chat_template_train.jinja + - training.output_dir=/scratchspace/dflash_bs16 + - training.num_train_epochs=1 + - training.training_seq_len=4096 + - training.save_steps=5000 + - training.logging_steps=1000 + - training.disable_tqdm=true + - training.answer_only_loss=true + - dflash.dflash_block_size=16 + - dflash.dflash_num_anchors=512 + - dflash.dflash_loss_decay_factor=7 + - dflash.dflash_mask_token_id=151669 + - dflash.dflash_architecture_config.num_hidden_layers=5 + environment: + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 8 + + # Step 2: vLLM smoke test (uses exported checkpoint from training) + task_1: + script: common/specdec/vllm_smoke_test.sh + environment: + - HF_MODEL_CKPT: <> + - DRAFT_CKPT_DIR: /scratchspace/dflash_bs16 + - SPEC_METHOD: "dflash" + - NUM_SPEC_TOKENS: "7" + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 1 + + # Step 3: HF AR evaluation + task_2: + script: common/specdec/ar_eval_mtbench.sh + args: + - --ckpt_dir /scratchspace/dflash_bs16 + - --osl 512 + - --steps 15 + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 1 diff --git a/tools/launcher/examples/Qwen/Qwen3.5-4B/chat_template_train.jinja b/tools/launcher/examples/Qwen/Qwen3.5-4B/chat_template_train.jinja new file mode 100644 index 0000000000..7c0393da27 --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3.5-4B/chat_template_train.jinja @@ -0,0 +1,30 @@ +{# Qwen3 chat template with {% generation %} tags for answer_only_loss training. + Based on the official Qwen3 template but simplified: + - Preserves system/user/assistant formatting and injection + - Adds {% generation %} tags around assistant content for loss masking + - Drops tool_call/tool_response formatting (not needed for SFT/spec-dec training) + + Usage in YAML: data.chat_template=path/to/chat_template_train.jinja + + See https://huggingface.co/docs/transformers/en/chat_templating#train-on-completions-only +#} +{%- if messages[0].role == 'system' -%} + {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' -}} +{%- endif -%} +{%- for message in messages -%} + {%- if message.role == 'user' -%} + {{- '<|im_start|>user\n' + message.content + '<|im_end|>\n' -}} + {%- elif message.role == 'assistant' -%} + {{- '<|im_start|>assistant\n' -}} + {%- generation -%} + {%- if loop.last and not message.content.startswith('') -%} + {{- '\n\n\n\n' -}} + {%- endif -%} + {{- message.content -}} + {%- endgeneration -%} + {{- '<|im_end|>\n' -}} + {%- endif -%} +{%- endfor -%} +{%- if add_generation_prompt -%} + {{- '<|im_start|>assistant\n' -}} +{%- endif -%} diff --git a/tools/launcher/examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml b/tools/launcher/examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml new file mode 100644 index 0000000000..5d7e739157 --- /dev/null +++ b/tools/launcher/examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml @@ -0,0 +1,81 @@ +# DFlash online speculative decoding training for Qwen3.5-4B. +# +# 3-step pipeline: +# task_0: Online DFlash training +# task_1: vLLM smoke test with DFlash speculative decoding +# task_2: HF AR evaluation (1 GPU) +# +# NOTE: Qwen3.5-4B has non-standard head_dim=160. The draft model uses z-lab's +# architecture (32 heads, head_dim=128) for vLLM KV cache compatibility. +# +# Reference: "DFlash: Block Diffusion for Flash Speculative Decoding" (arXiv:2602.06036) +# +# Usage: +# uv run launch.py --yaml examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml --yes +# uv run slurm.py --yaml modules/Model-Optimizer/tools/launcher/examples/Qwen/Qwen3.5-4B/hf_online_dflash.yaml --yes + +job_name: Qwen3.5-4B_DFlash_online +pipeline: + global_vars: + hf_model: /hf-local/Qwen/Qwen3.5-4B + + # Step 1: Online DFlash training + task_0: + script: common/specdec/dflash_online_training.sh + args: + - --config modules/Model-Optimizer/modelopt_recipes/general/speculative_decoding/dflash.yaml + - model.model_name_or_path=<> + - model.trust_remote_code=false + - data.data_path=/hf-local/modelopt/Speculative-Decoding-Dataset-v1-Qwen3-8B/sample-1K-openai.jsonl + - data.chat_template=examples/Qwen/Qwen3.5-4B/chat_template_train.jinja + - training.output_dir=/scratchspace/dflash_qwen3.5_4b + - training.num_train_epochs=1 + - training.training_seq_len=4096 + - training.save_steps=5000 + - training.logging_steps=1000 + - training.disable_tqdm=true + - training.answer_only_loss=true + - dflash.dflash_block_size=8 + - dflash.dflash_num_anchors=512 + - dflash.dflash_loss_decay_factor=4 + - dflash.dflash_mask_token_id=248070 + - dflash.dflash_architecture_config.num_hidden_layers=5 + - dflash.dflash_architecture_config.num_attention_heads=32 + - dflash.dflash_architecture_config.num_key_value_heads=8 + - dflash.dflash_architecture_config.head_dim=128 + - dflash.dflash_architecture_config.intermediate_size=9728 + - dflash.dflash_architecture_config.rope_theta=10000000 + environment: + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 8 + + # Step 2: vLLM smoke test with exported DFlash draft + task_1: + script: common/specdec/vllm_smoke_test.sh + environment: + - HF_MODEL_CKPT: <> + - DRAFT_CKPT_DIR: /scratchspace/dflash_qwen3.5_4b + - SPEC_METHOD: "dflash" + - NUM_SPEC_TOKENS: "7" + - REASONING_PARSER: "qwen3" + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 1 + + # Step 3: HF AR evaluation + task_2: + script: common/specdec/ar_eval_mtbench.sh + args: + - --ckpt_dir /scratchspace/dflash_qwen3.5_4b + - --osl 512 + - --steps 15 + slurm_config: + _factory_: "slurm_factory" + nodes: 1 + ntasks_per_node: 1 + gpus_per_node: 1 diff --git a/tools/launcher/launch.py b/tools/launcher/launch.py index 3447d1faa7..fdb867f08a 100644 --- a/tools/launcher/launch.py +++ b/tools/launcher/launch.py @@ -64,9 +64,10 @@ "modules/Model-Optimizer/modelopt/*", "modules/Model-Optimizer/modelopt_recipes/*", "modules/Model-Optimizer/examples/*", + "examples/*", "common/*", ], - relative_path=[LAUNCHER_DIR] * 7, + relative_path=[LAUNCHER_DIR] * 8, ) MODELOPT_SRC_PATH = os.path.join(LAUNCHER_DIR, "modules/Model-Optimizer/modelopt") diff --git a/tox.ini b/tox.ini index d08925f89f..e06661aa59 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ envlist= pre-commit-all py312-torch210-tf_latest-unit cuda13-gpu + cuda13-gpu-regression cuda13-gpu-megatron skipsdist = True toxworkdir = /tmp/{env:USER}-modelopt-tox @@ -68,6 +69,12 @@ commands_pre = commands = python -m pytest tests/gpu {env:COV_ARGS:} +[testenv:cuda13-gpu-regression] +commands_pre = + pip install -e .[hf,dev-test] +commands = + python -m pytest tests/gpu_regression {env:COV_ARGS:} + [testenv:cuda13-gpu-megatron] commands_pre = # Install deps here so that it gets installed even in --current-env