# Install required libraries
# transformers : Hugging Face model hub and training utilities
# datasets : easy dataset loading and preprocessing
# peft : parameter-efficient fine-tuning (LoRA)
# bitsandbytes : 4-bit / 8-bit quantization kernels
# trl : GRPOTrainer for RL-based fine-tuning
# accelerate : distributed / mixed-precision training
!pip install -q transformers datasets peft bitsandbytes trl accelerate
# for symbolic answer comparison
!pip install -q latex2sympy2 sympyQwen3 RL-Based Reasoning Fine-Tuning on MATH-500
This notebook demonstrates how to fine-tune Qwen3-1.7B for mathematical reasoning on the MATH-500 benchmark using Group Relative Policy Optimization (GRPO).
Dataset: MATH-500
MATH-500 is a curated subset of 500 problems from the full MATH benchmark, covering competition-level mathematics in 7 subjects (algebra, geometry, number theory, etc.). Each example contains: - problem: the mathematical question. - solution: the reference solution (used for answer extraction only, not shown to the model during training). - answer: the final answer extracted from the solution. - subject / level: metadata about the problem domain and difficulty.
Install Dependencies
Import Modules
import re
import torch
# Hugging Face libraries
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
# LoRA / PEFT
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# RL trainer
from trl import GRPOConfig, GRPOTrainerLoad the MATH-500 Dataset
# Load the 'test' split of MATH-500 from the Hugging Face Hub
dataset = load_dataset("HuggingFaceH4/MATH-500", split="test")
# MATH-500 is a fixed subset of 500 problems
dataset = dataset.select(range(500))# Print the dataset and the column names
print(dataset)
print(dataset.column_names)Dataset({
features: ['problem', 'solution', 'answer', 'subject', 'level', 'unique_id'],
num_rows: 500
})
['problem', 'solution', 'answer', 'subject', 'level', 'unique_id']
# Inspect the first sample
sample = dataset[0]
print("Subject:", sample['subject'])
print("Level:", sample['level'])
print("Problem:", sample['problem'])
print("Solution:", sample['solution'][:800])Subject: Precalculus
Level: 2
Problem: Convert the point $(0,3)$ in rectangular coordinates to polar coordinates. Enter your answer in the form $(r,\theta),$ where $r > 0$ and $0 \le \theta < 2 \pi.$
Solution: We have that $r = \sqrt{0^2 + 3^2} = 3.$ Also, if we draw the line connecting the origin and $(0,3),$ this line makes an angle of $\frac{\pi}{2}$ with the positive $x$-axis.
[asy]
unitsize(0.8 cm);
draw((-0.5,0)--(3.5,0));
draw((0,-0.5)--(0,3.5));
draw(arc((0,0),3,0,90),red,Arrow(6));
dot((0,3), red);
label("$(0,3)$", (0,3), W);
dot((3,0), red);
[/asy]
Therefore, the polar coordinates are $\boxed{\left( 3, \frac{\pi}{2} \right)}.$
Reward Functions
GRPO learns by sampling multiple responses for each prompt, then using scalar reward signals to rank them. We define two complementary reward functions:
Reward - correctness_reward: +2.0 if the final answer matches the reference, 0.0 otherwise. - format_reward: +0.5 if the model wraps its reasoning in <think>…</think> tags.
These rewards encourage the model to produce correct answers, and show its reasoning explicitly.
def extract_boxed_answer(text: str) -> str | None:
"""Extract the content of the answer in \\boxed{}."""
key = r"\boxed{"
results = []
idx = 0
while True:
start = text.find(key, idx)
if start == -1:
break
# Walk forward counting braces to find the matching closing brace
depth = 1
i = start + len(key)
while i < len(text) and depth > 0:
if text[i] == "{":
depth += 1
elif text[i] == "}":
depth -= 1
i += 1
results.append(text[start + len(key) : i - 1].strip())
idx = i
return results[-1] if results else None
def correctness_reward(prompts, completions, answer, **kwargs) -> list[float]:
"""
Reward +2.0 if the model's boxed answer matches the reference answer,
else 0.0. Both answers are compared after stripping whitespace.
"""
rewards = []
for completion, ref in zip(completions, answer):
# completions is a list of lists (one list of messages per sample)
response_text = completion[0]["content"]
predicted = extract_boxed_answer(response_text)
ref_clean = ref.strip()
if predicted is not None and predicted == ref_clean:
rewards.append(2.0)
else:
rewards.append(0.0)
return rewards
def format_reward(prompts, completions, **kwargs) -> list[float]:
"""
Reward +0.5 if the response contains explicit <think>…</think> reasoning
tags, encouraging the model to show its work.
"""
rewards = []
pattern = re.compile(r"<think>.*?</think>", re.DOTALL)
for completion in completions:
response_text = completion[0]["content"]
rewards.append(0.5 if pattern.search(response_text) else 0.0)
return rewardsFormat the Dataset for GRPO
SYSTEM_PROMPT = (
"You are a mathematical reasoning assistant. "
"Think step-by-step inside <think>…</think> tags, then write your final answer "
"inside a LaTeX \\boxed{} command."
)
def format_example(example):
"""
Convert a MATH-500 row into the chat-message format expected by GRPOTrainer.
GRPOTrainer expects a 'prompt' column containing a list of message dicts.
We also keep the reference 'answer' column for the reward function.
"""
# Extract the boxed answer from the full solution to use as ground truth
ref_answer = extract_boxed_answer(example["solution"]) or example["solution"][-50:]
return {
"prompt": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": example["problem"]},
],
"answer": ref_answer,
}# Apply formatting and keep only the columns GRPOTrainer needs
dataset = dataset.map(format_example, remove_columns=dataset.column_names)# First prompt messages
for msg in dataset[0]["prompt"]:
print(f" [{msg['role']}] {msg['content'][:120]}")
print("Reference answer:", dataset[0]["answer"]) [system] You are a mathematical reasoning assistant. Think step-by-step inside <think>…</think> tags, then write your final answe
[user] Convert the point $(0,3)$ in rectangular coordinates to polar coordinates. Enter your answer in the form $(r,\theta),$
Reference answer: tes are $\boxed{\left( 3, \frac{\pi}{2} \right)}.$
Quantization Configuration (4-bit QLoRA)
# BitsAndBytes configuration
bnb_config = BitsAndBytesConfig(
# Load the model using 4-bit precision
load_in_4bit=True,
# Quantization type (fp4 or nf4)
# nf4 is "normalized float 4" format, uses an asymmetric quantization scheme with 4-bit precision
# optimized for normally distributed weights (better than fp4 for neural networks)
bnb_4bit_quant_type="nf4",
# Compute dtype for 4-bit models
bnb_4bit_compute_dtype=torch.bfloat16,
# Use double quantization for 4-bit models
# Double quantization applies further quantization to the quantization constants
bnb_4bit_use_double_quant=True,
)Load the Base Model and Tokenizer
# Load Qwen3-1.7B
model_name = "Qwen/Qwen3-1.7B"# Load Qwen3 model from Hugging Face
model = AutoModelForCausalLM.from_pretrained(
model_name,
# Apply 4-bit quantization
quantization_config=bnb_config,
# Don't cache key/value states during training
use_cache=False,
# Load the entire model on the GPU if available
device_map="auto",
# Enable Qwen3's native thinking mode
attn_implementation="eager",
)The tied weights mapping and config for this model specifies to tie model.embed_tokens.weight to lm_head.weight, but both are present in the checkpoints, so we will NOT tie them. You should update the config with `tie_word_embeddings=False` to silence this warning
# Prepare model for k-bit (QLoRA) training
model = prepare_model_for_kbit_training(model)# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
# Ensure pad token is set
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
# Pad on the left for decoder-only generation
tokenizer.padding_side = "left"# Print the vocabulary size
print(tokenizer.vocab_size)151643
Apply LoRA (Parameter-Efficient Fine-Tuning)
# LoRA configuration
lora_config = LoraConfig(
# LoRA rank dimension (controls capacity of LoRA layers)
r=16,
# Scaling parameter for LoRA updates (higher alpha increases contribution of LoRA weights)
lora_alpha=64,
# Dropout rate for LoRA layers
lora_dropout=0.05,
# Specifies whether to add bias in LoRA layers
bias="none",
# "CAUSAL_LM" indicates that LoRA is applied for causal language modeling
task_type="CAUSAL_LM",
# Qwen3 attention projection names
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
)# Wrap the model with LoRA adapters
model = get_peft_model(model, lora_config)
# Print the fraction of trainable parameters with LoRA
model.print_trainable_parameters()trainable params: 17,432,576 || all params: 2,049,172,480 || trainable%: 0.8507
GRPO Training Configuration
GRPO (Group Relative Policy Optimization) is an RL algorithm designed for LLMs. For each prompt it: 1. Samples multiple completions from the current policy. 2. Scores each with the reward functions. 3. Normalises rewards within the group to compute advantages. 4. Updates the policy to increase the probability of high-reward completions, with a KL penalty to stay close to the reference policy.
# GRPO training configuration
grpo_config = GRPOConfig(
# Output directory where the model predictions and checkpoints will be stored
output_dir="./qwen3-math-grpo",
# Total training steps
max_steps=250,
# Number of prompts processed per optimisation step
per_device_train_batch_size=2,
# Gradient accumulation to simulate a larger effective batch
gradient_accumulation_steps=4,
# Number of response samples drawn per prompt during GRPO rollout
num_generations=4,
# Maximum tokens to generate per completion during rollout
max_completion_length=512,
# Learning rate
learning_rate=5e-6,
# Optimizer
optim="paged_adamw_8bit",
# Mixed-precision
bf16=False,
fp16=False,
# KL penalty coefficient, keeps policy from diverging too far from reference
beta=0.04,
# Log every N steps
logging_steps=10,
# Save a checkpoint every N steps
save_steps=50,
# Disable external reporting
report_to="none",
)RL Training with GRPOTrainer
# GRPOTrainer handles the full RL loop
trainer = GRPOTrainer(
model=model,
processing_class=tokenizer,
reward_funcs=[correctness_reward, format_reward],
args=grpo_config,
train_dataset=dataset,
)# Start RL training
trainer.train()The tokenizer has new PAD/BOS/EOS tokens that differ from the model config and generation config. The model config and generation config were aligned accordingly, being updated with the tokenizer's values. Updated tokens: {'bos_token_id': None, 'pad_token_id': 151643}.
Passing `generation_config` together with generation-related arguments=({'disable_compile'}) is deprecated and will be removed in future versions. Please pass either a `generation_config` object OR all generation parameters explicitly, but not both.
| Step | Training Loss |
|---|---|
| 10 | 0.000000 |
| 20 | 0.000005 |
| 30 | 0.000011 |
| 40 | 0.000010 |
| Step | Training Loss |
|---|---|
| 10 | 0.000000 |
| 20 | 0.000005 |
| 30 | 0.000011 |
| 40 | 0.000010 |
| 50 | 0.000011 |
| 60 | 0.000014 |
| 70 | 0.000020 |
| 80 | 0.001136 |
| 90 | 0.000028 |
| 100 | 0.000036 |
| 110 | 0.000031 |
| 120 | 0.000030 |
| 130 | 0.000035 |
| 140 | 0.000039 |
| 150 | 0.000036 |
| 160 | 0.000143 |
| 170 | 0.000046 |
| 180 | 0.000046 |
| 190 | 0.000038 |
| 200 | 0.000050 |
| 210 | 0.000039 |
| 220 | 0.000058 |
| 230 | 0.000032 |
| 240 | 0.000037 |
| 250 | 0.000034 |
TrainOutput(global_step=250, training_loss=7.859855078277178e-05, metrics={'train_runtime': 40279.4771, 'train_samples_per_second': 0.05, 'train_steps_per_second': 0.006, 'total_flos': 0.0, 'train_loss': 7.859855078277178e-05})
Inference with the Fine-Tuned Model
# Set model to inference mode
model.eval()
model.config.use_cache = Truefrom IPython.display import display, Markdown
# Function for generating responses to math problems
def solve_math(problem: str, max_new_tokens: int = 2048) -> None:
"""Generate a step-by-step solution for a given maths problem."""
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": problem},
]
# Apply Qwen3 chat template
inputs = tokenizer.apply_chat_template(
messages,
return_tensors="pt",
add_generation_prompt=True,
return_dict=True,
).to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=0.6,
top_p=0.95,
repetition_penalty=1.05,
eos_token_id=tokenizer.eos_token_id,
)
# Decode only the newly generated tokens and skip the prompt
generated_ids = outputs[0][inputs["input_ids"].shape[1]:]
response = tokenizer.decode(generated_ids, skip_special_tokens=True).strip()
# Render as formatted Markdown/LaTeX
display(Markdown(response))
# Extract the final answer
boxed = extract_boxed_answer(response)
print("Extracted answer:", boxed if boxed else "(no \\boxed{} found)")# Example 1: algebra
solve_math("Solve for x: 3x² - 12x + 9 = 0")So, dividing each term by 3: 3x² divided by 3 is x², -12x divided by 3 is -4x, and 9 divided by 3 is 3. So the equation simplifies to x² - 4x + 3 = 0. That looks simpler. Now, maybe I can factor this quadratic. Let me check.
Looking for two numbers that multiply to 3 (the constant term) and add up to -4 (the coefficient of the x term). Wait, the numbers would have to be factors of 3. Let’s think… factors of 3 are 1 and 3. But 1 and 3 add up to 4, which is positive. Since the middle term is -4x, both numbers should be negative. So -1 and -3. Yes, -1 times -3 is 3, and -1 plus -3 is -4. Perfect!
So the quadratic factors as (x - 1)(x - 3) = 0. Wait, let me check that. Expanding (x - 1)(x - 3): x² - 3x - x + 3 = x² - 4x + 3. Yep, that matches. So the solutions are x = 1 and x = 3.
But wait, let me make sure I didn’t make any mistakes. Let me verify by plugging them back into the original equation. For x = 1: 3(1)^2 -12(1) +9 = 3 -12 +9 = 0. Correct. For x = 3: 3(9) -12(3) +9 = 27 -36 +9 = 0. Also correct.
Alternatively, I could use the quadratic formula. The original equation was 3x² -12x +9 = 0. So a = 3, b = -12, c = 9. The quadratic formula is x = [-b ± sqrt(b² - 4ac)]/(2a). Let’s compute the discriminant first: b² -4ac = (-12)^2 -439 = 144 - 108 = 36. Then sqrt(36) is 6. So x = [12 ±6]/6. That gives (12+6)/6 = 18/6 = 3, and (12-6)/6 = 6/6 = 1. So same answers.
So both methods give x = 1 and x = 3. Therefore, the solutions are 1 and 3.
Wait, but the original equation after simplifying was x² -4x +3 = 0, which factors to (x-1)(x-3)=0. Yep, same result. So I think that’s it. The answer should be x = 1 and x = 3.
I don’t think there are any other solutions because it’s a quadratic equation, which can have at most two real roots. Since we found two, and they check out, that’s all. So the solution set is {1, 3}.
To solve the quadratic equation $ 3x^2 - 12x + 9 = 0 $, we begin by simplifying the equation:
\[ \frac{3x^2 - 12x + 9}{3} = 0 \quad \Rightarrow \quad x^2 - 4x + 3 = 0 \]
Step 1: Factor the Simplified Equation
We now focus on factoring $ x^2 - 4x + 3 $. We look for two numbers that multiply to $ 3 $ (the constant term) and add up to $ -4 $ (the coefficient of $ x $).
These numbers are $ -1 $ and $ -3 $. Thus, the equation factors as:
\[ x^2 - 4x + 3 = (x - 1)(x - 3) \]
Step 2: Solve the Factored Equation
Setting each factor equal to zero:
\[ x - 1 = 0 \quad \Rightarrow \quad x = 1 \] \[ x - 3 = 0 \quad \Rightarrow \quad x = 3 \]
Step 3: Verification (Optional)
We can confirm by substituting the solutions back into the original equation:
- For $ x = 1 $: $ 3(1)^2 - 12(1) + 9 = 3 - 12 + 9 = 0 $
- For $ x = 3 $: $ 3(3)^2 - 12(3) + 9 = 27 - 36 + 9 = 0 $
Both values satisfy the equation.
Final Answer
\[ \boxed{1 \text{ and } 3} \]
Extracted answer: 1 \text{ and } 3
# Example 2: MATH-500 sample
solve_math(dataset[0]["prompt"][1]["content"])Polar coordinates are given as (r, θ), where r is the distance from the origin to the point, and θ is the angle made with the positive x-axis. The formulas to convert from rectangular (x, y) to polar (r, θ) are:
r = √(x² + y²)
θ = arctan(y/x)
But wait, I need to be careful with θ here because arctan(y/x) can have multiple solutions depending on the quadrant. Also, since the original point is (0, 3), which is on the y-axis. Let me visualize this. The point (0, 3) is straight up along the y-axis. So, if I plot that on the coordinate plane, it’s 3 units above the origin.
So, let’s compute r first. Using the formula r = √(x² + y²). Here, x is 0 and y is 3. Plugging those values in:
r = √(0² + 3²) = √(0 + 9) = √9 = 3. Okay, that seems straightforward. So r is 3.
Now, θ. The formula is θ = arctan(y/x). But here, x is 0 and y is 3. So, plugging those in:
θ = arctan(3/0). Wait, division by zero? That’s undefined. Hmm. What does that mean?
Well, arctan of something divided by zero… Well, when x is 0, the line x=0 is the y-axis. The angle θ for a point on the y-axis is either π/2 or -π/2, right? Because the y-axis is perpendicular to the x-axis. So, if you’re on the positive y-axis, the angle is π/2 radians (which is 90 degrees), and if it’s on the negative y-axis, it’s -π/2 or 3π/2.
But since our point is (0, 3), which is on the positive y-axis. So θ should be π/2. However, I need to make sure that the arctan function isn’t giving me an error here. Since arctan(3/0) is undefined, but we know that the angle is π/2. So maybe θ is π/2.
But let me think again. Sometimes, when dealing with arctan, there’s a need to consider the quadrant. But since x is 0 and y is positive, the point is on the positive y-axis, which is the same as the vertical line. So θ is π/2.
Alternatively, sometimes people use the formula θ = arctan(y/x) but with adjustments for the quadrant. But in this case, since x is 0, the arctangent would be undefined, but we know the actual angle is π/2. So maybe θ is π/2.
Therefore, the polar coordinates are (3, π/2). Let me check if that makes sense. If we have r = 3 and θ = π/2, then converting back to rectangular coordinates: x = r cos θ = 3 cos(π/2) = 3 * 0 = 0. y = r sin θ = 3 sin(π/2) = 3 * 1 = 3. Yep, that gives us (0, 3), which matches the original point.
So, that seems correct. Therefore, the polar coordinates are (3, π/2).
Wait, but just to make sure there isn’t any other possible angle. For example, sometimes when you have points on the axes, the angle is considered as π/2 or 3π/2, depending on the direction. Since our point is on the positive y-axis, θ is π/2. So that’s correct.
Another way to think about it: the angle θ is measured from the positive x-axis. Since the point is on the y-axis, θ is π/2. So that’s the standard position angle.
I don’t think there’s any other possibility here. So the answer should be (3, π/2).
Final Answer The polar coordinates are .
To convert the rectangular coordinate \((0, 3)\) into polar coordinates \((r, \theta)\), we apply the standard conversion formulas:
- $ r = $
- $ = () $
Step 1: Calculate $ r $
Given: - $ x = 0 $ - $ y = 3 $
\[ r = \sqrt{0^2 + 3^2} = \sqrt{9} = 3 \]
Step 2: Calculate $ $
\[ \theta = \arctan\left(\frac{3}{0}\right) \]
This results in an undefined value due to division by zero. However, geometrically, the point \((0, 3)\) lies on the positive y-axis, which corresponds to an angle of \(\frac{\pi}{2}\) radians (or 90°) from the positive x-axis.
Final Result
Thus, the polar coordinates of the point \((0, 3)\) are:
\[ \boxed{(3, \frac{\pi}{2})} \]
Extracted answer: (3, \frac{\pi}{2})
# Example 3: number theory
solve_math("What is the remainder when 7^{100} is divided by 5?")First, I remember that when dealing with remainders, especially with large exponents, modular arithmetic can be helpful. Since we’re dividing by 5, maybe I can use properties of modular arithmetic to simplify this problem.
Let me recall Euler’s theorem or Fermat’s little theorem. Fermat’s little theorem states that if p is a prime number and a is not a multiple of p, then a^(p-1) ≡ 1 mod p. Here, p is 5, which is prime, and 7 is not a multiple of 5. So, applying Fermat’s little theorem here, 7^4 ≡ 1 mod 5. Wait, because p-1 is 4, so 7^4 ≡ 1 mod 5. That means that 7^4 is congruent to 1 when divided by 5.
So, if I can express 7^100 in terms of powers of 7^4, maybe I can simplify it. Let me check. Since 100 divided by 4 is 25, so 7^100 = (74)25. Then, using Fermat’s theorem, each 7^4 is 1 mod 5, so (1)^25 mod 5 is 1 mod 5. Therefore, 7^100 ≡ 1 mod 5. Therefore, the remainder when 7^100 is divided by 5 is 1.
Wait, but let me verify this because sometimes there can be mistakes in the steps. Let me double-check.
First, confirm Fermat’s little theorem: 7^4 ≡ 1 mod 5. Let’s compute 7 mod 5. 7 divided by 5 is 1 with remainder 2, so 7 ≡ 2 mod 5. Therefore, 7^1 mod 5 is 2, 7^2 is 2^2=4 mod 5, 7^3 is 24=8≡3 mod 5, 7^4 is 23=6≡1 mod 5. Yes, that’s correct. So 7^4 ≡ 1 mod 5. Therefore, 7^4k ≡ 1^k ≡ 1 mod 5. So 7^100 is (74)25 ≡ 1^25 ≡ 1 mod 5. So yes, the remainder is 1.
Alternatively, maybe I can compute it step by step with smaller exponents. Let’s see. Maybe using exponentiation by squaring or something. But since the previous method seems correct, maybe that’s sufficient.
But just to make sure, let’s try another approach. Let’s compute 7 mod 5 is 2. So 7^1 = 2 mod 5. 7^2 = 2^2 = 4 mod 5. 7^3 = 7^2 * 7 = 42=8≡3 mod5. 7^4=32=6≡1 mod5. Then 75=74 7 ≡12=2 mod5. So cycle repeats every 4. Therefore, the cycle length is 4. Therefore, 7^100. Since 100 divided by 4 is 25, so the remainder is 0? Wait, no. Wait, 7^4 ≡1, so 7^4k ≡1^k=1 mod5. So 7100=(74)^25 ≡1^25=1 mod5. So same result. So the remainder is 1.
Alternatively, if I compute 7^100 mod5. Since 7≡2 mod5, so 2^100 mod5. Now, 2^4=16≡1 mod5. So 2^4k ≡1^k=1 mod5. Therefore, 2100=(24)25≡125=1 mod5. So same answer. So yes, the remainder is 1.
Therefore, the answer should be 1.
Wait, but just to make sure, maybe I can compute it with smaller exponents. For example, 7^1=2, 7^2=4, 7^3=3, 7^4=1, 7^5=2, etc. So the cycle is 4. So 7^4k+1=2, 7^4k+2=4, 7^4k+3=3, 7^4k+4=1. Therefore, 7^100 is 7^(4*25)= (74)25 ≡1^25=1 mod5. Yep, same conclusion.
Another way: 7^100 = (74)25. Since 7^4=1 mod5, then (1)^25=1 mod5. So yes.
Therefore, the remainder is indeed 1.
I think that’s thorough. I don’t see any mistakes here. So the answer is 1.
Final Answer The remainder when \(7^{100}\) is divided by 5 is .
To solve the problem of finding the remainder when \(7^{100}\) is divided by 5, we apply Fermat’s Little Theorem. This theorem states that for a prime number \(p\) and an integer \(a\) not divisible by \(p\), we have:
\[ a^{p-1} \equiv 1 \pmod{p} \]
Here, \(p = 5\) and \(a = 7\). Since \(7\) is not divisible by \(5\), we apply the theorem:
\[ 7^{5-1} = 7^4 \equiv 1 \pmod{5} \]
This implies:
\[ 7^4 \equiv 1 \pmod{5} \]
We now reduce the exponent \(100\) modulo \(4\) (since \(7^4 \equiv 1\)):
\[ 100 \div 4 = 25 \text{ remainder } 0 \]
Thus,
\[ 7^{100} = (7^4)^{25} \equiv 1^{25} \equiv 1 \pmod{5} \]
Final Result
The remainder when \(7^{100}\) is divided by 5 is:
\[ \boxed{1} \]
Extracted answer: 1