munotes®

Artificial Intelligence Notes | B.Sc. (Computer Science) Semester 5 | Mumbai University | munotes

Get access to whole semester resourcesSemester Pass

Official Notes munotes.in

Artificial Intelligence

B.SC. (COMPUTER SCIENCE) · SEMESTER 5

Strictly as per the University of Mumbai NEP syllabus in force for B.Sc. (Computer Science)

For B.Sc. (Computer Science) students of the University of Mumbai and all its affiliated colleges

Open the book ↓

munotes.in Third Year

Artificial Intelligence

Copyright © 2026 munotes.in. All rights reserved.

Written and first published by munotes.in, 2026.

This book is free for individual students to read at munotes.in. No part of it may be reproduced, distributed, stored, translated or used for institutional or classroom purposes in any form without a prior written licence from munotes.in.

Licensing and permissions: contact@munotes.in

The text of statutes and of judgments reproduced in this book is in the public domain under section 52(1)(q) of the Copyright Act 1957. The commentary, arrangement, examples and questions are the original work of munotes.in.

munotes.in is an independent study resource for MU students. It is not affiliated with, endorsed by, or officially connected to the University of Mumbai. Course names and university references describe the students and syllabus the material relates to.

munotes.in

Contents

Module I Intelligent agents, problem solving and search, knowledge representation and logical reasoning, and reasoning under uncertainty

  1. What Artificial Intelligence Is 1
  2. Acting Rationally, or Thinking Like a Human 6
  3. The Agent and Its Environment 10
  4. Types of Environment 15
  5. The Simple Reflex Agent 20
  6. The Model-Based Reflex Agent 24
  7. The Goal-Based Agent 29
  8. The Utility-Based Agent 34
  9. The Learning Agent 39
  10. Formulating a Problem for Search 45
  11. The Search Tree, and How an Algorithm Is Judged 51
  12. Breadth First Search 57
  13. Depth First Search 62
  14. Uniform Cost Search 67
  15. Iterative Deepening Search 73
  16. Heuristics: Estimating What Is Left To Do 78
  17. Greedy Best First Search 85
  18. A* Search 90
  19. Admissibility, and Why A* Is Optimal 96
  20. Consistency, and A* on a Graph 102
  21. Recursive Best First Search 108
  22. Comparing Two Search Algorithms on One Problem 113
  23. Games as Search 119
  24. Minimax 124
  25. Alpha-Beta Pruning 129
  26. The Knowledge-Based Agent 136
  27. Propositional Logic: Syntax and Meaning 142
  28. Entailment, Models and Validity 147
  29. Inference in Propositional Logic 152
  30. Conjunctive Normal Form and Resolution 157
  31. First-Order Logic 163
  32. Inference in First-Order Logic: Unification and Chaining 168
  33. Rule-Based Systems and Expert Systems 175
  34. Planning and STRIPS 181
  35. Fuzzy Logic and the Membership Function 187
  36. Fuzzification, the Rule Base and Defuzzification 193
  37. Why an Agent Needs Probability 199
  38. The Joint Distribution and Inference by Enumeration 204
  39. Bayes Theorem 209
  40. Conditional Independence 215
  41. Bayesian Networks 221
  42. Inference in a Bayesian Network 227

Module II Machine learning, supervised models, probabilistic and latent variable models, unsupervised and reinforcement learning, and responsible AI

  1. What Machine Learning Is 234
  2. Supervised Learning 240
  3. Unsupervised Learning 246
  4. Reinforcement Learning: The Third Form 250
  5. Parametric and Nonparametric Models 254
  6. Bias and Variance 259
  7. Overfitting and Underfitting 265
  8. Regularization 271
  9. Gradient Descent 277
  10. Classification and Regression 284
  11. k-Nearest Neighbours 290
  12. k-NN for Regression, and What Limits the Method 296
  13. Entropy and Information Gain 302
  14. Decision Tree Learning 308
  15. Reading, Drawing and Pruning a Decision Tree 314
  16. The Naive Bayes Classifier 321
  17. Support Vector Machines: The Margin 328
  18. The Soft Margin and the Kernel 334
  19. The Artificial Neuron and the Perceptron 342
  20. The Multilayer Network and Backpropagation 349
  21. What Deep Learning Is 357
  22. Ensemble Methods, Bagging and the Random Forest 362
  23. Boosting and AdaBoost 370
  24. Evaluating a Model 378
  25. The Statistical Learning Framework 387
  26. Maximum Likelihood Estimation 395
  27. Learning with Complete Data 404
  28. Hidden Variables 412
  29. The EM Algorithm 420
  30. Hidden Markov Models 430
  31. The Forward Algorithm and Viterbi 439
  32. Clustering and k-Means 451
  33. Hierarchical Clustering, and Judging a Clustering 462
  34. Support, Confidence and Lift 475
  35. The Apriori Algorithm 485
  36. The Reinforcement Learning Framework 495
  37. Markov Decision Processes 505
  38. The Bellman Equations, Value Iteration and Policy Iteration 514
  39. Q-Learning 525
  40. Ethical Issues in AI Systems 537
  41. Bias and Fairness in AI Models 543
  42. Transparency and Explainability 553
  43. Accountability and Human Oversight 559
  44. Hallucination in Generative AI 564
  45. Deepfakes and Misuse 575
  46. Using an AI Library Responsibly 581
  47. What the Examination Asks, and How to Answer It 587
munotes.in

Module I

Intelligent agents, problem solving and search, knowledge representation and logical reasoning, and reasoning under uncertainty

munotes.in

Chapter One

What Artificial Intelligence Is

Syllabus topic Module 1, "Foundations of AI & Intelligent Agents: What is AI?"

In one line

Artificial intelligence is the branch of computer science that builds machines which do things we would call intelligent if a person did them.

In the wording a student can write in an examination: Artificial Intelligence is the study and construction of agents that perceive their environment and act so as to achieve the best expected outcome. It is a field of computer science concerned with building systems that perform tasks normally requiring human intelligence, such as reasoning, learning from experience, understanding language, recognising patterns and making decisions under uncertainty.

Where the phrase came from

The phrase was written down in 1955, in a proposal by John McCarthy, Marvin Minsky, Nathaniel Rochester and Claude Shannon for a summer research project at Dartmouth College in 1956. They asked for two months and ten men. The conjecture they proposed to work from is worth reading because it is still the field's working assumption:

every aspect of learning or any other feature of intelligence can in principle be so precisely

described that a machine can be made to simulate it

Everything in this paper is a descendant of that sentence. Search, logic, probability and machine learning are four different answers to "how precisely can it be described".

The four things people mean by the word

This grid is the answer to What is AI? that gets full marks, because it shows that the question has four honest answers and says which one this subject takes. Two questions are being crossed: is the goal to copy a human or to be rational, and is the target thought or behaviour?

Like a humanRationally
ThoughtSystems that think like people. The test is whether the machine's reasoning steps match a person's, so the evidence comes from psychology.Systems that think correctly. The test is whether the reasoning obeys the laws of logic and probability.
BehaviourSystems that act like people. The test is whether a person can tell the difference, which is the Turing test.Systems that act so as to do the best they can. The test is the outcome, measured against a stated performance measure.
  • Thinking humanly is cognitive modelling. It needs a theory of how people actually think, and it is a joint project with psychology rather than a purely engineering one.
  • Thinking rationally is the logic tradition. Aristotle's syllogisms are its ancestor, and Module 1's third and fourth rows are its modern form.
  • Acting humanly is the Turing test, below.
  • Acting rationally is the intelligent agent view, and it is the one MU's syllabus takes. Her very next label is Rational agents vs human thinking, and every following row of Module 1 is a tool an agent uses to act well: search, logic, probability.
munotes.in1

What Artificial Intelligence Is

The Turing test, read out of Turing's own paper

Alan Turing opened his 1950 paper with a refusal. He would not ask "Can machines think?", because that needs definitions of "machine" and "think" that nobody agrees on. He replaced the question with a game.

The imitation game. Three participants: a man, a woman, and an interrogator in a separate room who communicates with both by writing. The interrogator has to say which is which. The man's job is to make the interrogator get it wrong; the woman's job is to help. Turing's question is then:

What will happen when a machine takes the part of A in this game? Will the interrogator decide

wrongly as often when the game is played like this as he does when the game is played between a

man and a woman?

Three points about the test that are worth marks and are usually got wrong:

  1. It is a test of behaviour, not of thought. Turing designed it precisely so that the machine's internals do not matter. It belongs in the bottom-left box of the grid above.
  2. It is deliberately verbal, and Turing says why. The answers are to be typewritten, over a teleprinter between two rooms, "in order that tones of voice may not help the interrogator". The arrangement has, in his words, "the advantage of drawing a fairly sharp line between the physical and the intellectual capacities of a man": there would be "little point in trying to make a thinking machine more human by dressing it up in such artificial flesh."
  3. Turing predicted the objections and answered nine of them, in this order: the Theological Objection, the "Heads in the Sand" Objection, the Mathematical Objection (from Godel's theorem), the Argument from Consciousness, Arguments from Various Disabilities, Lady Lovelace's Objection, the Argument from Continuity in the Nervous System, the Argument from Informality of Behaviour, and the Argument from Extrasensory Perception. His own estimate was that "in about fifty years' time" a machine would play the game so well that an average interrogator "will not have more than 70 per cent chance of making the right identification after five minutes of questioning."

The test is a historical landmark, not a working goal. Almost no modern AI research aims at it, for a plain engineering reason: imitating a person means imitating a person's slowness and mistakes, which nobody wants to pay for. Its value is that it forced the field to define success by what a system does rather than by what it is made of.

The four things a modern AI system is asked to do

A definition is easier to remember when it is attached to capabilities. Almost everything in this paper falls under one of four headings, and each is a later row of MU's own syllabus.

munotes.in2

What Artificial Intelligence Is

CapabilityWhat it meansWhere this paper teaches it
ActingChoosing what to do nextAgents, and search, Module 1 rows 1 and 2
ReasoningDrawing conclusions from what is knownLogic and planning, Module 1 row 3
Coping with uncertaintyActing when the facts are not all inProbability, Module 1 row 4
LearningGetting better from experienceThe whole of Module 2

Strong and weak AI, narrow and general

Three pairs of words get used loosely. They are cheap marks when kept straight.

TermWhat it means
Weak (or narrow) AIA system built for one task: reading number plates, recommending films, scoring a loan. Every deployed AI system today is of this kind.
Strong AIThe claim that a suitably programmed machine would genuinely have a mind, understanding and consciousness, not merely behave as if it did. This is a philosophical claim, not an engineering one.
Artificial General IntelligenceAn engineering goal: one system competent across the full range of tasks a person can learn. Not achieved, and there is no agreement on how to measure it.

Weak against strong is about what the machine IS. Narrow against general is about what it can DO. A system could in principle be general and still have no mind at all.

What AI is not

This section exists because a chapter that only enthuses leaves a reader unable to say where the subject stops.

  • It is not a synonym for machine learning. Learning is one row of Module 2. Search, logic and planning are AI and contain no learning at all. A chess program using minimax learns nothing.
  • It is not a synonym for statistics, though Module 2 is largely statistical. AI asks what to DO; statistics asks what is TRUE of the data. The difference is the performance measure.
  • It is not automation. A washing machine's timer automates a task and chooses nothing. An agent chooses.
  • It is not consciousness, and no result in this paper bears on the question. Every algorithm here would work identically whether or not anything was going on inside.
  • It is not magic, and it is not new. Every method in this paper is arithmetic on numbers or symbol manipulation on structures, published between 1950 and 1997 in papers you could read.

Distinctions

Artificial IntelligenceMachine Learning
What it isThe whole field of building agents that act wellOne family of methods inside it
Needs datanot necessarilyyes, by definition
Example that is one and not the otherA* route finding; a STRIPS plannernothing: all ML is AI
Where on this syllabusboth modulesModule 2
munotes.in3

What Artificial Intelligence Is

Turing testA performance measure
Askscan a person tell the differencedid the agent do well
Judged bya human interrogatora number stated in advance
Belongs toacting humanlyacting rationally
Used in practice todaynoyes, everywhere in this paper

Quick revision

  • AI is the study and construction of agents that perceive an environment and act to achieve the best expected outcome.
  • The phrase was coined in the 1955 Dartmouth proposal (McCarthy, Minsky, Rochester, Shannon) for a 1956 summer project.
  • Four definitions, on two axes: thinking or acting, humanly or rationally. This syllabus takes acting rationally, the intelligent agent view.
  • The Turing test (Turing, 1950) replaces "can machines think" with the imitation game. It tests behaviour, is deliberately conducted in writing, and Turing answered nine objections to it.
  • Weak or narrow AI does one task; strong AI is the claim that the machine would truly have a mind; AGI is the engineering goal of one broadly competent system.
  • Four capability headings: acting, reasoning, coping with uncertainty, learning. They are MU's four rows of Module 1 plus the whole of Module 2.
  • AI is not the same as machine learning, not the same as statistics, not automation, and says nothing about consciousness.

Test yourself

1. Define artificial intelligence in one sentence fit for an examination. Artificial Intelligence is the study and construction of agents that perceive their environment and act so as to achieve the best expected outcome, performing tasks that normally require human intelligence such as reasoning, learning, perception and decision making under uncertainty.

2. Give the four definitions of AI as a grid and say which one this subject uses. The axes are thought against behaviour, and human against rational. Thinking humanly is cognitive modelling; thinking rationally is the logic tradition; acting humanly is the Turing test; acting rationally is the intelligent agent approach. This syllabus uses acting rationally.

3. Describe the Turing test and state what it tests. An interrogator communicates in writing with a machine and a person and must identify which is which. If the interrogator does no better than chance, the machine passes. It tests external behaviour only, and says nothing about how the machine reached its answers.

4. Why did Turing replace the question "Can machines think?" Because answering it requires agreed definitions of "machine" and "think", which do not exist. He substituted a question that can be settled by observation.

5. Distinguish weak AI from strong AI. Weak or narrow AI is a system built to perform a particular task, and is what exists today. Strong AI is the philosophical claim that a suitably programmed machine would actually possess a mind and understanding rather than simulating them.

munotes.in4

What Artificial Intelligence Is

6. Is a program that uses minimax to play chess an example of artificial intelligence, given that it learns nothing? Yes. Learning is one family of AI methods, not the definition of the field. Minimax is a rational decision procedure over a game tree and sits squarely in the acting-rationally box.

7. Name the two documents that fix the field's starting point and the year of each. Turing's "Computing Machinery and Intelligence", 1950, which gave it a test; and the Dartmouth summer research project proposal, 1955, which gave it its name.

Contents This chapter on its own page

munotes.in5

Chapter Two

Acting Rationally, or Thinking Like a Human

Syllabus topic Module 1, "Rational agents vs human thinking"

In one line

A rational agent does the thing that is expected to work out best, judged by a stated measure; a machine that thinks like a human reproduces the steps a person's mind actually takes, whether or not those steps work out best.

In the wording a student can write in an examination: the human-thinking approach aims to build systems whose internal reasoning matches human cognition, and is validated against evidence from psychology. The rational-agent approach aims to build systems that, given what they have perceived, select the action expected to maximise their performance measure. The two differ in their standard of success: resemblance to a person, against doing well.

Why the distinction matters before anything else is taught

Everything in this paper is an answer to "what should the agent do next", and you cannot judge an answer without a standard. The two standards give different verdicts on the same program.

Take a program that adds two five-digit numbers. A person doing this makes carrying errors, slows down when tired, and sometimes writes the digits in the wrong order. A program built to think like a human would have to reproduce those errors, because they are part of how people add. A program built to be rational simply gets the answer right. Both are legitimate research goals, and only one of them is what a student is asked to build in this paper.

The human-thinking programme

The goal is a system whose reasoning is the same reasoning a person does. Two things follow, and both are demanding.

It needs a theory of how people think. You cannot copy a process you cannot describe. So this programme depends on cognitive psychology, and its experiments are psychological experiments: give a person a puzzle, record the order in which they try things, and check whether the program tries things in the same order.

Its evidence is a match, not a score. Success is the program's behaviour resembling a person's in detail, including the timing, the errors and the things people find hard. A program that solved the puzzle instantly and correctly would be a failure by this standard, because no person does that.

This is called cognitive modelling, and it is a genuine field. It has produced results about human memory and problem solving. But it is not engineering, and a student building a route finder does not want it.

Turing's nine objections are the best map of what this programme was up against, because most of them are objections to the idea that a machine could think at all: the Theological Objection, the "Heads in the Sand" Objection, the Mathematical Objection, the Argument from Consciousness, Arguments from Various Disabilities, Lady Lovelace's Objection, the Argument from Continuity in the Nervous System, the Argument from Informality of Behaviour, and the Argument from Extrasensory Perception. Turing's own response was to sidestep the whole question by moving to behaviour, which is where the other programme starts.

munotes.in6

Acting Rationally, or Thinking Like a Human

The rational-agent programme

The goal is a system that acts well. "Well" is not left vague; it is defined, and the definition is the one this syllabus uses everywhere after this chapter.

An agent is rational when, for each possible percept sequence, it selects the action that is expected to maximise its performance measure, given the evidence the percept sequence provides and whatever built-in knowledge the agent has.

Read that in five pieces, because every piece is doing work and each one is worth marks.

  1. "For each possible percept sequence": rationality is about the action chosen in a situation, not about a fixed plan. The same agent may rightly do different things on different days.
  2. "Expected to maximise": expected, not guaranteed. An agent that takes the best bet and loses was still rational. This is the single most misunderstood word in the definition.
  3. "Its performance measure": the standard is external and stated in advance. Rationality is always relative to a measure; change the measure and the rational action changes.
  4. "Given the evidence the percept sequence provides": the agent is judged on what it could know, not on what was true. Missing a car that was invisible is not irrational.
  5. "And whatever built-in knowledge the agent has": the designer's knowledge counts as the agent's.

What rationality is not

This section exists because three separate things get confused with rationality, and each confusion loses marks.

It is not omniscience. An omniscient agent knows the actual outcome of every action. No real agent does. Rationality asks for the best decision from the available evidence, and a bad outcome from a good decision is not irrationality. Crossing a road after looking both ways is rational even if a cargo door falls from an aircraft.

It is not perfection. Perfection maximises actual performance; rationality maximises expected performance. Only the second is achievable, which is why it is the standard.

It is not the same as thinking. The definition mentions no internal process whatever. A lookup table that always happens to choose the best action is rational by this definition. Whether that is satisfying is a philosophical question; whether it is what MU examines is not.

Where each programme leads on this syllabus

Thinking like a humanActing rationally
The goalreproduce human reasoningchoose the best expected action
Validated againstpsychological evidencea stated performance measure
Success looks likethe same steps, the same errorsa higher score
Needs a theory ofthe human mindthe task
Where it appears on this syllabusthis chapter, and nowhere elseevery chapter after it
Who it servessomebody studying peoplesomebody building a system
munotes.in7

Acting Rationally, or Thinking Like a Human

Every following row of Module 1 is a tool for the second column. Search finds the action sequence that reaches a goal; logic works out what is true so the goal can be chosen; probability lets the agent act when it does not know. Module 2 is how the agent improves its own choices from experience. Not one of them claims to be how a person does it.

The one place the human side still earns its keep

Two arguments for studying human cognition survive even inside an engineering programme, and they are worth knowing because they are fair.

People are the only working example of general intelligence. Every narrow system in this paper does one task. If the goal is breadth, the only existing proof that breadth is possible is a person, so how people do it is evidence.

Some tasks are defined by human judgement. A translation is good if a speaker of the language accepts it. A recommendation is good if the person likes it. In these tasks the performance measure itself refers to people, so human behaviour cannot be left out of the specification.

Distinctions

RationalityOmniscience
Knowswhat the percepts providethe actual outcome of every action
Maximisesexpected performanceactual performance
Achievableyesno
Judged after the factno, the decision is judgedyes, the result is judged
A rational agentA human being
Standarda stated performance measurenone stated
Errorsonly when the expectation was wrongroutine and systematic
Memory and arithmeticexactapproximate
Studied bycomputer sciencepsychology

Quick revision

  • Rational agent: for each percept sequence, selects the action expected to maximise its performance measure, given the evidence of the percepts and its built-in knowledge.
  • The five load-bearing parts of that definition: per percept sequence, expected, its performance measure, the evidence available, built-in knowledge.
  • Human thinking is cognitive modelling: the standard is resemblance to a person, validated by psychology, and a program that does the task perfectly can fail that standard.
  • Rationality is not omniscience, not perfection and not a claim about internal thought.
  • A good decision with a bad outcome is rational. A lucky guess is not.
  • This syllabus takes the rational-agent view from here to the end.
  • The human side still matters for two honest reasons: people are the only working general intelligence, and some performance measures refer to people by definition.

Test yourself

1. Define a rational agent. An agent that, for each possible percept sequence, selects the action expected to maximise its performance measure, given the evidence provided by the percept sequence and whatever built-in knowledge the agent has.

munotes.in8

Acting Rationally, or Thinking Like a Human

2. Distinguish rationality from omniscience. An omniscient agent knows the actual outcome of its actions; a rational agent maximises the expected outcome from the evidence it has. Omniscience is impossible, which is why rationality is defined on expectation.

3. An agent crosses a road after looking both ways and is hit by debris falling from an aircraft. Was it rational? Yes. The decision was the best available on the evidence. Rationality judges the decision, not the outcome.

4. Why would a program that performs a task perfectly count as a failure in the human-thinking programme? Because that programme's standard is resemblance to human reasoning, including human slowness and human errors. Perfect performance is evidence that the program is not doing what a person does.

5. Give two honest reasons for studying human cognition even if you only want to build systems. People are the only existing example of general intelligence, so their methods are evidence that breadth is achievable; and in tasks such as translation or recommendation the performance measure is defined by human acceptance, so people are part of the specification.

6. Rationality is always relative to something. To what? To the performance measure. Change the measure and the rational action can change, so the measure must be stated before any agent can be called rational.

7. Which of the four definitions of AI does this syllabus adopt, and give one piece of evidence from the syllabus itself. Acting rationally. The evidence is that the very next labels are agent architectures, search, logic and probability, all of which are means of choosing a good action, and none of which claims to model human thought.

Contents This chapter on its own page

munotes.in9

Chapter Three

The Agent and Its Environment

Syllabus topic Module 1, "Computational agents", "Environment interaction"

In one line

An agent is anything that senses its surroundings and acts on them, and it is completely described by one rule: which action it takes after each possible run of things it has sensed.

In the wording a student can write in an examination: an agent is an entity that perceives its environment through sensors and acts upon that environment through actuators. Its behaviour is described by the agent function, a mapping from every possible percept sequence to an action. The agent program is the concrete implementation of that function on some physical or computational architecture.

The five words, defined once

Everything else in Module 1 is built on these, so they are defined here and not redefined later.

  • Percept: what the agent senses at one instant. For a vacuum cleaner, the pair (which room am I in, is it dirty).
  • Percept sequence: the complete history of everything the agent has ever perceived. This is the widest possible record of what the agent could know.
  • Action: what the agent does at one instant. For the vacuum cleaner: Suck, Left, Right, NoOp.
  • Agent function: the mapping from percept sequence to action. It is the agent's behaviour, described from outside.
  • Agent program: the code that computes that mapping. The function is what; the program is how.

Sensors are how percepts arrive. Actuators are how actions take effect. An environment is everything outside the agent that its actions can change and its sensors can detect.

Why the percept sequence and not just the current percept

This is the distinction the whole row of architectures turns on, so it is settled now.

The agent function is defined on the whole history, not on the latest percept. That is deliberate: it is the most general possible description, and it lets the definition cover agents with memory. An agent that ignores its history is a special case, not the general one. The next five chapters are about which agents need history and which do not, and the answer decides how much machinery an agent must carry.

PEAS: how a task is specified

Before an agent can be built, the task has to be written down. The standard four-part specification is called PEAS, and MU's own labels assume it in every later row.

LetterStands forFor an automated taxi
PPerformance measuresafe, fast, legal, comfortable, profitable
EEnvironmentMumbai roads, traffic, pedestrians, weather, passengers
AActuatorssteering, accelerator, brake, indicator, horn, display
SSensorscameras, speedometer, GPS, accelerometer, microphone

Three more, briefly, because a question may ask for PEAS for any task:

TaskPEAS
Medical diagnosishealthy patient, low cost, no missed diseasepatient, staff, hospitalquestions, tests ordered, diagnosis, treatmentsymptoms typed in, test results
Spam filterfraction correctly classified, no good mail losta user's mailbox and mail streamlabel as spam, label as inbox, deletemessage text, headers, sender
Part-picking robotfraction of parts in the right binconveyor belt, bins, partsjointed arm, grippercamera, joint angle sensors
munotes.in10

The Agent and Its Environment

The performance measure is the whole game

This is the sentence to remember: an action is not right or wrong in itself, it is right or wrong against a stated measure. The measure is chosen by the designer, and choosing it badly is the commonest way a working system does the wrong thing.

Take the vacuum cleaner and measure it on amount of dirt sucked up in eight hours. That measure looks reasonable and it is a disaster. The highest-scoring agent sucks up the dirt, dumps it back on the floor, and sucks it up again. It maximises the measure exactly as instructed.

Now measure it on having a clean floor, say one point per clean square per time step, with a penalty for electricity used. The dump-and-resuck agent scores nothing extra for the second suck and pays for the power. The behaviour we actually wanted is now the winning behaviour.

The lesson generalises. A measure on outcomes in the world is safer than a measure on the agent's own activity, because the agent can always manufacture more of its own activity.

The agent function made literal

The definition says the function is a table from percept sequence to action. Written out, it looks like this. The vacuum world has two squares, A and B, and each is Clean or Dirty, so there are four possible percepts.

# A table on the LAST percept only. This is a reflex agent.
REFLEX = {
    ("A", "Dirty"): "Suck",
    ("A", "Clean"): "Right",
    ("B", "Dirty"): "Suck",
    ("B", "Clean"): "Left",
}

def reflex_agent(percept_sequence):
    return REFLEX[percept_sequence[-1]]

history = []
for percept in [("A", "Dirty"), ("A", "Clean"), ("B", "Dirty"), ("B", "Clean")]:
    history.append(percept)
    print("%-16s -> %s" % (str(percept), reflex_agent(history)))
('A', 'Dirty')   -> Suck
('A', 'Clean')   -> Right
('B', 'Dirty')   -> Suck
('B', 'Clean')   -> Left

Four rows, and that agent is completely specified. Now write the table the definition actually asks for, on the whole percept sequence, and count the rows.

# Rows needed for a table on the WHOLE percept sequence, up to T steps.
# 4 possible percepts, so 4**k sequences of length k.
def rows(T, percepts=4):
    return sum(percepts ** k for k in range(1, T + 1))

for T in (1, 2, 4, 10, 30):
    print("lifetime of %2d steps: %d rows" % (T, rows(T)))

print()
print("a taxi camera at 27 MB/s for one hour of video:")
bits = 27_000_000 * 8 * 3600
print("  %d bits of percept, so 2**%d possible histories" % (bits, bits))
munotes.in11

The Agent and Its Environment

lifetime of  1 steps: 4 rows
lifetime of  2 steps: 20 rows
lifetime of  4 steps: 340 rows
lifetime of 10 steps: 1398100 rows
lifetime of 30 steps: 1537228672809129300 rows

a taxi camera at 27 MB/s for one hour of video:
  777600000000 bits of percept, so 2**777600000000 possible histories

Read the second column. A vacuum cleaner that runs for thirty steps needs a table with more rows than there are seconds in fifty billion years. A taxi's table cannot be written down in this universe.

That is the whole justification for the rest of the paper. The agent function is the right definition of behaviour and the wrong implementation of it. Every technique in Module 1 and Module 2 is a way to COMPUTE the agent function instead of storing it: rules in the next chapter, search after that, logic, probability, and finally a learned model.

The interaction, step by step

An agent and its environment run in a loop, and the order matters.

  1. The environment is in some state.
  2. The agent's sensors produce a percept from that state.
  3. The agent program computes an action from the percept and whatever it has stored.
  4. The actuators apply the action, and the environment moves to a new state.
  5. The performance measure records something about the new state.
  6. Go to 1.

Here is that loop with a real environment on the other side of it, so the agent is not the only thing in the program.

REFLEX = {("A", "Dirty"): "Suck", ("A", "Clean"): "Right",
          ("B", "Dirty"): "Suck", ("B", "Clean"): "Left"}

world = {"A": "Dirty", "B": "Dirty"}   # the environment's state
at = "A"                               # where the agent is
score = 0

for step in range(1, 7):
    percept = (at, world[at])                    # 2. sensors
    action = REFLEX[percept]                     # 3. the agent program
    if action == "Suck":                         # 4. actuators change the world
        world[at] = "Clean"
    elif action == "Right":
        at = "B"
    elif action == "Left":
        at = "A"
    clean = sum(1 for sq in world.values() if sq == "Clean")
    score += clean                               # 5. the performance measure
    print("step %d  percept %-16s action %-6s world %s  clean %d  score %d"
          % (step, str(percept), action, world, clean, score))
step 1  percept ('A', 'Dirty')   action Suck   world {'A': 'Clean', 'B': 'Dirty'}  clean 1  score 1
step 2  percept ('A', 'Clean')   action Right  world {'A': 'Clean', 'B': 'Dirty'}  clean 1  score 2
step 3  percept ('B', 'Dirty')   action Suck   world {'A': 'Clean', 'B': 'Clean'}  clean 2  score 4
step 4  percept ('B', 'Clean')   action Left   world {'A': 'Clean', 'B': 'Clean'}  clean 2  score 6
step 5  percept ('A', 'Clean')   action Right  world {'A': 'Clean', 'B': 'Clean'}  clean 2  score 8
step 6  percept ('B', 'Clean')   action Left   world {'A': 'Clean', 'B': 'Clean'}  clean 2  score 10
munotes.in12

The Agent and Its Environment

Both squares are clean by step 3 and the score keeps rising, which is correct: the measure rewards a clean floor at every step. But look at steps 4 to 6. The agent is walking back and forth across a clean house forever, burning electricity for nothing. The measure did not penalise movement, so the agent has no reason to stop. Add a penalty of one point per move and the same agent becomes the wrong agent, and the next chapter's problem appears: it cannot stop, because with only the current percept it cannot tell "both clean" from "this one clean".

Agent, program and architecture

Three words that get used as though they were one.

What it isExample
Agent functionthe mapping, percept sequence to actionthe four-row table above, conceptually
Agent programthe code computing itreflex_agent, eleven lines
Architecturethe machine the program runs on, with its sensors and actuatorsthe vacuum cleaner, or the taxi and its cameras

Agent = architecture + program. The program cannot ask for an action the actuators cannot perform, and cannot use a percept the sensors do not produce. A program that says "turn left gently" is useless on a robot whose only steering is full lock.

What it does not mean

An agent is not a program with a personality. It is any system with sensors and actuators. A thermostat is an agent. So is a reflex arc.

The agent function is not the agent program. The function is behaviour described from outside; the program is the implementation. Two completely different programs can compute the same function.

A percept is not a fact about the world. It is what the sensors reported. Sensors are limited and can be wrong, which is exactly why Module 1's fourth row exists.

The performance measure is not inside the agent. It is imposed from outside, by the designer, and the agent is judged against it. An agent that scores itself will always score well.

Rationality does not mean the same action every time in the same room. It means the best expected action given the whole percept sequence, and two visits to the same room with different histories can rightly get different actions.

Quick revision

  • Agent: perceives through sensors, acts through actuators. Agent = architecture + program.
  • Percept, percept sequence, action, agent function (percept sequence to action), agent program (its implementation).
  • The function is defined on the whole history because that is the most general description and it covers agents with memory.
  • PEAS: Performance measure, Environment, Actuators, Sensors. Write all four before building anything.
  • The performance measure decides what "right" means. Measure outcomes in the world, not the agent's own activity, or the agent will manufacture activity.
  • A table for the agent function is correct and unbuildable: 4 percepts and 30 steps need over 1.5 quintillion rows. Everything else in this paper is a way to compute the function instead of storing it.
  • The loop: state, percept, action, new state, score, repeat.
munotes.in13

The Agent and Its Environment

Test yourself

1. Define an agent, the agent function and the agent program. An agent perceives its environment through sensors and acts on it through actuators. The agent function maps every possible percept sequence to an action, and describes the agent's behaviour from outside. The agent program is the code that computes that function on a particular architecture.

2. What does PEAS stand for, and give a PEAS specification for a spam filter. Performance measure, Environment, Actuators, Sensors. Performance: fraction of messages classified correctly, with a heavy penalty for losing a wanted message. Environment: a user's mailbox and incoming mail. Actuators: label as spam, label as inbox, delete. Sensors: message text, headers, sender address.

3. Why is the agent function defined on the percept sequence rather than the current percept? Because it is the most general description of behaviour and it covers agents that use memory. An agent that depends only on the current percept is a special case of it.

4. A vacuum cleaner is scored on dirt collected per hour. What behaviour does that reward, and what is the fix? It rewards dumping collected dirt back on the floor and collecting it again, because that maximises dirt collected. The fix is to measure the state of the world, a clean floor at each time step, with a penalty for energy used.

5. How many rows would a table-driven agent function need in a world with four possible percepts and a lifetime of ten steps? The sum of 4 to the power k for k from 1 to 10, which is 1,398,100 rows. The program in this chapter computes it.

6. Distinguish a percept from a fact about the environment. A percept is what the sensors reported at an instant; a fact is how the world actually is. Sensors are partial and can be wrong, so the two can differ, which is the whole reason for reasoning under uncertainty.

7. Two students write completely different programs and the two agents behave identically in every situation. Have they implemented the same agent function? Yes. The agent function is the mapping from percept sequences to actions; identical behaviour in every situation is the same mapping. They have implemented the same function with different programs.

Contents This chapter on its own page

munotes.in14

Chapter Four

Types of Environment

Syllabus topic Module 1, "Types of environments"

In one line

Environments differ in ways that change what an agent has to be able to do, and there are seven standard questions to ask about any one of them.

In the wording a student can write in an examination: a task environment is classified along seven dimensions: fully or partially observable, single agent or multi agent, deterministic or stochastic, episodic or sequential, static or dynamic, discrete or continuous, and known or unknown. The classification determines which agent architecture is adequate, because each dimension rules out a simpler design.

Why classify at all

An agent design is only adequate relative to an environment. A design that works perfectly in one is useless in another, and the seven questions are how you find out which you are in before writing any code. The hardest case on every dimension is the real world, which is why the automated taxi is the standing example of a difficult task.

1. Fully observable or partially observable

Fully observable: the agent's sensors give it the complete state of the environment at each instant, so far as anything relevant to its choice of action is concerned.

Partially observable: they do not. Something relevant is hidden, either because the sensors are limited, because they are noisy, or because part of the state is somewhere else.

  • Fully observable: chess with a board in view, a crossword, the vacuum world if the agent can see both squares.
  • Partially observable: the vacuum world with a local dirt sensor only, poker, driving (you cannot see what is behind the lorry), medical diagnosis.
  • Unobservable: a special case with no sensors at all. Such an agent can still act sensibly if the world is predictable enough.

Consequence for the agent. A partially observable environment forces the agent to keep internal state, because the current percept does not determine the right action. That is exactly the step from the simple reflex agent to the model-based one, two chapters from now.

2. Single agent or multi agent

Single agent: the agent is the only decision maker. Everything else is part of the environment.

Multi agent: another entity is also choosing, and its choices depend on what our agent does.

The test is not whether other things move; it is whether their behaviour is best described as maximising a performance measure that depends on ours. A falling stone is part of the environment. A taxi in the next lane is another agent, because it will brake if you pull in front of it.

Multi agent splits in two:

  • Competitive: one agent's gain is another's loss. Chess. This is where Module 1's Adversarial search row comes from.
  • Cooperative: the measures agree at least partly. Two taxis both wanting to avoid a collision.
munotes.in15

Types of Environment

Consequence for the agent. In a competitive setting the agent must reason about what the other will do, which is minimax. It may also become rational to behave randomly, to stop the opponent predicting you, which never pays in a single agent setting.

3. Deterministic or stochastic

Deterministic: the next state is fixed completely by the current state and the action taken.

Stochastic: it is not. The same action in the same state can lead to different next states, and the agent can at best have probabilities.

  • Deterministic: chess, the 8-puzzle, the vacuum world as defined in the last chapter.
  • Stochastic: driving (a tyre may burst), a robot's wheels slipping, any system with real sensors.

"Nondeterministic" is a third word and is not a synonym for stochastic. A nondeterministic environment has several possible outcomes but attaches no probabilities to them, so the agent has to succeed whatever happens. A stochastic one attaches probabilities, so the agent can maximise an expectation.

Consequence for the agent. Determinism is what makes a plan a sequence of actions. Once the environment is stochastic, a plan has to be a policy: what to do in each state that might arise. That is the whole of Module 2's Markov Decision Processes.

4. Episodic or sequential

Episodic: the agent's experience divides into independent episodes. The action taken in one episode has no effect on the next.

Sequential: the current decision affects all future decisions.

  • Episodic: classifying a part on a conveyor belt; answering an exam question that stands alone; a spam filter judging one message.
  • Sequential: chess, driving, a game of any kind, a course of medical treatment.

Consequence for the agent. In an episodic environment the agent need not think ahead at all, which makes it much easier. Almost all of Module 2's supervised learning is episodic: each prediction stands alone. Almost all of Module 1 is sequential, which is why it is full of search.

5. Static or dynamic

Static: the environment does not change while the agent is deciding.

Dynamic: it does, so time spent thinking is time in which the world moved.

Semidynamic: the environment is static but the agent's SCORE changes with time. Chess with a clock is the standard example: the board does not move while you think, but your remaining time does.

  • Static: a crossword, an offline puzzle.
  • Dynamic: driving, a robot in a room with people in it.
  • Semidynamic: timed chess.

Consequence for the agent. In a dynamic environment the agent must act on incomplete deliberation, so an anytime algorithm that can give its best answer so far matters more than an optimal one that takes too long. This is the practical reason the search chapters report time complexity rather than only correctness.

munotes.in16

Types of Environment

6. Discrete or continuous

The distinction applies separately to the state, to time, and to the percepts and actions, and a question may ask about any of them.

  • Discrete state and time: chess. Finitely many board positions, moves at distinct instants.
  • Continuous state and time: driving. Position and speed are real numbers changing smoothly, and steering is a continuous action.
  • Mixed: a camera is a discrete sensor sampling a continuous world, and what it delivers is a grid of integers.

Consequence for the agent. Every search algorithm in Module 1 assumes a discrete state space with a finite set of actions at each state. A continuous problem has to be discretised before those algorithms apply, and the discretisation is a design decision that can make the problem easy or impossible.

7. Known or unknown

This is not the same as observable, and mixing the two is the commonest mistake on this topic.

Known: the agent knows the rules. It knows what its actions do, and in a stochastic environment it knows the probabilities.

Unknown: it does not, and it must learn them.

Observability is about the state; knownness is about the laws. All four combinations exist:

KnownUnknown
Fully observablechess: you see the board and know the rulesa new video game with the board on screen and no manual
Partially observablepoker: hidden cards, known rulesdriving in an unfamiliar country at night

Consequence for the agent. An unknown environment is the reason learning exists. It is also the difference between Module 2's Markov Decision Processes, where the model is known and the answer can be computed, and Q-Learning, where it is not and the agent has to find out by acting.

The classification, done

This table is the answer to "classify the following environment", and the six columns are the ones papers use.

Chess with a clockThe 8-puzzleDriving a taxiMedical diagnosisSpam filterPart-picking robot
Observablefullyfullypartiallypartiallyfullypartially
Agentsmultisinglemultisinglesinglesingle
Deterministicdeterministicdeterministicstochasticstochasticdeterministicstochastic
Episodicsequentialsequentialsequentialsequentialepisodicepisodic
Staticsemidynamicstaticdynamicdynamicstaticdynamic
Discretediscretediscretecontinuouscontinuousdiscretecontinuous
Knownknownknownknownunknownunknownknown

Two entries in that table are worth defending, because a marker may disagree and a student should be able to argue.

Spam filter, fully observable. The message is entirely available to the filter; nothing about it is hidden. What is hidden is the sender's INTENTION, but intention is not part of the environment state the filter acts on. Some texts call it partially observable for that reason; say which you mean.

munotes.in17

Types of Environment

Part-picking robot, episodic. Each part is judged on its own and the bin it goes in does not change how the next part should be judged. If the bins can overflow, it becomes sequential.

The hardest case

The worst case on every dimension at once is partially observable, multi agent, stochastic, sequential, dynamic, continuous and unknown. That is driving in a city you have never visited. It is why the automated taxi is used as the running example of a hard task, and why no algorithm in this paper solves it on its own.

Distinctions

Partially observableUnknown
What is missingpart of the current statethe rules of the environment
The fixkeep internal state, and reason under uncertaintylearn from experience
Examplepokera game whose rules you have not been told
Where on this syllabusmodel-based agents, Bayesian networksthe whole of Module 2
StochasticNondeterministic
Outcomesseveral, with probabilitiesseveral, with no probabilities
The agent aims atthe best expectationsuccess whatever happens
Needsa probability modela plan for every contingency
EpisodicSequential
This decision affects later onesnoyes
Lookahead needednoneyes
Typical ofclassificationgames, planning, control

What it does not mean

Fully observable does not mean simple. Chess is fully observable and unsolved.

Deterministic does not mean predictable by the agent. A deterministic environment the agent does not understand is effectively unpredictable to it, which is why "known" is a separate dimension.

Multi agent does not mean many moving objects. It means another entity is choosing, and its choice responds to yours.

Dynamic does not mean fast. It means the state changes while the agent deliberates, however slowly.

Continuous does not mean infinite state only. Time can be continuous while the state is discrete, and the dimensions are asked separately.

Quick revision

  • Seven dimensions: observable (fully or partially), agents (single or multi), deterministic or stochastic, episodic or sequential, static or dynamic, discrete or continuous, known or unknown.
  • Partially observable forces internal state. Stochastic forces a policy instead of a plan. Sequential forces lookahead. Dynamic forces acting on incomplete deliberation. Continuous forces discretisation. Unknown forces learning. Multi agent forces reasoning about the other, and can make randomising rational.
  • Semidynamic: the world is still but the score moves, as in timed chess.
  • Nondeterministic is not stochastic: outcomes without probabilities, so the agent must cover every case.
  • Observable is about the state; known is about the rules. All four combinations occur.
  • Hardest case, and the standing example: partially observable, multi agent, stochastic, sequential, dynamic, continuous, unknown.
munotes.in18

Types of Environment

Test yourself

1. List the seven dimensions on which a task environment is classified. Fully or partially observable; single or multi agent; deterministic or stochastic; episodic or sequential; static or dynamic; discrete or continuous; known or unknown.

2. Classify the environment of a taxi driving in Mumbai. Partially observable, multi agent, stochastic, sequential, dynamic, continuous and, for an unfamiliar city, unknown. It is the hardest case on every dimension.

3. Distinguish a partially observable environment from an unknown one. Partially observable means part of the current state is hidden from the sensors; unknown means the agent does not know the laws by which the environment behaves. One is fixed by keeping state and reasoning under uncertainty, the other by learning.

4. What is a semidynamic environment? Give an example. One in which the environment itself does not change while the agent deliberates, but the agent's performance score does. Chess played with a clock: the board is still, your remaining time is not.

5. Why does a partially observable environment force an agent to keep internal state? Because the current percept no longer determines the right action, so two situations needing different actions can look identical. The only way to tell them apart is to remember what came before.

6. Is a stone falling towards a robot another agent? No. Its behaviour is not usefully described as maximising a measure that depends on the robot's choices, so it is part of the environment. A second robot that would swerve to avoid a collision is another agent.

7. Which dimension is the reason the whole of Module 2 exists, and why? Known or unknown. If the agent already knew the environment's laws and the right answers, it would need no experience. Learning is the response to not knowing.

Contents This chapter on its own page

munotes.in19

Chapter Five

The Simple Reflex Agent

Syllabus topic Module 1, "simple reflex"

In one line

A simple reflex agent looks at what it can see right now and applies a rule; it remembers nothing at all.

In the wording a student can write in an examination: a simple reflex agent selects its action using only the current percept, ignoring the rest of the percept history. It is implemented as a set of condition-action rules of the form IF condition THEN action, where the condition is a test on the current percept.

Why the simplest architecture is worth a chapter

Two reasons, and both matter.

It is the design you get for free when the environment is fully observable, and in that case it is not a compromise but the correct answer. A thermostat is a simple reflex agent and there is nothing wrong with it.

And it is the design everybody reaches for by accident. Its two failure modes are the two commonest bugs in agent programs, so a student who can name them can also recognise them in their own code.

The form

A rule has a condition on the percept and an action.

if condition holds of the current percept:
    do this action

The whole agent is a set of such rules plus a way of choosing between the ones that match. That is it: no memory, no model, no goal, no numbers.

Written out for the vacuum world, where a percept is (which square am I in, is it dirty):

Condition, the current perceptAction
A is dirtySuck
A is cleanRight
B is dirtySuck
B is cleanLeft

Four rules. The whole agent function, complete, on one hand.

It running

The performance measure is one point per clean square per step, minus one point for each move, because electricity costs something. Both squares start dirty and the agent starts in A.

# A simple reflex agent: the action depends on the CURRENT percept alone.
RULES = {("A", "Dirty"): "Suck", ("A", "Clean"): "Right",
         ("B", "Dirty"): "Suck", ("B", "Clean"): "Left"}

def simple_reflex_agent(percept):
    return RULES[percept]

world, at, score = {"A": "Dirty", "B": "Dirty"}, "A", 0
for step in range(1, 9):
    percept = (at, world[at])
    action = simple_reflex_agent(percept)
    if action == "Suck":
        world[at] = "Clean"
    elif action == "Right":
        at = "B"
    elif action == "Left":
        at = "A"
    score += sum(1 for v in world.values() if v == "Clean")
    if action in ("Left", "Right"):
        score -= 1                      # one point for the electricity
    print("step %d  %-16s %-6s  A=%-5s B=%-5s  score %d"
          % (step, str(percept), action, world["A"], world["B"], score))
step 1  ('A', 'Dirty')   Suck    A=Clean B=Dirty  score 1
step 2  ('A', 'Clean')   Right   A=Clean B=Dirty  score 1
step 3  ('B', 'Dirty')   Suck    A=Clean B=Clean  score 3
step 4  ('B', 'Clean')   Left    A=Clean B=Clean  score 4
step 5  ('A', 'Clean')   Right   A=Clean B=Clean  score 5
step 6  ('B', 'Clean')   Left    A=Clean B=Clean  score 6
step 7  ('A', 'Clean')   Right   A=Clean B=Clean  score 7
step 8  ('B', 'Clean')   Left    A=Clean B=Clean  score 8
munotes.in20

The Simple Reflex Agent

The first three steps are perfect. The house is clean by step 3 and there is nothing left to do.

Read steps 4 to 8. The agent walks from B to A to B to A forever, paying a point each time. It cannot stop, and the reason is exactly the architecture: at step 4 its percept is (B, Clean), and the rule for (B, Clean) says Left. It has no way to know that A is also clean, because knowing that would mean remembering step 1, and it remembers nothing.

Final score after eight steps: 8. The next chapter runs the same world with a model and scores 13.

Failure one: it cannot act in a partially observable environment

This is the general statement of what just happened. If two different situations produce the same percept but require different actions, a simple reflex agent must get one of them wrong. It has one rule per percept and the two situations share a percept, so they share the rule.

In the vacuum world, (B, Clean) arises in two situations: A is dirty, so move; and A is clean, so stop. One percept, two right answers, and only one rule available.

This is not a defect in the rules and no better rule table fixes it. It is a limit of the architecture. The information needed is not in the percept, so no function of the percept can produce it.

Failure two: infinite loops

A simple reflex agent in a deterministic environment that returns to an identical percept will repeat exactly what it did last time, and so go round forever. The run above is the whole demonstration: (B, Clean) to Left to (A, Clean) to Right to (B, Clean).

There is one standard escape and it is worth knowing: randomise. A rule that says "if the square is clean, move in a randomly chosen direction" breaks the cycle, because the agent no longer does the same thing at the same percept. In the two-square vacuum world a randomising reflex agent will visit both squares eventually. This is the single case in Module 1 where a random choice is the rational choice, and it happens for the same reason as in a competitive game: predictability is the weakness.

Randomising is a patch and not a cure. It escapes the loop; it still cannot tell the two situations apart, so it still cannot decide to stop.

munotes.in21

The Simple Reflex Agent

Where this architecture is the right answer

A simple reflex agent is adequate, and preferable, when the environment is fully observable, so nothing relevant is hidden; and either episodic or such that each percept determines the right action.

Real examples: a thermostat, a lift's door sensor, a traffic light on a timer with a vehicle detector, the collision reflex in a robot vacuum, and a spam filter that judges each message only on the message. Nobody should put a world model in a thermostat.

Distinctions

Simple reflex agentTable-driven agent
Input to the decisionthe current perceptthe whole percept sequence
Sizeone entry per percept, tinyone entry per sequence, unbuildable
Can it use historynoyes, in principle
Practicalyesno
Simple reflexModel-based reflex
Keeps internal statenoyes
Works when partially observablenoyes
Can detect it is finishednoyes
Score in this chapter's world813
Needscondition-action rulesrules, plus a transition model and a sensor model

What it does not mean

"Simple" is not an insult and not a synonym for bad. For a fully observable task it is the correct design and the cheapest.

It is not the same as the table-driven agent. The table-driven agent is indexed by the whole percept sequence and is unbuildable; the reflex agent is indexed by the current percept and is tiny. Confusing the two is the commonest error on this topic.

It has no memory of any kind, not even of its own last action. If it seems to remember, something has been added and it is no longer this architecture.

It is not stateless in the programming sense only. The rules themselves are knowledge, put there by the designer. What it lacks is state that changes as it runs.

Randomising does not make it partially observable capable. It escapes loops and nothing more.

Quick revision

  • Simple reflex agent: action from the current percept only, by condition-action rules, IF condition THEN action.
  • Complete for the vacuum world in four rules.
  • Failure one: two situations with the same percept needing different actions cannot both be handled. It fails whenever the environment is partially observable.
  • Failure two: in a deterministic environment it can loop forever, because the same percept always produces the same action.
  • The escape from loops is to randomise the choice. It is a patch: it breaks cycles, it does not add knowledge.
  • Correct design when the environment is fully observable and the current percept determines the right action: thermostats, door sensors, per-message spam filters.
  • On this chapter's world it scores 8; the model-based agent scores 13 on the same world, and the difference is that it can stop.
munotes.in22

The Simple Reflex Agent

Test yourself

1. Define a simple reflex agent and give the general form of its rules. An agent that chooses its action from the current percept alone, ignoring history. Its rules have the form IF condition on the current percept THEN action.

2. Write the complete rule set for the two-square vacuum world. If A is dirty, Suck. If A is clean, move Right. If B is dirty, Suck. If B is clean, move Left.

3. Name the two failure modes and give an example of each. It cannot act correctly in a partially observable environment: the percept (B, Clean) arises both when A is dirty and when A is clean, and those need different actions. And it can loop forever: in the same world it moves Left, Right, Left, Right endlessly once both squares are clean.

4. Why can no better set of rules fix the first failure? Because a rule is a function of the percept, and the information needed to distinguish the two situations is not in the percept. No function of the percept can recover it.

5. What is the standard escape from an infinite loop, and what does it not fix? Randomising the action at the repeating percept, which breaks the cycle because the agent no longer does the same thing every time. It does not give the agent the missing information, so it still cannot tell that the work is finished.

6. Give three real systems for which this architecture is the right choice, and say what they have in common. A thermostat, a lift door sensor, a spam filter judging one message. In each case the environment is fully observable for the purposes of the decision, and the current percept determines the correct action.

7. A student says a simple reflex agent has no knowledge. Correct them. It has the knowledge its designer put into the rules, which can be substantial. What it lacks is internal state that changes as it runs, so it cannot accumulate knowledge from experience.

Contents This chapter on its own page

munotes.in23

Chapter Six

The Model-Based Reflex Agent

Syllabus topic Module 1, "model-based"

In one line

A model-based agent keeps a picture of the world in its head, updates it after every percept and every action, and decides from the picture instead of from the percept.

In the wording a student can write in an examination: a model-based reflex agent maintains internal state, a representation of the aspects of the world that its percepts do not reveal. The state is updated using two pieces of knowledge: a transition model, which says how the world changes, including as a result of the agent's own actions; and a sensor model, which says how the state of the world is reflected in the percepts. The agent then applies condition-action rules to the updated state rather than to the raw percept.

Why internal state is the fix

The previous chapter established the problem exactly: two situations can produce the same percept and need different actions. If the information is not in the percept, the only other place it can come from is the past, and using the past means keeping something.

The agent does not keep the whole percept history. That is the table-driven agent and it is unbuildable. It keeps a summary of the history that is sufficient for the decision, and working out what that summary must contain is the design problem.

For the vacuum world the summary is small: what do I believe about the square I am not standing in. Two extra facts, and the agent becomes able to finish.

The two models

The state is updated from two sources and both have a name. Getting the names the right way round is worth marks.

Transition modelSensor model
Answershow does the world changehow does the world show up in a percept
Coversthe effects of my own actions, and changes I did not causewhat my sensors report, given the state
In the vacuum worldsucking makes this square clean; nothing else changes on its ownI see the square I am in and its dirt, and nothing about the other square
Later in this bookthe transition function of an MDP, chapter 79the emission matrix of an HMM, chapter 72

The update loop

Four steps, run in this order, every time round.

  1. Predict: apply the transition model for the action just taken, to get the state the world should now be in.
  2. Update from the percept: apply the sensor model in reverse, using what was actually perceived to correct or sharpen the predicted state.
  3. Decide: apply the rules to the state.
  4. Act, and remember what action was taken, because step 1 next time needs it.
munotes.in24

The Model-Based Reflex Agent

It running, on the same world

Both squares dirty, agent starts in A, one point per clean square per step, minus one per move. Identical to the previous chapter in every respect except the agent.

# A model-based reflex agent: it keeps a MODEL of the parts it cannot see.
class ModelBasedAgent:
    def __init__(self):
        self.model = {"A": "unknown", "B": "unknown"}

    def __call__(self, percept):
        here, dirt = percept
        self.model[here] = dirt                       # update state from percept
        if dirt == "Dirty":
            self.model[here] = "Clean"                # and from the action's effect
            return "Suck"
        other = "B" if here == "A" else "A"
        if self.model[other] == "Clean":
            return "NoOp"                             # nothing left to do: STOP
        return "Right" if here == "A" else "Left"

agent = ModelBasedAgent()
world, at, score = {"A": "Dirty", "B": "Dirty"}, "A", 0
for step in range(1, 9):
    percept = (at, world[at])
    action = agent(percept)
    if action == "Suck":
        world[at] = "Clean"
    elif action == "Right":
        at = "B"
    elif action == "Left":
        at = "A"
    score += sum(1 for v in world.values() if v == "Clean")
    if action in ("Left", "Right"):
        score -= 1
    print("step %d  %-16s %-6s  model %-36s  score %d"
          % (step, str(percept), action, str(agent.model), score))
step 1  ('A', 'Dirty')   Suck    model {'A': 'Clean', 'B': 'unknown'}        score 1
step 2  ('A', 'Clean')   Right   model {'A': 'Clean', 'B': 'unknown'}        score 1
step 3  ('B', 'Dirty')   Suck    model {'A': 'Clean', 'B': 'Clean'}          score 3
step 4  ('B', 'Clean')   NoOp    model {'A': 'Clean', 'B': 'Clean'}          score 5
step 5  ('B', 'Clean')   NoOp    model {'A': 'Clean', 'B': 'Clean'}          score 7
step 6  ('B', 'Clean')   NoOp    model {'A': 'Clean', 'B': 'Clean'}          score 9
step 7  ('B', 'Clean')   NoOp    model {'A': 'Clean', 'B': 'Clean'}          score 11
step 8  ('B', 'Clean')   NoOp    model {'A': 'Clean', 'B': 'Clean'}          score 13

Watch the model column, which is the agent's belief and not the world.

  • Step 1: it is in A and sees Dirty. It records Dirty, decides to Suck, and immediately records Clean because it knows what sucking does. That is the transition model in one line.
  • Step 2: the percept (A, Clean) is now not enough on its own, and it does not need to be. The model says B is unknown, so there is work to do and it moves right.
  • Step 3: B is dirty. Suck, and record it.
  • Step 4: the percept is (B, Clean), the identical percept that made the simple reflex agent move. This agent looks at its model, sees A recorded as Clean, and returns NoOp. It has worked out that it is finished.
  • Steps 5 to 8: NoOp, costing nothing, scoring 2 every step.

Final score 13, against the simple reflex agent's 8 on the same world. The whole difference is that it can stop, and it can stop because it remembered.

munotes.in25

The Model-Based Reflex Agent

What "unknown" is doing in the model

The initial model is not "both clean" or "both dirty". It is unknown, and that is the honest representation of an agent that has just been switched on. It matters twice.

It stops the agent concluding it is finished before it has looked. If the model started at Clean for both, step 1 would have sucked and step 2 would have returned NoOp with B still filthy.

And it is the first appearance of a theme that runs to the end of the book: an agent's state is a belief, not a fact, and the honest thing to store is what it actually knows. In Module 1's fourth row that belief becomes a probability distribution; in Module 2 it becomes a fitted model. The structure is the same.

Where the model can be wrong

A model-based agent acts on its belief, so a wrong belief produces a wrong action, confidently.

  • The world changed and the agent did not see it. Somebody drops dirt in A at step 5. The model still says Clean and the agent sits doing NoOp on a dirty floor. This is what makes a dynamic environment hard.
  • The action did not do what the model says. Sucking fails one time in five. The model records Clean, the square is dirty. This is a stochastic environment, and the fix is not a better model of this kind but a probabilistic one.
  • The sensors were wrong. The dirt sensor misreports. Then even the directly perceived part of the model is unreliable.

None of these is an argument against keeping a model. They are the argument for keeping a model with probabilities in it, which is Module 1's fourth row, and for learning the model instead of being given it, which is Module 2.

The vocabulary, because two pairs get confused

WordMeansNot to be confused with
Internal statewhat the agent has stored about the worldthe state of the environment, which is the real thing
Belief statethe agent's internal state when it may be uncertainthe true state
Transition modelhow the world changesthe sensor model
Sensor modelhow the world shows in perceptsthe transition model

Distinctions

Simple reflexModel-based reflex
Decides fromthe current perceptinternal state, updated from the percept
Internal statenoneyes
Needscondition-action rulesrules, a transition model and a sensor model
Partially observablefailsworks
Can it tell that it is finishednoyes
Score on this chapter's world813
Model-based reflexGoal-based
Knows where it isyesyes
Knows where it wants to beno, only what to do nextyes, explicitly
If the goal changesthe rules must be rewrittenthe goal is changed and the rest stands
Considers action sequencesnoyes, which is search
munotes.in26

The Model-Based Reflex Agent

What it does not mean

The model is not the world. It is what the agent believes. A chapter that blurs the two makes every later error in this book invisible.

It does not store the percept history. It stores a summary sufficient for the decision. Storing the history would be the table-driven agent.

It is still a reflex agent. The final step is still a rule applied to a situation. What changed is that the situation is now the internal state and not the raw percept, which is why the name keeps the word "reflex".

A model does not make the agent correct. It makes it correct as long as the model is. A stale or wrong model produces confident wrong actions.

"Unknown" is not the same as "clean". Initialising a model to a definite value the agent has not observed is a bug, and it is the specific bug that would make this agent stop before it started.

Quick revision

  • Model-based reflex agent: keeps internal state, updates it from a transition model (how the world changes, including by its own actions) and a sensor model (how the world appears in percepts), then applies rules to the state.
  • The update loop: predict from the last action, correct from the percept, decide, act and remember.
  • It solves the simple reflex agent's first failure, because the missing information now comes from the past instead of from the percept.
  • On the same vacuum world it scores 13 against the simple reflex agent's 8, and the difference is that it returns NoOp at step 4.
  • The state must start as unknown, not as a guessed value.
  • It fails when the world changes unseen, when an action does not do what the model says, or when the sensors lie. Those three failures are the reason for probability in Module 1 and learning in Module 2.
  • It is still reflex: a rule applied to a situation. Only the situation changed.

Test yourself

1. Define a model-based reflex agent. An agent that maintains internal state representing the parts of the world its percepts do not reveal, updates that state using a transition model and a sensor model, and then applies condition-action rules to the state rather than to the percept.

2. What is the transition model, and what is the sensor model? The transition model says how the world changes, including as a result of the agent's own actions. The sensor model says how the state of the world is reflected in what the sensors report.

munotes.in27

The Model-Based Reflex Agent

3. In this chapter's run, why does step 4 return NoOp when the simple reflex agent moved Left? Both see the percept (B, Clean). The model-based agent also has A recorded as Clean in its internal state, so it can conclude that nothing is left to do. The simple reflex agent has only the percept, which does not contain that fact.

4. Why is the model initialised to "unknown" rather than to "clean"? Because the agent has observed nothing yet. If it began by believing both squares clean, it would return NoOp after cleaning the first square and leave the second dirty.

5. Give three ways the model can become wrong, and name the environment property responsible in each case. The world changes without the agent seeing it, which is a dynamic environment. An action fails to have its expected effect, which is a stochastic environment. The sensors misreport, which is noise and makes even the perceived part unreliable.

6. Is a model-based agent still a reflex agent? Justify. Yes. Its final step is a condition-action rule applied to a situation, with no consideration of goals or of action sequences. What changed is that the situation is the internal state, not the raw percept.

7. Distinguish internal state from the state of the environment. The state of the environment is how the world actually is. Internal state is what the agent has stored about it, which may be incomplete, stale or wrong. The agent acts on the second and is judged on the first.

Contents This chapter on its own page

munotes.in28

Chapter Seven

The Goal-Based Agent

Syllabus topic Module 1, "goal-based"

In one line

A goal-based agent is told what it is trying to achieve rather than what to do, so it has to work out for itself which actions get it there.

In the wording a student can write in an examination: a goal-based agent holds an explicit representation of a goal, a description of a desirable state of the world. Instead of applying rules to the current situation, it considers the consequences of sequences of actions, using its model of how the world changes, and selects a sequence that reaches a goal state. The process of finding such a sequence is search, and if the actions are described symbolically it is planning.

Why a rule is not enough

The model-based agent of the last chapter works, and its rules encode a strategy: if this square is dirty, suck; if the other is not known clean, go there; otherwise stop. That strategy was worked out by the designer and written into the rules.

Now change the task. Suppose the requirement becomes "get both squares clean and end up in square A", because the charging point is there. Every rule has to be rewritten. Suppose it becomes "clean only square B". Rewritten again. The agent has no representation of what it is for, so it cannot adapt to a change in what it is for.

A goal-based agent separates two things a reflex agent fuses: what I want and how to get it. Change the goal, and the machinery that finds the route is untouched.

The three parts

PartWhat it isIn the vacuum world
The current statewhere the agent believes it is now(in A, A dirty, B dirty)
The transition modelwhat each action does to a stateSuck cleans this square, Right moves to B, Left moves to A
The goal testa test that says whether a state is good enoughboth squares Clean

Given those three, the agent can generate states it has never been in, look at them, and ask the goal test. That is the whole idea, and it is the reason the model-based agent's transition model was introduced first: a goal-based agent cannot work without one.

It running: the plan is found, not given

The program below is given the start state, the effect of each action and the goal test. It is not given the answer. It tries every sequence of length 1, then every sequence of length 2, and so on, and stops at the first that satisfies the goal test.

# A goal-based agent: it searches action SEQUENCES for one that reaches the goal.
from itertools import product

def result(state, action):
    at, a, b = state
    if action == "Suck":
        return (at, "Clean", b) if at == "A" else (at, a, "Clean")
    if action == "Right":
        return ("B", a, b)
    if action == "Left":
        return ("A", a, b)
    return state

def is_goal(state):
    return state[1] == "Clean" and state[2] == "Clean"

start = ("A", "Dirty", "Dirty")
ACTIONS = ("Suck", "Left", "Right")

for length in range(1, 5):
    for plan in product(ACTIONS, repeat=length):
        state = start
        for action in plan:
            state = result(state, action)
        if is_goal(state):
            print("shortest plan found, length %d: %s" % (length, " then ".join(plan)))
            print("start %s  ->  end %s" % (str(start), str(state)))
            raise SystemExit
munotes.in29

The Goal-Based Agent

shortest plan found, length 3: Suck then Right then Suck
start ('A', 'Dirty', 'Dirty')  ->  end ('B', 'Clean', 'Clean')

Three things are worth noticing, and each one is a later chapter.

The plan was found by trying things. Nobody told the agent that sucking first was a good idea. It generated sequences and tested them. That is search in its crudest form.

It found the SHORTEST plan, because it tried short ones first. That is not an accident of this program, it is a property of searching by increasing depth, and it is the whole subject of Breadth First Search and Iterative Deepening Search.

It is wildly wasteful. With three actions, trying all sequences up to length 4 means 3 + 9 + 27 + 81 = 120 sequences, on a problem with only eight states. The rest of MU's second row is about not being this wasteful: keeping track of states already seen, expanding the most promising node first, and using an estimate of how far is left.

Changing the goal changes nothing else

Here is the payoff. To make the goal "both clean and back in A", one line changes:

def is_goal(state):
    return state[0] == "A" and state[1] == "Clean" and state[2] == "Clean"

The transition model, the action list and the search are untouched. A reflex agent would have needed every rule rewritten. That separation is what a goal buys, and it is why goal-based design is where anything resembling flexible behaviour begins.

What a goal cannot do

A goal is binary: a state either satisfies it or it does not. Three consequences follow, and all three are the argument for the next chapter.

It cannot choose between two plans that both succeed. In the run above, Suck then Right then Suck reaches the goal and so does Right then Suck then Left then Suck. The first is shorter and cheaper. The goal test cannot see the difference, because both end in a goal state.

It cannot trade off conflicting goals. Get there quickly and get there safely are both goals, and they disagree. A binary test cannot say how much speed is worth how much risk.

munotes.in30

The Goal-Based Agent

It cannot cope with a goal that cannot be reached with certainty. If sucking works only four times in five, no plan guarantees a clean house. A goal test asks whether the state is good; it has no way to say a 92 per cent chance is better than a 64 per cent chance.

Each of those needs a number on outcomes rather than a yes or no, and a number on outcomes is a utility function.

Goals, and the word planning

MU's third row names Planning basics (STRIPS concept), and this is where the connection is made once so it need not be repeated.

Search and planning are the same activity described at two levels. In search, states are opaque: the algorithm knows only that one state differs from another and that the goal test accepts some of them. In planning, a state is a set of facts and an action says which facts it requires and which it changes. That structure lets a planner reason about a problem far too large to enumerate. Planning and STRIPS is that chapter; the vacuum plan found above is the same idea with the structure thrown away.

Distinctions

Model-based reflexGoal-based
Represents what it wantsnoyes, explicitly
Decides bya rule on the current stateconsidering sequences of actions
If the objective changesrewrite the ruleschange the goal, keep everything else
Needs a transition modelyes, to track stateyes, to imagine unvisited states
Can compare two successful plansnot applicableno, both simply succeed
GoalUtility
Value of a stateyes or noa number
Can rank two successesnoyes
Handles conflicting objectivesnoyes, by trading them off
Handles uncertaintyno, only certainty of reaching the goalyes, by expected value

What it does not mean

A goal-based agent is not slower than a reflex agent by nature. It does more work per decision, but it can also plan once and then execute. The cost is deliberation, not motion.

Having a goal is not the same as having a plan. The goal is the destination; the plan is the route, and finding it is the work.

The goal test is not a rule. A rule says what to do; the goal test says whether a state is acceptable and says nothing about how to get there.

"Goal-based" does not mean one goal. A goal is a set of acceptable states, which may be described by several conditions. What it cannot do is rank the acceptable ones.

Search is not a synonym for trial and error in the real world. The agent tries sequences in its model, not in the environment. Nothing is sucked while the plan is being found, which is exactly why a transition model is needed.

munotes.in31

The Goal-Based Agent

Quick revision

  • Goal-based agent: holds an explicit goal, a description of desirable states, and finds a sequence of actions reaching one, using its transition model. Finding the sequence is search; with structured states and actions it is planning.
  • Three parts: current state, transition model, goal test.
  • What it buys: the objective is separated from the method, so changing the goal leaves the search machinery untouched.
  • On the vacuum world the shortest plan is Suck then Right then Suck, found by trying sequences in increasing length.
  • Trying all sequences up to length 4 costs 120 of them on an eight-state problem. Module 1's second row is about doing better.
  • What a goal cannot do: rank two plans that both succeed, trade off conflicting objectives, or prefer a higher chance of success. All three need a number on outcomes.
  • Search and planning are the same activity: planning is search with states as sets of facts.

Test yourself

1. Define a goal-based agent. An agent holding an explicit representation of a goal, a description of desirable states of the world, which chooses its actions by considering the consequences of sequences of actions under its transition model and selecting a sequence that reaches a goal state.

2. What three components does it need? A representation of the current state, a transition model saying what each action does, and a goal test saying whether a state is acceptable.

3. Why does having a goal force the agent to consider sequences rather than single actions? Because a goal is generally not reachable in one action. To tell whether an action is useful the agent must ask where it leads, and that means evaluating what follows it.

4. What is the shortest plan for the two-square vacuum world starting dirty in A, and how was it found? Suck, then Right, then Suck. It was found by generating sequences of increasing length and testing whether each one ended in a goal state, so the first found is the shortest.

5. Name the three things a goal cannot do, and say what is needed instead. It cannot rank two plans that both reach the goal, cannot trade off conflicting objectives, and cannot prefer a plan with a higher probability of success. All three require a numerical measure of how good an outcome is, which is a utility function.

6. What changes in a goal-based agent if the requirement becomes "clean both squares and finish in square A"? Only the goal test. The transition model, the set of actions and the search procedure are unchanged. In a reflex agent every rule would have to be rewritten.

munotes.in32

The Goal-Based Agent

7. Explain the relationship between search and planning. They are the same activity at different levels of description. In search the algorithm treats states as opaque objects distinguished only by identity and the goal test. In planning a state is a set of facts and each action declares which facts it requires and which it changes, which allows reasoning about problems far too large to enumerate.

Contents This chapter on its own page

munotes.in33

Chapter Eight

The Utility-Based Agent

Syllabus topic Module 1, "utility-"

In one line

A utility-based agent puts a number on how good each outcome is, so it can pick the best of several plans that all work, and can weigh a small chance of a great outcome against a large chance of a fair one.

In the wording a student can write in an examination: a utility-based agent uses a utility function, a mapping from a state (or a sequence of states) to a real number measuring how desirable it is. Where outcomes are uncertain, the agent computes the expected utility of each action, the sum over possible outcomes of their probability times their utility, and selects the action of maximum expected utility. This is the principle of maximum expected utility, and it is the formal statement of rational behaviour used throughout this paper.

Why a goal is not enough

The previous chapter ended with three things a binary goal cannot do. Each becomes possible the moment states carry numbers.

Ranking two successes. Two plans clean the house. One takes three actions, the other four. A goal test says "both fine". A utility function that subtracts the cost of each move says which is better, and by how much.

Trading off conflicting objectives. Fast and safe disagree. With numbers, the question becomes an arithmetic one: is the two minutes saved worth the extra risk, at these values.

Preferring a better chance. If sucking works four times in five, no plan is certain. Utility lets the agent compare a plan that succeeds 92 times in 100 with one that succeeds 64 times in 100, and to notice that the safer plan also costs more electricity.

The two things you must be given

A utility-based agent cannot be built out of thin air. It needs two numerical inputs, and both are design decisions that a marker may ask you to justify.

  1. A utility function on outcomes. Here: a clean square at the end is worth 5. That is a choice; 5 is not discovered.
  2. Probabilities for the uncertain effects of actions. Here: sucking works with probability 0.8. Where those come from is the subject of Module 1's fourth row, and how they are learned from data is Module 2.

Add the costs, which are negative utility: every move costs 1 and every suck costs 0.2 in electricity.

Expected utility, defined and then computed

For an action with possible outcomes numbered 1 to n:

EU(action) = sum over i of P(outcome i) * U(outcome i)

Read it in words: take each thing that could happen, multiply how good it is by how likely it is, and add them up. Nothing more.

For one Suck on a dirty square in A, with the other square dirty:

munotes.in34

The Utility-Based Agent

EU(Suck) = 0.8 U(A clean, B dirty) + 0.2 U(A dirty, B dirty) - 0.2

= 0.8 5 + 0.2 0 - 0.2

= 4.0 - 0.2

= 3.8

The 0.2 subtracted at the end is the electricity. That figure, 3.8, appears in the table below as the expected utility of the one-action plan Suck, so the hand arithmetic and the program agree.

Comparing whole plans

The program pushes a probability distribution over states through each action of a plan, accumulates the cost as it goes, and then computes the expected value of the squares that are clean at the end.

# A utility-based agent. It puts a NUMBER on every outcome, so it can compare two
# plans that BOTH reach the goal, which a goal-based agent cannot.
# Sucking works with probability 0.8. A clean square at the end is worth 5.
# Every move costs 1 and every suck costs 0.2 in electricity.
P_WORKS, MOVE_COST, SUCK_COST, CLEAN_VALUE = 0.8, 1.0, 0.2, 5.0

def step(dist, action):
    """Push a probability distribution over states through one action."""
    out, cost = {}, 0.0
    for (at, a, b), p in dist.items():
        if action == "Suck":
            cost += p * SUCK_COST
            here = a if at == "A" else b
            if here == "Dirty":
                done = (at, "Clean", b) if at == "A" else (at, a, "Clean")
                out[done] = out.get(done, 0.0) + p * P_WORKS
                out[(at, a, b)] = out.get((at, a, b), 0.0) + p * (1 - P_WORKS)
            else:
                out[(at, a, b)] = out.get((at, a, b), 0.0) + p
        elif action in ("Left", "Right"):
            cost += p * MOVE_COST
            nxt = ("A" if action == "Left" else "B", a, b)
            out[nxt] = out.get(nxt, 0.0) + p
        else:
            out[(at, a, b)] = out.get((at, a, b), 0.0) + p
    return out, cost

def expected_utility(plan, start):
    dist, spent = {start: 1.0}, 0.0
    for action in plan:
        dist, cost = step(dist, action)
        spent += cost
    value = sum(p * CLEAN_VALUE * sum(1 for s in st[1:] if s == "Clean")
                for st, p in dist.items())
    return value - spent

start = ("A", "Dirty", "Dirty")
PLANS = [("Suck", "Right", "Suck"),
         ("Suck", "Suck", "Right", "Suck", "Suck"),
         ("Right", "Suck", "Left", "Suck"),
         ("Suck",),
         ()]
print("plan                                           P(goal)  expected utility")
for plan in PLANS:
    d = {start: 1.0}
    for action in plan:
        d, _ = step(d, action)
    pgoal = sum(p for st, p in d.items() if st[1] == "Clean" and st[2] == "Clean")
    label = " then ".join(plan) if plan else "do nothing"
    print("%-44s %7.3f  %15.3f" % (label, pgoal, expected_utility(plan, start)))
print()
best = max(PLANS, key=lambda pl: expected_utility(pl, start))
print("chooses: %s" % (" then ".join(best) if best else "do nothing"))
plan                                           P(goal)  expected utility
Suck then Right then Suck                      0.640            6.600
Suck then Suck then Right then Suck then Suck   0.922            7.800
Right then Suck then Left then Suck            0.640            5.600
Suck                                           0.000            3.800
do nothing                                     0.000            0.000

chooses: Suck then Suck then Right then Suck then Suck
munotes.in35

The Utility-Based Agent

Read the table row by row, because every row settles one of the three things a goal could not do.

Row 1 and row 3 both reach the goal with probability 0.640, and they are exactly the two plans the previous chapter could not choose between. Utility separates them: 6.600 against 5.600. The difference is one extra move, costing 1.

Row 2 is the agent's choice, and it is the interesting one. It sucks twice in each square. That is pointless if sucking always works, and it is the right thing when sucking works four times in five: the probability of finishing rises from 0.640 to 0.922, and the two extra sucks cost only 0.4 between them. A goal-based agent would never have considered it, because one suck already "reaches the goal" in its model.

Row 4 is the single action worked by hand above, 3.800, and it confirms the arithmetic.

Row 5 is doing nothing, worth 0.000, which is the baseline every other row is measured against.

Why utility is the definition of rationality used from here on

The definition in Acting Rationally, or Thinking Like a Human said an agent is rational when it selects the action expected to maximise its performance measure. This chapter is where that sentence becomes computable. Expected utility IS the expected performance measure, and maximum expected utility is the rule that implements the definition.

That is why the same quantity reappears three more times in this book under three more names:

WhereWhat it is calledWhat it is
Reasoning under uncertaintyexpected valueprobability times value, summed
Markov decision processesthe value of a state under a policyexpected discounted utility of what follows
Evaluating a modelexpected loss, or riskexpected utility with the sign turned round

Utility against money, and why the function is not linear

One subtlety that is worth 5 marks and is usually missed. Utility is not the same as the quantity being measured.

Offered a certain 500 rupees or a coin flip for 1,000, most people take the 500, although the expected rupees are identical. That is not irrational. It means their utility for money is not linear: the first 500 rupees is worth more to them than the second 500. An agent whose utility function bends this way is called risk averse; one whose function bends the other way is risk seeking; a straight line is risk neutral.

munotes.in36

The Utility-Based Agent

So a utility function is where an agent's attitude to risk lives. Two agents with the same probabilities and the same money can rationally make opposite choices, because their utility functions differ. There is no single correct utility function to be discovered; there is a designer's choice to be justified.

Distinctions

Goal-basedUtility-based
Value of a stateyes or noa real number
Ranks two successful plansnoyes
Conflicting objectivescannot trade offtrades off numerically
Uncertain outcomesno preference between chancesmaximises expected utility
Needsa goal testa utility function and probabilities
UtilityPerformance measure
Whose it isinternal to the agent, it uses it to chooseexternal, the designer judges the agent by it
Purposeto decideto evaluate
When they agreethe agent is well designed
Risk averseRisk neutralRisk seeking
Utility of moneybends downstraightbends up
Prefersthe certain amountindifferentthe gamble
Rationalyesyesyes

What it does not mean

Utility is not the performance measure. The performance measure is how the designer judges the agent from outside. The utility function is inside the agent and is what it uses to choose. A well-designed agent has one that leads to a good score on the other, and confusing them makes it impossible to say what went wrong when they diverge.

Maximum expected utility does not mean the best outcome happens. It means the best average over what might happen. An agent that takes the highest expected utility and gets an unlucky result was still rational.

Utility numbers are not probabilities. They are not between 0 and 1 and they do not add to 1. Any scale will do, because only the ordering and the ratios of differences matter.

A higher probability of success is not automatically better. Row 2 of the table wins because the extra certainty is worth more than the extra electricity. Change the electricity cost to 2 per suck and row 1 wins instead. The numbers decide, not the story.

Risk aversion is not a bias to be corrected. It is a shape of utility function, and it is perfectly rational.

Quick revision

  • Utility-based agent: uses a utility function from outcomes to real numbers, and where outcomes are uncertain chooses the action of maximum expected utility.
  • Expected utility: sum over outcomes of probability times utility. Written out: EU(a) = sum P(outcome) * U(outcome).
  • It needs two given things: a utility function and probabilities. Both are design decisions.
  • It can do the three things a goal cannot: rank two successes, trade off conflicting objectives, and prefer a better chance.
  • On this chapter's world it chooses Suck, Suck, Right, Suck, Suck, which raises the chance of finishing from 0.640 to 0.922 for 0.4 in extra electricity. A goal-based agent could not have considered it.
  • Utility is the agent's internal measure; the performance measure is the designer's external one.
  • Utility is not linear in the underlying quantity. A curve that bends down is risk averse, a straight line risk neutral, one that bends up risk seeking, and all three are rational.
munotes.in37

The Utility-Based Agent

Test yourself

1. Define a utility-based agent and state the principle it acts on. An agent that maps outcomes to real numbers with a utility function and, where outcomes are uncertain, selects the action whose expected utility is greatest. The principle is maximum expected utility.

2. Write the formula for expected utility and explain each part. EU(a) is the sum over possible outcomes of P(outcome given a) times U(outcome). P is how likely the outcome is, U is how desirable it is, and the sum is the average desirability weighted by likelihood.

3. Compute the expected utility of one Suck on a dirty square, given a success probability of 0.8, a clean square worth 5, and a suck costing 0.2. 0.8 times 5 plus 0.2 times 0, minus 0.2, which is 4.0 minus 0.2, that is 3.8.

4. Two plans both clean the house. Why can a goal-based agent not choose between them, and how does a utility-based agent do so? A goal test returns only yes or no, and both plans end in a goal state, so it is indifferent. A utility function assigns a number that includes the cost of each move, so the shorter plan scores higher, 6.600 against 5.600 in this chapter's run.

5. Why does the agent in this chapter choose to suck twice in the same square? Because sucking succeeds only four times in five. Sucking twice raises the probability of finishing the job from 0.640 to 0.922, and the two extra sucks cost 0.4 in total, which is far less than the extra expected value.

6. Distinguish the utility function from the performance measure. The utility function is internal to the agent and is what it uses to choose actions. The performance measure is external, chosen by the designer, and is what the agent is judged by. A good design makes maximising the first produce a high score on the second.

7. A person prefers a certain 500 rupees to a fair coin flip for 1,000. Is this irrational? Explain in terms of utility. No. The expected number of rupees is the same, but the person's utility for money is not linear: the second 500 rupees adds less utility than the first, so the certain amount has the higher expected utility for them. This shape of utility function is called risk aversion.

Contents This chapter on its own page

munotes.in38

Chapter Nine

The Learning Agent

Syllabus topic Module 1, "learning agents"

In one line

A learning agent is any of the previous four with a second machine bolted on: something that watches how well it is doing and changes the first machine.

In the wording a student can write in an examination: a learning agent has four conceptual components. The performance element selects actions and is the whole of whichever agent architecture is being used. The critic observes the outcomes and reports how well the agent is doing against a fixed performance standard. The learning element uses the critic's feedback to modify the performance element. The problem generator proposes exploratory actions that are suboptimal in the short term but yield informative experience.

Why an agent must be able to learn

Three reasons, and the third is the one that decides it.

The designer cannot foresee every situation. A rule table for a taxi would have to enumerate every road, every weather condition and every other driver's habits.

The designer may not know the answers. Nobody can write down, in advance, the exact probability that this vacuum cleaner's motor lifts this carpet's dirt.

The environment can be unknown. This is the seventh dimension from Types of Environment, and it is decisive: if the agent does not know the laws it is operating under, no amount of cleverness in the performance element helps. It has to find them out, and finding them out from experience is learning.

The four components

ComponentIts jobIn the run below
Performance elementchoose an action from what is knowndecides whether to Suck, using the current estimate
Criticobserve the outcome and score it against a fixed standardreports after each attempt whether the suck worked
Learning elementchange the performance elementrecomputes the estimated success rate
Problem generatorsuggest actions that are informative rather than bestwould suggest trying a suck even when the estimate says do not bother

Two of those four are routinely left out of student answers and both are worth marks.

The critic is necessary because the percepts alone do not say whether the agent did well. The percept after a failed suck is just "dirty". Only a fixed external standard turns that into "that went badly". The standard must be outside the agent and must not be changeable by it, or the agent will learn to score itself well rather than to act well.

The problem generator exists because the best-known action is not the most informative one. An agent that always takes what it currently believes is best never discovers anything better. This is the exploration against exploitation problem, and it comes back in Q-Learning as the epsilon-greedy rule.

It running

The environment's suck succeeds 6 times in 10, and the agent is never told so. Sucking costs 2 and a clean square is worth 5, so attempting a suck pays only while the estimated success rate is above 2 divided by 5, which is 0.4. That threshold is what turns a learned number into a changed decision.

munotes.in39

The Learning Agent

# A learning agent. It does NOT know how often Suck works. The CRITIC watches the
# result, the LEARNING ELEMENT updates the estimate, and the PERFORMANCE ELEMENT
# decides from it. Sucking costs 2 and a clean square is worth 5, so sucking is
# worth attempting only while the estimated success rate is above 2/5 = 0.4.
TRUE_P = 0.6          # the environment's real rate. The agent is never told it.
SUCK_COST, CLEAN_VALUE = 2.0, 5.0
THRESHOLD = SUCK_COST / CLEAN_VALUE

def pseudo_random(seed):
    """A deterministic generator, so this book's printed run is reproducible.
    The constants are the ones Numerical Recipes uses for a 32-bit LCG."""
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

stream = pseudo_random(7)
attempts = successes = 0
print("sucking pays while the estimate is above %.2f" % THRESHOLD)
print()
print("trial  worked?  estimate  the performance element decides")
for trial in range(1, 13):
    worked = next(stream) < TRUE_P                  # the environment decides
    attempts += 1                                   # the critic reports
    successes += 1 if worked else 0
    estimate = (successes + 1) / (attempts + 2)     # the learning element, smoothed
    decision = "Suck" if estimate > THRESHOLD else "do not Suck"
    print("%5d  %-7s  %8.3f  %s" % (trial, "yes" if worked else "no", estimate, decision))
print()
print("after %d trials the estimate is %.3f and the truth is %.1f"
      % (attempts, estimate, TRUE_P))
sucking pays while the estimate is above 0.40

trial  worked?  estimate  the performance element decides
    1  yes         0.667  Suck
    2  no          0.500  Suck
    3  no          0.400  do not Suck
    4  no          0.333  do not Suck
    5  yes         0.429  Suck
    6  no          0.375  do not Suck
    7  yes         0.444  Suck
    8  yes         0.500  Suck
    9  yes         0.545  Suck
   10  no          0.500  Suck
   11  no          0.462  Suck
   12  yes         0.500  Suck

after 12 trials the estimate is 0.500 and the truth is 0.6

Four things in that output, and every one of them is an honest property of learning rather than a defect in the program.

The decision changes as the estimate changes. At trials 3, 4 and 6 the agent has seen enough failures that sucking no longer looks worth the electricity, and it stops. At trial 5 it changes its mind again. The learning element is not producing a number for its own sake; it is changing what the performance element does.

munotes.in40

The Learning Agent

The estimate is wrong, and it should be. After twelve trials it says 0.500 and the truth is 0.6. Twelve observations cannot pin down a probability. A learner's output is an estimate from a sample, and a book that showed it converging neatly on 0.6 in twelve steps would be lying about what learning is like. This is the first appearance of what Bias and Variance makes precise.

Early estimates swing wildly and later ones do not. From 0.667 to 0.333 in three trials, then hardly moving after trial 8. Each new observation is a smaller fraction of the total, so it moves the average less. That is the whole reason more data helps.

The plus one and plus two are doing real work. The estimate is (successes + 1) / (attempts + 2) rather than successes / attempts. With the plain fraction, one failure at trial 1 would give an estimate of exactly 0, the agent would conclude sucking never works, stop trying, and never get another observation to correct itself. This is Laplace smoothing, and The Naive Bayes Classifier uses it again for exactly the same reason: a probability of zero taken from a small sample is a trap that cannot be escaped.

Where the other four architectures sit inside this one

The learning agent does not replace the previous four. The performance element is one of them, and the diagram is the same whichever one it is.

Performance elementWhat the learning element could then change
Simple reflexthe condition-action rules themselves
Model-based reflexthe transition model, so the agent learns what its actions do
Goal-basedthe model used to search, or which goals to adopt
Utility-basedthe utility function, or the probabilities in it

The run above is a learning agent whose performance element is utility-based: it has a utility function it was given and a probability it has to learn.

Where the whole of Module 2 fits in this diagram

This is the table to hold on to, because it is the answer to a Q.3 that crosses the two modules. Every one of MU's Module 2 labels is a piece of machinery for the learning element.

Module 2 labelWhich component it belongs toWhat it learns from
Supervised learningthe learning elementa critic that gives the right answer for each case
Unsupervised learningthe learning elementno critic at all, only the percepts
Reinforcement learningthe learning element, with the critic giving a rewarda number, delayed, for a whole sequence
Decision trees, k-NN, naive Bayes, SVM, neural networkshow the learning element represents what it has learned
Bias and variance, overfitting, regularizationhow well the learning element is doing its job
Evaluating a modelthe critic's own instrument
Markov decision processes and Q-learninga performance element and a learning element togetherreward
munotes.in41

The Learning Agent

The three forms of learning MU names in her first Module 2 label are three kinds of critic, and that is the cleanest way to hold them apart: supervised has a critic that says what the right answer was, reinforcement has a critic that says only how good the result was, unsupervised has no critic.

What the critic is not

The critic is not a part of the environment and it is not a part of the performance element.

The performance standard the critic applies has to come from outside the agent, and this is a point of substance rather than pedantry. An agent that could rewrite its own standard would improve its score by lowering the bar, which is why the standard is fixed. In supervised learning the standard arrives as labelled data; in reinforcement learning it arrives as a reward signal; in both cases the agent cannot alter it.

The critic is also not the performance measure the designer uses to judge the agent. The critic's standard is a signal inside the agent's learning loop. They should agree, and when they do not, the agent will optimise the one it can see.

Distinctions

Performance elementLearning element
Jobchoose the next actionchange how actions are chosen
Runsevery stepwhen feedback arrives
In the run abovethe threshold testthe estimate update
CriticProblem generator
Jobsay how well the agent didsuggest an informative action
Pointsbackwards, at what happenedforwards, at what to try
Without itthe agent cannot tell improvement from declinethe agent never discovers anything better than it already believes
ExploitationExploration
Takesthe best action currently knownan action chosen to learn from
Short-term scorehigherlower
Long-term scorecan be permanently worsecan find something better
Whose jobperformance elementproblem generator

What it does not mean

A learning agent is not a separate fifth architecture that replaces the others. It is a wrapper. The performance element is one of the four, and the diagram is the same in each case.

Learning is not only about improving performance on the same task. It is often about discovering what the task actually is, which is what an unknown environment means.

The critic is not the sensors. Percepts say what happened; the critic says whether that was good, by applying a standard the percepts do not contain.

More experience does not guarantee a better estimate on any particular run. It guarantees that the estimate stops swinging. Look at trial 10: a failure moved the estimate down, away from the truth, and that is normal.

munotes.in42

The Learning Agent

The problem generator is not a bug or a source of noise. Deliberately taking a worse action to learn something is the only escape from a local answer, and an agent without it is stuck with whatever it happened to believe first.

Quick revision

  • Learning agent: four components. Performance element (chooses actions, and is one of the other four architectures), critic (scores outcomes against a fixed external performance standard), learning element (modifies the performance element), problem generator (proposes informative but suboptimal actions).
  • Learning is needed because the designer cannot foresee everything, may not know the answers, and because the environment may be unknown.
  • The critic's standard must be external and fixed, or the agent optimises its own scorekeeping.
  • The problem generator is the exploration half of exploration against exploitation, which returns in Q-Learning.
  • In the run: the estimate changes the decision at trials 3, 4 and 6; the final estimate is 0.500 against a truth of 0.6; early estimates swing and later ones do not.
  • Laplace smoothing, the plus one over plus two, stops an early run of failures producing an estimate of exactly zero from which the agent could never recover.
  • The three forms of learning are three kinds of critic: supervised says what the right answer was, reinforcement says only how good the result was, unsupervised says nothing.
  • The whole of Module 2 is machinery for the learning element.

Test yourself

1. Name the four components of a learning agent and give each one's job. The performance element chooses actions. The critic observes outcomes and reports how well the agent did against a fixed performance standard. The learning element modifies the performance element using that feedback. The problem generator suggests exploratory actions that are informative although not currently best.

2. Why must the performance standard be outside the agent? Because an agent able to change its own standard would raise its score by lowering the standard rather than by acting better. Fixing it externally means the only way to score higher is to improve.

3. What does the problem generator contribute, and what is the problem it addresses called? It proposes actions taken for what they reveal rather than for their immediate value, so the agent can discover options better than its current belief. The problem is exploration against exploitation.

4. In this chapter's run the final estimate is 0.500 while the true rate is 0.6. Is the learner broken? No. Twelve observations are far too few to determine a probability closely. An estimate from a finite sample differs from the truth, and the honest property to expect from more data is that the estimate stops swinging, not that it lands exactly.

munotes.in43

The Learning Agent

5. Why is the estimate computed as (successes + 1) divided by (attempts + 2)? It is Laplace smoothing. The plain ratio would return exactly zero after an early failure, the agent would conclude that sucking never works and stop attempting it, and it would then never observe anything that could correct the belief.

6. How do the three forms of learning map onto the critic? They are three kinds of critic. Supervised learning has a critic that supplies the correct answer for each case. Reinforcement learning has a critic that supplies only a reward saying how good the outcome was. Unsupervised learning has no critic.

7. A student says the learning agent is the fifth and best architecture, replacing the other four. Correct them. The learning agent wraps one of the other four rather than replacing it. Its performance element is a simple reflex, model-based, goal-based or utility-based agent, and what the learning element modifies depends on which: the rules, the transition model, the search model or the utility function and its probabilities.

Contents This chapter on its own page

munotes.in44

Chapter Eleven

The Search Tree, and How an Algorithm Is Judged

Syllabus topic Module 1, "Uninformed search"

In one line

A search algorithm builds a tree of partial routes, and the four things we judge it on are: will it find an answer, is the answer the best one, how long does it take, and how much memory does it need.

In the wording a student can write in an examination: search algorithms build a search tree over the state space, in which each node represents a path from the initial state. They are evaluated on four criteria. Completeness: is it guaranteed to find a solution if one exists. Optimality: is the solution found guaranteed to be of least cost. Time complexity: how many nodes are generated. Space complexity: how many nodes are held in memory at once.

The state space and the search tree are two different things

This is the distinction on which everything else in the row depends, and it is where students lose the most marks.

The state space is a property of the problem. It has nine nodes for the district map, one per town, and it does not change however you search it.

The search tree is a property of the search. Its nodes are paths, not states. If two routes reach Chinch, the tree has two nodes holding the state Chinch. The tree is built as the algorithm runs, and on a graph with cycles it can be infinite even though the state space has nine states: Amba to Bori to Amba to Bori, forever.

State spaceSearch tree
A node isa statea path from the start
Size for the district map9, fixedunbounded unless repeats are stopped
Existsbefore the searchonly while the search runs
Can contain the same state twicenoyes, once per route to it

The parts of a search

Every algorithm in this row is the same four lines with one thing changed. Being able to write this general form is worth marks on its own, because then each algorithm is a one-sentence answer.

put the initial path on the FRONTIER
repeat:
    if the frontier is empty: fail
    take a path OFF THE FRONTIER          <- the only thing that differs
    if its last state satisfies the goal test: return the path
    EXPAND it: for each action, add the extended path to the frontier

Everything that distinguishes breadth first from depth first from A is the phrase "take a path off the frontier". Take the oldest and you have breadth first search. Take the newest and you have depth first search. Take the cheapest so far and you have uniform cost search. Take the one with the lowest estimated total and you have A.

Three words to fix now.

munotes.in51

The Search Tree, and How an Algorithm Is Judged

  • Frontier, also called the open list: the paths generated but not yet expanded. It is the boundary between the explored and the unexplored.
  • Reached or explored set, also called the closed list: the states already dealt with, kept so the search does not do the same work twice.
  • Expand: take a node, generate all its children, and put them on the frontier.

A node is not a state, and a node carries four things

A node is a bookkeeping record. To return a route rather than merely announce that one exists, each node must carry:

FieldWhy it is needed
the stateto test the goal, and to look up the actions
the parent nodeto reconstruct the path once the goal is found
the action takenso the answer can be given as actions, not only as states
the path cost so far, gfor uniform cost search and for A*

The programs in this book keep the whole path in a list instead of a parent pointer. That is slightly wasteful of memory and much easier to read, and for a book the second consideration wins. A production implementation keeps the pointer.

Repeated states, and why they must be handled

A search that does not notice it has been somewhere before will, on the district map, generate Amba to Bori to Amba to Bori to Amba forever. Three levels of care are possible and a paper may ask for the difference.

  1. Do nothing. Correct only on a tree-shaped state space, where there is exactly one route to each state.
  2. Do not go back to the state you just came from, and do not revisit a state already on this path. Cheap, and it removes all cycles. This is what Iterative Deepening Search does.
  3. Keep a reached set of every state ever reached. Removes all repeated work, at the cost of memory proportional to the number of states reached.

Option 3 is what makes graph search different from tree search, and the names are examinable: tree search keeps no reached set, graph search does.

The four measures

Completeness. If a solution exists, is the algorithm guaranteed to find it? Depth first search on an infinite space is not complete: it can go down one branch forever while the answer sits on the next branch.

Optimality. Is the solution returned guaranteed to be the cheapest? Note the word cheapest, not shortest. Breadth first search finds the route with the fewest steps, which is not the cheapest whenever steps have different costs. On the district map it finds a 3-hop 26 km route while the cheapest is a 4-hop 25 km route, and that is not a bug in breadth first search: it is optimal in the number of steps and is not claiming anything else.

munotes.in52

The Search Tree, and How an Algorithm Is Judged

Time complexity, counted in nodes generated rather than seconds, because seconds depend on the machine and nodes do not.

Space complexity, counted in nodes held at once. This is the measure that decides which algorithms are usable in practice, and students routinely ignore it. An algorithm that needs a hundred million nodes in memory is unusable on a laptop no matter how fast it is, which is exactly why Recursive Best First Search exists.

The three symbols

Every complexity statement in the following chapters is in terms of these, so they are defined once.

SymbolMeans
bthe branching factor: the maximum number of successors of any node
dthe depth of the shallowest goal: the number of steps in the shortest solution
mthe maximum depth of the state space, which may be infinite

For the district map, b is 4, because Chinch, Erandol and Fanas each have four roads. For the 8-puzzle, b is between 2 and 4 depending on where the blank is, and its average is about 2.67.

Why the tree explodes

The number of nodes in a tree of branching factor b down to depth d is 1 plus b plus b squared and so on, which comes to (b**(d+1) - 1) / (b - 1). Written out for real values:

# How big the search tree gets. b is the branching factor, d the depth.
print(" b    d   nodes in the tree   if 100000 nodes a second")
for b in (2, 3, 10):
    for d in (2, 4, 8, 12, 16):
        n = (b ** (d + 1) - 1) // (b - 1)
        secs = n / 100000
        if secs < 60:
            when = "%.1f seconds" % secs
        elif secs < 3600:
            when = "%.1f minutes" % (secs / 60)
        elif secs < 86400 * 365:
            when = "%.1f days" % (secs / 86400)
        else:
            when = "%.0f years" % (secs / 86400 / 365)
        print("%2d %4d %19d   %s" % (b, d, n, when))
 b    d   nodes in the tree   if 100000 nodes a second
 2    2                   7   0.0 seconds
 2    4                  31   0.0 seconds
 2    8                 511   0.0 seconds
 2   12                8191   0.1 seconds
 2   16              131071   1.3 seconds
 3    2                  13   0.0 seconds
 3    4                 121   0.0 seconds
 3    8                9841   0.1 seconds
 3   12              797161   8.0 seconds
 3   16            64570081   10.8 minutes
10    2                 111   0.0 seconds
10    4               11111   0.1 seconds
10    8           111111111   18.5 minutes
10   12       1111111111111   128.6 days
10   16   11111111111111111   3523 years

Read down the last block. At a branching factor of 10, depth 8 takes about twenty minutes and depth 12 takes four months. Four more levels multiplied the work by ten thousand. No faster computer fixes this: a machine a thousand times faster buys three more levels. The only thing that helps is not generating most of the tree, and that is what the heuristic chapters are for.

munotes.in53

The Search Tree, and How an Algorithm Is Judged

The table every following chapter fills in

CompleteOptimalTimeSpace
Breadth firstyes, if b is finiteonly if every step costs the sameO(b**d)O(b**d)
Uniform costyes, if every step cost is positiveyessee its chaptersee its chapter
Depth first, tree searchnonoO(b**m)O(b*m)
Depth limitedno, if the limit is below dnoO(b**limit)O(b*limit)
Iterative deepeningyes, if b is finiteonly if every step costs the sameO(b**d)O(b*d)
Greedy best firstno in tree search, yes in graph search on a finite spacenodepends entirely on the heuristicsame
A*yesyes, with an admissible heuristicdepends on the heuristickeeps every generated node

Two rows of that table are the whole story of the row. Breadth first search has O(bd) SPACE, and that is what kills it: at b of 10 and d of 12, a hundred gigabytes of frontier. Iterative deepening has O(b*d) space** for the same time complexity, which is why it is the standard uninformed search rather than breadth first.

Distinctions

Tree searchGraph search
Keeps a reached setnoyes
Can loop forever on a cyclic spaceyesno
Extra memorynoneone entry per state reached
Which is rightonly when the space really is a treewhenever states can be revisited
CompleteOptimal
Promisesit will find an answerthe answer it finds is the cheapest
Depth first searchnono
Breadth first searchyesonly with uniform step costs
The two are independentan algorithm can be complete and not optimal
Time complexitySpace complexity
Counted innodes generatednodes held at once
Why not secondsseconds depend on the machine
Decideshow long you waitwhether it runs at all

What it does not mean

Optimal does not mean shortest. It means least total path cost. Breadth first search finds the fewest steps; that is only the cheapest when all steps cost the same.

Complete does not mean it will finish quickly. A complete algorithm on a large space may take longer than the age of the universe and still be complete.

The search tree is not drawn in advance. It is generated as the algorithm runs, and a good algorithm generates only a small part of it.

b is the branching factor of the STATE SPACE, not of the tree drawn. It does not change when you change algorithms.

munotes.in54

The Search Tree, and How an Algorithm Is Judged

A node is not a state. One state can appear in many nodes, one per route reaching it, and it is precisely because of that that the reached set exists.

Quick revision

  • State space: nodes are states, a property of the problem. Search tree: nodes are paths, a property of the search, and can be infinite where the state space is finite.
  • The general algorithm: put the start on the frontier, then repeatedly take a path off it, goal-test it, and expand. The only difference between the six algorithms is which path is taken off the frontier.
  • A node carries state, parent, action and path cost g.
  • Tree search keeps no reached set and can loop; graph search keeps one and cannot.
  • Four measures: completeness, optimality (cheapest, not shortest), time in nodes generated, space in nodes held at once.
  • b branching factor, d depth of the shallowest goal, m maximum depth.
  • Tree size is (b(d+1) - 1) / (b - 1). At b of 10, depth 8 takes minutes and depth 12 takes months: four levels cost a factor of ten thousand.**
  • Space is usually the binding constraint. Breadth first is O(b**d) in space; iterative deepening is O(b*d) for the same time.

Test yourself

1. Distinguish the state space from the search tree. The state space is the graph of states and actions belonging to the problem; it has one node per state and does not depend on the algorithm. The search tree has one node per path examined, is built as the search runs, and can be infinite on a state space with cycles.

2. Give the general form of a search algorithm and say what distinguishes the individual algorithms. Put the initial path on the frontier; repeatedly remove a path, test its final state against the goal, and expand it by adding extended paths to the frontier. The algorithms differ only in which path is removed from the frontier.

3. What four things does a node carry, and why each? The state, to test the goal and find the actions; the parent, to reconstruct the path; the action taken, so the answer can be given as actions; and the path cost so far, needed by uniform cost search and A*.

4. Name the four evaluation criteria and define each. Completeness, whether a solution is found if one exists. Optimality, whether the solution found has least cost. Time complexity, the number of nodes generated. Space complexity, the number of nodes held in memory at once.

5. Breadth first search returns a 26 km route on the district map when a 25 km route exists. Is it broken? No. It is optimal in the number of steps, and it returns the route with fewest steps, which is three. The 25 km route has four steps. Breadth first search is only cost-optimal when every step costs the same.

munotes.in55

The Search Tree, and How an Algorithm Is Judged

6. Define b, d and m, and give b for the district map. b is the branching factor, the largest number of successors of any node; d is the depth of the shallowest goal; m is the maximum depth of the space. For the district map b is 4, since Chinch, Erandol and Fanas each have four roads.

7. Why is space complexity usually the binding constraint rather than time? Because memory runs out before patience does. Breadth first search at branching factor 10 and depth 12 would need of the order of a hundred gigabytes for its frontier, so it cannot be run at all, whereas an algorithm with the same time complexity and linear space can be left to run.

Contents This chapter on its own page

munotes.in56

Chapter Sixteen

Heuristics: Estimating What Is Left To Do

Syllabus topic Module 1, "Informed search"

In one line

A heuristic is a cheap guess at how much work is left, and a search that has one can look in the right direction instead of looking everywhere.

In the wording a student can write in an examination: a heuristic function h(n) is an estimate of the cost of the cheapest path from the state at node n to a goal state. It is problem specific knowledge supplied to the search algorithm, it must be cheap to compute, and h(goal) must be 0. A search that uses one is called an informed or heuristic search; one that does not is uninformed or blind.

The three functions, kept apart

These three symbols are used for the rest of the row and confusing any two of them makes every following chapter unreadable.

SymbolNameWhat it isKnown exactly
g(n)path costthe cost of the path from the start to n, along the route foundyes, it has been travelled
h(n)heuristican ESTIMATE of the cheapest cost from n to a goalno, it is a guess
f(n)evaluation functiong(n) + h(n), the estimated cost of the whole route through nno, because h is a guess

The asymmetry is the whole idea. g looks backwards and is a fact. h looks forwards and is a guess. The uninformed algorithms of the last five chapters used only g, which is why they had to look in every direction: they had no information at all about which direction the goal lay in.

Where a heuristic comes from

A heuristic is not conjured. The standard and examinable method is relaxation: take the problem, delete a constraint, and the exact cost of the easier problem is a heuristic for the harder one.

A relaxed problem's exact answer can never exceed the real problem's, because every real solution is still a solution of the relaxed problem. So relaxation automatically produces a heuristic that never overestimates, which is exactly the property the next two chapters need.

Worked on the two standing problems:

ProblemConstraint deletedThe heuristic that results
The district maproads; travel in a straight linestraight-line distance to the goal
The 8-puzzletiles may pass through each otherManhattan distance, the total rows plus columns each tile must travel
The 8-puzzlea tile may teleport to its home squaremisplaced tiles, a count

Three heuristics for the 8-puzzle, computed

# Three heuristics for the 8-puzzle, computed on one board so they can be compared.
GOAL = (0, 1, 2, 3, 4, 5, 6, 7, 8)

def show(state):
    return "\n".join(" ".join("_" if v == 0 else str(v) for v in state[r * 3:r * 3 + 3])
                     for r in range(3))

def h0(state):
    """The trivial heuristic: guess nothing."""
    return 0

def h1(state):
    """Misplaced tiles. The blank is NOT a tile and is not counted."""
    return sum(1 for i, v in enumerate(state) if v != 0 and v != GOAL[i])

def h2(state):
    """Manhattan distance: for each tile, the rows plus columns it must travel."""
    total = 0
    for i, v in enumerate(state):
        if v == 0:
            continue
        goal_i = GOAL.index(v)
        total += abs(i // 3 - goal_i // 3) + abs(i % 3 - goal_i % 3)
    return total

BOARD = (7, 2, 4,
         5, 0, 6,
         8, 3, 1)
print("the board"); print(show(BOARD)); print()
print("the goal"); print(show(GOAL)); print()
print("h0, guess nothing      :", h0(BOARD))
print("h1, misplaced tiles    :", h1(BOARD))
print("h2, Manhattan distance :", h2(BOARD))
print()
print("tile  at (row,col)  wants (row,col)  rows+cols to travel")
for i, v in enumerate(BOARD):
    if v == 0:
        continue
    g = GOAL.index(v)
    d = abs(i // 3 - g // 3) + abs(i % 3 - g % 3)
    print("%4d  %11s  %15s  %d" % (v, str((i // 3, i % 3)), str((g // 3, g % 3)), d))
print()
print("h2 total:", h2(BOARD), " and this board needs 26 moves, found by search")
print("so h0 <= h1 <= h2 <= 26: all three never overestimate, and h2 is closest")
munotes.in78

Heuristics: Estimating What Is Left To Do

the board
7 2 4
5 _ 6
8 3 1

the goal
_ 1 2
3 4 5
6 7 8

h0, guess nothing      : 0
h1, misplaced tiles    : 8
h2, Manhattan distance : 18

tile  at (row,col)  wants (row,col)  rows+cols to travel
   7       (0, 0)           (2, 1)  3
   2       (0, 1)           (0, 2)  1
   4       (0, 2)           (1, 1)  2
   5       (1, 0)           (1, 2)  2
   6       (1, 2)           (2, 0)  3
   8       (2, 0)           (2, 2)  2
   3       (2, 1)           (1, 0)  2
   1       (2, 2)           (0, 1)  3

h2 total: 18  and this board needs 26 moves, found by search
so h0 <= h1 <= h2 <= 26: all three never overestimate, and h2 is closest

Read the three numbers against the truth. The board genuinely needs 26 moves. h0 says 0, h1 says 8, h2 says 18. All three are under 26, which is the property called admissibility and is the subject of chapter 20. And 18 is a far more useful guess than 8, which is the property called dominance.

The blank is not counted as a tile in either heuristic. Counting it breaks the guarantee: the blank moves on every single move, so including it would let the estimate exceed the real number of moves.

Dominance: one heuristic is better than another

h2 is at least as large as h1 at every single state, because a misplaced tile is at least one row or column from home, so it contributes at least 1 to the Manhattan sum as well as 1 to the count. When that holds everywhere, h2 dominates h1.

munotes.in79

Heuristics: Estimating What Is Left To Do

h2(n) >= h1(n) for every n, and both never exceed the truth

A dominating heuristic is always the better one to use, provided it is still cheap to compute. The reason is worth one line and comes back in A*: a larger estimate that still never overestimates lets the algorithm rule out more branches, and it can never cause a wrong answer.

That claim is a measurement, so here is the measurement. The program finds a board whose optimal solution is exactly 14 moves, then solves it three times with the same algorithm and three different heuristics, counting the nodes generated each time.

# Measure the effect of a heuristic on the 8-puzzle. A* with h0 (which makes it
# uniform cost search), h1 (misplaced tiles) and h2 (Manhattan distance), on a
# board whose optimal solution is 14 moves.
import heapq
from collections import deque
GOAL = (0, 1, 2, 3, 4, 5, 6, 7, 8)

def succ(s):
    i = s.index(0)
    r, c = divmod(i, 3)
    for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
        nr, nc = r + dr, c + dc
        if 0 <= nr < 3 and 0 <= nc < 3:
            j = nr * 3 + nc
            board = list(s)
            board[i], board[j] = board[j], board[i]
            yield tuple(board)

def h0(s):
    return 0

def h1(s):
    return sum(1 for i, v in enumerate(s) if v and v != GOAL[i])

def h2(s):
    total = 0
    for i, v in enumerate(s):
        if v:
            g = GOAL.index(v)
            total += abs(i // 3 - g // 3) + abs(i % 3 - g % 3)
    return total

def astar(start, h):
    generated = 1
    frontier = [(h(start), 0, start)]
    best = {start: 0}
    while frontier:
        f, g, s = heapq.heappop(frontier)
        if best.get(s, 10 ** 9) < g:
            continue
        if s == GOAL:
            return g, generated
        for m in succ(s):
            ng = g + 1
            if ng < best.get(m, 10 ** 9):
                best[m] = ng
                generated += 1
                heapq.heappush(frontier, (ng + h(m), ng, m))
    return None, generated

# find a board whose optimal solution is 14 moves, by walking out from the goal
depth = {GOAL: 0}
queue = deque([GOAL])
board14 = None
while queue:
    s = queue.popleft()
    if depth[s] == 14:
        board14 = s
        break
    for m in succ(s):
        if m not in depth:
            depth[m] = depth[s] + 1
            queue.append(m)

print("a board at optimal depth 14:", board14)
for name, h in (("h0 none (= uniform cost)", h0), ("h1 misplaced tiles", h1),
                ("h2 Manhattan distance", h2)):
    cost, gen = astar(board14, h)
    print("  %-26s solution %d moves, %8d nodes generated" % (name, cost, gen))
munotes.in80

Heuristics: Estimating What Is Left To Do

a board at optimal depth 14: (7, 6, 2, 4, 3, 5, 0, 1, 8)
  h0 none (= uniform cost)   solution 14 moves,     4767 nodes generated
  h1 misplaced tiles         solution 14 moves,      394 nodes generated
  h2 Manhattan distance      solution 14 moves,       87 nodes generated

Four thousand seven hundred and sixty-seven nodes, down to eighty-seven. All three found the same 14-move answer, so nothing was given up. A cheap count of how far each tile is from home did the work of examining fifty-four times as many states.

These are this book's own figures on one board, using a reached set, and they are smaller than the averages usually published, which are taken over many random instances and often without one. The shape is what matters and it is the same: no heuristic, thousands; a weak one, hundreds; a dominating one, tens.

The straight-line heuristic on the standing map

For the district map, relaxation deletes the roads: fly in a straight line. The coordinates are in Formulating a Problem for Search, and the resulting estimate to Jalna, rounded down, is:

Townh(n), km in a straight linetrue cheapest road distance to Jalna
Amba2025
Bori1517
Chinch1519
Devi1112
Erandol812
Fanas55
Gokul66
Hivra37
Jalna00

Every h is at most the true cost, in every row. That is not luck: the map was built so that every road's length is at least the straight-line distance between its ends, so no road journey can be shorter than flying. Admissibility, and Why A* Is Optimal turns this table into a proof.

Two rows are worth staring at, because they are where the next two chapters get their teeth.

Fanas and Gokul are exact: h equals the truth, 5 and 6. A heuristic that is exact everywhere would let a search walk straight to the answer with no wasted work at all.

Hivra is badly wrong: h is 3 and the truth is 7, because the river makes the direct road 16 km. h is still not an overestimate, so nothing breaks, but the estimate is misleading. Erandol is the same trap and worse: h is 8, the truth is 12, and the ROAD to Erandol from Amba costs 33. The next chapter follows a heuristic that trusts this row and pays 47 km for a 25 km journey.

What makes a heuristic good

Four properties, and a real heuristic trades them against each other.

  1. It never overestimates. Formally, admissibility, chapter 20. Without it A* loses its guarantee.
  2. It is as large as possible. Dominance. A bigger admissible estimate does more work for you.
  3. It is cheap. A perfect heuristic could be computed by solving the problem, which is useless. The whole saving is that h is computed in microseconds and the search it prunes would take hours. A heuristic that costs more than the branches it saves is a loss.
  4. h(goal) is 0, and h is never negative.
munotes.in81

Heuristics: Estimating What Is Left To Do

Property 2 and property 3 pull in opposite directions, and that tension is the practical art of it. Manhattan distance is a better estimate than misplaced tiles and costs about the same, so it wins outright. A heuristic that solved a relaxed problem by search at every node would estimate beautifully and be slower than searching.

Distinctions

g(n)h(n)
Directionbackwards, start to nforwards, n to a goal
Exactyes, the path was travelledno, an estimate
Problem specificno, any cost function will doyes, entirely
Used byuniform cost searchgreedy best first search
Uninformed searchInformed search
Usesthe goal test and step costs onlyplus a heuristic h
Knows the direction of the goalnoyes, approximately
Examples in this rowBFS, DFS, UCS, IDSgreedy, A*, RBFS
h1, misplaced tilesh2, Manhattan distance
Countstiles not in placerows plus columns to travel
On the standing board818
Relaxationa tile may teleport hometiles may pass through each other
Dominatesnoyes, it dominates h1

What it does not mean

A heuristic is not a rule of thumb about what to do. It is a number estimating remaining cost. The everyday sense of the word is different and leads students to write about "using heuristics to decide", which earns nothing.

A heuristic is not a guarantee. It can be wrong at any state. Hivra's estimate is off by more than half.

Bigger is not always better. Bigger is better among heuristics that never overestimate. An estimate that overestimates can be very large and makes the search return wrong answers.

h is not the same as f. h is the estimate of what remains; f is g plus h, the estimate of the whole journey. Greedy best first search orders on h, A* on f, and that difference is the next two chapters.

The blank is not a tile. Both 8-puzzle heuristics exclude it, and including it destroys the guarantee.

A perfect heuristic is not the goal. It would cost as much as solving the problem. The goal is a good estimate that is almost free.

Quick revision

  • h(n): an estimate of the cheapest cost from n to a goal. Problem specific, cheap, h(goal) = 0, never negative.
  • g(n) looks backwards and is exact; h(n) looks forwards and is a guess; f(n) = g(n) + h(n) estimates the whole route.
  • Relaxation is where a heuristic comes from: delete a constraint and solve the easier problem exactly. The answer can never exceed the real cost, so relaxation gives an admissible heuristic automatically.
  • 8-puzzle heuristics: misplaced tiles (relax so a tile may teleport home) and Manhattan distance (relax so tiles may pass through each other). The blank is not a tile in either.
  • On the standing board: h1 is 8, h2 is 18, and the truth is 26 moves.
  • Dominance: h2 is at least h1 everywhere, so h2 dominates and is the better choice while still being cheap.
  • District map: h is the straight-line distance. Exact at Fanas and Gokul; off by 4 at Hivra because of the river, and off by 4 at Erandol, whose road from Amba is 33 km. Those two rows are the traps the next chapters spring.
  • Four properties of a good heuristic: never overestimates, as large as possible, cheap, and zero at the goal. The second and third pull against each other.
munotes.in82

Heuristics: Estimating What Is Left To Do

Test yourself

1. Define a heuristic function and state its three requirements. h(n) estimates the cost of the cheapest path from the state at n to a goal. It must be problem specific, cheap to compute, and zero at any goal state, and it is never negative.

2. Distinguish g, h and f. g(n) is the exact cost of the path already travelled from the start to n. h(n) is an estimate of the cost still to come from n to a goal. f(n) is g(n) plus h(n), an estimate of the total cost of a route through n.

3. What is relaxation, and why does it produce a heuristic that never overestimates? Relaxation deletes a constraint from the problem and solves the easier problem exactly. Every solution of the real problem is still a solution of the relaxed one, so the relaxed optimum is at most the real optimum, and the estimate can never exceed the truth.

4. Compute both 8-puzzle heuristics for the board 7 2 4 / 5 blank 6 / 8 3 1 against the goal blank 1 2 / 3 4 5 / 6 7 8. Misplaced tiles is 8, since every tile is out of place. Manhattan distance is 18, the sum of 3, 1, 2, 2, 3, 2, 2 and 3 for tiles 7, 2, 4, 5, 6, 8, 3 and 1. The board actually needs 26 moves, so both are under it.

5. Why is the blank excluded from both heuristics? Because the blank moves on every single move. Counting its displacement would allow the estimate to exceed the true number of moves, destroying the guarantee that the heuristic never overestimates.

munotes.in83

Heuristics: Estimating What Is Left To Do

6. What does it mean for one heuristic to dominate another, and why is the dominating one preferred? h2 dominates h1 when h2(n) is at least h1(n) at every state and both are admissible. The dominating one is preferred because a larger estimate that still never overestimates lets the search discard more branches, and it cannot cause a wrong answer.

7. On the standing map h(Hivra) is 3 while the true cheapest road distance to Jalna is 7. Is the heuristic broken? No. A heuristic is an estimate and is allowed to be wrong; what matters is that it does not exceed the truth, and 3 is less than 7. The estimate is misleading rather than invalid, and the direct road is long because a river lies between Hivra and Jalna.

Contents This chapter on its own page

munotes.in84

Chapter Nineteen

Admissibility, and Why A* Is Optimal

Syllabus topic Module 1, "admissibility"

In one line

A heuristic is admissible when it never guesses too high, and that one property is what makes A* return the cheapest route rather than merely a route.

In the wording a student can write in an examination: a heuristic h is admissible if for every node n,

h(n) <= h*(n)

where h(n) is the true cost of the cheapest path from n to a goal. An admissible heuristic therefore never overestimates the remaining cost; it is an optimistic estimate, or a lower bound. With an admissible h, tree-search A is guaranteed to return an optimal solution.

The definition, in three equivalent phrasings

All three appear in papers and all three mean the same thing, and being able to move between them is worth marks.

PhrasingStatement
Never overestimatesh(n) is at most the true remaining cost
Optimisticit always thinks the goal is at least as near as it really is
A lower boundh(n) is a lower bound on h*(n)

Two consequences follow at once from the definition and are often asked. h(goal) must be 0, because the true remaining cost at a goal is 0 and nothing is at most 0 except 0 and negatives. And h(n) = 0 for every n is admissible, trivially, which is exactly why uniform cost search is a special case of A* and inherits its optimality.

Where the original word came from

Read the 1968 paper and the word is used the other way round. Hart, Nilsson and Raphael write:

We call an algorithm admissible if it is guaranteed to find an optimal path from s to a preferred goal node of s for any graph

and their Theorem 1 is:

If h(n) <= h(n) for all n, then A is admissible

So in the source, the ALGORITHM is what is admissible and the condition on h is the hypothesis that makes it so. Modern usage moved the adjective onto the heuristic, which is what MU prints and what this book uses. A student who reads the original will meet the older usage and should recognise it rather than conclude that something is wrong.

Proving it, on the standing map

Do not assume the straight-line heuristic is admissible. The way to establish it is to compute the true cheapest road distance from every town, which is what a uniform cost search run outwards from the goal gives, and compare.

# Is the straight-line heuristic admissible on the standing map? Do not assume it:
# compute the TRUE cheapest road distance from every town to Jalna and compare.
import heapq
ROAD = {
    "Amba":    {"Bori": 8, "Chinch": 7, "Erandol": 33},
    "Bori":    {"Amba": 8, "Chinch": 12, "Devi": 5},
    "Chinch":  {"Amba": 7, "Bori": 12, "Erandol": 7, "Gokul": 13},
    "Devi":    {"Bori": 5, "Fanas": 7, "Hivra": 9},
    "Erandol": {"Amba": 33, "Chinch": 7, "Fanas": 9, "Gokul": 6},
    "Fanas":   {"Devi": 7, "Erandol": 9, "Hivra": 2, "Jalna": 5},
    "Gokul":   {"Chinch": 13, "Erandol": 6, "Jalna": 6},
    "Hivra":   {"Devi": 9, "Fanas": 2, "Jalna": 16},
    "Jalna":   {"Fanas": 5, "Gokul": 6, "Hivra": 16},
}
SLD = {"Amba": 20, "Bori": 15, "Chinch": 15, "Devi": 11, "Erandol": 8,
       "Fanas": 5, "Gokul": 6, "Hivra": 3, "Jalna": 0}

def cheapest_to(goal):
    """Uniform cost search outwards from the goal: the true h* for every town."""
    best = {goal: 0}
    frontier = [(0, goal)]
    while frontier:
        g, node = heapq.heappop(frontier)
        if g > best.get(node, float("inf")):
            continue
        for nxt, c in ROAD[node].items():
            if g + c < best.get(nxt, float("inf")):
                best[nxt] = g + c
                heapq.heappush(frontier, (g + c, nxt))
    return best

TRUE = cheapest_to("Jalna")
print("town      h(n)   h*(n)   h <= h*?   slack")
worst = None
for n in sorted(ROAD):
    ok = SLD[n] <= TRUE[n]
    slack = TRUE[n] - SLD[n]
    if worst is None or slack > worst[1]:
        worst = (n, slack)
    print("%-9s %4d %7d   %-8s %5d" % (n, SLD[n], TRUE[n], "yes" if ok else "NO", slack))
print()
print("admissible at every one of the %d towns: %s"
      % (len(ROAD), all(SLD[n] <= TRUE[n] for n in ROAD)))
print("least accurate: %s, short by %d km" % worst)
print()
print("now break admissibility at ONE town, by 2 km, and run A* again:")
BAD = dict(SLD); BAD["Fanas"] = 7          # the truth is 5
print("  h(Fanas) = %d, h*(Fanas) = %d, admissible? %s"
      % (BAD["Fanas"], TRUE["Fanas"], BAD["Fanas"] <= TRUE["Fanas"]))

def a_star(h):
    frontier = [(h["Amba"], 0, ["Amba"])]
    best = {}
    while frontier:
        f, g, path = heapq.heappop(frontier)
        node = path[-1]
        if node in best and best[node] <= g:
            continue
        best[node] = g
        if node == "Jalna":
            return g, path
        for child, c in sorted(ROAD[node].items()):
            heapq.heappush(frontier, (g + c + h[child], g + c, path + [child]))
    return None, None

for name, h in (("the straight-line h", SLD), ("h with Fanas over by 2", BAD)):
    cost, route = a_star(h)
    print("  %-26s returns %d km: %s" % (name, cost, " > ".join(route)))
munotes.in96

Admissibility, and Why A* Is Optimal

town      h(n)   h*(n)   h <= h*?   slack
Amba        20      25   yes          5
Bori        15      17   yes          2
Chinch      15      19   yes          4
Devi        11      12   yes          1
Erandol      8      12   yes          4
Fanas        5       5   yes          0
Gokul        6       6   yes          0
Hivra        3       7   yes          4
Jalna        0       0   yes          0

admissible at every one of the 9 towns: True
least accurate: Amba, short by 5 km

now break admissibility at ONE town, by 2 km, and run A* again:
  h(Fanas) = 7, h*(Fanas) = 5, admissible? False
  the straight-line h        returns 25 km: Amba > Bori > Devi > Fanas > Jalna
  h with Fanas over by 2     returns 26 km: Amba > Chinch > Erandol > Gokul > Jalna
munotes.in97

Admissibility, and Why A* Is Optimal

Two kilometres of over-optimism at one town out of nine costs the optimal answer. That is how tight the condition is, and it is why the word appears in MU's own label. Admissibility is not a nicety; it is the hypothesis of the theorem, and losing it loses the conclusion immediately.

Why the straight-line distance is admissible without checking every town

The program checked nine towns. The general argument is two lines and is what makes the heuristic safe on a map of nine thousand towns.

Every road between two towns is at least as long as the straight line between them, because a straight line is the shortest path between two points. So any journey by road from n to the goal is at least as long as the straight line from n to the goal. Therefore the straight-line distance is at most the cheapest road distance, which is the definition.

That is the argument the 1968 paper itself gives, in its own example of cities connected by roads, and it is also the general reason relaxation works: the straight line is the exact answer to the relaxed problem in which you may fly.

It depends on a property of the map, not of geometry. If a road could be shorter than the straight line, the argument fails. The standing map was built with every winding factor at least 1 precisely so that it holds, and that construction is declared in Formulating a Problem for Search rather than assumed here.

The proof that A* is optimal

Tree search, admissible h. Proof by contradiction, and it is short enough to reproduce in an examination.

Suppose A returns a suboptimal goal node t, with g(t) greater than C, the cost of an optimal solution.

  1. Let n be a node on an optimal path that is still on the frontier at the moment t is selected. Such an n must exist: the start is on the optimal path, and the optimal path's nodes cannot all have been expanded, because then the optimal goal would have been generated and, being cheaper, would have been selected before t.
  2. Because n is on an optimal path, g(n) is the true cheapest cost to n, and the remaining cost from n is h(n). So g(n) + h(n) = C*.
  3. By admissibility, h(n) <= h(n). So f(n) = g(n) + h(n) <= g(n) + h(n) = C*.
  4. For the goal t, h(t) = 0, so f(t) = g(t), which by assumption is greater than C*.
  5. Hence f(n) <= C < f(t), so n had a strictly smaller f than t and A would have selected n rather than t. That contradicts the assumption.
munotes.in98

Admissibility, and Why A* Is Optimal

Step 3 is the only place admissibility is used, and it is used exactly once. That is the answer to "where does admissibility come in": it is what lets f(n) be bounded above by C* for a node on the optimal path, and everything else is bookkeeping.

Step 4 uses h(goal) = 0. A heuristic that reported a positive value at the goal would break the proof at that step, which is why that requirement is part of the definition and not a convention.

Optimally efficient, which is a different and stronger claim

The 1968 paper proves something beyond optimality, and it is worth knowing because it explains why nothing has replaced A*.

Section III shows that A is not only admissible but optimal in the sense that no other admissible algorithm expands fewer nodes using the same information. The paper's own words: A is not only admissible but optimal, in the sense that no other admissible algorithm expands fewer nodes.

The claim has a condition, the paper's consistency assumption, and that condition is the whole of the next chapter. What it means in practice: given the same heuristic, any algorithm that guarantees an optimal answer must expand every node whose f is below C, because any one of them might hide a cheaper route, and A expands exactly those and no more. There is no cleverer ordering to be found.

What admissibility does not give you

Three things it is routinely assumed to guarantee and does not.

It does not make A fast. The 8-puzzle heuristic h0 = 0 is admissible and makes A into uniform cost search. Admissibility guarantees the answer, not the work.

It does not survive graph search on its own. With a reached set that never reconsiders a settled node, an admissible but inconsistent heuristic can make A* return a suboptimal route. That is the next chapter, and it is why MU prints both words.

It does not mean the estimate is good. Look at the slack column: the heuristic is short by 5 km at Amba and by 4 at three more towns. It is admissible everywhere and mediocre in several places.

Distinctions

AdmissibleConsistent
Conditionh(n) <= h*(n)h(n) <= cost(n, n') + h(n') for every edge
A condition oneach node separatelyeach EDGE
Guarantees optimality of A* intree searchgraph search
Which is strongerweakerstronger: consistency implies admissibility
h(n)h*(n)
Isthe estimate we computethe true cheapest remaining cost
Known at search timeyes, cheaplyno, that is the whole problem
Admissibility saysh is at most h*
munotes.in99

Admissibility, and Why A* Is Optimal

Admissible heuristic (modern)Admissible algorithm (1968)
The adjective describeshthe search algorithm
Meansnever overestimatesguaranteed to find an optimal path
Used byMU's syllabus and this bookHart, Nilsson and Raphael

What it does not mean

Admissible does not mean accurate. It means never too high. A heuristic can be admissible and useless, and h = 0 is the extreme case.

It is not a property of the algorithm in modern usage, although it was in 1968. Both usages exist and mean different things.

It does not require h to be a lower bound on the cost of the particular path found. It is a lower bound on the cost of the CHEAPEST remaining path, which is a smaller number and therefore a stronger requirement.

Overestimating a little is not a little wrong. Two kilometres at one town lost the optimal route on a nine-town map. The guarantee is all or nothing.

Admissibility alone is not enough for graph search. The commonest error on this topic, and the reason the next chapter exists.

Quick revision

  • Admissible: h(n) <= h*(n) at every node. Never overestimates; optimistic; a lower bound.
  • Two consequences: h(goal) = 0, and h = 0 everywhere is admissible, which makes uniform cost search a special case of A*.
  • Straight-line distance is admissible because no road is shorter than the straight line, so no road journey is shorter than flying. That argument, and this book's map, are both in the 1968 paper's own example.
  • Proved on the standing map by computing h* at all nine towns. Slack ranges from 0 at Fanas and Gokul to 5 at Amba.
  • Breaking it by 2 km at one town changes the answer from 25 km to 26 km. The guarantee is all or nothing.
  • The proof: if A returned a suboptimal t, some node n on the optimal path is still on the frontier, f(n) = g(n) + h(n) <= g(n) + h(n) = C* < g(t) = f(t), so n would have been chosen. Admissibility is used once, in the middle inequality.
  • Optimally efficient: no admissible algorithm using the same heuristic expands fewer nodes, subject to the consistency assumption.
  • Admissibility does not give speed, and does not suffice for graph search.

Test yourself

1. Define an admissible heuristic. A heuristic h is admissible if h(n) is at most h*(n), the true cost of the cheapest path from n to a goal, at every node n. It never overestimates the remaining cost.

2. Show that h(n) = 0 for all n is admissible, and say what A becomes. True remaining costs are never negative, so 0 is a lower bound everywhere and the heuristic is admissible. A then orders on g alone, which is uniform cost search.

munotes.in100

Admissibility, and Why A* Is Optimal

3. Why is straight-line distance admissible on a road map? Because a straight line is the shortest path between two points, so every road is at least as long as the straight line between its ends, and therefore any road journey from a town to the goal is at least the straight-line distance. The estimate is thus never above the true cost.

4. Prove that A with an admissible heuristic returns an optimal solution in tree search. Suppose it returns t with g(t) greater than the optimal cost C. Some node n on an optimal path remains on the frontier, and for it g(n) + h(n) equals C. By admissibility h(n) is at most h(n), so f(n) is at most C. Since h(t) is 0, f(t) equals g(t), which exceeds C*. So f(n) is less than f(t) and n would have been selected instead, a contradiction.

5. Where exactly is admissibility used in that proof, and what would happen without it? Only in the step bounding f(n) by C. Without it h(n) could exceed h(n), f(n) could exceed C, and there would be nothing to stop A selecting the dearer goal first.

6. This chapter overestimated one town's heuristic by 2 km out of nine towns. What happened, and what does it show? A* returned 26 km by Chinch, Erandol and Gokul instead of the optimal 25 km by Bori, Devi and Fanas. It shows that the guarantee is all or nothing: a small violation at a single node is enough to lose the optimal answer.

7. Does admissibility guarantee that A* is optimal in graph search? Explain. No. With a reached set that never reconsiders a state already settled, an admissible but inconsistent heuristic can cause a suboptimal route to be returned, because a state can be closed by an expensive route before the cheap route to it is found. Graph search needs consistency, or else the ability to reopen closed nodes.

Contents This chapter on its own page

munotes.in101

Chapter Twenty

Consistency, and A* on a Graph

Syllabus topic Module 1, "consistency"

In one line

Consistency is a condition on every edge rather than on every node, and it is what makes A* safe once you start remembering which states you have already finished with.

In the wording a student can write in an examination: a heuristic h is consistent, also called monotonic, if for every node n and every successor n' of n reached by an action of cost c(n, n'),

h(n) <= c(n, n') + h(n')

This is a triangle inequality: the estimate at n may not exceed the cost of one step plus the estimate from where that step lands. With a consistent heuristic, f is non-decreasing along every path, and graph-search A* is optimal.

Why admissibility was not enough

Admissibility, and Why A* Is Optimal proved optimality for tree search, which keeps no record of states already dealt with. Every practical implementation keeps one, because without it the same states are re-derived endlessly.

And that record is exactly what breaks the proof. Graph-search A* settles a state the first time it is selected and then refuses cheaper routes to it. That refusal is sound only if the first selection really was by the cheapest route. Admissibility does not guarantee that. Consistency does.

The condition, read in words

h(n) <= c(n, n') + h(n')

Read it as a promise the heuristic makes about itself: taking one real step and then estimating cannot be more optimistic than estimating from where you started. If the estimate at Devi is 11, and Devi to Fanas costs 7, then the estimate at Fanas must be at least 4. Anything less would mean the estimate had suddenly become more pessimistic about a shorter remaining journey, which is incoherent.

The name monotonic comes from the consequence: rearrange the inequality and add g(n) to both sides.

g(n) + h(n) <= g(n) + c(n, n') + h(n')

= g(n') + h(n')

so f(n) <= f(n')

f never decreases along any path. That is the property the algorithm actually uses, and it is worth deriving in an examination because it is three lines and it explains everything else.

Consistency implies admissibility

One direction is a theorem and the other is false, and papers ask for both.

Consistency implies admissibility. Take the cheapest path from n to a goal, say n, n1, n2, ..., goal. Apply the condition at each step and add up: h(n) <= c(n,n1) + h(n1) <= c(n,n1) + c(n1,n2) + h(n2) <= ... <= (the whole path cost) + h(goal). Since h(goal) = 0, the last line is exactly h(n) <= h*(n), which is admissibility.

Admissibility does not imply consistency. The counter-example is below, and it is the point of the chapter.

munotes.in102

Consistency, and A* on a Graph

The counter-example, built and run

Four nodes. The heuristic is checked for admissibility at every node, and for consistency on every edge, by the program rather than by inspection.

# An ADMISSIBLE but INCONSISTENT heuristic, and what it does to A* when a closed
# node is never reopened. Four nodes; the numbers are chosen so the failure is
# forced rather than lucky.
import heapq

EDGE = {"S": {"A": 2, "B": 5},
        "A": {"S": 2, "B": 2},
        "B": {"S": 5, "A": 2, "G": 2},
        "G": {"B": 2}}
H = {"S": 0, "A": 4, "B": 0, "G": 0}      # admissible, and NOT consistent
TRUE = {"S": 6, "A": 4, "B": 2, "G": 0}   # the real cheapest cost to G

print("admissible?  h(n) <= true cost to G, at every node")
for n in ("S", "A", "B", "G"):
    print("   %s: h=%d  true=%d  %s" % (n, H[n], TRUE[n], "yes" if H[n] <= TRUE[n] else "NO"))
print()
print("consistent?  h(u) <= cost(u,v) + h(v), for every edge")
bad = []
for u in EDGE:
    for v, c in EDGE[u].items():
        ok = H[u] <= c + H[v]
        if not ok:
            bad.append((u, v, c))
        print("   %s -> %s  c=%d   h(%s)=%d  c+h(%s)=%d   %s"
              % (u, v, c, u, H[u], v, c + H[v], "yes" if ok else "NO"))
print()
print("violated on:", bad)
print()

def a_star(reopen):
    frontier = [(H["S"], 0, ["S"])]
    closed = {}
    log = []
    while frontier:
        f, g, path = heapq.heappop(frontier)
        node = path[-1]
        if node in closed and not (reopen and g < closed[node]):
            continue
        closed[node] = g
        log.append("%s(g=%d,f=%d)" % (node, g, f))
        if node == "G":
            return g, path, log
        for child, c in sorted(EDGE[node].items()):
            heapq.heappush(frontier, (g + c + H[child], g + c, path + [child]))
    return None, None, log

for reopen in (False, True):
    cost, path, log = a_star(reopen)
    print("%-28s cost %d  route %s" % ("reopening closed nodes: " + str(reopen),
                                       cost, " > ".join(path)))
    print("    expanded: " + "  ".join(log))
print()
print("the cheapest route is S > A > B > G at 2 + 2 + 2 = 6")
admissible?  h(n) <= true cost to G, at every node
   S: h=0  true=6  yes
   A: h=4  true=4  yes
   B: h=0  true=2  yes
   G: h=0  true=0  yes

consistent?  h(u) <= cost(u,v) + h(v), for every edge
   S -> A  c=2   h(S)=0  c+h(A)=6   yes
   S -> B  c=5   h(S)=0  c+h(B)=5   yes
   A -> S  c=2   h(A)=4  c+h(S)=2   NO
   A -> B  c=2   h(A)=4  c+h(B)=2   NO
   B -> S  c=5   h(B)=0  c+h(S)=5   yes
   B -> A  c=2   h(B)=0  c+h(A)=6   yes
   B -> G  c=2   h(B)=0  c+h(G)=2   yes
   G -> B  c=2   h(G)=0  c+h(B)=2   yes

violated on: [('A', 'S', 2), ('A', 'B', 2)]

reopening closed nodes: False cost 7  route S > B > G
    expanded: S(g=0,f=0)  B(g=5,f=5)  A(g=2,f=6)  G(g=7,f=7)
reopening closed nodes: True cost 6  route S > A > B > G
    expanded: S(g=0,f=0)  B(g=5,f=5)  A(g=2,f=6)  B(g=4,f=4)  G(g=6,f=6)

the cheapest route is S > A > B > G at 2 + 2 + 2 = 6
munotes.in103

Consistency, and A* on a Graph

The heuristic is admissible at all four nodes and inconsistent on two edges, and the algorithm returns 7 instead of 6. Follow the four expansions in the first run, because the failure happens in one line.

  1. S is expanded at f of 0. Its children go on the frontier: A with g 2 and f 2 plus 4 equals 6, and B with g 5 and f 5 plus 0 equals 5.
  2. B is selected at f of 5, ahead of A at 6, and is settled with g of 5. That is the fatal step. B's estimate is over-optimistic, 0 against a true 2, and that made the dear route to it look cheap.
  3. A is expanded at f of 6. It generates B again, now with g of 4, which is genuinely better. The closed set refuses it, because B is already settled.
  4. G is reached from the settled, dearer B, and the answer is 7.

f decreased along a path, and that is the symptom. f(A) is 6 and f(B) by way of A is 4. A search that assumes f never decreases has had its assumption broken, and the second run shows the two possible repairs.

The two repairs, and which is used where

There are exactly two ways to make graph-search A* optimal, and a paper may ask for either.

Use a consistent heuristic. Then f never decreases, so the first time a state is selected it is by its cheapest route, and closing it is safe. This is what happens in practice, because almost every heuristic derived by relaxation is consistent.

Allow reopening. Keep the closed set, but when a strictly cheaper route to a closed node is found, put it back on the frontier. That is what the second run does, and what the 1968 paper's own step 7 prescribes: Remark as open any closed node n_i which is a successor of n and for which f(n_i) is smaller now than it was when n_i was marked closed. It restores optimality at the cost of re-expanding nodes, and in the run above it cost one extra expansion.

So the 1968 algorithm was written to handle inconsistency and the textbook version usually is not. When a paper asks "is graph-search A* optimal with an admissible heuristic", the correct answer is: not in general; it is optimal if the heuristic is consistent, or if closed nodes may be reopened.

munotes.in104

Consistency, and A* on a Graph

Is the straight-line heuristic consistent

Yes, and the argument is the triangle inequality, which is the same argument the 1968 paper gives.

Let d(m, n) be the straight-line distance between towns m and n. Any road between them is at least as long, so c(m, n) >= d(m, n). And straight-line distances obey the triangle inequality, d(m, n) + d(n, goal) >= d(m, goal). Put the two together:

c(m, n) + h(n) >= d(m, n) + d(n, goal) >= d(m, goal) = h(m)

which is the consistency condition. Note what it rests on: that no road is shorter than the straight line. That is a property of the map, and it is the property the standing map was constructed to have.

Rounding needs one word of care. This book's h is the straight-line distance rounded down, and rounding down can only make h smaller, which can only help both conditions. Rounding up could break admissibility, and is the kind of small decision that quietly loses a guarantee.

Where consistency can genuinely fail

Do not leave with the impression that inconsistency is only a textbook curiosity. It arises in real work in two ways.

A heuristic assembled from several sources. Take the maximum of two admissible heuristics and the result is admissible, and if both are consistent the maximum is consistent too. Take a heuristic that is computed differently in different regions of the state space, and consistency is easily lost, which is exactly the 1968 paper's constructed example: it computes h one way at odd-numbered nodes and another way at even-numbered ones, so that h(s) = 8 while a node six units away has h = 1.

A learned or estimated heuristic. Anything fitted from data, including the models of Module 2, is under no obligation to satisfy an edge condition. A learned heuristic is usually neither admissible nor consistent, and using one means giving up the guarantee knowingly or adding reopening.

Distinctions

AdmissibleConsistent
Conditionh(n) <= h*(n)h(n) <= c(n, n') + h(n')
Quantified overnodesedges
Needs to knowthe true remaining costonly one step cost and two estimates
Guaranteestree-search A* optimalgraph-search A* optimal, and f non-decreasing
Implicationconsistency implies thisthis does not imply consistency
f non-decreasingf can decrease
Heuristic isconsistentinconsistent
Closing a selected nodesafeunsafe
First selection of a state isby its cheapest routenot necessarily
In the run abovesecond case, cost 6first case, cost 7
Consistent heuristicReopening closed nodes
What it fixesthe causethe symptom
Extra expansionsnonesome, one in the run above
Used bymodern textbook A*the original 1968 algorithm, step 7
munotes.in105

Consistency, and A* on a Graph

What it does not mean

Consistency is not about the nodes. It is a condition on every edge, and that is what makes it checkable without knowing any true cost.

Monotonic does not mean h is monotonic. h may rise and fall. It is f that never decreases, and the name refers to that.

An inconsistent heuristic is not necessarily wrong at any node. The one above is admissible everywhere. Inconsistency is an incoherence between neighbouring estimates, not an error at a point.

Reopening is not a hack. It is in the original published algorithm, and it is the correct repair when a consistent heuristic is not available.

Almost all does not mean all. Heuristics from relaxation are consistent, but heuristics stitched together from different rules, and heuristics learned from data, need not be.

Quick revision

  • Consistent (monotonic): h(n) <= c(n, n') + h(n') for every edge. A triangle inequality on the estimates.
  • Adding g(n) to both sides gives f(n) <= f(n'): f never decreases along a path. That is what the name monotonic refers to.
  • Consistency implies admissibility, by summing the condition along the cheapest path to a goal and using h(goal) = 0. The converse is false.
  • Admissible but inconsistent breaks graph search. In the four-node example the answer is 7 instead of 6: B is settled at g of 5 by the dear route because h(B) is over-optimistic, and the closed set then refuses the g of 4 route found through A.
  • The symptom is f decreasing along a path: f(A) is 6 and f(B) through A is 4.
  • Two repairs: use a consistent heuristic, or reopen a closed node when a strictly cheaper route to it appears. The 1968 algorithm's step 7 is the second.
  • Straight-line distance is consistent, by c(m,n) + h(n) >= d(m,n) + d(n,goal) >= d(m,goal) = h(m). It rests on no road being shorter than the straight line, which is a property of the map.
  • Rounding h down is safe; rounding up can break admissibility.

Test yourself

1. State the consistency condition and explain why it is called a triangle inequality. For every node n and successor n' reached at cost c(n, n'), h(n) is at most c(n, n') plus h(n'). It has the form of the triangle inequality because it says that going directly cannot be estimated as longer than going via an intermediate point.

2. Derive the monotonicity of f from consistency. Add g(n) to both sides of the condition: g(n) + h(n) is at most g(n) + c(n, n') + h(n'). The right-hand side is g(n') + h(n'), so f(n) is at most f(n'), and f does not decrease along any path.

munotes.in106

Consistency, and A* on a Graph

3. Prove that consistency implies admissibility. Apply the condition along the cheapest path from n to a goal and add the inequalities. The result is that h(n) is at most the total cost of that path plus h at the goal. Since h at a goal is 0, h(n) is at most the cheapest remaining cost, which is admissibility.

4. Give an admissible but inconsistent heuristic and describe what it does to graph-search A. In the four-node example, h(S) is 0, h(A) is 4, h(B) is 0 and h(G) is 0, against true costs of 6, 4, 2 and 0, so it is admissible. It violates consistency on the edge from A to B, where h(A) of 4 exceeds the step cost of 2 plus h(B) of 0. Graph-search A settles B by the 5-cost route, then refuses the cheaper 4-cost route found through A, and returns a total of 7 rather than 6.

5. Name the two ways to make graph-search A* optimal. Use a consistent heuristic, so that f never decreases and the first selection of a state is by its cheapest route. Or allow a closed node to be reopened when a strictly cheaper route to it is found, which is what the 1968 algorithm's step 7 does.

6. Show that the straight-line heuristic is consistent on a road map. Every road is at least as long as the straight line between its ends, and straight-line distances satisfy the triangle inequality. So the road cost from m to n plus the straight-line distance from n to the goal is at least the straight-line distance from m to n plus that from n to the goal, which is at least the straight-line distance from m to the goal, namely h(m).

7. Why is "monotonic" a confusing name, and what exactly is monotonic? Because h itself is not monotonic and may rise and fall from node to node. What is monotonic, in the sense of non-decreasing, is f along any path, and that is a consequence of the edge condition on h.

Contents This chapter on its own page

munotes.in107

Chapter Twenty-Two

Comparing Two Search Algorithms on One Problem

Syllabus topic Module 1, "Compare the performance and efficiency of both algorithms", "Uninformed search"

In one line

Comparing two search algorithms means counting five specific things on one problem, and the five disagree with each other, which is the whole reason the comparison is interesting.

In the wording a student can write in an examination: two search algorithms are compared on a fixed problem instance by measuring the cost of the solution found, the number of nodes generated, the number of nodes expanded, the peak size of the frontier, and whether the solution is optimal. The first and last measure the QUALITY of the answer; the middle three measure the WORK done. A comparison reporting only one of the five is incomplete.

What to measure, and why each one

MeasureWhat it isWhat it tells you
Solution costthe path cost of the answer returnedwhether the answer is any good
Optimalis that cost the least possiblewhether the algorithm kept its promise
Nodes generatedhow many nodes were created at allthe total work, including work thrown away
Nodes expandedhow many had their children generatedthe useful work
Peak frontierthe most nodes held at one momentwhether the algorithm can run at all

The peak frontier is the measure students leave out and the one that decides real problems. An algorithm that generates fewer nodes and needs a hundred times the memory is the worse choice on a large instance. It is also the measure that separates A* from RBFS, which is exactly the pair the practical asks about.

Generated and expanded are not the same, and the gap matters. A node is generated when it is created and put on the frontier; it is expanded when it is taken off and its own children are made. Nodes generated and never expanded are wasted work, so the ratio between the two is a measure of how much the algorithm threw away.

Why wall-clock time is not in the table

It is tempting and it is the wrong measurement for a write-up, for three reasons that are worth stating in a viva.

It measures the machine, not the algorithm. The same program on a different laptop gives a different number, so nothing can be concluded.

It measures the implementation. A heap is faster than a sorted list for the same algorithm. Timing compares your code, not the method.

On a problem small enough to trace by hand, it measures noise. Nine towns take microseconds, and the variation between runs exceeds the difference between the algorithms.

Node counts have none of those problems. They are properties of the algorithm and the instance, and they are the same on every machine. Report nodes; mention time only if the instance is large enough for it to mean something, and then say which machine.

munotes.in113

Comparing Two Search Algorithms on One Problem

The comparison, measured

# The practical's own instruction: "Compare the performance and efficiency of both
# algorithms." Four algorithms, ONE problem, five measurements each, in the table
# a practical write-up needs.
import heapq
from collections import deque

ROAD = {
    "Amba":    {"Bori": 8, "Chinch": 7, "Erandol": 33},
    "Bori":    {"Amba": 8, "Chinch": 12, "Devi": 5},
    "Chinch":  {"Amba": 7, "Bori": 12, "Erandol": 7, "Gokul": 13},
    "Devi":    {"Bori": 5, "Fanas": 7, "Hivra": 9},
    "Erandol": {"Amba": 33, "Chinch": 7, "Fanas": 9, "Gokul": 6},
    "Fanas":   {"Devi": 7, "Erandol": 9, "Hivra": 2, "Jalna": 5},
    "Gokul":   {"Chinch": 13, "Erandol": 6, "Jalna": 6},
    "Hivra":   {"Devi": 9, "Fanas": 2, "Jalna": 16},
    "Jalna":   {"Fanas": 5, "Gokul": 6, "Hivra": 16},
}
SLD = {"Amba": 20, "Bori": 15, "Chinch": 15, "Devi": 11, "Erandol": 8,
       "Fanas": 5, "Gokul": 6, "Hivra": 3, "Jalna": 0}
START, GOAL = "Amba", "Jalna"
INF = float("inf")

def km(path):
    return sum(ROAD[path[i]][path[i + 1]] for i in range(len(path) - 1))

class Meter:
    """One counter object per run, so nothing is measured by hand."""
    def __init__(self):
        self.generated = 1       # the start node counts
        self.expanded = 0
        self.peak = 1

def bfs(m):
    frontier = deque([[START]])
    reached = {START}
    while frontier:
        m.peak = max(m.peak, len(frontier))
        path = frontier.popleft()
        m.expanded += 1
        for child in sorted(ROAD[path[-1]]):
            if child in reached:
                continue
            m.generated += 1
            if child == GOAL:
                return path + [child]
            reached.add(child)
            frontier.append(path + [child])
    return None

def ids(m):
    def dls(path, limit):
        if path[-1] == GOAL:
            return path
        if len(path) - 1 == limit:
            return None
        m.expanded += 1
        for child in sorted(ROAD[path[-1]]):
            if child in path:
                continue
            m.generated += 1
            m.peak = max(m.peak, len(path) + 1)
            found = dls(path + [child], limit)
            if found:
                return found
        return None
    for limit in range(0, 10):
        found = dls([START], limit)
        if found:
            return found
    return None

def astar(m):
    frontier = [(SLD[START], 0, [START])]
    best = {}
    while frontier:
        m.peak = max(m.peak, len(frontier))
        f, g, path = heapq.heappop(frontier)
        node = path[-1]
        if node in best and best[node] <= g:
            continue
        best[node] = g
        m.expanded += 1
        if node == GOAL:
            return path
        for child, cost in sorted(ROAD[node].items()):
            m.generated += 1
            heapq.heappush(frontier, (g + cost + SLD[child], g + cost, path + [child]))
    return None

def rbfs(m):
    def go(path, g, f_limit):
        node = path[-1]
        m.expanded += 1
        m.peak = max(m.peak, len(path))
        if node == GOAL:
            return path, g
        kids = []
        for child, cost in sorted(ROAD[node].items()):
            if child in path:
                continue
            m.generated += 1
            kids.append([max(g + cost + SLD[child], g + SLD[node]), g + cost, child])
        if not kids:
            return None, INF
        while True:
            kids.sort()
            best = kids[0]
            if best[0] > f_limit:
                return None, best[0]
            alt = kids[1][0] if len(kids) > 1 else INF
            found, best[0] = go(path + [best[2]], best[1], min(f_limit, alt))
            if found is not None:
                return found, best[0]
    return go([START], 0, INF)[0]

print("problem: %s to %s on the district map, 9 towns, 15 roads" % (START, GOAL))
print()
print("algorithm  cost  hops  generated  expanded  peak in memory  optimal?")
for name, fn in (("BFS", bfs), ("IDS", ids), ("A*", astar), ("RBFS", rbfs)):
    m = Meter()
    route = fn(m)
    print("%-9s %5d %5d %10d %9d %15d  %s"
          % (name, km(route), len(route) - 1, m.generated, m.expanded, m.peak,
             "yes" if km(route) == 25 else "NO, 25 exists"))
print()
print("route each one returned:")
for name, fn in (("BFS", bfs), ("IDS", ids), ("A*", astar), ("RBFS", rbfs)):
    print("  %-5s %s" % (name, " > ".join(fn(Meter()))))
munotes.in114

Comparing Two Search Algorithms on One Problem

problem: Amba to Jalna on the district map, 9 towns, 15 roads

algorithm  cost  hops  generated  expanded  peak in memory  optimal?
BFS          26     3          9         6               3  NO, 25 exists
IDS          26     3         31        13               4  NO, 25 exists
A*           25     4         25         8              18  yes
RBFS         25     4         17         8               5  yes

route each one returned:
  BFS   Amba > Chinch > Gokul > Jalna
  IDS   Amba > Chinch > Gokul > Jalna
  A*    Amba > Bori > Devi > Fanas > Jalna
  RBFS  Amba > Bori > Devi > Fanas > Jalna

Reading the table, which is what the marks are for

A write-up that prints the table and stops earns half the marks. The reading is the answer.

No column names one winner. BFS does the least total work of any of the four, 9 nodes generated, and returns the wrong route. A* returns the right route and holds eighteen nodes at once. There is no row that is best in every column, and that is the finding, not a failure of the experiment.

BFS against IDS: the same answer for three times the generation. Both return 26 km in three hops, because both are optimal in the number of steps and neither is optimal in cost. IDS generated 31 nodes against BFS's 9, which is its repeated passes. And its peak memory is 4 against 3, which on this tiny map is nothing, and on a problem at depth 12 with a branching factor of 10 is the difference between 120 nodes and a hundred gigabytes. The pair to compare is exactly the pair the practical sets, and this is what to say about it.

A against RBFS: the same answer, and the memory column is the whole story. Both return 25 km in four hops and both expanded 8 nodes. A generated 25 nodes and held 18 at its peak; RBFS generated 17 and held 5. On nine towns that is a curiosity. The peak frontier of A* grows exponentially with the depth of the solution and RBFS's grows linearly, so on a real instance the same two numbers become "runs" and "cannot be started". That is the comparison the practical wants and it is a sentence, not a table.

munotes.in115

Comparing Two Search Algorithms on One Problem

The optimal column is not a bonus, it is a promise. BFS and IDS are not broken: neither claims cost optimality on unequal step costs. Reporting them as failures would be misreading their contract, and a viva may test exactly that.

Writing it up, and what the viva asks

A practical write-up for this pair has six parts, and they follow from the table above.

  1. The problem, stated exactly. Start, goal, the graph, and the step costs. Two algorithms compared on different instances have not been compared.
  2. Both implementations, with the counters visible in the code rather than added by hand.
  3. The table, one row per algorithm, the five measures.
  4. The routes returned, in full. Two algorithms can agree on cost and disagree on route.
  5. The reading: which measure each algorithm wins, and which measure decides the choice for this problem. Name the measure.
  6. The limit of the experiment: one instance proves nothing about the general case. Say so.

Point 6 is the honest one and it is worth a mark. Nine towns is one instance. A* beating uniform cost search by one expansion here is not evidence of anything; the 8-puzzle measurement in Heuristics: Estimating What Is Left To Do, where the same algorithm went from 4,767 nodes to 87, is.

The viva questions this table answers directly: which algorithm used least memory and why; which found the cheapest route and why the others did not; what would change if every road were the same length; and why you did not report the time.

What changes if the step costs are equal

A good question to be ready for, because it is the quickest test of whether the four algorithms are understood.

If every road cost the same, then ordering by cost is ordering by depth. BFS and IDS become cost optimal, because fewest steps is now cheapest. Uniform cost search becomes BFS. A with a heuristic still expands fewer nodes than BFS, so it remains worth using, and RBFS still uses less memory than A. Two of the four rows change their optimal column and none of the work columns changes character.

Distinctions

Nodes generatedNodes expanded
Counted whena node is created and put on the frontierit is taken off and its children made
Includes work thrown awayyesno
In the A* row258
What the gap measureshow much the algorithm created and never used
munotes.in116

Comparing Two Search Algorithms on One Problem

Peak frontierNodes generated
Measuresmemory, at one instanttotal work, over the run
Decideswhether the algorithm can runhow long it takes
A* against RBFS here18 against 525 against 17
Solution costOptimal
Isa numberyes or no
BFS here26 kmno, 25 exists
Why that is not a bugBFS promises fewest steps, not least cost

What it does not mean

Fewer nodes generated is not the same as better. BFS generated the fewest of the four and returned the wrong answer.

Wall-clock time is not a measure of an algorithm. It measures the machine, the implementation and, on a small instance, the noise.

One instance is not a comparison of algorithms. It is a comparison of their behaviour on one instance, which is what a practical asks for and all it establishes.

An algorithm that is not optimal has not failed. It has to be judged against what it promises. BFS and IDS promise fewest steps.

Peak frontier is not the same as total memory used over the run. It is the most held at any one instant, which is what the machine has to supply.

Quick revision

  • Five measures: solution cost, optimal or not, nodes generated, nodes expanded, peak frontier. The first two are the answer's quality, the last three the work.
  • Peak frontier is the measure that decides real problems and the one usually omitted.
  • Generated counts creation, expanded counts having children made. The gap is work thrown away: A* generated 25 and expanded 8.
  • Do not report wall-clock time: it measures the machine, the implementation, and on a small instance the noise. Report node counts, which are machine independent.
  • The measured table on the standing map: BFS 26 km / 9 generated / peak 3, IDS 26 km / 31 / peak 4, A* 25 km / 25 / peak 18, RBFS 25 km / 17 / peak 5.
  • BFS against IDS: same answer, three times the generation, and one node more memory here, which becomes the whole difference at depth.
  • A* against RBFS: same answer, same expansions, 18 against 5 in memory. That gap grows exponentially against linearly, so it becomes "runs" against "cannot start".
  • A write-up has six parts and the last is the honest one: one instance proves nothing general.

Test yourself

1. Name the five things to measure when comparing two search algorithms. The cost of the solution found, whether it is optimal, the number of nodes generated, the number of nodes expanded, and the peak size of the frontier.

2. Distinguish nodes generated from nodes expanded, and say what the gap means. A node is generated when it is created and placed on the frontier; it is expanded when it is removed and its own children are generated. The difference is work the algorithm created and never used: A* generated 25 nodes here and expanded only 8.

munotes.in117

Comparing Two Search Algorithms on One Problem

3. Why is wall-clock time a poor measure for this write-up? Because it depends on the machine and on the implementation rather than on the algorithm, and on a nine-town problem the run-to-run variation is larger than the difference between the algorithms. Node counts are properties of the algorithm and the instance.

4. BFS returned 26 km and A* returned 25 km. Is BFS broken? No. BFS guarantees the fewest steps and returns a three-hop route; it guarantees least cost only when all step costs are equal, and the roads here are 2 km to 33 km. It kept the promise it makes.

5. A and RBFS returned the same route and expanded the same number of nodes. On what basis would you choose between them? On memory. A held 18 nodes at its peak and RBFS held 5. The peak for A grows exponentially with the depth of the solution and for RBFS linearly, so on a large instance A cannot be started while RBFS runs.

6. Which algorithm did the least total work here, and why is that not enough to recommend it? BFS, with 9 nodes generated. It is not enough because the route it returned was not the cheapest, so the least work bought the wrong answer.

7. What would change in the table if every road on the map were 10 km long? BFS and IDS would become cost optimal, because fewest steps would then be cheapest, so their optimal column would change to yes. Uniform cost search would behave exactly as BFS. A would still expand fewer nodes than BFS thanks to the heuristic, and RBFS would still use far less memory than A.

Contents This chapter on its own page

munotes.in118

Chapter Twenty-Four

Minimax

Syllabus topic Module 1, "Minimax"

In one line

Minimax works out the value of a position by assuming both players play as well as they can: you take the best you can get, and your opponent takes the worst they can give you.

In the wording a student can write in an examination: the minimax value of a node is the utility of the terminal state reached when both players play optimally from that node onward. At a terminal node it is the utility. At a MAX node it is the maximum of its children's minimax values; at a MIN node it is the minimum. Minimax search computes this by a depth first traversal of the game tree, and MAX plays the move leading to the child of greatest value.

The definition, written properly

MINIMAX(s) = UTILITY(s, MAX) if TERMINAL(s)

= max over a in ACTIONS(s) of MINIMAX(RESULT(s, a)) if PLAYER(s) = MAX

= min over a in ACTIONS(s) of MINIMAX(RESULT(s, a)) if PLAYER(s) = MIN

Three lines, one per case, and being able to write them is a whole 5-mark answer. Read the middle line as: MAX's value at a node is the best it can reach, and the last as: MIN's value at a node is the worst it can inflict.

The values are all from MAX's point of view. MIN is not maximising a second number of its own; because the game is zero sum, MIN minimising MAX's number IS MIN maximising its own. Introducing a second number is the commonest way this gets confused.

The tree, and then the values

The standing tree: MAX at the root, three MIN children, three terminals under each. The terminal utilities are given; every other value is worked out.

BranchIts three terminals
first3, 12, 8
second2, 4, 6
third14, 5, 2

Work upwards, one level at a time. At each MIN node take the smallest of its three terminals: the first branch is worth 3, the second 2, the third 2. At the root, MAX takes the largest of 3, 2 and 2, which is 3.

So the value of the game is 3, and MAX should play the first branch. Read what that means, because it is the whole interpretation of the number: if MAX plays the first branch, then whatever MIN does, MAX ends with at least 3. And there is no move that guarantees more, because MIN can hold both other branches to 2.

The value is a guarantee, not a prediction. MAX ends with exactly 3 only if MIN plays well. If MIN blunders and picks the 12, MAX does better. Minimax is the floor, not the forecast.

It running

# Minimax on a three-ply tree: MAX at the root, three MIN children, three
# terminals under each. The tree is written as a nested list so the reader can
# draw it, and every value is computed rather than filled in.
TREE = ["MAX", [
    ["MIN", [3, 12, 8]],
    ["MIN", [2, 4, 6]],
    ["MIN", [14, 5, 2]],
]]

examined = []

def minimax(node, depth=0):
    if isinstance(node, int):                 # a terminal: its utility
        examined.append(node)
        return node
    player, children = node
    values = [minimax(c, depth + 1) for c in children]
    value = max(values) if player == "MAX" else min(values)
    print("%s%-3s of %-14s = %2d" % ("  " * depth, player, str(values), value))
    return value

best = minimax(TREE)
print()
print("minimax value of the root:", best)
print("terminals examined:", len(examined), examined)
print()
print("so MAX plays the FIRST branch, and can guarantee at least", best)
munotes.in124

Minimax

  MIN of [3, 12, 8]     =  3
  MIN of [2, 4, 6]      =  2
  MIN of [14, 5, 2]     =  2
MAX of [3, 2, 2]      =  3

minimax value of the root: 3
terminals examined: 9 [3, 12, 8, 2, 4, 6, 14, 5, 2]

so MAX plays the FIRST branch, and can guarantee at least 3

All nine terminals were examined, in left to right order. That is the fact the next chapter attacks: two of those nine could not possibly have changed the answer, and alpha-beta pruning is the observation that says which two.

Why the traversal is depth first

The recursion above reaches a leaf before it evaluates anything, which is depth first order, and that is not an accident of the code.

A MAX node's value needs all its children, so the whole subtree under each child must be finished before the parent can report. Depth first order finishes subtrees in the order they are needed and holds only the current path plus the siblings at each level, giving space O(b*m).

Breadth first order would be useless here. Minimax has no early exit of its own: the answer is not found when a good leaf is met, it is found when the last subtree reports. So there is nothing to gain from examining shallow nodes first and a great deal of memory to lose.

Its properties

PropertyValueWhy
Completeyes, if the tree is finiteit visits the whole tree
Optimalyes, against an optimal opponentthat is what the definition says
TimeO(b**m)every node of a tree of branching factor b and depth m
SpaceO(b*m)the current path and its siblings, as in depth first search

O(bm) is the sentence that kills it on a real game**, and the figures are in Games as Search: Shannon's 30 legal moves and 40 moves of play give about 10 to the power 120 nodes. Minimax on a full chess tree is not slow, it is impossible. The two repairs are the subject matter of the rest of the topic.

munotes.in125

Minimax

The two repairs

Both are needed and they are independent, which is worth saying because students often think alpha-beta is what makes chess programs possible on its own. It is not.

Cut off the depth and evaluate. Replace TERMINAL(s) with a test that also stops at a fixed depth, and replace UTILITY there with an evaluation function estimating who is winning. This changes the answer from exact to approximate and is what makes any game program possible at all.

def minimax_cutoff(node, depth):
    if TERMINAL(node) or depth == 0:
        return EVALUATE(node)
    if PLAYER(node) is MAX:
        return max(minimax_cutoff(child, depth - 1) for child in children)
    return min(minimax_cutoff(child, depth - 1) for child in children)

Prune. Do not examine nodes that cannot affect the answer. This changes the work and not the answer at all, which is why it is the more elegant of the two and why it has its own chapter.

A program with a cutoff and no pruning reaches a shallow depth and plays weakly. A program with pruning and no cutoff still cannot finish. Chess programs use both, and Games as Search records Shannon's own third idea, quiescence, as the refinement of the first.

The three-player case, and why MU's algorithm stops at two

Brief, because a paper can ask whether minimax generalises. It does, and the generalisation is instructive.

With three or more players, a single number no longer suffices: each node must carry a vector of utilities, one per player, and each player maximises its own component. The game is generally no longer zero sum, alliances become rational, and the pruning of the next chapter largely stops working because a bound on one player's value says little about another's. So the two-player zero sum restriction in MU's label is doing real work, not simplifying for convenience.

Distinctions

MAX nodeMIN node
Whose turnoursthe opponent's
Takesthe largest child valuethe smallest child value
Wantsa big numbera small number
Both values are fromMAX's point of viewMAX's point of view
Minimax valueUtility
Defined atevery nodeterminal nodes only
Iswhat the node is worth under optimal playthe actual outcome of the game
At a terminal nodeequal to the utilityitself
MinimaxDepth first search
Traversal orderthe same, depth firstdepth first
Stops earlynever, it needs every childat the first goal
Returnsa value, and then a movea path
SpaceO(b*m)O(b*m)
munotes.in126

Minimax

What it does not mean

Minimax does not predict the game. It computes a guarantee under optimal opposition. A weak opponent gives MAX more than the minimax value.

MIN is not maximising a second number. Because the game is zero sum, minimising MAX's value is the whole of MIN's objective.

It is not a search for a good move by trial. It is an exact computation of a value, from which the move follows.

It does not stop when it finds a winning leaf. A MAX node cannot report until every child has reported, so a win at the first leaf proves nothing until the siblings are known. That is precisely what alpha-beta pruning changes.

The values on the leaves are not scores of the position in play. They are utilities of finished games. Numbers estimating an unfinished position come from an evaluation function, which is a separate idea.

Quick revision

  • Minimax value: the utility reached under optimal play by both sides. Terminal: the utility. MAX node: the maximum of its children. MIN node: the minimum.
  • All values are from MAX's point of view; zero sum is what allows one number.
  • On the standing tree the three MIN nodes are worth 3, 2 and 2, and the root is 3. MAX plays the first branch and is guaranteed at least 3.
  • A guarantee, not a prediction. A blundering MIN gives MAX more.
  • Nine terminals examined, left to right. Two of them could not have changed the answer, which is the next chapter.
  • Depth first traversal, because a node needs every child before it can report. Time O(b**m), space O(b*m).
  • O(bm) makes full chess impossible: about 10 to the power 120 nodes. Two independent repairs: a depth cutoff with an evaluation function, which makes the answer approximate, and pruning**, which does not change the answer at all.
  • Three or more players needs a vector of utilities per node, is generally not zero sum, and largely defeats pruning.

Test yourself

1. Define the minimax value of a node in all three cases. At a terminal node it is the utility to MAX. At a MAX node it is the maximum of the minimax values of its children. At a MIN node it is the minimum of them.

2. Compute the minimax value of the standing tree and say which move MAX plays. The three MIN nodes take the smallest of their terminals, giving 3, 2 and 2. The root MAX takes the largest of those, which is 3. MAX plays the first branch.

3. What does the value 3 actually guarantee? That by playing the first branch MAX finishes with at least 3 whatever MIN does, and that no other move guarantees more, since MIN can hold both remaining branches to 2.

munotes.in127

Minimax

4. Why does minimax not stop as soon as it finds a good leaf? Because a MAX node's value is the maximum over all its children, so it cannot be reported until every child has reported. A good leaf in the first subtree says nothing until the others are known. Pruning is the separate observation that some of them need not be examined.

5. Give minimax's time and space complexity and say why the time figure matters. Time O(b**m) and space O(b*m). The time figure matters because on chess, with about 30 legal moves per position and about 40 moves of play, it means of the order of 10 to the power 120 nodes, so the full computation is impossible rather than merely slow.

6. Name the two repairs and say precisely what each changes. A depth cutoff with an evaluation function, which stops the search early and estimates the value of the position reached, changing the answer from exact to approximate. And pruning, which avoids examining nodes that cannot affect the result, changing the amount of work and not the answer at all.

7. Why does MU's label restrict adversarial search to two players, and what breaks with three? With three or more players each node needs a vector of utilities, one per player, and each player maximises its own component. The game is then generally not zero sum, alliances can be rational, and a bound on one player's value tells you little about another's, so alpha-beta pruning largely stops working.

Contents This chapter on its own page

munotes.in128

Chapter Twenty-Five

Alpha-Beta Pruning

Syllabus topic Module 1, "Alpha-Beta pruning"

In one line

Alpha-beta pruning notices that some branches cannot change the answer, whatever is inside them, and refuses to look.

In the wording a student can write in an examination: alpha-beta pruning is applied to minimax search and returns exactly the same value while examining fewer nodes. Two bounds are carried down the tree: alpha, the value of the best choice found so far for MAX anywhere along the current path, and beta, the best found so far for MIN. A MAX node stops examining children as soon as its value reaches beta or more; a MIN node stops as soon as its value reaches alpha or less. Pruning does not affect the result.

The two bounds, in words that stay straight

This is where the topic goes wrong for most students, so the two lines are worth memorising exactly.

  • alpha is the best MAX can already guarantee somewhere along the path from the root. It starts at minus infinity and only ever rises.
  • beta is the best MIN can already guarantee along that path. It starts at plus infinity and only ever falls.

The mnemonic that does not fail: alpha belongs to MAX and pushes UP; beta belongs to MIN and pushes DOWN. The interval from alpha to beta is the window of values still worth knowing about. When the window closes, nothing below is worth examining.

The cutoff conditions, and why each one is valid

At a MIN node, stop when its value is alpha or less.

The MIN node's value can only go down as more children are examined, because it takes a minimum. It is already at or below alpha, and alpha is a value MAX can get elsewhere. So MAX will never choose this branch: whatever the remaining children hold, this node cannot become attractive. The remaining children can be skipped.

At a MAX node, stop when its value is beta or more.

Symmetrically. The MAX node's value can only rise, it is already at or above beta, and beta is a value MIN can force elsewhere, so MIN will never allow the game to reach this node.

Note what is being reasoned about: the PARENT's choice, not this node's. A branch is pruned because the player above will not pick it, not because its own value is bad. That is the sentence that makes the topic click, and it is why the bounds come from ancestors.

The algorithm

alphabeta(node, alpha, beta):        MIN mirrors every line of it
    if node is terminal: return UTILITY(node)
    if PLAYER is MAX:
        value = -infinity
        for each child:
            value = max(value, alphabeta(child, alpha, beta))
            if value >= beta: return value          the BETA cutoff
            alpha = max(alpha, value)   ... MIN cuts on value <= alpha
munotes.in129

Alpha-Beta Pruning

Two implementation points that decide correctness.

The cutoff is checked before alpha or beta is updated, and with >= rather than >. Using strict inequality still gives the right value but prunes less.

Alpha and beta are passed down, never up. What travels up is the node's value. A version that assigns to a shared global alpha prunes wrongly, and it is the commonest bug in a student implementation.

It running, on the same tree as minimax

# Alpha-beta pruning on the SAME tree as the minimax chapter, so the saving can
# be counted. alpha is the best value MAX can already guarantee anywhere above;
# beta is the best MIN can already guarantee. A node stops as soon as it cannot
# affect the value above it.
TREE = ["MAX", [
    ["MIN", [3, 12, 8]],
    ["MIN", [2, 4, 6]],
    ["MIN", [14, 5, 2]],
]]

INF = float("inf")
examined = []

def show(v):
    return "-inf" if v == -INF else ("+inf" if v == INF else "%d" % v)

def alphabeta(node, alpha, beta, depth=0):
    pad = "  " * depth
    if isinstance(node, int):
        examined.append(node)
        print("%sleaf %2d" % (pad, node))
        return node
    player, children = node
    if player == "MAX":
        value = -INF
        for i, child in enumerate(children):
            value = max(value, alphabeta(child, alpha, beta, depth + 1))
            if value >= beta:
                print("%sCUT: MAX has %d >= beta %s, skipping %d sibling(s)"
                      % (pad, value, show(beta), len(children) - i - 1))
                return value
            alpha = max(alpha, value)
        print("%sMAX = %2d   alpha = %s" % (pad, value, show(alpha)))
        return value
    value = INF
    for i, child in enumerate(children):
        value = min(value, alphabeta(child, alpha, beta, depth + 1))
        if value <= alpha:
            print("%sCUT: MIN has %d <= alpha %s, skipping %d sibling(s)"
                  % (pad, value, show(alpha), len(children) - i - 1))
            return value
        beta = min(beta, value)
    print("%sMIN = %2d   beta = %s" % (pad, value, show(beta)))
    return value

best = alphabeta(TREE, -INF, INF)
print()
print("value of the root:", best, " and minimax gave 3 on the same tree")
print("terminals examined:", len(examined), examined)
print("minimax examined 9, so", 9 - len(examined), "were never looked at")
    leaf  3
    leaf 12
    leaf  8
  MIN =  3   beta = 3
    leaf  2
  CUT: MIN has 2 <= alpha 3, skipping 2 sibling(s)
    leaf 14
    leaf  5
    leaf  2
  CUT: MIN has 2 <= alpha 3, skipping 0 sibling(s)
MAX =  3   alpha = 3

value of the root: 3  and minimax gave 3 on the same tree
terminals examined: 7 [3, 12, 8, 2, 14, 5, 2]
minimax examined 9, so 2 were never looked at

The value is 3, exactly as minimax gave, and two terminals were never looked at. Follow the one interesting moment.

munotes.in130

Alpha-Beta Pruning

The first branch is examined in full. Nothing has been established yet, so alpha is minus infinity and there is nothing to prune against. Its three terminals give MIN a value of 3, and the root's alpha rises to 3: MAX can now guarantee 3.

The second branch is cut after ONE terminal. Its first terminal is 2. This is a MIN node, so its value can only fall from 2; and 2 is already at or below alpha, which is 3. So MAX will never choose this branch, and the 4 and the 6 are never examined. Whatever they were, even a thousand, this MIN node could not exceed 2.

The third branch is examined in full and is cut on its last child, which saves nothing here but is the same rule firing. Its terminals 14, 5 and 2 drive its value down to 2, which reaches alpha at the last moment.

Move ordering decides everything

The saving above is two nodes out of nine, which is small, and it is small because of the order the branches happened to be in. That is the most important practical fact about alpha-beta and it is measurable.

# Move ordering decides how much alpha-beta saves. Same nine leaf values, all six
# orderings of the three branches, with the leaves examined counted each time.
# Then the best case in theory, which is what a chess program is chasing.
INF = float("inf")

def alphabeta(node, alpha, beta, count):
    if isinstance(node, int):
        count[0] += 1
        return node
    player, children = node
    if player == "MAX":
        value = -INF
        for child in children:
            value = max(value, alphabeta(child, alpha, beta, count))
            if value >= beta:
                return value
            alpha = max(alpha, value)
        return value
    value = INF
    for child in children:
        value = min(value, alphabeta(child, alpha, beta, count))
        if value <= alpha:
            return value
        beta = min(beta, value)
    return value

BRANCH = {"A": ["MIN", [3, 12, 8]], "B": ["MIN", [2, 4, 6]], "C": ["MIN", [14, 5, 2]]}
print("order   value   leaves examined of 9")
for order in ("ABC", "ACB", "BAC", "BCA", "CAB", "CBA"):
    count = [0]
    value = alphabeta(["MAX", [BRANCH[k] for k in order]], -INF, INF, count)
    print("  %s       %d           %d" % (order, value, count[0]))

print()
print("in theory, with b moves at each of d levels:")
print("  d   plain minimax   alpha-beta, worst   alpha-beta, best")
for b, d in ((3, 4), (3, 6), (30, 4), (30, 6), (30, 10)):
    plain = b ** d
    best = b ** (d // 2) * 2 - 1 if d % 2 == 0 else b ** ((d + 1) // 2) + b ** (d // 2) - 1
    print("b=%2d d=%2d %14d %19d %18d" % (b, d, plain, plain, best))
print()
print("the best case examines about b**(d/2) nodes instead of b**d, which is the")
print("same as searching TWICE AS DEEP for the same work. Shannon 1950 measured")
print("about 30 legal moves in a typical chess position, so b = 30 is his figure.")
munotes.in131

Alpha-Beta Pruning

order   value   leaves examined of 9
  ABC       3           7
  ACB       3           7
  BAC       3           9
  BCA       3           9
  CAB       3           7
  CBA       3           7

in theory, with b moves at each of d levels:
  d   plain minimax   alpha-beta, worst   alpha-beta, best
b= 3 d= 4             81                  81                 17
b= 3 d= 6            729                 729                 53
b=30 d= 4         810000              810000               1799
b=30 d= 6      729000000           729000000              53999
b=30 d=10 590490000000000     590490000000000           48599999

the best case examines about b**(d/2) nodes instead of b**d, which is the
same as searching TWICE AS DEEP for the same work. Shannon 1950 measured
about 30 legal moves in a typical chess position, so b = 30 is his figure.

Every ordering returns 3, which is the correctness claim: pruning cannot change the answer.

The work varies from 7 to 9 out of 9. The two orderings that examine everything are the ones beginning with branch B, whose MIN value is 2: starting with a weak branch sets alpha low, and a low alpha prunes nothing. The rule that follows is the practical one: try the best-looking move first.

The theoretical table is the reason this matters. In the worst order alpha-beta examines every node and saves nothing at all, O(bd). In the best order it examines about b(d/2), which at b of 30 and d of 10 is 48 million instead of 590 thousand million: about twelve thousand times less work.

And the right way to state that saving is Shannon's way: b(d/2) instead of bd means the same work buys twice the depth. A chess program that could see five moves ahead can now see ten, and depth is strength.

How the ordering is actually obtained

Worth one paragraph, because "try the best move first" is circular: knowing which move is best is the problem being solved.

Real programs approximate it, and three techniques are standard. Cheap static rules: in chess, try captures and checks before quiet moves. Iterative deepening: search to depth 1, then 2, then 3, and at each new depth try the moves in the order the previous depth preferred. That is the same iterative deepening as in the uninformed row, used here for a completely different purpose, and it is why chess programs are built on it. Remembering: a transposition table stores the value found for a position, so a position reached by a different order of moves is not searched again.

munotes.in132

Alpha-Beta Pruning

Its properties

PropertyValue
Value returnedidentical to minimax, always
Completeyes, if the tree is finite
Optimalyes, against an optimal opponent
Time, worst orderingO(b**d), no saving at all
Time, best orderingO(b**(d/2))
Time, random orderingabout O(b**(3d/4))
SpaceO(b*d), as minimax

The random-ordering figure is the standard published result and this book has not measured it, so it is given as the known figure rather than as a measurement of ours. What this book does measure is the six orderings above.

Distinctions

alphabeta
Belongs toMAXMIN
Starts atminus infinityplus infinity
Movesup onlydown only
Cuts ata MIN node whose value is alpha or lessa MAX node whose value is beta or more
MinimaxAlpha-beta
Value returnedthe minimax valuethe same value
Terminals on the standing tree97
Best-case timeO(b**d)O(b**(d/2))
Depends on move orderingnoentirely
PruningA depth cutoff
Changes the answerno, neveryes, to an estimate
Savesworkwork
Needed for a chess programyesyes, and they are independent

What it does not mean

Alpha-beta does not change the answer. It returns the minimax value exactly. Any implementation that returns something else is wrong.

It is not a different algorithm from minimax. It is minimax with two bounds carried down and an early return.

alpha is not "the value of the current node". It is the best MAX can guarantee anywhere on the path above, which is why it is inherited and not computed locally.

Pruning does not always save anything. In the worst ordering it examines every node. Two of the six orderings measured above save nothing.

The best case is not typical. It requires the best move examined first at every node, which is exactly what is not known. Programs approximate it with static rules, iterative deepening and transposition tables.

Twice as deep is not twice as good in a trivial sense. It means the same computation reaches twice the depth, and since strength grows with depth, that is where the practical gain lies.

Quick revision

  • Alpha-beta pruning returns exactly the minimax value while examining fewer nodes.
  • alpha: the best MAX can already guarantee above; starts at minus infinity, only rises. beta: the best MIN can already guarantee; starts at plus infinity, only falls.
  • Cut at a MIN node when its value is alpha or less; at a MAX node when its value is beta or more. The reasoning is about the parent's choice, not this node's quality.
  • Bounds pass down; values pass up. A shared global alpha is the classic bug.
  • On the standing tree: value 3, 7 terminals against minimax's 9. The second branch is cut after one terminal, because 2 is already at or below alpha of 3 and a MIN value can only fall.
  • Move ordering decides everything. Measured over all six orderings: 7, 7, 9, 9, 7, 7 of 9. The two that save nothing begin with the weakest branch.
  • Worst order O(bd), no saving. Best order O(b(d/2)), which at b of 30 and d of 10 is 48 million against 590 thousand million. The same work buys twice the depth.
  • Ordering is approximated by static rules, iterative deepening reusing the previous depth's preference, and a transposition table.
munotes.in133

Alpha-Beta Pruning

Test yourself

1. Define alpha and beta. alpha is the value of the best choice found so far for MAX at any point along the current path from the root; it begins at minus infinity and only increases. beta is the best found so far for MIN along that path; it begins at plus infinity and only decreases.

2. Give both cutoff conditions and justify one of them. A MIN node stops when its value is alpha or less; a MAX node stops when its value is beta or more. For the first: a MIN node's value can only fall as more children are examined, it is already at or below a value MAX can obtain elsewhere, so MAX will never choose this branch and the remaining children cannot matter.

3. On the standing tree, why is the second branch cut after a single terminal? Its first terminal is 2. The node is a MIN node, so its value can only fall below 2, and alpha is already 3 from the first branch. MAX can guarantee 3 elsewhere, so it will never choose a branch worth at most 2, and the remaining two terminals are irrelevant.

4. Does pruning ever change the value returned? What does it change? Never. It returns exactly the minimax value. It changes only the number of nodes examined.

5. State the best and worst case time complexities and what determines which you get. Worst case O(bd), the same as plain minimax, with no saving. Best case O(b(d/2)). Which you get is determined entirely by the order in which moves are examined at each node; the best case needs the best move examined first everywhere.

6. Why is "try the best move first" circular, and how do real programs get round it? Because identifying the best move is the problem being solved. Programs approximate the order with cheap static rules such as trying captures first, with iterative deepening that reuses the previous shallower search's preferred order, and with a transposition table that remembers values already computed for a position.

munotes.in134

Alpha-Beta Pruning

7. Express the best-case saving in the way that shows why it matters in practice. Examining about b(d/2) nodes instead of bd means the same amount of work reaches twice the depth. Since playing strength grows with search depth, alpha-beta roughly doubles the depth a program can reach, which at Shannon's branching figure of 30 and a depth of 10 is 48 million nodes instead of 590 thousand million.

Contents This chapter on its own page

munotes.in135

Chapter Twenty-Six

The Knowledge-Based Agent

Syllabus topic Module 1, "Knowledge-based agents"

In one line

A knowledge-based agent keeps sentences about the world rather than rules about what to do, and works out what follows from them.

In the wording a student can write in an examination: a knowledge-based agent maintains a knowledge base, a set of sentences in a formal knowledge representation language, each asserting something about the world. It has two operations: TELL, which adds a sentence, and ASK, which queries what follows. The answer to an ASK must follow from what has been told, by logical entailment, and the process of deriving it is inference.

The change from Module 1's first two rows

Every architecture so far answered the question "what should I do next" directly. This row answers a different question first: "what is true". The action then follows from the truth, rather than from a rule.

A reflex or model-based agentA knowledge-based agent
Storescondition-action rules, and statesentences that are true
To behave differently yourewrite the rulestell it another fact
Can it explain itselfnoyes, the derivation is the explanation
Can it answer a question nobody anticipatednoyes, if it follows from what it knows
Fails byhaving no rule for the situationnot having been told enough

The third and fourth rows are why this row exists at all. A rule table can only do what somebody thought of. A knowledge base can answer any question that follows from its contents, including questions its author never considered, and it can say how it got the answer.

TELL and ASK

The whole interface is two operations, and stating them is worth marks.

  • TELL(KB, sentence): add a sentence to the knowledge base. This is how perception enters. Every percept is turned into a sentence and told.
  • ASK(KB, query): does the query follow from the knowledge base? The answer must be yes, no, or unknown.

Three answers, not two, and this is the most useful fact in the chapter. ASK returns:

AnswerMeans
yesthe query is true in every world consistent with the knowledge base. It is entailed.
noit is false in every such world. Its negation is entailed.
unknownit is true in some and false in others. The knowledge base is silent.

An agent that treats unknown as no is unsound and will walk into a pit. A rule-based agent has no way to express unknown at all, which is one more reason the row exists.

The smallest world where something must be deduced

Six squares in a three-by-two grid. Some squares contain a pit. A square next to a pit feels a breeze, and a square not next to one does not. Walking into a pit is fatal.

munotes.in136

The Knowledge-Based Agent

The agent has walked square 1,1 and felt no breeze; then square 2,1 and felt a breeze. It has never seen a pit, because a pit cannot be seen, only felt from next door.

That is the whole point of the setting: the conclusions the agent needs are not in its percepts. The percept at 2,1 is "breeze". The question is "which squares are safe", and no percept says anything about a square the agent has not stood in.

Working out what follows

The mechanical way to answer an ASK is to enumerate the worlds. A world is an assignment of pit or no pit to each of the six squares, so there are 2 to the power 6, that is 64 of them. Keep the ones consistent with what has been felt, then look at what is true in all of them.

# The knowledge-based agent, in the smallest world where something has to be
# DEDUCED rather than seen. Six squares, pits somewhere, and a breeze is felt in
# any square next to a pit. The agent has walked 1,1 (no breeze) and 2,1 (breeze)
# and has never seen a pit. What does it now know?
from itertools import product

SQUARES = ["1,1", "1,2", "2,1", "2,2", "3,1", "3,2"]

def neighbours(sq):
    x, y = (int(v) for v in sq.split(","))
    out = []
    for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
        nx, ny = x + dx, y + dy
        if 1 <= nx <= 3 and 1 <= ny <= 2:
            out.append("%d,%d" % (nx, ny))
    return out

VISITED = {"1,1", "2,1"}
BREEZE = {"2,1"}                 # felt a breeze here
NO_BREEZE = {"1,1"}              # felt none here

def possible(pits):
    if pits & VISITED:
        return False             # the agent stood there and did not fall in
    for sq in BREEZE:
        if not any(n in pits for n in neighbours(sq)):
            return False         # a breeze needs a pit next door
    for sq in NO_BREEZE:
        if any(n in pits for n in neighbours(sq)):
            return False         # no breeze means no pit next door
    return True

worlds = []
for bits in product([False, True], repeat=len(SQUARES)):
    pits = {sq for sq, has in zip(SQUARES, bits) if has}
    if possible(pits):
        worlds.append(pits)

print("visited 1,1 with no breeze, and 2,1 with a breeze. no pit ever seen.")
print("%d of the %d conceivable worlds are consistent with that:"
      % (len(worlds), 2 ** len(SQUARES)))
for w in worlds:
    print("   pits at", " ".join(sorted(w)))
print()
print("now ASK the knowledge base about each square:")
for sq in SQUARES:
    always = all(sq in w for w in worlds)
    never = all(sq not in w for w in worlds)
    verdict = ("a pit is CERTAIN, it is ENTAILED" if always else
               "a pit is IMPOSSIBLE, safe" if never else
               "UNKNOWN: a pit in some worlds and not in others")
    print("   %-4s %s" % (sq, verdict))
print()
print("1,2 is provably safe although the agent has never been there, and 2,2 and")
print("3,1 are genuinely unknown. A knowledge base answers three ways, not two.")
munotes.in137

The Knowledge-Based Agent

visited 1,1 with no breeze, and 2,1 with a breeze. no pit ever seen.
6 of the 64 conceivable worlds are consistent with that:
   pits at 3,1
   pits at 3,1 3,2
   pits at 2,2
   pits at 2,2 3,2
   pits at 2,2 3,1
   pits at 2,2 3,1 3,2

now ASK the knowledge base about each square:
   1,1  a pit is IMPOSSIBLE, safe
   1,2  a pit is IMPOSSIBLE, safe
   2,1  a pit is IMPOSSIBLE, safe
   2,2  UNKNOWN: a pit in some worlds and not in others
   3,1  UNKNOWN: a pit in some worlds and not in others
   3,2  UNKNOWN: a pit in some worlds and not in others

1,2 is provably safe although the agent has never been there, and 2,2 and
3,1 are genuinely unknown. A knowledge base answers three ways, not two.

Square 1,2 is provably safe and the agent has never been there. That is the whole value of a knowledge base in one line. Nothing the agent perceived said anything about 1,2; the conclusion comes from the sentence "no breeze at 1,1 means no pit next to 1,1", which the agent was told once and applies here.

And 2,2 and 3,1 are genuinely unknown. In some consistent worlds 2,2 has a pit and in others 3,1 does. The knowledge base does not guess, and an agent that read unknown as safe would have a one-in-two chance of dying. What to do when the answer is unknown is Module 1's fourth row, and this is where the need for it appears.

The three ways an ASK is answered, mechanically

The enumeration above is the definition of entailment made into a procedure, and it is worth seeing as a general recipe.

  1. List every world, that is every assignment of true or false to every symbol.
  2. Discard the worlds in which the knowledge base is false.
  3. For the query: true in all survivors means yes; false in all means no; otherwise unknown.

This is called model checking and it is correct and unusable at scale: with n symbols there are 2 to the power n worlds. Sixty-four here; a knowledge base about a chessboard has 2 to the power 64. Inference in Propositional Logic and Conjunctive Normal Form and Resolution are how it is done without enumerating.

munotes.in138

The Knowledge-Based Agent

The knowledge level and the implementation level

A distinction worth 5 marks and easy to state.

At the knowledge level you say only what the agent knows: "no breeze at 1,1", "a breeze means a pit next door". This is the specification, and it can be written before any code.

At the implementation level you say how it is stored and searched: as a list of clauses, as a set of Python tuples, in a database.

The knowledge level is where the agent is designed, and the point of the separation is that the same knowledge can be implemented many ways, and the agent's behaviour is determined by the knowledge rather than by the implementation. That is the property the previous architectures did not have: changing a reflex agent's behaviour meant changing its code.

Declarative and procedural

The same distinction under its other name, which papers also use.

DeclarativeProcedural
The agent is givensentences that are trueinstructions to follow
Adding knowledge meanstelling it a sentenceediting the program
This row isdeclarative
Module 1's first row wasprocedural

The honest version of this: real systems are both. A knowledge-based agent's inference engine is procedural code; what it reasons over is declarative. The claim of this row is only that the KNOWLEDGE should be declarative, so that it can be added to, inspected and explained.

Distinctions

TELLASK
Doesadds a sentencequeries what follows
Used forperception, and background knowledgedeciding what to do
Changes the knowledge baseyesno
yesnounknown
The query istrue in every consistent worldfalse in every onetrue in some, false in others
The knowledge baseentails itentails its negationis silent
Treating this as the othersis unsound, and fatal in the pit world
Knowledge levelImplementation level
Sayswhat is knownhow it is stored and searched
Writtenfirst, as a specificationsecond
Determines behaviouryesno

What it does not mean

A knowledge base is not a database. A database answers what it was told. A knowledge base answers what follows from what it was told, which is a larger set, and it can answer "unknown".

TELL is not assignment. It adds a sentence that must remain consistent with the rest. Telling a knowledge base something that contradicts it makes everything derivable, which is a real failure mode and not a curiosity.

Unknown is not no. It is the third answer, and an agent that collapses it into no is unsound. Collapsing it into yes is worse.

A knowledge-based agent is not slow because it reasons. It is slow if its inference is done by enumerating worlds. The next four chapters are about not doing that.

The knowledge base is not the agent's percepts. Percepts are told to it as sentences, and the interesting conclusions are the ones no percept contains, which is what square 1,2 demonstrates.

munotes.in139

The Knowledge-Based Agent

Quick revision

  • Knowledge-based agent: keeps a knowledge base of sentences asserting what is true, with two operations, TELL and ASK.
  • ASK has three answers: yes (true in every consistent world, that is entailed), no (false in every one), unknown (true in some, false in others). Treating unknown as no is unsound.
  • The shift from earlier architectures: store what is true, not what to do. Behaviour changes by telling it a fact; it can explain itself; it can answer questions its author never considered.
  • The six-square pit world: 64 conceivable worlds, 6 consistent with a breeze at 2,1 and none at 1,1. 1,2 is provably safe although never visited; 2,2, 3,1 and 3,2 are genuinely unknown.
  • Model checking: enumerate worlds, discard those where the knowledge base is false, and check the query in the survivors. Correct, and 2 to the power n in the number of symbols.
  • Knowledge level says what is known; implementation level says how it is stored. The agent is designed at the knowledge level.
  • Declarative knowledge with a procedural inference engine is the honest description of a real system.

Test yourself

1. Define a knowledge-based agent and name its two operations. An agent that maintains a knowledge base of sentences in a formal representation language, each asserting something about the world, with TELL to add a sentence and ASK to query what follows from the base.

2. What are the three possible answers to an ASK, and what does each mean? Yes, meaning the query is true in every world consistent with the knowledge base and so is entailed by it. No, meaning it is false in every such world. Unknown, meaning it is true in some and false in others, so the knowledge base is silent about it.

3. In the six-square pit world the agent has never visited 1,2. How can it know that 1,2 is safe? Because it felt no breeze at 1,1, and it was told that a square with no breeze has no pit next to it. 1,2 is next to 1,1, so no consistent world places a pit there. The conclusion comes from the knowledge base, not from any percept about 1,2.

4. Why is treating unknown as no unsound, and what does it cost here? Because a query that is unknown may be true, so answering no asserts something the knowledge base does not support. In the pit world 2,2 and 3,1 are unknown, and an agent that read unknown as "no pit" would step into one about half the time.

munotes.in140

The Knowledge-Based Agent

5. Describe model checking and say why it does not scale. Enumerate every assignment of truth values to the symbols, discard the assignments in which the knowledge base is false, and check whether the query holds in all the survivors. It does not scale because there are 2 to the power n assignments for n symbols: 64 for six squares, and over 18 million million million for sixty-four.

6. Distinguish the knowledge level from the implementation level. The knowledge level states what the agent knows, independently of storage. The implementation level states how those sentences are represented and searched. The agent's behaviour is determined at the knowledge level, which is why the same knowledge may be implemented in many ways.

7. Give two things a knowledge-based agent can do that a rule-based reflex agent cannot. It can answer a question nobody anticipated when it was built, provided the answer follows from what it knows; and it can explain its answer, because the derivation is available. It can also report that it does not know, which a rule table cannot express.

Contents This chapter on its own page

munotes.in141

Chapter Twenty-Seven

Propositional Logic: Syntax and Meaning

Syllabus topic Module 1, "Propositional logic"

In one line

Propositional logic is a language of statements that are either true or false, joined by five connectives whose meaning is completely fixed by a truth table.

In the wording a student can write in an examination: propositional logic is a formal language whose atomic sentences are propositional symbols, each standing for a statement that is either true or false. Complex sentences are built from atomic ones with five logical connectives: negation, conjunction, disjunction, implication and biconditional. The meaning of a sentence is given by its truth value in a model, an assignment of true or false to every symbol, and is computed from the truth values of its parts by the connectives' truth tables.

The syntax

Two rules, and everything in the language is built by them.

An atomic sentence is a single propositional symbol, written with a capital letter: Rain, Cancelled, P, Q. It stands for a statement that has a truth value, and nothing inside it is visible to the logic. Rain is one symbol. The logic cannot see that it is about weather, cannot ask where it is raining, and cannot relate it to HeavyRain. That limit is what First-Order Logic removes.

A complex sentence is built with a connective:

ConnectiveWrittenNameRead as
notnot Pnegationit is not the case that P
andP and Qconjunctionboth
orP or Qdisjunctionat least one
impliesP implies Qimplicationif P then Q
iffP iff QbiconditionalP if and only if Q

Two names to have ready. A symbol or its negation is a literal: P and not P are literals, P and Q is not. The parts of a conjunction are its conjuncts; the parts of a disjunction are its disjuncts.

Precedence, which decides what a sentence means

Without brackets, the connectives bind in this order, tightest first:

not then and then or then implies then iff

So not P and Q means (not P) and Q, not not (P and Q). And P or Q implies R means (P or Q) implies R. Those two are the errors that cost marks, and the safe habit is to bracket anything that mixes connectives.

Implication is right associative: P implies Q implies R means P implies (Q implies R). It is a different sentence from (P implies Q) implies R, and a paper can ask you to show that.

The semantics: a model, and the five truth tables

A model is an assignment of true or false to every propositional symbol. With n symbols there are 2 to the power n models. A sentence's truth value in a model is computed bottom up from its parts.

munotes.in142

Propositional Logic: Syntax and Meaning

# The truth table of every connective, as a GRID so a phone does not stack it.
from itertools import product

def tf(b):
    return "T" if b else "F"

print(" P | Q | not P | P and Q | P or Q | P imp Q | P iff Q")
print("---|---|-------|---------|--------|---------|--------")
for p, q in product([True, False], repeat=2):
    print(" %s | %s |   %s   |    %s    |   %s    |    %s    |    %s"
          % (tf(p), tf(q), tf(not p), tf(p and q), tf(p or q),
             tf((not p) or q), tf(p == q)))
print()
print("the two rows students get wrong, both for 'P implies Q':")
print("  P false, Q true  -> T   a false premise makes the implication TRUE")
print("  P false, Q false -> T   so does a false premise with a false conclusion")
print("  P implies Q is FALSE on exactly one row: P true and Q false")
 P | Q | not P | P and Q | P or Q | P imp Q | P iff Q
---|---|-------|---------|--------|---------|--------
 T | T |   F   |    T    |   T    |    T    |    T
 T | F |   F   |    F    |   T    |    F    |    F
 F | T |   T   |    F    |   T    |    T    |    F
 F | F |   T   |    F    |   F    |    T    |    T

the two rows students get wrong, both for 'P implies Q':
  P false, Q true  -> T   a false premise makes the implication TRUE
  P false, Q false -> T   so does a false premise with a false conclusion
  P implies Q is FALSE on exactly one row: P true and Q false

The same table set out as the definitions a paper wants:

SentenceTrue exactly when
not PP is false
P and Qboth are true
P or Qat least one is true
P implies QP is false, or Q is true
P iff Qboth have the same value

Implication, and the two things beginners get wrong

This is the highest-value part of the chapter, because implication is the connective every rule in a knowledge base is written with, and it does not mean what the English "if" suggests.

P implies Q is TRUE whenever P is false. Two of the four rows. "If the moon is made of cheese then I am the Vice Chancellor" is a true sentence of propositional logic, because the moon is not made of cheese. This is called material implication, and it is a deliberate choice: the truth table is fixed, and it is the only definition that makes the connective useful for inference.

munotes.in143

Propositional Logic: Syntax and Meaning

It says nothing about causation. Rain implies Cancelled does not claim the rain caused the cancellation, only that we shall not find rain with a match in progress. A logic that tried to express causation would need much more machinery.

The practical consequence, which is the examinable one: P implies Q is false on exactly one row, where P is true and Q is false. To disprove an implication you must find a case where the premise holds and the conclusion fails. Nothing else refutes it.

And the standard trap: P implies Q is not the same as Q implies P. Rain implies Cancelled does not give Cancelled implies Rain; the match might be cancelled for a hundred other reasons. Their truth tables differ on two rows. The reverse is called the converse, and asserting it is a named fallacy.

Two equivalences worth knowing by heart

Both are used constantly in the next two chapters, and both can be checked on the table above.

P implies Q is equivalent to not P or Q. Compare the columns: identical on all four rows. This is what makes conjunctive normal form possible, because it removes implication entirely.

P implies Q is equivalent to not Q implies not P, the contrapositive. Also identical on all four rows. The contrapositive is equivalent; the converse Q implies P and the inverse not P implies not Q are not. Papers ask for exactly this distinction.

Two more names the row needs

De Morgan's laws, which move a negation through a connective:

not (P and Q) is equivalent to (not P) or (not Q)

not (P or Q) is equivalent to (not P) and (not Q)

Read them in words: "not both" means "at least one is not", and "neither" means "not this and not that". They are the reason the CNF conversion in Conjunctive Normal Form and Resolution can push every negation inward onto the symbols.

Distribution, which is the step that actually produces CNF:

P or (Q and R) is equivalent to (P or Q) and (P or R)

What propositional logic cannot say

Worth stating here so the limits are known before First-Order Logic removes them, because a paper may ask for exactly this comparison.

It cannot talk about objects. SquareOneOneIsSafe is one symbol. It has no parts, so the logic cannot say "this square" and "that square" are the same kind of thing.

It cannot generalise. "Every square next to a breeze-free square is safe" cannot be written as one sentence. It has to be written out once per square, and a world with a hundred squares needs a hundred sentences that are obviously the same sentence.

munotes.in144

Propositional Logic: Syntax and Meaning

It cannot relate. There is no way to say that 1,2 is next to 1,1. Adjacency has to be built into the symbol names, which the logic cannot read.

And yet it is enough for a great deal. Digital circuits, satisfiability solving, and every rule engine in Rule-Based Systems and Expert Systems work at this level, and modern solvers handle propositional problems with millions of symbols.

Distinctions

SyntaxSemantics
Concernswhich strings are sentenceswhat a sentence means
Given bythe two formation rulestruth values in models
A sentence can bewell formed or nottrue or false in a model
P implies QQ implies Pnot Q implies not P
Namethe implicationthe conversethe contrapositive
Equivalent to the firstnoyes
Differs ontwo rowsnone
LiteralClauseSentence
Isa symbol or its negationa disjunction of literalsanything well formed
ExampleP, not QP or not Q or R(P and Q) implies R

What it does not mean

A propositional symbol is not a word. Rain is an indivisible symbol; the letters are for human convenience and the logic cannot see them.

P implies Q does not mean P causes Q. It rules out one combination, P true with Q false, and says nothing about why.

P implies Q is not false when P is false. It is true. Two of its four rows are true for that reason, and that is material implication.

or is not exclusive. P or Q is true when both are true. Exclusive or is a different connective and has to be written out.

Precedence is not left to right. not binds tightest, then and, then or, then implies, then iff, and implies groups to the right.

A model is not the real world. It is an assignment of truth values to symbols. The logic never touches the world; it works over models.

Quick revision

  • Atomic sentence: a propositional symbol, capital letter, indivisible. Complex sentence: built with not, and, or, implies, iff.
  • Literal: a symbol or its negation. Clause: a disjunction of literals.
  • Precedence, tightest first: not, and, or, implies, iff. implies is right associative.
  • A model assigns true or false to every symbol; n symbols give 2 to the power n models.
  • P implies Q is true whenever P is false, and false on exactly one row: P true, Q false. This is material implication and it says nothing about causation.
  • P implies Q equals not P or Q, and equals its contrapositive not Q implies not P. Its converse Q implies P is not equivalent.
  • De Morgan: not (P and Q) is not P or not Q; not (P or Q) is not P and not Q.
  • Distribution: P or (Q and R) is (P or Q) and (P or R).
  • It cannot talk about objects, cannot generalise, cannot express relations. All three need first-order logic.
munotes.in145

Propositional Logic: Syntax and Meaning

Test yourself

1. Give the syntax of propositional logic. An atomic sentence is a propositional symbol standing for a statement that is true or false. A complex sentence is formed from sentences by one of the five connectives: negation, conjunction, disjunction, implication and biconditional.

2. Write the truth table for implication and say on how many rows it is false. True, true gives true; true, false gives false; false, true gives true; false, false gives true. It is false on exactly one row, where the premise is true and the conclusion false.

3. Is "if the moon is made of cheese then I am the Vice Chancellor" true in propositional logic? Explain. Yes. The premise is false, and an implication with a false premise is true. This is material implication: the connective rules out only the combination of a true premise with a false conclusion.

4. What does not P and Q mean, and why is the answer not obvious? It means (not P) and Q, because negation binds more tightly than conjunction. It is not obvious because the English reading "not P and Q" suggests the negation of the whole conjunction, which would be written not (P and Q).

5. Distinguish the converse, the inverse and the contrapositive of P implies Q, and say which is equivalent. The converse is Q implies P, the inverse is not P implies not Q, and the contrapositive is not Q implies not P. Only the contrapositive is equivalent to the original; the converse and inverse are not.

6. State De Morgan's laws and read each in words. not (P and Q) is equivalent to not P or not Q, that is, not both means at least one is not. not (P or Q) is equivalent to not P and not Q, that is, neither means not this and not that.

7. Give three things propositional logic cannot express, with an example of one. It cannot refer to objects, cannot generalise over them, and cannot express relations between them. For example, "every square adjacent to a breeze-free square is safe" cannot be written as a single sentence; it must be written out once for each square, and the logic cannot see that the sentences are instances of one rule.

Contents This chapter on its own page

munotes.in146

Chapter Twenty-Eight

Entailment, Models and Validity

Syllabus topic Module 1, "Propositional logic & inference"

In one line

One set of sentences entails another when the second is true in every case where the first is, which is checked by going through the cases.

In the wording a student can write in an examination: a knowledge base KB entails a sentence a, written KB entails a, if a is true in every model in which KB is true. Entailment is a relation between sentences and is defined entirely by the semantics; it has nothing to do with any algorithm. A model of a set of sentences is a model in which they are all true.

The definition, said three ways

All three are the same statement and papers use all three.

PhrasingStatement
Modelsevery model of KB is a model of a
Impossible otherwisethere is no model in which KB is true and a is false
Informationa adds nothing that KB did not already contain

The third phrasing is the one worth internalising. Entailment means the conclusion was already there. Inference does not create information; it makes explicit what the knowledge base already committed to. That is why a sound inference procedure can never be surprising, and why a knowledge base that is wrong yields wrong conclusions with perfect reliability.

It checked, on a knowledge base small enough to print whole

Two sentences: "if it rains the match is cancelled", and "it is raining". Three symbols, so eight models.

# Entailment by model checking, on a knowledge base small enough to print whole.
from itertools import product

def ev(s, m):
    if isinstance(s, str):
        return m[s]
    op = s[0]
    if op == "not":
        return not ev(s[1], m)
    if op == "and":
        return ev(s[1], m) and ev(s[2], m)
    if op == "or":
        return ev(s[1], m) or ev(s[2], m)
    if op == "implies":
        return (not ev(s[1], m)) or ev(s[2], m)
    return ev(s[1], m) == ev(s[2], m)

def show(s):
    if isinstance(s, str):
        return s
    if s[0] == "not":
        return "not " + show(s[1])
    sign = {"and": " and ", "or": " or ", "implies": " => ", "iff": " <=> "}[s[0]]
    return "(" + show(s[1]) + sign + show(s[2]) + ")"

def tf(b):
    return "T" if b else "F"

# "If it rains the match is cancelled." "It is raining."   Is the match cancelled?
KB = [("implies", "Rain", "Cancelled"), "Rain"]
QUERIES = ["Cancelled", ("not", "Cancelled"), "Rain", "Wet"]
SYMS = ["Cancelled", "Rain", "Wet"]

print("knowledge base:")
for s in KB:
    print("   ", show(s))
print()
print("Ca | Ra | We | KB | Cancelled")
print("---|----|----|----|----------")
kb_models = []
for vals in product([True, False], repeat=3):
    m = dict(zip(SYMS, vals))
    kb = all(ev(s, m) for s in KB)
    if kb:
        kb_models.append(m)
    print(" %s |  %s |  %s |  %s |     %s"
          % (tf(m["Cancelled"]), tf(m["Rain"]), tf(m["Wet"]), tf(kb), tf(m["Cancelled"])))
print()
print("the KB is true in %d of the 8 models. in those models:" % len(kb_models))
for q in QUERIES:
    yes = all(ev(q, m) for m in kb_models)
    no = all(not ev(q, m) for m in kb_models)
    print("   %-16s %s" % (show(q), "ENTAILED" if yes else
                           ("REFUTED, false in all of them" if no else "UNKNOWN")))
print()
print("and the four words, checked on the same machinery:")
for name, s in (("P or not P", ("or", "Rain", ("not", "Rain"))),
                ("P and not P", ("and", "Rain", ("not", "Rain"))),
                ("Rain", "Rain")):
    all_m = [dict(zip(SYMS, v)) for v in product([True, False], repeat=3)]
    t = sum(1 for m in all_m if ev(s, m))
    kind = ("VALID, true in all 8" if t == 8 else
            "UNSATISFIABLE, true in none" if t == 0 else
            "SATISFIABLE, true in %d of 8" % t)
    print("   %-14s %s" % (name, kind))
munotes.in147

Entailment, Models and Validity

knowledge base:
    (Rain => Cancelled)
    Rain

Ca | Ra | We | KB | Cancelled
---|----|----|----|----------
 T |  T |  T |  T |     T
 T |  T |  F |  T |     T
 T |  F |  T |  F |     T
 T |  F |  F |  F |     T
 F |  T |  T |  F |     F
 F |  T |  F |  F |     F
 F |  F |  T |  F |     F
 F |  F |  F |  F |     F

the KB is true in 2 of the 8 models. in those models:
   Cancelled        ENTAILED
   not Cancelled    REFUTED, false in all of them
   Rain             ENTAILED
   Wet              UNKNOWN

and the four words, checked on the same machinery:
   P or not P     VALID, true in all 8
   P and not P    UNSATISFIABLE, true in none
   Rain           SATISFIABLE, true in 4 of 8

Read the KB column: only two of the eight models satisfy the knowledge base. In both of them Cancelled is true, so Cancelled is entailed. Wet is true in one of the two and false in the other, so it is unknown: the knowledge base says nothing about whether the ground is wet, and correctly refuses to guess.

The two models differ only in Wet, and that is what unknown looks like. A knowledge base does not narrow the world to one possibility; it narrows it to a set, and anything that varies inside that set is unknown.

Model checking: correct, and hopeless

The procedure above IS the definition of entailment, turned into an algorithm:

  1. Enumerate all 2 to the power n models.
  2. Keep the models in which every sentence of KB is true.
  3. The query is entailed if it is true in all of them.

And it is exponential in the number of symbols, unavoidably. Three symbols gave eight rows. A knowledge base about a chessboard has 64 squares, so 2 to the power 64 models, which is over 18 million million million rows. Deciding entailment in propositional logic is co-NP-complete, so nobody expects a method that is always fast.

munotes.in148

Entailment, Models and Validity

That is why the next two chapters exist. They do not make the problem easy; they avoid enumerating the models by manipulating the sentences instead, and they are fast on the knowledge bases that arise in practice.

The four words, and the relations between them

A paper will ask for these four separated, and the relations between them are the marks.

WordDefinitionExample
Validtrue in every model. Also called a tautology.P or not P
Satisfiabletrue in at least one modelP, P and Q
Unsatisfiabletrue in no model. Also inconsistent.P and not P
Entailed by KBtrue in every model in which KB is trueCancelled, above

Three relations follow, and each is a one-line proof.

Valid implies satisfiable, and not the reverse. Rain is satisfiable, true in four models of eight, and not valid.

A sentence is unsatisfiable exactly when its negation is valid. If a is true in no model, not a is true in all of them.

The deduction theorem: KB entails a exactly when the single sentence KB implies a is valid. So entailment reduces to validity.

And the refutation form, which is the one the next chapter uses: KB entails a exactly when KB and not a is unsatisfiable. Read it in words: if the conclusion could be false while the knowledge base held, the knowledge base would not entail it; so entailment means assuming the opposite produces a contradiction. That equivalence is the entire basis of proof by resolution.

Soundness and completeness, defined here so the next chapter can use them

An inference procedure derives sentences from a knowledge base. Two properties matter, and they are about the procedure rather than about the logic.

  • Sound, or truth preserving: everything it derives is entailed. A procedure that derives something not entailed is unsound and worthless, because its conclusions can be false when the knowledge base is true.
  • Complete: everything entailed can be derived. An incomplete procedure may fail to find a conclusion that genuinely follows.

The two are independent. A procedure that derives nothing at all is sound and useless. A procedure that derives everything is complete and useless. Both are wanted, and both are achievable in propositional logic: model checking is sound and complete, and so is resolution.

munotes.in149

Entailment, Models and Validity

Logical equivalence, and the one thing to be careful about

Two sentences are logically equivalent when each entails the other, which is the same as having identical truth values in every model. Written a is equivalent to b.

Equivalence is a relation between sentences; the biconditional is a connective. P iff Q is a sentence that may be true or false. "P is equivalent to Q" is a claim ABOUT two sentences, true or not as a matter of fact. The connection is exact: a is equivalent to b precisely when a iff b is valid. Mixing the two is a standard error and the sentence above is the answer to it.

Distinctions

ValidSatisfiableUnsatisfiable
True inevery modelat least oneno model
Also calledtautologyconsistentinconsistent
Its negation isunsatisfiablevalid
ExampleP or not PPP and not P
EntailmentImplication
Isa relation between sentencesa connective inside a sentence
WrittenKB entails aP implies Q
Has a truth valueno, it holds or it does notyes, per model
Connected byKB entails a iff KB implies a is valid
SoundComplete
Promiseseverything derived is entailedeverything entailed can be derived
Failure looks likederiving a falsehoodfailing to find a truth
A procedure deriving nothing issoundnot complete

What it does not mean

Entailment is not an algorithm. It is a relation defined by the semantics. Model checking and resolution are algorithms for deciding it, and they are not the definition.

Entailment is not implication. One is a relation between sentences; the other is a connective. They are linked by the deduction theorem and they are not the same thing.

A knowledge base does not determine one world. It narrows the possible worlds to a set. Anything varying within that set is unknown, which is what the Wet row shows.

Valid does not mean true. It means true in every model, which is much stronger. Rain may be true today and is not valid.

Complete does not mean correct. Soundness is correctness. A complete but unsound procedure derives everything, including falsehoods.

Inference does not add information. Everything derivable was already entailed. That is why a wrong knowledge base yields wrong conclusions reliably.

Quick revision

  • KB entails a: a is true in every model in which KB is true. Equivalently, there is no model with KB true and a false. Equivalently, a adds no information.
  • Model checking: enumerate all 2 to the power n models, keep those satisfying KB, check the query in all survivors. Sound and complete, and exponential; deciding entailment is co-NP-complete.
  • On the worked knowledge base, 2 of 8 models survive. Cancelled is entailed, Wet is unknown, and the two surviving models differ only in Wet.
  • The four words: valid (true in all models, a tautology), satisfiable (true in at least one), unsatisfiable (true in none, inconsistent), entailed (true in all models of KB).
  • a is unsatisfiable exactly when not a is valid.
  • Deduction theorem: KB entails a iff KB implies a is valid. Refutation form: iff KB and not a is unsatisfiable. The second is the basis of resolution.
  • Sound: everything derived is entailed. Complete: everything entailed is derivable. Independent, and both wanted.
  • Logical equivalence is a relation between sentences; a is equivalent to b iff a iff b is valid.
munotes.in150

Entailment, Models and Validity

Test yourself

1. Define entailment. A knowledge base entails a sentence when that sentence is true in every model in which the knowledge base is true. Equivalently, there is no model in which the knowledge base holds and the sentence fails.

2. On the worked knowledge base, why is Cancelled entailed but Wet unknown? Only two of the eight models satisfy the knowledge base, and Cancelled is true in both, so it is entailed. Wet is true in one of those two and false in the other, so the knowledge base does not settle it.

3. Describe model checking and state its complexity. Enumerate every assignment of truth values to the symbols, keep those in which every sentence of the knowledge base is true, and report the query as entailed if it holds in all of them. It examines 2 to the power n models for n symbols, and deciding propositional entailment is co-NP-complete.

4. Define valid, satisfiable and unsatisfiable, with an example of each. Valid means true in every model, for example P or not P. Satisfiable means true in at least one model, for example P. Unsatisfiable means true in no model, for example P and not P.

5. State the two reformulations of entailment and say which resolution uses. The deduction theorem: KB entails a exactly when KB implies a is valid. The refutation form: KB entails a exactly when KB and not a is unsatisfiable. Resolution uses the refutation form: it adds the negated query and looks for a contradiction.

6. Distinguish soundness from completeness and give a procedure that has one and not the other. Soundness means everything derived is entailed; completeness means everything entailed can be derived. A procedure that derives nothing at all is sound but not complete. One that derives every sentence is complete but not sound.

7. Distinguish logical equivalence from the biconditional, and state the exact link. Logical equivalence is a relation between two sentences, holding when they have the same truth value in every model. The biconditional is a connective forming a sentence that may be true or false in a given model. The link is that two sentences are logically equivalent precisely when the biconditional joining them is valid.

Contents This chapter on its own page

munotes.in151

Chapter Twenty-Nine

Inference in Propositional Logic

Syllabus topic Module 1, "inference"

In one line

Inference is deriving new sentences from old by fixed rules, so that a conclusion can be reached without going through every possible world.

In the wording a student can write in an examination: an inference rule is a pattern licensing the derivation of a conclusion from premises. A rule is sound if its conclusion is entailed by its premises, which is checked by confirming that the corresponding implication is valid. A proof or derivation is a sequence of sentences, each either in the knowledge base or obtained from earlier ones by a rule, ending in the query. Inference by rules avoids enumerating models and is therefore the practical alternative to model checking.

Why not just check the models

Entailment, Models and Validity gave a procedure that is sound, complete, and exponential: 2 to the power n models for n symbols. Inference by rules works on the sentences instead, and on the knowledge bases that arise in practice it touches a tiny fraction of the model space.

It has a second advantage that matters as much and is easy to forget: a derivation is an explanation. Model checking answers yes and can say nothing about why. A proof is a list of lines with reasons, which a person can read, check and argue with. That is what The Knowledge-Based Agent meant by saying such an agent can explain itself.

The rules

Seven rules cover everything MU's row needs. Each is sound, and each is checked the same way: the implication from premises to conclusion is valid, which can be confirmed on a truth table.

Modus ponens. From P implies Q and P, derive Q.

P implies Q, P

therefore Q

This is the rule every rule-based system is built on and the one whose misuse is a named fallacy. From P implies Q and Q you may not derive P; that is affirming the consequent, and it is unsound. The cancelled match does not prove it rained.

Modus tollens. From P implies Q and not Q, derive not P.

P implies Q, not Q

therefore not P

This is the contrapositive at work: the match was not cancelled, so it did not rain. The matching fallacy is denying the antecedent: from P implies Q and not P, concluding not Q. It did not rain, therefore the match was not cancelled. Unsound; the match may have been cancelled for another reason.

And-elimination. From P and Q, derive P. And derive Q.

And-introduction. From P and Q, derive P and Q.

Or-introduction. From P, derive P or Q, for any Q at all. It looks useless and is not: it is how a conclusion is widened to match a clause in a proof.

munotes.in152

Inference in Propositional Logic

Unit resolution. From P or Q and not Q, derive P. This is the special case that Conjunctive Normal Form and Resolution generalises, and it is worth noticing that modus ponens IS unit resolution once P implies Q is rewritten as not P or Q.

Biconditional elimination. From P iff Q, derive P implies Q and Q implies P.

A derivation, with a reason on every line

The knowledge base is about a student's result. Three rules and three facts.

# Inference as a DERIVATION: apply rules, write down each line with its reason.
# The knowledge base is a small set of definite clauses about a student's result.
RULES = [
    (["Attendance", "PassedInternal"], "Eligible"),
    (["Eligible", "PassedExternal"], "Passed"),
    (["Passed"], "Certificate"),
]
FACTS = ["Attendance", "PassedInternal", "PassedExternal"]

print("knowledge base")
for prem, con in RULES:
    print("   %s  implies  %s" % (" and ".join(prem), con))
for f in FACTS:
    print("   %s" % f)
print()
print("forward chaining, with the reason for every line")
known = list(FACTS)
line = 0
for f in FACTS:
    line += 1
    print("   %2d. %-14s given" % (line, f))
changed = True
while changed:
    changed = False
    for prem, con in RULES:
        if con in known:
            continue
        if all(p in known for p in prem):
            known.append(con)
            line += 1
            print("   %2d. %-14s modus ponens, from %s"
                  % (line, con, " and ".join(prem)))
            changed = True
print()
print("derived:", ", ".join(k for k in known if k not in FACTS))
print()
print("and what happens if the student fails the external examination:")
known = ["Attendance", "PassedInternal"]
changed = True
while changed:
    changed = False
    for prem, con in RULES:
        if con not in known and all(p in known for p in prem):
            known.append(con)
            changed = True
print("   derived:", ", ".join(k for k in known if k not in ("Attendance", "PassedInternal")))
print("   Passed is NOT derived, and neither is Certificate. Nothing was assumed.")
knowledge base
   Attendance and PassedInternal  implies  Eligible
   Eligible and PassedExternal  implies  Passed
   Passed  implies  Certificate
   Attendance
   PassedInternal
   PassedExternal

forward chaining, with the reason for every line
    1. Attendance     given
    2. PassedInternal given
    3. PassedExternal given
    4. Eligible       modus ponens, from Attendance and PassedInternal
    5. Passed         modus ponens, from Eligible and PassedExternal
    6. Certificate    modus ponens, from Passed

derived: Eligible, Passed, Certificate

and what happens if the student fails the external examination:
   derived: Eligible
   Passed is NOT derived, and neither is Certificate. Nothing was assumed.

Six lines, each with its reason, and Certificate is the conclusion. That is what a proof looks like, and a paper asking for a derivation wants exactly this shape: numbered lines, and for each one either "given" or the rule and the earlier lines it used.

munotes.in153

Inference in Propositional Logic

The second run is the more important one. Remove PassedExternal and Eligible is still derived, while Passed and Certificate are not. Nothing was assumed and nothing was guessed: what does not follow is simply not derived. A sound inference procedure fails silently and correctly, which is the behaviour The Knowledge-Based Agent called the third answer.

Forward chaining and backward chaining

Two directions to run the same rules, and MU's third row names them again in Inference in First-Order Logic: Unification and Chaining, so the distinction is introduced here on the propositional case.

Forward chainingBackward chaining
Starts fromthe factsthe query
Askswhat else followswhat would have to be true for this
Directiondata drivengoal driven
Deriveseverything derivableonly what bears on the query
Good whenyou want all consequences, or facts arrive one at a timeyou have one specific question
Example abovederived Eligible, Passed, Certificateasking Certificate would ask Passed, then Eligible and PassedExternal

Forward chaining can do a great deal of irrelevant work; backward chaining does none, but may re-derive the same subgoal many times. Both are sound, both are complete for the kind of knowledge base below, and which is better depends entirely on whether you have one question or many.

Definite clauses, and the one case where inference is easy

The knowledge base above is of a special and very useful shape, and naming it is worth marks.

A definite clause is a disjunction of literals with exactly one positive literal. Written the other way round, it is a rule: P1 and P2 and ... implies Q, with a single conclusion. A Horn clause is a disjunction with at most one positive literal, so it is either a definite clause or a set of premises leading to a contradiction.

Why it matters: entailment for Horn clauses can be decided in time linear in the size of the knowledge base, by forward chaining, instead of exponentially. The restriction is real: P or Q is not a Horn clause, so a knowledge base needing to say "either a pit or a wumpus, we do not know which" falls outside it and needs the full machinery of the next chapter.

That is the trade this row keeps making. Every rule engine in Rule-Based Systems and Expert Systems is a Horn-clause system, fast and restricted, and resolution is general and slow.

Soundness, checked rather than asserted

To show a rule is sound, write the implication from its premises to its conclusion and confirm that it is valid. For modus ponens that sentence is

munotes.in154

Inference in Propositional Logic

((P implies Q) and P) implies Q

and it is true on all four rows of P and Q, so the rule is sound. Do the same for affirming the consequent and the sentence

((P implies Q) and Q) implies P

is FALSE when P is false and Q is true

which is why that pattern is a fallacy and not a rule. A rule is sound or unsound as a matter of arithmetic on a truth table, not as a matter of opinion.

Distinctions

Modus ponensAffirming the consequent
FromP implies Q and PP implies Q and Q
DerivesQP
Soundyesno, a fallacy
Fails whenneverP false, Q true
Modus tollensDenying the antecedent
FromP implies Q and not QP implies Q and not P
Derivesnot Pnot Q
Soundyesno, a fallacy
Model checkingInference by rules
Works onmodelssentences
Cost2 to the power n alwayssmall in practice on real knowledge bases
Produces an explanationnoyes, the derivation
Sound and completeyesyes, for the rules above on Horn clauses

What it does not mean

An inference rule is not a fact about the world. It is a pattern whose soundness is a property of the truth tables, independent of what the symbols mean.

Modus ponens does not run backwards. From P implies Q and Q, nothing follows about P. That is a fallacy with a name.

Failing to derive something does not refute it. It means it does not follow. The query is unknown, not false.

Forward chaining is not better than backward chaining. They answer different needs: all consequences against one question.

A Horn clause restriction is not a technicality. P or Q is outside it, and any knowledge base with a genuine disjunction of possibilities needs resolution.

Or-introduction is not a trick. Deriving P or Q from P is sound, because a true disjunct makes the disjunction true, and it is how conclusions are matched to clauses in a proof.

Quick revision

  • Inference rule: a pattern licensing a conclusion from premises. Sound if the implication from premises to conclusion is valid.
  • Modus ponens: from P implies Q and P, derive Q. Its fallacy is affirming the consequent.
  • Modus tollens: from P implies Q and not Q, derive not P. Its fallacy is denying the antecedent.
  • Also: and-elimination, and-introduction, or-introduction, unit resolution, biconditional elimination.
  • Modus ponens is unit resolution, once P implies Q is rewritten as not P or Q.
  • A proof is numbered lines, each "given" or a rule with the lines it used. The reason column is what makes it a proof.
  • Forward chaining is data driven and derives everything; backward chaining is goal driven and derives only what bears on the query.
  • A definite clause has exactly one positive literal; a Horn clause at most one. Horn entailment is decidable in linear time by forward chaining. P or Q is not Horn.
  • A sound procedure fails silently: what does not follow is simply not derived.
munotes.in155

Inference in Propositional Logic

Test yourself

1. State modus ponens and modus tollens. Modus ponens: from P implies Q together with P, derive Q. Modus tollens: from P implies Q together with not Q, derive not P.

2. Name both fallacies associated with implication and say why each is unsound. Affirming the consequent, deriving P from P implies Q and Q, which fails when P is false and Q is true. Denying the antecedent, deriving not Q from P implies Q and not P, which fails when P is false and Q is true. In each case a model exists in which the premises hold and the conclusion does not.

3. How would you show that modus ponens is sound? Write the sentence ((P implies Q) and P) implies Q and check it on a truth table. It is true on all four rows, so it is valid, so the conclusion is entailed by the premises.

4. What must a proof contain besides the sentences? A reason for every line: either that the sentence is given, or the inference rule used together with the earlier lines it was applied to. Without the reasons it is a list of sentences, not a derivation.

5. Distinguish forward from backward chaining, and say when each is preferable. Forward chaining starts from the facts and derives everything that follows, which suits a case where all consequences are wanted or facts arrive over time. Backward chaining starts from the query and works out what would have to hold, which suits a single specific question and avoids irrelevant work.

6. Define a definite clause and a Horn clause, and say why the distinction matters. A definite clause is a disjunction of literals with exactly one positive literal, equivalently a rule with a single conclusion. A Horn clause has at most one positive literal. It matters because entailment for a Horn knowledge base can be decided in time linear in its size by forward chaining, rather than exponentially.

7. In this chapter's second run the student had no external pass. What was derived, and what does the result show? Only Eligible was derived; Passed and Certificate were not. It shows that a sound procedure derives exactly what follows and nothing more: the missing conclusions were not guessed, assumed or reported as false, they were simply not derived.

Contents This chapter on its own page

munotes.in156

Chapter Thirty

Conjunctive Normal Form and Resolution

Syllabus topic Module 1, "inference"

In one line

Every sentence can be rewritten as a list of clauses, and then one single rule of inference is enough to prove anything that follows.

In the wording a student can write in an examination: a sentence is in conjunctive normal form (CNF) when it is a conjunction of clauses, each clause being a disjunction of literals. Every propositional sentence has a logically equivalent CNF. The resolution rule takes two clauses containing complementary literals, one with P and one with not P, and derives the clause containing all their other literals, called the resolvent. Resolution applied to a CNF knowledge base together with the negated query is refutation complete: it derives the empty clause exactly when the query is entailed.

Why one rule is better than seven

Inference in Propositional Logic gave seven rules. Seven rules means seven choices at every step, and a search over which rule to apply where. One rule means one choice: which pair of clauses to resolve.

Robinson's own justification for a rule too large for a person to like is worth quoting, because it is the design principle of the whole field of automated reasoning. From the opening of the 1965 paper:

an inference principle needs to be sound and effective

and, on why the traditional preference for small steps no longer applies when the agent is a machine:

when the agent carrying out the application is a computing machine, the traditional limitation on the complexity of inference principles is no longer very appropriate

That is the chapter's thesis. Human logic keeps its steps small so a reader can check them. A machine does not care, so the right rule to give it is the most powerful single one available.

Converting to CNF: five steps, in this order

The order matters. Doing them out of order produces a sentence that is still correct and is not in CNF.

1. Eliminate the biconditional. P iff Q becomes (P implies Q) and (Q implies P).

2. Eliminate the implication. P implies Q becomes not P or Q. This is the equivalence from Propositional Logic: Syntax and Meaning, and after this step the only connectives left are not, and and or.

3. Move negation inwards, by De Morgan's laws, until every not sits directly on a symbol.

not (P and Q) becomes (not P) or (not Q)

not (P or Q) becomes (not P) and (not Q)

not (not P) becomes P

4. Distribute or over and.

P or (Q and R) becomes (P or Q) and (P or R)

5. Flatten. Drop the brackets of nested ands and ors, and write the result as a list of clauses.

munotes.in157

Conjunctive Normal Form and Resolution

Worked on one sentence, the wumpus rule "a square has a breeze if and only if a neighbour has a pit", in the two-neighbour case:

B iff (P1 or P2)

step 1: (B implies (P1 or P2)) and ((P1 or P2) implies B)

step 2: (not B or P1 or P2) and (not (P1 or P2) or B)

step 3: (not B or P1 or P2) and ((not P1 and not P2) or B)

step 4: (not B or P1 or P2) and (not P1 or B) and (not P2 or B)

Three clauses. Read what they say: if there is a breeze then a neighbour has a pit, and if either neighbour has a pit then there is a breeze, split into two. The biconditional has become three separate facts, each usable on its own.

Step 4 can make the sentence much larger, in the worst case exponentially. That is the cost of CNF, and it is why practical systems avoid distributing where they can.

The resolution rule

Two clauses, one containing a literal and the other its negation. Remove the pair and join the rest.

(A or B or P) and (C or D or not P)

gives (A or B or C or D)

Why it is sound, in one line: P is either true or false. If P is true, the second clause needs one of C or D. If P is false, the first needs one of A or B. Either way one of A, B, C, D holds. The argument uses no premise about which case obtains, which is exactly why the rule works without knowing anything about P.

Two special cases and their names. Resolving two clauses of one literal each, P and not P, gives the empty clause, written {} or with a box. It is a disjunction of nothing, so nothing can make it true: it is unsatisfiable, and deriving it means the clauses it came from cannot all be true. And resolving P or Q with not Q gives P, which is the unit resolution of the previous chapter.

Proof by refutation

The strategy comes straight from the refutation form of entailment in Entailment, Models and Validity: KB entails a exactly when KB and not a is unsatisfiable.

  1. Convert the knowledge base to CNF.
  2. Negate the query and convert that to CNF too.
  3. Add all those clauses together.
  4. Resolve pairs repeatedly.
  5. If the empty clause appears, the set is unsatisfiable, so the query is entailed. If no new clauses can be produced and no empty clause has appeared, the query is not entailed.
munotes.in158

Conjunctive Normal Form and Resolution

Step 2 is the step students forget, and forgetting it makes the method look useless: resolving the knowledge base with itself proves nothing. The proof is a proof by contradiction, so the thing to add is the OPPOSITE of what you want.

It running, both ways

# Resolution: one rule of inference, applied to clauses, until the empty clause
# appears. A clause is a frozenset of literals; "-P" means not P.
def negate(lit):
    return lit[1:] if lit.startswith("-") else "-" + lit

def resolve(c1, c2):
    """Every resolvent of two clauses: drop one complementary pair."""
    out = []
    for lit in c1:
        if negate(lit) in c2:
            new = (c1 - {lit}) | (c2 - {negate(lit)})
            out.append((lit, frozenset(new)))
    return out

def show(c):
    return "{}" if not c else "{" + ", ".join(sorted(c)) + "}"

def prove(clauses, name):
    clauses = [frozenset(c) for c in clauses]
    print(name)
    for c in clauses:
        print("   given   ", show(c))
    seen = set(clauses)
    step = 0
    while True:
        new = []
        for i in range(len(clauses)):
            for j in range(i + 1, len(clauses)):
                for lit, r in resolve(clauses[i], clauses[j]):
                    if r in seen:
                        continue
                    if any(negate(x) in r for x in r):
                        continue           # a tautology: useless, skip it
                    step += 1
                    print("   resolve %s with %s on %s  ->  %s"
                          % (show(clauses[i]), show(clauses[j]), lit, show(r)))
                    if not r:
                        print("   THE EMPTY CLAUSE. the set is unsatisfiable, so the")
                        print("   original query is PROVED, in %d resolution steps." % step)
                        return True
                    seen.add(r)
                    new.append(r)
        if not new:
            print("   no new clauses. the set is satisfiable, so the query is NOT proved.")
            return False
        clauses.extend(new)

# "If it rains the match is cancelled. If the match is cancelled we study.
#  It is raining."  Prove: we study.  Negate the query and look for a contradiction.
prove([["-Rain", "Cancelled"],        # Rain => Cancelled
       ["-Cancelled", "Study"],       # Cancelled => Study
       ["Rain"],                      # Rain
       ["-Study"]],                   # the NEGATED query
      "proving Study by refutation:")
print()
prove([["-Rain", "Cancelled"],
       ["Rain"],
       ["-Wet"]],                     # the negated query: is Wet entailed?
      "and the same machinery on a query that is NOT entailed:")
proving Study by refutation:
   given    {-Rain, Cancelled}
   given    {-Cancelled, Study}
   given    {Rain}
   given    {-Study}
   resolve {-Rain, Cancelled} with {-Cancelled, Study} on Cancelled  ->  {-Rain, Study}
   resolve {-Rain, Cancelled} with {Rain} on -Rain  ->  {Cancelled}
   resolve {-Cancelled, Study} with {-Study} on Study  ->  {-Cancelled}
   resolve {-Rain, Cancelled} with {-Cancelled} on Cancelled  ->  {-Rain}
   resolve {-Cancelled, Study} with {Cancelled} on -Cancelled  ->  {Study}
   resolve {Cancelled} with {-Cancelled} on Cancelled  ->  {}
   THE EMPTY CLAUSE. the set is unsatisfiable, so the
   original query is PROVED, in 6 resolution steps.

and the same machinery on a query that is NOT entailed:
   given    {-Rain, Cancelled}
   given    {Rain}
   given    {-Wet}
   resolve {-Rain, Cancelled} with {Rain} on -Rain  ->  {Cancelled}
   no new clauses. the set is satisfiable, so the query is NOT proved.
munotes.in159

Conjunctive Normal Form and Resolution

Six resolutions and the empty clause appears, so Study is entailed. Read the key pair: {Cancelled} was derived from the rule and the fact, and {-Cancelled} was derived from the other rule and the negated query. Those two contradict, the empty clause follows, and the contradiction proves the query.

The second run is the one that shows the method is not a trick. Asking whether Wet is entailed, the prover derives {Cancelled} and then stops: no pair of remaining clauses has complementary literals, no empty clause appears, and the answer is correctly not proved. The knowledge base says nothing about wet ground, and resolution reports exactly that.

Refutation complete, which is weaker than complete and is enough

The precise statement of what Robinson proved, and getting this right is worth marks.

Resolution is refutation complete: if a set of clauses is unsatisfiable, resolution will derive the empty clause from it. It is not complete in the sense of deriving every entailed sentence: from {P} alone, resolution cannot derive P or Q, although P or Q is entailed.

And refutation completeness is all that is needed, because of the refutation form of entailment. To decide whether a is entailed, do not try to derive a; add not a and derive the empty clause. The weaker property, combined with the right strategy, does the whole job.

Cost, and the three standard economies

Resolution decides propositional entailment, and deciding it is co-NP-complete, so no fast method is expected. Three refinements are standard and each has a name.

  • Discard tautologies. A clause containing both P and not P is true in every model and can never help. The program above does this.
  • Discard subsumed clauses. If {P} is already present, {P, Q} adds nothing; the smaller clause is stronger.
  • Unit preference. Resolve with one-literal clauses first. Each such resolution makes a clause shorter, and the empty clause is the shortest of all, so it is progress in the right direction.

A fourth is worth naming because it is what modern solvers actually use: the DPLL algorithm, which searches over assignments with unit propagation and pure-literal elimination rather than resolving clauses. Resolution is the theory; DPLL and its descendants are the engineering, and they handle millions of clauses.

Distinctions

CNFDNF
Isa conjunction of disjunctionsa disjunction of conjunctions
Shape(A or B) and (C or D)(A and B) or (C and D)
Used forresolution, and SAT solvingreading off models
CompleteRefutation complete
Derivesevery entailed sentencethe empty clause from any unsatisfiable set
Resolution isnoyes
Enough to decide entailmentyesyes, with the negated query
munotes.in160

Conjunctive Normal Form and Resolution

Modus ponensResolution
Applies toa rule and a factany two clauses with complementary literals
Number of rules neededseven, with itone
Handles P or Qnoyes
Complete forHorn clausesall of propositional logic, by refutation

What it does not mean

CNF is not a simplification. Distribution can make a sentence exponentially larger. It is a normal form, chosen because one rule works on it.

Resolution does not prove a sentence directly. It derives a contradiction from the negation. Forgetting to negate the query is the standard error.

The empty clause is not "nothing derived". It is a derived clause with no literals, which no model can satisfy, and deriving it is the whole proof.

Resolution is not complete in the ordinary sense. From {P} it cannot derive P or Q. It is refutation complete, which is what is needed.

Failure to derive the empty clause is not a timeout. When no new clauses can be produced, the set is satisfiable and the query is definitely not entailed, as the second run shows.

One rule is not simpler for a human. It is simpler for a machine, which is Robinson's own point: the limitation on the complexity of an inference step existed because a person had to follow it.

Quick revision

  • CNF: a conjunction of clauses, each a disjunction of literals. Every sentence has an equivalent CNF.
  • Five steps, in order: eliminate iff, eliminate implies (P implies Q to not P or Q), move not inwards by De Morgan, distribute or over and, flatten. Distribution can blow up the size.
  • Resolution: from two clauses with complementary literals, derive the clause of all their other literals, the resolvent. Sound because P is either true or false and each case leaves one of the remaining literals.
  • Proof by refutation: CNF the knowledge base, negate the query, add it, resolve. The empty clause means the query is entailed.
  • On the worked example: 6 resolutions to the empty clause, from {Cancelled} and {-Cancelled}, the second coming from the negated query. On a query that is not entailed the prover stops with no empty clause and reports correctly.
  • Refutation complete, not complete. From {P} it cannot derive P or Q. Refutation completeness plus the negated query decides entailment, which is enough.
  • Economies: discard tautologies, discard subsumed clauses, unit preference. Modern solvers use DPLL and its descendants instead.
  • Robinson 1965: a machine's inference rule need not be small, because the traditional limit on complexity existed for human readers.
munotes.in161

Conjunctive Normal Form and Resolution

Test yourself

1. Define conjunctive normal form. A sentence is in conjunctive normal form when it is a conjunction of clauses, each clause being a disjunction of literals, where a literal is a symbol or its negation.

2. Give the five steps of the conversion, in order. Eliminate biconditionals; eliminate implications by rewriting P implies Q as not P or Q; move negations inwards with De Morgan's laws until each applies to a symbol; distribute or over and; then flatten the nesting into a list of clauses.

3. State the resolution rule and justify its soundness. From two clauses, one containing a literal and the other its negation, derive the clause containing all their remaining literals. It is sound because the literal is either true or false: if true, the second clause requires one of its other literals; if false, the first does. Either way one of the remaining literals holds.

4. How is resolution used to prove that a query is entailed? Convert the knowledge base to CNF, negate the query and convert that to CNF, add all the clauses together, and resolve pairs repeatedly. If the empty clause is derived the combined set is unsatisfiable, so the knowledge base entails the query.

5. What is the empty clause, and what does deriving it mean? A clause with no literals. It is a disjunction of nothing, so no model can make it true, which means it is unsatisfiable. Deriving it shows that the clauses it came from cannot all hold, which in a refutation proof establishes the query.

6. Resolution is refutation complete but not complete. Explain the difference and why the weaker property suffices. Complete would mean deriving every entailed sentence; resolution cannot, since from {P} it cannot derive P or Q. Refutation complete means it derives the empty clause from any unsatisfiable set. That suffices because entailment is equivalent to the unsatisfiability of the knowledge base together with the negated query.

7. Convert B iff (P1 or P2) to CNF and say what the resulting clauses mean. Eliminating the biconditional gives (B implies (P1 or P2)) and ((P1 or P2) implies B); eliminating implications and applying De Morgan and distribution gives the three clauses not B or P1 or P2, not P1 or B, and not P2 or B. They say that a breeze requires a neighbouring pit, and that either neighbouring pit produces a breeze.

Contents This chapter on its own page

munotes.in162

Chapter Thirty-One

First-Order Logic

Syllabus topic Module 1, "First-Order Logic"

In one line

First-order logic talks about objects and the relations between them, so one sentence can say something about everything at once.

In the wording a student can write in an examination: first-order logic extends propositional logic with terms that denote objects, predicates that denote relations, functions that denote mappings from objects to objects, and two quantifiers: the universal quantifier, read "for all", and the existential quantifier, read "there exists". An atomic sentence is a predicate applied to terms. Sentences are built from atomic ones by the propositional connectives and by quantification.

What propositional logic could not do

Three failures, and each is repaired by one piece of the new language.

FailureExampleThe repair
Cannot refer to objectsSquare12IsSafe has no partsterms: constants, variables, functions
Cannot express relationsno way to say 1,2 is next to 1,1predicates of more than one argument
Cannot generaliseone sentence per square, all obviously the samequantifiers

The third is the one that matters most in practice. In the six-square pit world of The Knowledge-Based Agent the rule "a breeze means a pit next door" had to be written once per square. In a hundred squares it is a hundred sentences, and the logic cannot see that they are instances of one thing. First-order logic writes it once.

The syntax

Terms denote objects. Three kinds:

KindWrittenDenotes
Constant symbolAsha, Amba, Square12one particular object
Variablex, y, san object, not yet fixed
Function termMother(Asha), Plus(x, 1)the object the function gives for those arguments

A function is not a predicate, and confusing them is the commonest error on this topic. Mother(Asha) is a term: it names a person, and it is neither true nor false. IsMotherOf(Rekha, Asha) is an atomic sentence: it is true or false. A function returns an object; a predicate returns a truth value. The test: can you put it after "the"? "The mother of Asha" is a term. "Rekha is the mother of Asha" is a sentence.

Predicate symbols denote relations. Safe(s) is a relation of one argument, a property. Adjacent(s1, s2) is a relation of two. Between(a, b, c) of three.

An atomic sentence is a predicate applied to terms: Safe(Square12), Adjacent(x, Square11), IsMotherOf(Mother(Asha), Asha).

Complex sentences use the same five connectives as before, plus quantification.

The two quantifiers

Universal, for all. for all x, P(x) is true when P holds of every object.

Existential, there exists. exists x, P(x) is true when P holds of at least one object.

Two idioms, and they are the whole of the marks on quantifiers.

munotes.in163

First-Order Logic

A universal quantifier goes with an implication. "All students who attended are eligible" is

for all s, Student(s) and Attended(s) implies Eligible(s)

Writing for all s, Student(s) and Eligible(s) instead says everything in the universe is a student and is eligible, which is false and is the standard mistake. The implication is what restricts the claim to the objects you meant.

An existential quantifier goes with a conjunction. "Some student is eligible" is

exists s, Student(s) and Eligible(s)

Writing exists s, Student(s) implies Eligible(s) is far weaker than intended: an implication is true whenever its premise is false, so a single non-student anywhere in the universe makes that sentence true. It is satisfied by a chair.

The pairing is worth memorising as a slogan: "for all" with "implies", "exists" with "and".

Nesting, and why order matters

Two quantifiers of the same kind may be swapped freely. Two of different kinds may not, and this is the standard 5-mark question.

for all x, exists y, Loves(x, y)

exists y, for all x, Loves(x, y)

The first says everybody loves somebody, possibly a different somebody each. The second says there is one particular person whom everybody loves. The second is much stronger and implies the first; the first does not imply the second.

The general rule: swapping for all and exists changes the meaning, because the inner quantifier's choice may depend on the outer one's object. When exists is inside, the object it picks can vary with the outer object; when it is outside, it cannot.

The connection between the two quantifiers

They are duals, and each can be defined from the other by pushing a negation through it.

for all x, P(x) is equivalent to not (exists x, not P(x))

exists x, P(x) is equivalent to not (for all x, not P(x))

Read the first in words: everything is P exactly when nothing is not P. These are De Morgan's laws for quantifiers, and they matter for the same reason the propositional ones did: they let a negation be pushed inward, which is the first step of converting to clause form.

The consequence worth stating: "not all students passed" is not "no student passed". The first is not (for all s, Passed(s)), which is exists s, not Passed(s), one failure. The second is for all s, not Passed(s). Papers ask for exactly this.

Semantics: the interpretation

A model in propositional logic assigned true or false to each symbol. A model in first-order logic is more elaborate, and naming its parts is worth marks.

PartWhat it is
Domain, or universe of discoursethe non-empty set of objects the sentences are about
Interpretation of a constantwhich object of the domain it names
Interpretation of a predicatewhich tuples of objects the relation holds of
Interpretation of a functiona mapping from tuples of objects to objects
munotes.in164

First-Order Logic

Two consequences. The domain must be non-empty, or for all x, P(x) would be trivially true and exists x, P(x) never true, and the two would stop being duals. And the domain may be infinite, which is where first-order inference stops being a matter of enumeration: propositional logic had 2 to the power n models and first-order logic can have unboundedly many.

Equality, and what it buys

x = y is a built-in predicate, true when both terms denote the same object. It is worth its own mention because it does something no other predicate can.

Without equality, "Asha has exactly one mother" cannot be said. With it:

exists m, IsMotherOf(m, Asha) and (for all m2, IsMotherOf(m2, Asha) implies m2 = m)

And it is how distinctness is asserted: not (Asha = Vikram). First-order logic does not assume two different names denote different objects, which surprises people. Mumbai and Bombay may denote the same object unless you say otherwise.

Decidability, which is the price of the expressive power

This is the honest cost, and a paper can ask for it.

Propositional entailment is decidable: hard, co-NP-complete, and a procedure always terminates with the right answer.

First-order entailment is semi-decidable, also called not decidable. There is a procedure that will find a proof if one exists, but there is no procedure guaranteed to terminate when the query is not entailed: it may run forever. That is a theorem, not a gap in current knowledge, and it is what Robinson's paper and every theorem prover since have had to live with.

The practical consequence: real systems restrict the language. Definite clauses only, giving Prolog and every rule engine in Rule-Based Systems and Expert Systems; or a decidable fragment, as description logics do. The full logic is used where a person can supervise the search.

Writing English in first-order logic

A paper will ask for translations. The pattern to follow is: identify the objects, the predicates, then the quantifier, then apply the two idioms above.

EnglishFirst-order logic
Asha attendedAttended(Asha)
Every student attendedfor all s, Student(s) implies Attended(s)
Some student did not attendexists s, Student(s) and not Attended(s)
No student failedfor all s, Student(s) implies not Failed(s)
Only students attendedfor all s, Attended(s) implies Student(s)
Every student passed at least one paperfor all s, Student(s) implies (exists p, Paper(p) and Passed(s, p))
There is a paper every student passedexists p, Paper(p) and (for all s, Student(s) implies Passed(s, p))
munotes.in165

First-Order Logic

The last two are the nesting pair again, in the form a paper sets it. And note row five: "only students attended" reverses the implication, which is a different sentence from row two and a favourite question.

Distinctions

FunctionPredicate
Returnsan objecta truth value
Is atermsentence, when applied
ExampleMother(Asha)IsMotherOf(Rekha, Asha)
Testfits after "the"can be true or false
for allexists
Read asfor all, for everythere exists, for some
Pairs withimpliesand
True whenthe body holds of every objectof at least one
Its negation isexists of the negated bodyfor all of the negated body
Propositional logicFirst-order logic
Talks aboutwhole statementsobjects, relations, functions
Can generalisenoyes, with quantifiers
Models2 to the power n, finitearbitrarily many, domain may be infinite
Entailmentdecidable, co-NP-completesemi-decidable

What it does not mean

A function symbol is not a predicate. Mother(Asha) names a person and has no truth value.

for all with and is not a harmless variant. for all s, Student(s) and Eligible(s) claims everything in the universe is an eligible student.

exists with implies is not a harmless variant either. It is satisfied by any object that is not a student, so it claims almost nothing.

Swapping quantifiers is not safe. for all x, exists y and exists y, for all x are different sentences, and the second is stronger.

"Not all" is not "none". not (for all s, Passed(s)) is exists s, not Passed(s): one failure suffices.

Two different names do not denote two different objects. Distinctness has to be asserted with equality.

First-order logic is not decidable. It is semi-decidable: a proof will be found if one exists, and a non-entailed query may never terminate.

Quick revision

  • Terms denote objects: constants, variables, function terms. Predicates denote relations. An atomic sentence is a predicate applied to terms.
  • A function returns an object, a predicate returns a truth value. Mother(Asha) against IsMotherOf(Rekha, Asha).
  • for all pairs with implies; exists pairs with and. The other pairings say things you did not mean.
  • Order of unlike quantifiers matters: for all x, exists y, Loves(x, y) is everybody loves somebody; exists y, for all x, Loves(x, y) is one person loved by all, which is stronger.
  • Duals: for all x, P(x) is not (exists x, not P(x)), and conversely. So "not all passed" is "at least one failed", not "none passed".
  • A model is a non-empty domain plus an interpretation of every constant, predicate and function. The domain may be infinite.
  • Equality is built in, and lets uniqueness and distinctness be said. Two names may denote one object unless stated otherwise.
  • First-order entailment is semi-decidable: a proof is found if one exists; a non-entailed query may not terminate. Practical systems restrict the language to definite clauses or to a decidable fragment.
munotes.in166

First-Order Logic

Test yourself

1. Name the four kinds of symbol first-order logic adds, and say what each denotes. Constant symbols denote particular objects; variables denote unspecified objects; function symbols denote mappings from objects to objects and build terms; predicate symbols denote relations and build atomic sentences.

2. Distinguish a function from a predicate with an example. A function applied to terms gives a term, which names an object and has no truth value, for example Mother(Asha). A predicate applied to terms gives a sentence, which is true or false, for example IsMotherOf(Rekha, Asha).

3. Write "every student who attended is eligible" and explain why the connective must be an implication. for all s, Student(s) and Attended(s) implies Eligible(s). With a conjunction instead, the sentence would assert of every object in the universe that it is a student, that it attended and that it is eligible, which is not the claim.

4. Write "some student is eligible" and explain why the connective must be a conjunction. exists s, Student(s) and Eligible(s). With an implication, the sentence would be satisfied by any object that is not a student, since an implication with a false premise is true, so it would assert almost nothing.

5. Distinguish for all x, exists y, Loves(x, y) from exists y, for all x, Loves(x, y). The first says everyone loves someone, and the person loved may differ from lover to lover. The second says there is one particular individual whom everyone loves. The second implies the first and the first does not imply the second.

6. State the relation between the two quantifiers and use it on "not all students passed". for all x, P(x) is equivalent to not (exists x, not P(x)), and exists x, P(x) to not (for all x, not P(x)). So "not all students passed" is not (for all s, Passed(s)), which is exists s, not Passed(s): at least one student failed, which is quite different from no student passing.

7. Compare the decidability of propositional and first-order entailment, and say what practical systems do about it. Propositional entailment is decidable, though co-NP-complete. First-order entailment is only semi-decidable: a proof will be found when one exists, but a procedure need not terminate when the query is not entailed. Practical systems therefore restrict the language, most often to definite clauses, which is what Prolog and rule engines do.

Contents This chapter on its own page

munotes.in167

Chapter Thirty-Two

Inference in First-Order Logic: Unification and Chaining

Syllabus topic Module 1, "First-Order Logic"

In one line

Unification is the step that finds which objects a rule is talking about, and once you have it, first-order inference is the same two directions of reasoning as before.

In the wording a student can write in an examination: a substitution is a mapping from variables to terms. Unification takes two atomic sentences and returns the most general unifier, the substitution that makes them identical while committing to as little as possible, or fails if none exists. Generalised modus ponens uses it: given a rule whose premises unify with known facts under a substitution, the conclusion with that substitution applied may be derived. Forward chaining applies the rules to the facts until nothing new follows; backward chaining starts from the query and works back to the facts.

Why unification is needed at all

Propositional modus ponens matched sentences exactly. First-order sentences contain variables, so exact matching finds almost nothing.

The rule says Student(s) and Attended(s) implies Eligible(s). The facts say Student(Asha) and Attended(Asha). Nothing matches exactly, because the rule has s where the facts have Asha. Unification is the operation that discovers the substitution {s/Asha}, and it is the whole reason a single rule can serve a thousand students.

Substitution and the most general unifier

A substitution is written {x/Meera, y/Anil}: replace x by Meera and y by Anil. Applying it to a sentence replaces every occurrence of those variables.

A unifier of two sentences is a substitution making them identical. There can be many. Knows(Anil, x) and Knows(y, z) are unified by {y/Anil, x/z} and also by {y/Anil, x/Meera, z/Meera}. The most general unifier, or MGU, is the one that constrains the fewest variables: {y/Anil, x/z}. It is unique up to renaming, and it is what an algorithm should return, because committing early to Meera would throw away answers.

Unification, run

# Unification: the algorithm that makes first-order inference mechanical. A term is
# a string; a lower-case initial means a VARIABLE, upper case a constant, and a
# tuple is a compound term, ("Knows", "x", "Anil").
def is_var(t):
    return isinstance(t, str) and t[0].islower()

def unify(x, y, sub=None):
    """The most general unifier of x and y, or None if they do not unify."""
    if sub is None:
        sub = {}
    if sub is None:
        return None
    if x == y:
        return sub
    if is_var(x):
        return unify_var(x, y, sub)
    if is_var(y):
        return unify_var(y, x, sub)
    if isinstance(x, tuple) and isinstance(y, tuple) and len(x) == len(y):
        for a, b in zip(x, y):
            sub = unify(a, b, sub)
            if sub is None:
                return None
        return sub
    return None

def unify_var(v, x, sub):
    if v in sub:
        return unify(sub[v], x, sub)
    if isinstance(x, str) and x in sub:
        return unify(v, sub[x], sub)
    if occurs(v, x, sub):
        return None                      # the OCCUR CHECK
    out = dict(sub)
    out[v] = x
    return out

def occurs(v, x, sub):
    if v == x:
        return True
    if isinstance(x, str) and x in sub:
        return occurs(v, sub[x], sub)
    if isinstance(x, tuple):
        return any(occurs(v, part, sub) for part in x)
    return False

def apply_sub(t, sub):
    """Substitute until nothing changes: the COMPOSED form of the unifier."""
    if isinstance(t, str):
        return apply_sub(sub[t], sub) if t in sub else t
    return tuple([t[0]] + [apply_sub(p, sub) for p in t[1:]])

def show(t):
    if isinstance(t, tuple):
        return "%s(%s)" % (t[0], ", ".join(show(p) for p in t[1:]))
    return t

CASES = [
    (("Knows", "Anil", "x"), ("Knows", "Anil", "Meera")),
    (("Knows", "Anil", "x"), ("Knows", "y", "Bhavna")),
    (("Knows", "Anil", "x"), ("Knows", "y", ("Mother", "y"))),
    (("Knows", "Anil", "x"), ("Knows", "x", "Bhavna")),
    (("Knows", "Anil", "x"), ("Teaches", "Anil", "x")),
    ("x", ("Mother", "x")),
]
print("unifying two atomic sentences:")
for a, b in CASES:
    s = unify(a, b)
    if s is None:
        result = "DO NOT UNIFY"
    else:
        result = "{" + ", ".join("%s/%s" % (k, show(apply_sub(v, s)))
                                 for k, v in sorted(s.items())) + "}"
    print("   %-28s %-32s %s" % (show(a), show(b), result))
print()
print("the fourth case fails because one name cannot be two people at once, and")
print("the last fails the OCCUR CHECK: x cannot be a term that contains x.")
print()
print("the substitutions above are printed COMPOSED: the algorithm actually")
print("produces {x/Mother(y), y/Anil} on the third case and the composed form,")
print("{x/Mother(Anil), y/Anil}, is what a paper expects to see.")
munotes.in168

Inference in First-Order Logic: Unification and Chaining

unifying two atomic sentences:
   Knows(Anil, x)               Knows(Anil, Meera)               {x/Meera}
   Knows(Anil, x)               Knows(y, Bhavna)                 {x/Bhavna, y/Anil}
   Knows(Anil, x)               Knows(y, Mother(y))              {x/Mother(Anil), y/Anil}
   Knows(Anil, x)               Knows(x, Bhavna)                 DO NOT UNIFY
   Knows(Anil, x)               Teaches(Anil, x)                 DO NOT UNIFY
   x                            Mother(x)                        DO NOT UNIFY

the fourth case fails because one name cannot be two people at once, and
the last fails the OCCUR CHECK: x cannot be a term that contains x.

the substitutions above are printed COMPOSED: the algorithm actually
produces {x/Mother(y), y/Anil} on the third case and the composed form,
{x/Mother(Anil), y/Anil}, is what a paper expects to see.

Read the three failures, because each fails for a different reason and papers ask for exactly these.

Row four fails because the same variable appears in both sentences. x would have to be both Anil and Bhavna. The standard repair is standardising apart: rename the variables of one sentence before unifying, so Knows(Anil, x) meets Knows(x1, Bhavna) and unifies to {x1/Anil, x/Bhavna}. Every real implementation does this before every unification attempt, and forgetting it makes correct rules mysteriously fail.

Row five fails because the predicate symbols differ. Knows is not Teaches, and no substitution changes a predicate symbol.

munotes.in169

Inference in First-Order Logic: Unification and Chaining

Row six fails the occur check. x cannot be unified with Mother(x), because the substitution would have to replace x inside its own value, giving Mother(Mother(Mother(...))) forever. The check costs time on every unification, and Prolog omits it by default for speed, which is why a Prolog program can be made to loop by unifying a variable with a term containing it.

Generalised modus ponens

The rule that uses unification. Given a rule p1 and p2 and ... implies q, and facts f1, f2, ..., if a substitution s makes each pi identical to some fi, derive q with s applied.

Student(s) and Attended(s) implies Eligible(s), Student(Asha), Attended(Asha)

with s = {s/Asha}

therefore Eligible(Asha)

It is one rule doing the work of infinitely many propositional instances. Without it, the first-order rule would have to be propositionalised: instantiated once for every object in the domain, which is impossible if the domain is infinite and merely wasteful if it is large.

Forward and backward chaining, run over the same rules

# Forward and backward chaining over the SAME first-order rule set, so the two
# directions can be compared. The rules are definite clauses with variables.
def is_var(t):
    return isinstance(t, str) and t[0].islower()

def unify(x, y, sub):
    if sub is None:
        return None
    if x == y:
        return sub
    if is_var(x):
        return bind(x, y, sub)
    if is_var(y):
        return bind(y, x, sub)
    if isinstance(x, tuple) and isinstance(y, tuple) and len(x) == len(y):
        for a, b in zip(x, y):
            sub = unify(a, b, sub)
            if sub is None:
                return None
        return sub
    return None

def bind(v, x, sub):
    if v in sub:
        return unify(sub[v], x, sub)
    out = dict(sub)
    out[v] = x
    return out

def sub_in(t, s):
    if isinstance(t, str):
        return sub_in(s[t], s) if t in s else t
    return tuple([t[0]] + [sub_in(p, s) for p in t[1:]])

def show(t):
    if isinstance(t, tuple):
        return "%s(%s)" % (t[0], ", ".join(show(p) for p in t[1:]))
    return t

# "A student who has attended and passed the internal is eligible."
# "An eligible student who passed the external has passed."
RULES = [([("Attended", "s"), ("PassedInternal", "s")], ("Eligible", "s")),
         ([("Eligible", "s"), ("PassedExternal", "s")], ("Passed", "s"))]
FACTS = [("Attended", "Asha"), ("PassedInternal", "Asha"), ("PassedExternal", "Asha"),
         ("Attended", "Vikram"), ("PassedInternal", "Vikram")]

def forward():
    known = list(FACTS)
    print("FORWARD chaining: start from the facts, derive everything")
    for f in FACTS:
        print("   given  ", show(f))
    added = True
    while added:
        added = False
        for premises, conclusion in RULES:
            for sub in match(premises, {}, known):
                new = sub_in(conclusion, sub)
                if new not in known:
                    known.append(new)
                    print("   derive ", show(new), "  from",
                          ", ".join(show(sub_in(p, sub)) for p in premises))
                    added = True
    return known

def match(premises, sub, known):
    """Every substitution making all the premises true against `known`."""
    if not premises:
        yield sub
        return
    first, rest = premises[0], premises[1:]
    for fact in known:
        s = unify(first, fact, dict(sub))
        if s is not None:
            yield from match(rest, s, known)

def backward(goal, known, depth=0):
    """Ask the goal. Print the question before answering it."""
    print("   %sask %s" % ("  " * depth, show(goal)))
    for fact in known:
        if unify(goal, fact, {}) is not None:
            print("   %s  yes, it is a given fact" % ("  " * depth))
            return True
    for premises, conclusion in RULES:
        s = unify(goal, conclusion, {})
        if s is None:
            continue
        print("   %s  try the rule that concludes %s" % ("  " * depth, show(conclusion)))
        if all(backward(sub_in(p, s), known, depth + 1) for p in premises):
            print("   %s  yes" % ("  " * depth))
            return True
    print("   %s  no" % ("  " * depth))
    return False

known = forward()
print()
print("BACKWARD chaining: start from the question")
backward(("Passed", "Asha"), FACTS)
print()
print("and the same question about the student with no external pass:")
backward(("Passed", "Vikram"), FACTS)
munotes.in170

Inference in First-Order Logic: Unification and Chaining

FORWARD chaining: start from the facts, derive everything
   given   Attended(Asha)
   given   PassedInternal(Asha)
   given   PassedExternal(Asha)
   given   Attended(Vikram)
   given   PassedInternal(Vikram)
   derive  Eligible(Asha)   from Attended(Asha), PassedInternal(Asha)
   derive  Eligible(Vikram)   from Attended(Vikram), PassedInternal(Vikram)
   derive  Passed(Asha)   from Eligible(Asha), PassedExternal(Asha)

BACKWARD chaining: start from the question
   ask Passed(Asha)
     try the rule that concludes Passed(s)
     ask Eligible(Asha)
       try the rule that concludes Eligible(s)
       ask Attended(Asha)
         yes, it is a given fact
       ask PassedInternal(Asha)
         yes, it is a given fact
       yes
     ask PassedExternal(Asha)
       yes, it is a given fact
     yes

and the same question about the student with no external pass:
   ask Passed(Vikram)
     try the rule that concludes Passed(s)
     ask Eligible(Vikram)
       try the rule that concludes Eligible(s)
       ask Attended(Vikram)
         yes, it is a given fact
       ask PassedInternal(Vikram)
         yes, it is a given fact
       yes
     ask PassedExternal(Vikram)
       no
     no

The difference is in one line of each output. Forward chaining derived Eligible(Vikram), which is of no use whatever to the question "did Asha pass": it was derived because forward chaining derives everything. Backward chaining asking about Asha never mentions Vikram at all.

And the second backward run shows what failure looks like. It works down to PassedExternal(Vikram), finds no fact and no rule concluding it, and reports no, so Passed(Vikram) is not derived. Note what it did not do: it did not conclude that Vikram failed. The query is unanswered, not answered negatively, which is the unknown of The Knowledge-Based Agent.

Choosing between the two directions

Forward chainingBackward chaining
Starts fromthe factsthe query
Calleddata drivengoal driven
Derivesevery consequenceonly what bears on the query
Wasted workanything irrelevant, Eligible(Vikram) abovenone, in principle
Repeated worknone, facts are storedthe same subgoal can be asked many times
Terminatesyes, when nothing new followsneeds a loop check on recursive rules
Suitsa monitoring system, facts arriving over timea diagnostic system, one question at a time
Used byproduction rule engines, Rule-Based Systems and Expert SystemsProlog
munotes.in171

Inference in First-Order Logic: Unification and Chaining

The standard fixes for each weakness are worth naming. Forward chaining's irrelevance is reduced by magic sets, which rewrite the rules to be goal-directed. Backward chaining's repetition is removed by memoisation, storing each subgoal's answers, which is what tabled Prolog does.

And backward chaining needs a loop check. Given Ancestor(x, y) implies Ancestor(x, y) or any left-recursive rule, it will ask the same goal forever. The program above is not loop-safe, and a real one keeps the current goal stack and refuses to re-ask a goal already on it.

Resolution in first-order logic, in one paragraph

Conjunctive Normal Form and Resolution generalises to first-order logic, and unification is the only new ingredient. Two clauses resolve when a literal of one and the negation of a literal of the other unify; the resolvent is the remaining literals with the unifier applied.

One extra step is needed to get to clause form: quantifiers must be removed. Universal quantifiers are dropped, since variables in a clause are read as universally quantified anyway. Existential ones are removed by Skolemisation, replacing the existentially quantified variable by a new function of the enclosing universal variables. And first-order resolution can run forever on a non-entailed query, because first-order entailment is only semi-decidable.

Distinctions

UnifierMost general unifier
Isany substitution making two sentences identicalthe one committing to the fewest variables
Uniquenoyes, up to renaming variables
Why the MGUcommitting early throws away answers
Generalised modus ponensPropositionalising
Handles variables byunification, onceinstantiating the rule for every object
Works on an infinite domainyesno
Number of sentencesthe rule, onceone per object
Standardising apartThe occur check
Preventsa shared variable name defeating a legitimate matcha variable unified with a term containing it
Donebefore each unification attemptinside unification
Omitted bynobodyProlog, by default, for speed

What it does not mean

Unification is not pattern matching on strings. It works on the structure of terms and produces a substitution, and it can fail for three distinct reasons.

The MGU is not "the first unifier found". It is the least committed one, and returning a more specific unifier loses answers.

Failure to unify does not mean the sentences are inconsistent. Knows(Anil, x) and Knows(x, Bhavna) fail only because of a shared variable name, and standardising apart makes them unify.

munotes.in172

Inference in First-Order Logic: Unification and Chaining

Forward chaining is not the opposite of backward chaining in correctness. Both are sound and both are complete for definite clauses. They differ in what work they do.

Backward chaining failing does not mean the query is false. It means it does not follow. Concluding otherwise is the closed-world assumption, which is an extra assumption and not a consequence of the logic.

Dropping the occur check is not free. It makes unification faster and allows a program to build an infinite term and hang.

Quick revision

  • Substitution: a map from variables to terms, {x/Meera}. Unification finds one making two atomic sentences identical; the most general unifier commits to the fewest variables and is unique up to renaming.
  • Unification fails for three reasons: different predicate or function symbols; a shared variable name, repaired by standardising apart; and the occur check, a variable against a term containing it.
  • Generalised modus ponens: if a substitution makes a rule's premises match known facts, derive the conclusion with that substitution. One rule replaces infinitely many propositional instances, and works on an infinite domain where propositionalising cannot.
  • Forward chaining is data driven and derives everything, including Eligible(Vikram) when the question was about Asha. Backward chaining is goal driven and never mentions Vikram.
  • Forward chaining wastes work on irrelevance, fixed by magic sets. Backward chaining repeats subgoals, fixed by memoisation, and needs a loop check on recursive rules.
  • Failure of backward chaining means unknown, not false.
  • First-order resolution is the propositional rule plus unification, after quantifiers are removed: universals dropped, existentials by Skolemisation. It can run forever on a non-entailed query.

Test yourself

1. Define a substitution, a unifier and the most general unifier. A substitution maps variables to terms. A unifier of two sentences is a substitution that makes them identical. The most general unifier is the unifier that constrains the fewest variables, and it is unique up to the renaming of variables.

2. Give three reasons two atomic sentences may fail to unify. Their predicate or function symbols differ, and no substitution changes a symbol. The same variable name occurs in both sentences and would have to take two values, which is repaired by standardising apart. Or the occur check fails, because a variable would have to be bound to a term containing itself.

3. What is standardising apart and why is it necessary? Renaming the variables of one sentence before attempting to unify, so that a shared variable name does not defeat a legitimate match. Knows(Anil, x) and Knows(x, Bhavna) do not unify as written, and do unify once the second is renamed.

4. State generalised modus ponens and say what it replaces. Given a rule whose premises unify with known facts under a substitution, derive the rule's conclusion with that substitution applied. It replaces propositionalising the rule, that is instantiating it once for every object in the domain, which is impossible on an infinite domain.

munotes.in173

Inference in First-Order Logic: Unification and Chaining

5. In this chapter's run, what did forward chaining derive that backward chaining never touched, and why? Eligible(Vikram). Forward chaining derives every consequence of the facts, whether or not it bears on any question. Backward chaining asking whether Asha passed only ever asks about Asha.

6. Backward chaining reported "no" for Passed(Vikram). What exactly does that establish? That Passed(Vikram) does not follow from the knowledge base, because no fact asserts it and no applicable rule succeeds. It does not establish that Vikram failed; that would require the closed-world assumption, which is an extra assumption beyond the logic.

7. What must be done to first-order sentences before resolution can be applied, and what is the extra step called? They must be put in clause form, which requires removing the quantifiers. Universal quantifiers are simply dropped, since variables in a clause are read as universally quantified. Existential quantifiers are removed by Skolemisation, replacing the existentially quantified variable with a new function of the enclosing universally quantified variables.

Contents This chapter on its own page

munotes.in174

Chapter Thirty-Three

Rule-Based Systems and Expert Systems

Syllabus topic Module 1, "Rule-based systems"

In one line

A rule-based system keeps its knowledge as a list of IF-THEN rules, separate from the program that applies them, so the knowledge can be read, changed and explained by somebody who cannot program.

In the wording a student can write in an examination: a rule-based system, or production system, has three parts. The rule base, a set of production rules of the form IF conditions THEN actions, holding the domain knowledge. The working memory, or fact base, holding what is currently known about the case. And the inference engine, which repeatedly executes a match-resolve-act cycle: match the rules against working memory, resolve which of the matching rules to fire, and act by asserting its conclusion. An expert system is a rule-based system whose rule base encodes human expertise in a narrow domain.

The architecture

PartWhat it holdsWho writes it
Rule basethe domain knowledge, as IF-THEN rulesa domain expert, with a knowledge engineer
Working memorythe facts of the case in handthe user, and the engine's own conclusions
Inference enginenothing about the domaina programmer, once
Explanation facilitythe trail of rules firedgenerated
Knowledge acquisitionthe means of adding rules
User interfacethe questions and the answers

The separation of the rule base from the inference engine is the whole architectural idea, and it is what a paper is asking about. The engine is written once and knows nothing about medicine, banking or crop disease. Change the domain by replacing the rules; the engine is untouched. That is The Knowledge-Based Agent's declarative principle made into a product.

The match-resolve-act cycle

Three steps, repeated until no rule can fire. This is forward chaining with a scheduler in front of it.

  1. Match. Find every rule whose conditions are satisfied by working memory. The set of them is the conflict set or agenda.
  2. Resolve. Choose one. The rule for choosing is the conflict-resolution strategy.
  3. Act. Fire it: assert its conclusion into working memory, and record why.

Step 2 exists because more than one rule is usually ready, and the order changes what happens: a rule that fires may make another rule's conditions true, or make them false. A production system without a stated conflict-resolution strategy is not fully specified.

The standard strategies, and any real system uses several in order:

StrategyChooses
Priority, or saliencethe rule the author marked most important
Specificitythe rule with the most conditions, being the most specific match
Recencythe rule matching the most recently added fact
Refractorinessnever the same rule on the same facts twice, which stops infinite firing
Orderthe first rule in the file, as a last resort
munotes.in175

Rule-Based Systems and Expert Systems

It running, with the explanation

# A rule-based expert system with a real inference ENGINE: a match-resolve-act
# cycle, a conflict-resolution strategy, and an explanation trail.
RULES = [
    # (name, priority, premises, conclusion)
    ("R1", 10, ["fever", "cough", "body ache"], "influenza suspected"),
    ("R2", 10, ["fever", "rash"],               "viral exanthem suspected"),
    ("R3", 20, ["influenza suspected", "breathless"], "refer to hospital"),
    ("R4",  5, ["fever"],                       "advise fluids and rest"),
    ("R5", 15, ["fever", "fever above 5 days"], "order a blood test"),
]

def engine(working_memory, trace=True):
    """Match, resolve, act, until no rule fires. Highest priority wins."""
    memory = list(working_memory)
    fired = []
    why = {}
    cycle = 0
    while True:
        cycle += 1
        # MATCH: every rule whose premises are all satisfied and whose
        # conclusion is not yet known
        agenda = [r for r in RULES
                  if r[0] not in fired and all(p in memory for p in r[2])
                  and r[3] not in memory]
        if not agenda:
            break
        # RESOLVE: the conflict-resolution strategy. Highest priority, then
        # most premises, then the order the rules were written.
        agenda.sort(key=lambda r: (-r[1], -len(r[2]), RULES.index(r)))
        if trace:
            print("   cycle %d: %d rule(s) ready: %s"
                  % (cycle, len(agenda), ", ".join(r[0] for r in agenda)))
        name, prio, premises, conclusion = agenda[0]
        # ACT
        memory.append(conclusion)
        fired.append(name)
        why[conclusion] = (name, premises)
        if trace:
            print("        fire %s (priority %d) -> %s" % (name, prio, conclusion))
    return memory, fired, why

def explain(fact, why, facts, depth=0):
    pad = "      " + "   " * depth
    if fact in facts:
        print("%s%s: observed" % (pad, fact))
        return
    name, premises = why[fact]
    print("%s%s: by %s, because" % (pad, fact, name))
    for p in premises:
        explain(p, why, facts, depth + 1)

for case in (["fever", "cough", "body ache", "breathless"],
             ["fever", "rash"],
             ["cough"]):
    print("observed:", ", ".join(case) if case else "nothing")
    memory, fired, why = engine(case)
    print("   concluded:", ", ".join(f for f in memory if f not in case) or "nothing")
    deepest = [f for f in memory if f not in case]
    if deepest:
        print("   WHY %s?" % deepest[-1 if len(deepest) < 3 else 1])
        explain(deepest[-1 if len(deepest) < 3 else 1], why, case)
    print()
observed: fever, cough, body ache, breathless
   cycle 1: 2 rule(s) ready: R1, R4
        fire R1 (priority 10) -> influenza suspected
   cycle 2: 2 rule(s) ready: R3, R4
        fire R3 (priority 20) -> refer to hospital
   cycle 3: 1 rule(s) ready: R4
        fire R4 (priority 5) -> advise fluids and rest
   concluded: influenza suspected, refer to hospital, advise fluids and rest
   WHY refer to hospital?
      refer to hospital: by R3, because
         influenza suspected: by R1, because
            fever: observed
            cough: observed
            body ache: observed
         breathless: observed

observed: fever, rash
   cycle 1: 2 rule(s) ready: R2, R4
        fire R2 (priority 10) -> viral exanthem suspected
   cycle 2: 1 rule(s) ready: R4
        fire R4 (priority 5) -> advise fluids and rest
   concluded: viral exanthem suspected, advise fluids and rest
   WHY advise fluids and rest?
      advise fluids and rest: by R4, because
         fever: observed

observed: cough
   concluded: nothing
munotes.in176

Rule-Based Systems and Expert Systems

Three things in that output are the marks.

The conflict set is printed at every cycle, and it usually has more than one rule in it. At cycle 2, R3 and R4 are both ready. R3 fires because its priority is 20 and R4's is 5, and the order matters: R3's conclusion is the one a doctor needs first.

The cycle is genuinely a cycle, not a single pass. R3's conditions include influenza suspected, which did not exist at cycle 1. It became true because R1 fired. Rules make other rules applicable, which is why the engine loops rather than sweeping once.

The explanation is a tree of rules down to observations. refer to hospital came from R3, which needed influenza suspected, which came from R1, which needed three things the user actually reported. That is the trail a doctor can argue with, and no other technique in this book produces one. A neural network reaching the same conclusion can say nothing at all about why, which is the subject of Transparency and Explainability.

And the third case is the honest one. A cough alone fires nothing, and the system concludes nothing. It does not guess.

What the explanation facility actually provides

Papers ask for these two by name.

WHY, asked while the system is running: why are you asking me this question? The answer is the rule the engine is trying to satisfy, and the goal that rule serves.

HOW, asked of a conclusion: how did you reach that? The answer is the trail printed above, the rules fired and the observations at the leaves.

Both come free from recording the rule that asserted each fact. That is a three-line change to the engine, and it is the whole basis of the claim that an expert system is transparent.

Where expert systems worked

This is not a historical aside. A paper can ask for examples, and the honest ones are specific.

SystemDomainWhat it shows
DENDRALinterpreting mass spectra of moleculesthe first, and the one that established that narrow expertise could be encoded
MYCINdiagnosing bacterial infections of the bloodabout 450 rules, with certainty factors for uncertainty; reported to match specialists in its narrow domain
XCON, also called R1configuring VAX computer ordersthe commercial success, thousands of rules, saving a manufacturer real money
PROSPECTORmineral explorationreasoning with geological evidence

What they have in common is the condition under which the approach works: a narrow domain, a human expert who can state the rules, and a problem where the rules are reliable. Where those three hold, a rule-based system is still the right answer today, and business rule engines are a large industry.

munotes.in177

Rule-Based Systems and Expert Systems

Where they failed, and why

Four failures, and naming them is what turns this topic from a history lesson into an answer.

The knowledge acquisition bottleneck. Getting rules out of an expert is slow, and experts frequently cannot state what they know. A radiologist who reads a film in two seconds cannot list the rules used. This is the single reason machine learning displaced the approach: Module 2's methods learn the rules from examples instead of asking for them.

Brittleness. Outside its narrow domain a rule-based system has no fallback and no common sense. Given a case its rules do not cover it produces nothing, or worse, fires an inappropriate rule confidently. It has no notion of being outside its competence.

Maintenance. With a thousand rules, adding one can silently break another through the conflict set. XCON's rule base became notoriously expensive to maintain, and nobody could say what the whole thing did.

Uncertainty handled by bolt-on. Real expertise is probabilistic, and rules are not. MYCIN's certainty factors were an ad hoc numerical scheme that worked in practice and had no proper semantics. Module 1's fourth row, Bayesian Networks, is the principled replacement, and it arrived after the expert systems era for exactly that reason.

The efficiency problem, and the algorithm that solved it

Worth one paragraph because a paper may name it. Matching a thousand rules against a thousand facts on every cycle is prohibitively slow if done naively, since most rules have not changed status since the last cycle.

The Rete algorithm compiles the rule base into a network in which each condition test is shared between every rule that uses it, and it keeps the partial matches between cycles, updating only what the last fired rule changed. It trades memory for time, and it is what makes a production system with thousands of rules run at all. Every serious rule engine uses it or a descendant.

Distinctions

Rule baseWorking memory
Holdsgeneral knowledge, the rulesthe facts of this case
Changesrarely, when knowledge is addedconstantly, during a run
Written bythe domain expertthe user, and the engine
Rule-based systemExpert system
Isthe architecturea rule-based system encoding human expertise
Needs a human expertnoyes, by definition
Exampleany business rule engineMYCIN, XCON
Forward chaining engineBackward chaining engine
Driven byfacts arrivinga question asked
Suitsmonitoring, configurationdiagnosis
The cyclematch, resolve, actgoal, subgoal, ask the user
munotes.in178

Rule-Based Systems and Expert Systems

Explanation by rule trailA learned model's explanation
Availablealways, freeonly by extra machinery
Isthe actual reasonan approximation of the reason
Where in this bookhereTransparency and Explainability

What it does not mean

A rule-based system is not a program with a lot of if-statements. The rules are data, matched by a separate engine. If they are compiled into the control flow, the architecture's whole benefit is gone.

Conflict resolution is not an implementation detail. Two strategies can produce different conclusions from the same rules and facts, so the strategy is part of the system's meaning.

An expert system does not know it is out of its depth. That is brittleness, and it is why they were dangerous outside their domain.

Certainty factors are not probabilities. MYCIN's scheme was ad hoc and does not obey the probability axioms. Bayesian networks are the principled treatment.

Explanation is not a feature that was added. It falls out of recording which rule asserted each fact, and it is the architecture's main advantage over a learned model.

Rules are not obsolete. They remain right for a narrow domain with stateable, reliable rules, and business rule engines are widely used. What failed was the ambition of encoding general expertise by hand.

Quick revision

  • Three parts: rule base (IF-THEN production rules, the knowledge), working memory (the facts of this case), inference engine (domain independent). Plus an explanation facility, knowledge acquisition and a user interface.
  • The rule base is separate from the engine. Change the domain by changing the rules.
  • The engine runs a match-resolve-act cycle until no rule fires. The matching rules are the conflict set or agenda.
  • Conflict-resolution strategies: priority, specificity, recency, refractoriness, order. A system without one is not fully specified, and two strategies can give different answers.
  • The cycle loops because a fired rule can make another rule applicable: R3 needed influenza suspected, which R1 produced.
  • WHY answers why a question is being asked; HOW answers how a conclusion was reached, as a trail of rules down to observations. Both come from recording which rule asserted each fact.
  • Worked: DENDRAL, MYCIN (about 450 rules, certainty factors), XCON, PROSPECTOR. The condition: a narrow domain, a willing expert, reliable rules.
  • Failed on: the knowledge acquisition bottleneck, brittleness, maintenance, and uncertainty as a bolt-on. The first is why Module 2 exists; the last is why Bayesian networks do.
  • The Rete algorithm shares condition tests between rules and keeps partial matches between cycles, trading memory for time.

Test yourself

1. Name the three main components of a rule-based system and say what each holds. The rule base, holding the domain knowledge as IF-THEN production rules. The working memory, holding the facts of the case currently being reasoned about. And the inference engine, which applies the rules and contains no domain knowledge itself.

munotes.in179

Rule-Based Systems and Expert Systems

2. Describe the match-resolve-act cycle. Match: find every rule whose conditions are satisfied by working memory, forming the conflict set. Resolve: choose one of them by the conflict-resolution strategy. Act: fire it, asserting its conclusion into working memory. Repeat until no rule can fire.

3. Why is a conflict-resolution strategy necessary, and name four. Because more than one rule is usually ready and the order of firing changes the outcome, since a fired rule can make another rule's conditions true or false. Priority or salience, specificity, recency, refractoriness, and file order as a last resort.

4. In this chapter's run, why did rule R3 not fire at cycle 1? Because one of its conditions, influenza suspected, was not yet in working memory. It became true only when R1 fired at cycle 1, which is why the engine loops instead of sweeping the rules once.

5. What does the explanation facility provide, and where does it come from? WHY, explaining why the system is asking a question, in terms of the rule it is trying to satisfy; and HOW, explaining a conclusion as the trail of rules fired down to the user's own observations. Both follow from recording which rule asserted each fact.

6. Name two expert systems and the domain of each, and state the three conditions under which the approach works. MYCIN diagnosed bacterial blood infections with about 450 rules; XCON configured computer orders. The approach works when the domain is narrow, a human expert can state the rules, and the rules are reliable.

7. Give the four reasons expert systems failed, and say which two later parts of this syllabus answer them. The knowledge acquisition bottleneck, since experts often cannot state what they know; brittleness outside the domain, with no common sense and no awareness of incompetence; maintenance, since one new rule can break another through the conflict set; and uncertainty handled by ad hoc devices such as certainty factors. Machine learning in Module 2 answers the first by learning rules from examples, and Bayesian networks answer the last with a principled treatment of uncertainty.

Contents This chapter on its own page

munotes.in180

Chapter Thirty-Four

Planning and STRIPS

Syllabus topic Module 1, "STRIPS"

In one line

Planning is search in which a state is a set of facts and an action says which facts it needs, which it adds and which it deletes.

In the wording a student can write in an examination: in the STRIPS representation a state is a set of ground literals, understood as the complete description of the world, so anything not listed is false. An operator has three parts: a precondition, the literals that must hold for it to apply; an add list, the literals it makes true; and a delete list, the literals it makes false. A plan is a sequence of operators leading from the initial state to a state containing the goal, which is itself a set of literals.

What planning adds to search

Formulating a Problem for Search said that in ordinary search a state is opaque: the algorithm knows only that two states differ and that the goal test accepts some of them. In planning, the state has structure, and three things follow that make large problems tractable.

Ordinary searchPlanning
A state isan opaque objecta set of literals
An action isa name with a result functiona precondition, add list and delete list
The goal isa test, a black boxa set of literals, so partial goals are visible
The algorithm canonly generate and testsee which action achieves which goal literal

The third row is what pays. Because the goal is a set of literals, a planner can look at a goal literal it has not achieved, look at the add lists, and see which operators could possibly achieve it. A search algorithm with an opaque goal test cannot ask that question at all. That is why planning scales to problems with thousands of literals where blind search cannot.

The representation

A state is a set of literals, and it is read under the closed-world assumption: anything not in the set is false. So a state need not list what is not true, which is what keeps it small.

{ on A B, on table B, on table C, clear A, clear C }

That single state says, among other things, that B is not clear and that A is not on the table, without saying so, because those literals are absent. The assumption is what makes the representation compact and it is an assumption: a real world in which you simply do not know whether B is clear cannot be described this way.

An operator has four parts, three of which are sets of literals.

PartWhat it is
Name, with parametersstack A on B
Preconditionmust be a subset of the current state for the operator to apply
Add listliterals added to the state
Delete listliterals removed from the state
munotes.in181

Planning and STRIPS

And the result of applying it is exactly:

new state = (old state minus the delete list) union the add list

That one line is the whole semantics of an operator and is worth memorising. Note the order: delete first, then add. A literal in both lists survives.

The frame problem, which this representation solves

Worth stating because it is the reason the add and delete lists exist and a paper can ask for it.

Suppose you describe the effect of moving a block using ordinary logic. You must say what changes, and you must also say what does not: the other blocks stay where they are, the table is still a table, the colour of everything is unchanged. Writing all of that out for every action is called the frame problem, and doing it with explicit axioms is hopeless because the list of things that did not change is enormous.

STRIPS solves it by a convention rather than by an axiom: everything not mentioned in the add or delete list is assumed unchanged. That is called the STRIPS assumption, and it is what makes the representation usable. The cost is that an action with far-reaching or conditional effects cannot be expressed.

A complete worked plan

Blocks world. Three blocks. Start with A on B, and both B and C on the table. The goal is a tower: A on B on C.

This problem is chosen because the first step must UNDO part of the goal. on A B is already true at the start and is required at the end, and yet the plan has to take A off B first, because B cannot be stacked onto C while A is sitting on it. A planner that simply worked through the goal literals in order, protecting each one once achieved, would fail here.

# STRIPS: a state is a SET OF LITERALS, an operator has a precondition, an add
# list and a delete list, and a plan is found by forward search. Blocks world.
from collections import deque

def operators():
    """Every legal instance of the three operators, over blocks A, B, C."""
    blocks = ["A", "B", "C"]
    out = []
    for b in blocks:
        for t in blocks:
            if b == t:
                continue
            # move b from the table onto t
            out.append(("stack %s on %s" % (b, t),
                        {"clear " + b, "clear " + t, "on table " + b},
                        {"on %s %s" % (b, t)},
                        {"clear " + t, "on table " + b}))
            # move b from t onto the table
            out.append(("unstack %s from %s" % (b, t),
                        {"clear " + b, "on %s %s" % (b, t)},
                        {"on table " + b, "clear " + t},
                        {"on %s %s" % (b, t)}))
        for t in blocks:
            for u in blocks:
                if len({b, t, u}) != 3:
                    continue
                # move b from t onto u
                out.append(("move %s from %s to %s" % (b, t, u),
                            {"clear " + b, "clear " + u, "on %s %s" % (b, t)},
                            {"on %s %s" % (b, u), "clear " + t},
                            {"on %s %s" % (b, t), "clear " + u}))
    return out

OPS = operators()

def applicable(state, op):
    return op[1] <= state

def apply_op(state, op):
    return (state - op[3]) | op[2]

START = frozenset({"on A B", "on table B", "on table C", "clear A", "clear C"})
GOAL = frozenset({"on B C", "on A B"})

def plan(start, goal):
    """Breadth first over states: the shortest plan, in operators."""
    seen = {start}
    queue = deque([(start, [])])
    while queue:
        state, steps = queue.popleft()
        if goal <= state:
            return steps, state
        for op in OPS:
            if not applicable(state, op):
                continue
            nxt = apply_op(state, op)
            if nxt in seen:
                continue
            seen.add(nxt)
            queue.append((frozenset(nxt), steps + [op]))
    return None, None

def show(state):
    return ", ".join(sorted(state))

print("start:", show(START))
print("goal :", show(GOAL))
print()
steps, final = plan(START, GOAL)
state = START
for i, op in enumerate(steps, 1):
    print("%d. %s" % (i, op[0]))
    print("      precondition %s" % show(op[1]))
    print("      add          %s" % show(op[2]))
    print("      delete       %s" % show(op[3]))
    state = apply_op(state, op)
    print("      state now    %s" % show(state))
print()
print("goal reached:", GOAL <= state)
print("plan length:", len(steps), "operators")
munotes.in182

Planning and STRIPS

start: clear A, clear C, on A B, on table B, on table C
goal : on A B, on B C

1. unstack A from B
      precondition clear A, on A B
      add          clear B, on table A
      delete       on A B
      state now    clear A, clear B, clear C, on table A, on table B, on table C
2. stack B on C
      precondition clear B, clear C, on table B
      add          on B C
      delete       clear C, on table B
      state now    clear A, clear B, on B C, on table A, on table C
3. stack A on B
      precondition clear A, clear B, on table A
      add          on A B
      delete       clear B, on table A
      state now    clear A, on A B, on B C, on table C

goal reached: True
plan length: 3 operators

Read step 1. on A B was already true, and the plan's first act is to delete it. Then step 3 puts it back. A student asked "why is planning hard" can answer from this one example: achieving one part of a goal can require undoing another, so the order of the subgoals is itself part of the problem.

munotes.in183

Planning and STRIPS

The classic version of this trap is called the Sussman anomaly: start with C on A, and A and B on the table, and ask for A on B on C. Neither subgoal can be achieved first without undoing the other, and the early planners that worked through goals one at a time and protected what they had achieved could not solve it at all.

Progression and regression

Two directions, and MU's phrase Planning basics expects both to be named.

ProgressionRegression
Also calledforward state-space searchbackward, or goal-stack planning
Starts atthe initial statethe goal
Applies operatorsforwards, checking preconditionsbackwards: pick a goal literal, find an operator whose add list contains it, and make that operator's precondition the new goal
Branchingevery applicable operator, often thousandsonly operators relevant to a goal literal
The program above isprogression

Regression's advantage is relevance. In a world with a hundred blocks, thousands of operators apply at every state and almost none of them helps. Regression only ever considers operators that achieve something actually wanted. Its difficulty is that a regressed goal is a set of literals that may be inconsistent, or unachievable, and detecting that is not easy.

Partial-order planning, in one paragraph

Named because a paper may ask for it. A total-order plan is a sequence: step 1, then 2, then 3. A partial-order plan commits only to the orderings that matter: stack B on C before stacking A on B, and leave anything independent unordered. The benefit is that independent subproblems can be solved separately and combined, which is the least commitment principle: do not decide anything you do not yet have to. The program above produces a total order because breadth first search over states can produce nothing else.

How planning meets the rest of this book

Two links worth making explicit, because they are the kind of cross-module question Q.3 sets.

A planning problem is a search problem, so every algorithm in MU's second row applies to it. The program above uses breadth first search. Using A* needs a heuristic, and planning's structured state is what lets one be derived automatically: relax the problem by ignoring the delete lists, count how many goal literals remain, and you have an admissible heuristic obtained by exactly the relaxation method of Heuristics: Estimating What Is Left To Do. That is the whole idea of modern planning, and it is why planners got dramatically better in the 1990s.

A planner is a goal-based agent, in the sense of The Goal-Based Agent. It has a goal, a transition model, and it searches action sequences. What it adds is the structure that lets the search be guided.

munotes.in184

Planning and STRIPS

Distinctions

PreconditionAdd listDelete list
Must bea subset of the state
Effectnone, it is a testliterals become trueliterals become false
Appliedbeforeafter the delete listfirst
State in ordinary searchState in STRIPS
Isan opaque objecta set of literals, closed world
The goal isa testa set of literals
The planner can see which action helpsnoyes
ProgressionRegression
Fromthe startthe goal
Considersevery applicable operatoronly relevant ones
Riskenormous branchinginconsistent or unachievable regressed goals
Total orderPartial order
Commits toa full sequenceonly the orderings that matter
Principleleast commitment
Independent subplansmust be interleaved by handcombine naturally

What it does not mean

A state is not a partial description. Under the closed-world assumption it is complete: anything absent is false. A world in which something is genuinely unknown cannot be represented.

The delete list is not the negation of the add list. They are independent sets, and a literal may appear in both, in which case it survives, because the deletion happens first.

A precondition is not an effect. It is tested and changes nothing.

Planning is not a different problem from search. It is search over a structured state space, and the structure is what allows heuristics to be derived rather than invented.

Achieving the goal literals one at a time does not work. The worked plan deletes on A B, which is part of the goal, at its first step. The Sussman anomaly is the standard example where doing it one at a time fails entirely.

STRIPS does not handle conditional or far-reaching effects. The STRIPS assumption, that anything unmentioned is unchanged, is what buys the compactness and what limits the expressiveness.

Quick revision

  • STRIPS: a state is a set of ground literals under the closed-world assumption; anything absent is false. An operator has a precondition, an add list and a delete list.
  • new state = (old state minus delete list) union add list. Delete first, then add, so a literal in both survives.
  • The frame problem is having to state what does not change. STRIPS solves it by the STRIPS assumption: anything unmentioned is unchanged. That is a convention, not an axiom, and it limits expressiveness.
  • The worked plan: unstack A from B, stack B on C, stack A on B. Step 1 deletes a goal literal that step 3 restores, which is why planning is hard. The classic version is the Sussman anomaly.
  • Progression searches forward from the start; regression or goal-stack planning searches backward from the goal and considers only relevant operators.
  • Partial-order planning commits only to orderings that matter, following least commitment.
  • Planning's structured state lets a heuristic be derived: ignore the delete lists and count unachieved goal literals. That is relaxation, and it is why modern planners work.
munotes.in185

Planning and STRIPS

Test yourself

1. Describe the STRIPS representation of a state and an operator. A state is a set of ground literals, complete under the closed-world assumption so that anything not listed is false. An operator has a precondition, the literals that must be present for it to apply; an add list of literals it makes true; and a delete list of literals it makes false.

2. Give the rule for applying an operator, and say why the order of the two steps matters. The new state is the old state with the delete list removed and the add list added. The deletion happens first, so a literal appearing in both lists survives; doing it the other way round would remove it.

3. What is the frame problem and how does STRIPS deal with it? The frame problem is the need to state, for every action, everything that does not change as well as what does, which is impractical with explicit axioms. STRIPS adopts the convention that anything not mentioned in the add or delete list is unchanged, which is called the STRIPS assumption.

4. Give the three-step plan for building A on B on C from A on B with B and C on the table, and say what is instructive about it. Unstack A from B, stack B on C, stack A on B. It is instructive because the first step deletes on A B, which is part of the goal and was already true at the start: achieving one part of a goal can require undoing another, so the ordering of subgoals is itself part of the problem.

5. Distinguish progression from regression planning. Progression searches forward from the initial state, applying every operator whose precondition holds, which branches very widely. Regression searches backward from the goal: it takes an unachieved goal literal, finds an operator whose add list contains it, and makes that operator's precondition the new goal, so it only ever considers relevant operators.

6. What is a partial-order plan, and what principle does it follow? A plan that commits only to the orderings between steps that actually matter, leaving independent steps unordered. It follows the least commitment principle: do not decide anything you are not yet obliged to decide.

7. How does the STRIPS representation make it possible to derive a heuristic automatically? Because the goal is a set of literals and each operator declares what it adds, the problem can be relaxed by ignoring the delete lists, so nothing achieved is ever undone. The number of goal literals still unachieved in that relaxed problem is then an admissible estimate of the work remaining, obtained by exactly the relaxation method used for search heuristics.

Contents This chapter on its own page

munotes.in186

Chapter Thirty-Five

Fuzzy Logic and the Membership Function

Syllabus topic Module 1, "Fuzzy Logic"

In one line

A fuzzy set lets a thing belong to a category by degree, so "warm" can be 0.4 true rather than having to be simply yes or no.

In the wording a student can write in an examination: a fuzzy set A over a universe of discourse is characterised by a membership function which assigns to every element a grade of membership between 0 and 1, where 0 is complete non-membership and 1 complete membership. An ordinary set, called a crisp set, is the special case in which the membership function takes only the values 0 and 1. Fuzzy logic is the logic of such sets, with truth values in the whole interval from 0 to 1 rather than only at its ends.

Why a crisp set is sometimes the wrong tool

Consider the set of warm temperatures. To make it a crisp set you must pick a boundary, say 22 degrees. Then 21.9 degrees is not warm at all and 22.0 is completely warm, and a thermostat built on that set changes its behaviour abruptly across a tenth of a degree that no person can feel.

The difficulty is not that the boundary was badly chosen. There is no correct boundary, because the word does not have one. Words like warm, tall, heavy, fast, near and expensive are vague: their extension has no sharp edge, and forcing one on them misrepresents them.

Zadeh's proposal is to stop trying. Let membership be a number between 0 and 1, and let a temperature be warm to degree 0.4.

Note what this is not a response to. It is not about not knowing the temperature; the temperature is known exactly. It is about the word not having a sharp boundary. That distinction is the whole of the section on probability below.

The membership function

A fuzzy set IS its membership function; there is nothing else to it. Three shapes cover almost all practical use.

ShapeDefined byUsed for
Triangularthree points: where it starts, peaks and endsa value with one ideal point
Trapezoidalfour points: rise, plateau, falla range that is fully acceptable in the middle
Gaussian, or bella centre and a widtha smooth, unbounded tail

The shape is a modelling decision, and papers sometimes ask how it is chosen. In practice it is elicited from an expert, tuned against observed behaviour, or learned. There is no fact of the matter about the right shape for "warm", which is the honest position and should be stated rather than hidden.

Three fuzzy sets, computed

# Fuzzy sets: a MEMBERSHIP FUNCTION instead of in-or-out, and the three set
# operations it defines. All figures computed, none asserted.
def trapezoid(x, a, b, c, d):
    """0 below a, rising to 1 at b, 1 until c, falling to 0 at d."""
    if x <= a or x >= d:
        return 0.0
    if x < b:
        return (x - a) / (b - a)
    if x <= c:
        return 1.0
    return (d - x) / (d - c)

def cold(t):   return trapezoid(t, -99, -99, 15, 22)
def warm(t):   return trapezoid(t, 18, 23, 27, 32)
def hot(t):    return trapezoid(t, 28, 34, 99, 99)

print("temperature, degrees C, and its membership of three fuzzy sets")
print("  t | cold | warm | hot  | and it is BOTH warm and hot at")
print(" ---|------|------|------|-----")
for t in (10, 16, 20, 25, 30, 33, 36):
    both = "yes" if warm(t) > 0 and hot(t) > 0 else "no"
    print(" %2d | %.2f | %.2f | %.2f | %s" % (t, cold(t), warm(t), hot(t), both))
print()
print("a CRISP set would have to answer yes or no at every one of those rows.")
print("at 30 degrees it is warm to degree %.2f and hot to degree %.2f." % (warm(30), hot(30)))
print()
print("the three operations, at t = 30:")
w, h, c = warm(30), hot(30), cold(30)
print("  union          max(warm, hot)   = max(%.2f, %.2f) = %.2f" % (w, h, max(w, h)))
print("  intersection   min(warm, hot)   = min(%.2f, %.2f) = %.2f" % (w, h, min(w, h)))
print("  complement     1 - warm         = 1 - %.2f        = %.2f" % (w, 1 - w))
print()
print("and the law that fuzzy logic BREAKS, at t = 30:")
print("  warm AND not warm = min(%.2f, %.2f) = %.2f, which is not 0" % (w, 1 - w, min(w, 1 - w)))
print("  warm OR  not warm = max(%.2f, %.2f) = %.2f, which is not 1" % (w, 1 - w, max(w, 1 - w)))
print("  in ordinary logic those are 0 and 1 always. here they are not.")
munotes.in187

Fuzzy Logic and the Membership Function

temperature, degrees C, and its membership of three fuzzy sets
  t | cold | warm | hot  | and it is BOTH warm and hot at
 ---|------|------|------|-----
 10 | 1.00 | 0.00 | 0.00 | no
 16 | 0.86 | 0.00 | 0.00 | no
 20 | 0.29 | 0.40 | 0.00 | no
 25 | 0.00 | 1.00 | 0.00 | no
 30 | 0.00 | 0.40 | 0.33 | yes
 33 | 0.00 | 0.00 | 0.83 | no
 36 | 0.00 | 0.00 | 1.00 | no

a CRISP set would have to answer yes or no at every one of those rows.
at 30 degrees it is warm to degree 0.40 and hot to degree 0.33.

the three operations, at t = 30:
  union          max(warm, hot)   = max(0.40, 0.33) = 0.40
  intersection   min(warm, hot)   = min(0.40, 0.33) = 0.33
  complement     1 - warm         = 1 - 0.40        = 0.60

and the law that fuzzy logic BREAKS, at t = 30:
  warm AND not warm = min(0.40, 0.60) = 0.40, which is not 0
  warm OR  not warm = max(0.40, 0.60) = 0.60, which is not 1
  in ordinary logic those are 0 and 1 always. here they are not.
munotes.in188

Fuzzy Logic and the Membership Function

Three things to take from the table.

At 20 degrees the temperature is cold to 0.29 and warm to 0.40, both at once. That is not a contradiction and not an error: the sets overlap, and overlapping is the point. In a crisp partition every temperature belongs to exactly one set.

At 30 degrees it is both warm and hot. The sets are designed to overlap so that the controller's output changes smoothly as the temperature rises, which is what the next chapter is about.

Membership of the three sets does not add to 1. At 20 degrees they sum to 0.69, and at 30 to 0.73. That alone distinguishes a membership function from a probability distribution, and it is the quickest way to answer the question below.

The three operations

Zadeh's original definitions, and they are the ones papers ask for.

OperationDefinition
Union, A or Bthe maximum of the two memberships
Intersection, A and Bthe minimum of the two memberships
Complement, not A1 minus the membership

Why max and min rather than, say, addition or multiplication: they are the only pair that reduce to ordinary union and intersection when the memberships are only 0 and 1, and preserve the associative and distributive laws. Other choices exist and are used, called t-norms and t-conorms: product and probabilistic sum are the common alternative pair. Min and max are the standard and are what an examination expects.

What fuzzy logic gives up

This is the section a paper can test and most notes omit, and the arithmetic above is the answer.

In ordinary logic, P and not P is always false and P or not P is always true. Those are the law of non-contradiction and the law of the excluded middle. In fuzzy logic with min, max and one-minus, at a membership of 0.40:

warm and not warm = min(0.40, 0.60) = 0.40

warm or not warm = max(0.40, 0.60) = 0.60

Neither law holds. Something can be warm and not warm to degree 0.4 at once. That is a deliberate consequence of the definitions, not a flaw, and it is the price of modelling vagueness. The maximum of min(m, 1 - m) is 0.5, reached when the membership is exactly 0.5, which is the point of maximum vagueness.

munotes.in189

Fuzzy Logic and the Membership Function

Fuzzy against probability, which is the confusion to settle

Both use numbers between 0 and 1 and they mean different things. A paper asking for the difference expects all four rows of this table.

Fuzzy membershipProbability
Representsvagueness: the word has no sharp boundaryuncertainty: the fact is not known
The underlying fact isknown exactlyunknown
Must sum to 1 over the alternativesnoyes
Combined bymax, min, one minusthe probability axioms and Bayes theorem
Resolved bynothing, it does not resolveobserving, and then it becomes 0 or 1

The decisive example. "This 30 degree day is warm to degree 0.4" and "there is a 0.4 chance that tomorrow is warm" are completely different claims. The first is about today, whose temperature is known exactly, and it will never become 0 or 1. The second is about tomorrow, and when tomorrow arrives the number collapses to 0 or 1.

So they are not competitors and one does not replace the other. Reasoning Under Uncertainty is MU's next row and it is about the second kind of number entirely.

A few more terms

Each is one line and each can be asked.

  • Support: the set of elements with membership greater than 0. For warm above it is temperatures strictly between 18 and 32.
  • Core: the elements with membership exactly 1. For warm, 23 to 27.
  • Crossover point: where membership is 0.5.
  • Alpha-cut: the crisp set of elements with membership at least alpha. It is how a fuzzy set is turned back into an ordinary one when a yes-or-no answer is finally needed.
  • Height: the largest membership any element has. A normal fuzzy set has height 1.
  • Linguistic variable: a variable whose values are words, temperature taking cold, warm, hot. The words are called linguistic terms and each is a fuzzy set.
  • Hedge: a modifier applied to a term. very warm is conventionally the membership squared, which pushes middling values down; somewhat warm is the square root, which pushes them up.

Distinctions

Crisp setFuzzy set
Membership0 or 1anything in the interval
Boundarysharpgraded
An element can be in two disjoint categoriesnoyes, to different degrees
Is a special case of the otheryes, of the fuzzy set
Law of excluded middleIn fuzzy logic
P or not Palways truemax(m, 1 - m), at least 0.5, not always 1
P and not Palways falsemin(m, 1 - m), up to 0.5, not always 0
SupportCoreAlpha-cut
Membershipgreater than 0exactly 1at least alpha
Is acrisp setcrisp setcrisp set
munotes.in190

Fuzzy Logic and the Membership Function

What it does not mean

Fuzzy does not mean imprecise or approximate. The memberships are exact numbers and the arithmetic is exact. What is graded is the category, not the calculation.

A membership function is not a probability distribution. It need not sum to 1, it is about vagueness rather than uncertainty, and it does not collapse to 0 or 1 when something is observed.

A fuzzy set is not a set with uncertain contents. It is a set with graded contents, and the grades are known exactly.

Overlapping sets are not a modelling error. They are how smooth behaviour is obtained, and the next chapter depends on them.

Min and max are not the only possible operations, but they are the standard, and they are the only common pair that reduces correctly to ordinary set operations at the ends.

Losing the excluded middle is not a defect to be repaired. It is the consequence of allowing degrees, and the arithmetic above is what that costs.

Quick revision

  • A fuzzy set is its membership function, giving every element a grade in the interval from 0 to 1. A crisp set is the case where only 0 and 1 occur.
  • It models vagueness, the absence of a sharp boundary to a word, not ignorance of a fact.
  • Shapes: triangular, trapezoidal, Gaussian. The shape is a modelling decision, elicited, tuned or learned.
  • Operations: union is max, intersection is min, complement is one minus.
  • Overlap is deliberate: at 20 degrees the reading is cold 0.29 and warm 0.40; at 30 degrees warm 0.40 and hot 0.33.
  • Memberships do not sum to 1: 0.69 at 20 degrees, 0.73 at 30. That alone separates them from probabilities.
  • Neither the excluded middle nor non-contradiction holds: at 0.40, warm and not warm is 0.40 and warm or not warm is 0.60. The worst case is 0.5, at maximum vagueness.
  • Fuzzy against probability: vagueness against uncertainty; the fact known against unknown; no sum rule against a sum rule; max and min against Bayes; never resolves against resolving on observation.
  • Terms: support, core, crossover point, alpha-cut, height, normal, linguistic variable and its terms, hedges (very squares, somewhat takes the square root).

Test yourself

1. Define a fuzzy set and a crisp set. A fuzzy set is characterised by a membership function assigning every element of the universe a grade of membership in the interval from 0 to 1. A crisp, that is ordinary, set is the special case in which the membership function takes only the values 0 and 1.

munotes.in191

Fuzzy Logic and the Membership Function

2. Why is a crisp set the wrong tool for the category "warm"? Because the word has no sharp boundary. Any threshold makes a tenth of a degree the difference between not warm at all and completely warm, and there is no correct threshold to be found, since the vagueness is in the word rather than in the measurement.

3. Give the three fuzzy set operations. Union is the maximum of the two memberships, intersection is the minimum, and complement is one minus the membership.

4. At 30 degrees a reading is warm to 0.40 and hot to 0.33. Is that a contradiction? No. The two fuzzy sets overlap by design, so an element may belong to both to different degrees. Overlap is what makes a fuzzy controller's output change smoothly rather than jumping at a threshold.

5. Show that fuzzy logic does not satisfy the law of the excluded middle. With a membership of 0.40, warm or not warm is the maximum of 0.40 and 0.60, which is 0.60 and not 1. Similarly warm and not warm is the minimum, 0.40, and not 0. The worst case is a membership of 0.5, where both come to 0.5.

6. Distinguish a fuzzy membership from a probability, giving two clear differences. A membership grades a vague category when the underlying fact is known exactly, and memberships over the alternatives need not sum to 1. A probability quantifies uncertainty about an unknown fact, must sum to 1 over the alternatives, is combined by the probability axioms, and collapses to 0 or 1 once the fact is observed.

7. Define support, core and alpha-cut. The support is the crisp set of elements whose membership is greater than 0. The core is the crisp set whose membership is exactly 1. An alpha-cut is the crisp set of elements whose membership is at least alpha, and it is how a fuzzy set is reduced to an ordinary one when a definite answer is required.

Contents This chapter on its own page

munotes.in192

Chapter Thirty-Six

Fuzzification, the Rule Base and Defuzzification

Syllabus topic Module 1, "Fuzzification"

In one line

A fuzzy controller takes a real measurement in and gives a real number out, and in between it turns the measurement into degrees of membership, fires its rules, combines their outputs and squeezes the result back into one number.

In the wording a student can write in an examination: a fuzzy inference system operates in four stages. Fuzzification converts each crisp input into grades of membership of its linguistic terms. Rule evaluation computes the firing strength of each rule, usually as the minimum of its antecedent memberships, and clips that rule's output set at that strength. Aggregation combines all the clipped output sets, usually by taking the maximum at each point. Defuzzification converts the aggregated fuzzy set back into a single crisp value, usually by the centroid. The whole scheme is the Mamdani method.

The four stages

StageInOutUsually done by
Fuzzificationa crisp measurementa membership grade per termevaluating each membership function
Rule evaluationthe gradesa clipped output set per rulemin over the antecedents
Aggregationthe clipped setsone fuzzy setmax at each output value
Defuzzificationthat fuzzy setone crisp numberthe centroid

Note the shape of the whole thing: crisp in, crisp out. The fuzziness is entirely internal. A fuzzy controller attached to a fan is handed a temperature in degrees and must produce a fan speed in per cent; nothing outside it knows about membership functions.

The rules

A fuzzy rule looks like a production rule and behaves differently in one crucial respect.

IF temperature is warm AND humidity is high THEN fan speed is fast

Every rule fires, on every input, to some degree. A crisp rule either applies or does not; a fuzzy rule has a firing strength between 0 and 1, and a rule of strength 0 simply contributes nothing. There is therefore no conflict resolution in a fuzzy system: Rule-Based Systems and Expert Systems needed a strategy to choose one rule from the conflict set, and a fuzzy system needs none, because it uses them all in proportion.

That is why the output is smooth. As the temperature rises, one rule's strength falls while another's rises, and the crisp output slides between them rather than jumping.

The chain, run on one measurement

Temperature 30 degrees, humidity 80 per cent. Four rules, three output sets for the fan.

# The full Mamdani chain, on one real measurement: fuzzify, fire the rules,
# aggregate, defuzzify by centroid, and a crisp number comes out.
def tri(x, a, b, c):
    if x <= a or x >= c:
        return 0.0
    return (x - a) / (b - a) if x < b else (c - x) / (c - b)

# INPUT 1: room temperature, degrees C
def t_cold(t):  return tri(t, -10, 10, 22)
def t_warm(t):  return tri(t, 18, 25, 32)
def t_hot(t):   return tri(t, 28, 40, 55)
# INPUT 2: humidity, per cent
def h_low(h):   return tri(h, -10, 20, 50)
def h_high(h):  return tri(h, 40, 75, 110)
# OUTPUT: fan speed, per cent, as three fuzzy sets over 0 to 100
def f_slow(v):  return tri(v, -20, 10, 40)
def f_med(v):   return tri(v, 25, 50, 75)
def f_fast(v):  return tri(v, 60, 90, 120)

RULES = [
    ("if cold then slow",             lambda t, h: t_cold(t),                 f_slow),
    ("if warm and low then medium",   lambda t, h: min(t_warm(t), h_low(h)),  f_med),
    ("if warm and high then fast",    lambda t, h: min(t_warm(t), h_high(h)), f_fast),
    ("if hot then fast",              lambda t, h: t_hot(t),                  f_fast),
]

def mamdani(t, h, verbose=True):
    if verbose:
        print("measurement: temperature %.1f C, humidity %.0f%%" % (t, h))
        print()
        print("STEP 1 fuzzify the inputs")
        print("   cold %.3f   warm %.3f   hot %.3f" % (t_cold(t), t_warm(t), t_hot(t)))
        print("   low  %.3f   high %.3f" % (h_low(h), h_high(h)))
        print()
        print("STEP 2 fire every rule: its strength is the min of its conditions")
    fired = []
    for name, strength_of, out_set in RULES:
        w = strength_of(t, h)
        fired.append((w, out_set))
        if verbose:
            print("   %-32s strength %.3f" % (name, w))
    if verbose:
        print()
        print("STEP 3 clip each rule's output set at its strength, and take the")
        print("       maximum over rules at every output value (aggregation)")
    # STEP 4: defuzzify by the centroid of the aggregated set, sampled at 1% steps
    num = den = 0.0
    for i in range(0, 1001):
        v = i / 10.0
        mu = max(min(w, out(v)) for w, out in fired)
        num += mu * v
        den += mu
    crisp = num / den if den else 0.0
    if verbose:
        print()
        print("STEP 4 defuzzify: the centroid of the aggregated set")
        print("   fan speed = %.2f%%" % crisp)
    return crisp

mamdani(30.0, 80.0)
print()
print("the same controller over a range of inputs, to show it is SMOOTH:")
print("  temp | humidity | fan speed")
for t, h in ((15, 50), (20, 30), (24, 30), (24, 80), (30, 80), (36, 80), (45, 50)):
    print("  %4.0f | %8.0f | %8.2f%%" % (t, h, mamdani(float(t), float(h), verbose=False)))
munotes.in193

Fuzzification, the Rule Base and Defuzzification

measurement: temperature 30.0 C, humidity 80%

STEP 1 fuzzify the inputs
   cold 0.000   warm 0.286   hot 0.167
   low  0.000   high 0.857

STEP 2 fire every rule: its strength is the min of its conditions
   if cold then slow                strength 0.000
   if warm and low then medium      strength 0.000
   if warm and high then fast       strength 0.286
   if hot then fast                 strength 0.167

STEP 3 clip each rule's output set at its strength, and take the
       maximum over rules at every output value (aggregation)

STEP 4 defuzzify: the centroid of the aggregated set
   fan speed = 82.08%

the same controller over a range of inputs, to show it is SMOOTH:
  temp | humidity | fan speed
    15 |       50 |    16.01%
    20 |       30 |    40.17%
    24 |       30 |    50.00%
    24 |       80 |    85.13%
    30 |       80 |    82.08%
    36 |       80 |    84.47%
    45 |       50 |    84.47%
munotes.in194

Fuzzification, the Rule Base and Defuzzification

Follow the four steps on the single measurement.

Step 1, fuzzification. 30 degrees is warm to 0.286 and hot to 0.167 and not cold at all. 80 per cent humidity is high to 0.857 and not low. Note that the measurement is exact: the controller is not uncertain about the temperature. It is converting an exact number into degrees of membership of vague categories, which is what Fuzzy Logic and the Membership Function said fuzziness is.

Step 2, rule evaluation. Two rules have strength 0 and contribute nothing. if warm and high then fast fires at min(0.286, 0.857) which is 0.286, the weaker of its two conditions. The minimum is the right combinator for and: a rule is no stronger than its weakest condition.

Step 3, aggregation. The fast output set is clipped at 0.286 by one rule and at 0.167 by another, and the maximum at each point is taken, so the stronger clipping wins. The result is one fuzzy set over fan speeds.

Step 4, defuzzification. The centroid of that set is 82.08 per cent, and that is the number sent to the fan.

Why smoothness is the point

Read the second table, which is the case for the whole technique.

At 24 degrees and 30 per cent humidity the fan runs at 50.00 per cent. Raise the humidity to 80 per cent and it goes to 85.13. Raise the temperature to 30 and it settles to 82.08, and at 36 and 45 degrees it reaches 84.47. Every one of those is a different number, and the changes are gradual.

A crisp controller with a threshold at 25 degrees would give 50 per cent at 24.9 and 100 per cent at 25.1, and a real fan would then hunt: the room cools slightly, the fan drops to 50, the room warms, the fan jumps to 100, forever. The oscillation is the actual engineering problem fuzzy control solves, and it is why fuzzy controllers went into washing machines, air conditioners and camera autofocus.

And note the honest row. From 36 to 45 degrees the output does not change at all, because both are fully hot and no rule distinguishes them. A fuzzy controller is only as discriminating as its rules, and this one saturates.

munotes.in195

Fuzzification, the Rule Base and Defuzzification

Defuzzification: five methods

A paper can ask for two or three of these by name.

MethodTakesNote
Centroid, or centre of areathe centre of gravity of the aggregated setthe standard; smooth, and the most expensive
Bisectorthe value splitting the area in halfclose to the centroid, differently biased
Mean of maximumthe average of the values with the highest membershipcheap; ignores the shape
Smallest of maximumthe least such valuebiased low
Largest of maximumthe greatestbiased high

The centroid is the default because it takes account of every rule that fired, including weak ones, so the output moves continuously. The maximum-based methods look only at the peak and can jump when the peak moves from one rule's set to another's.

The centroid has one real defect worth stating: it cannot reach the extremes. Even with every rule demanding maximum speed, the centroid of the fast set is below 100, which is why the table saturates at 84.47 rather than at 100. Where the full range is needed the output sets are widened deliberately, or a different method is used.

Mamdani and Sugeno

Two named methods, and the difference is one line, which is exactly what a paper wants.

Mamdani, above: a rule's consequent is a fuzzy set, and the outputs are aggregated and defuzzified.

Sugeno, also called Takagi-Sugeno-Kang or TSK: a rule's consequent is a function of the inputs, often just a constant. There is no output fuzzy set and no aggregation to defuzzify; the answer is the weighted average of the rules' outputs, weighted by their firing strengths.

MamdaniSugeno
Consequenta fuzzy seta function of the inputs, often a constant
Defuzzificationcentroid of an aggregated setweighted average of rule outputs
Costhighermuch lower
Interpretable by a personmoreless
Suitsexpert-written rulescontrol, and rules fitted from data

Sugeno's weighted average is cheap and differentiable, which is why it is the form used when the rules are tuned by learning, and why a Sugeno system is the usual choice for a neuro-fuzzy controller.

Where fuzzy control is actually used

Concrete, because "it is used in industry" earns nothing.

Washing machines choose a cycle from load weight and water turbidity. Air conditioners and heat pumps set compressor speed from temperature and its rate of change. Camera autofocus and image stabilisation. Automatic transmissions choose a gear. Lift scheduling. Cement kiln and blast furnace control, which was among the first serious applications because the process is too complex to model with equations and an operator's rules of thumb were available.

The common thread, and this is the examinable generalisation: fuzzy control suits a system that is hard to model with equations but for which a human operator's rules are available, and where smooth behaviour matters. Where an accurate mathematical model exists, classical control theory is better and should be used.

munotes.in196

Fuzzification, the Rule Base and Defuzzification

Distinctions

FuzzificationDefuzzification
Directioncrisp to fuzzyfuzzy to crisp
Wherethe first stagethe last
Done byevaluating membership functionsusually the centroid
A crisp ruleA fuzzy rule
Firesor does notalways, to some degree
Needs conflict resolutionyesno, all rules contribute in proportion
Outputa jump at the thresholda smooth slide
min for andmax for aggregation
Applied toa rule's own conditionsacross different rules
Meaningno stronger than the weakest conditionthe strongest recommendation at each output value

What it does not mean

Fuzzification is not the whole method. It is the first of four stages, and a controller that stopped there would have produced membership grades and no output.

A fuzzy controller's output is not fuzzy. It is a single crisp number. Crisp in, crisp out.

A rule with strength 0 has not been rejected. It fired at strength 0 and contributed nothing. There is no selection step.

The minimum and the maximum are not interchangeable. Minimum combines a rule's own conditions; maximum combines across rules. Swapping them changes the system.

The centroid cannot reach the ends of the output range. The table above saturates at 84.47 per cent, not 100, and that is a property of the method rather than a bug.

Fuzzy control is not better than classical control. It is better where no good model exists and an operator's rules do. With an accurate model, classical control wins.

Quick revision

  • Four stages: fuzzification, rule evaluation, aggregation, defuzzification. Crisp in, crisp out; the fuzziness is internal.
  • A rule's firing strength is the minimum of its antecedent memberships. Every rule fires, so there is no conflict resolution.
  • Aggregation takes the maximum at each output value across rules.
  • On temperature 30 and humidity 80: warm 0.286, hot 0.167, high 0.857; the two firing rules have strengths 0.286 and 0.167; the centroid is 82.08 per cent.
  • Smoothness is the point. 50.00, 85.13, 82.08, 84.47 at different inputs, changing gradually. A threshold controller would oscillate around its boundary.
  • Defuzzification methods: centroid (the standard), bisector, mean of maximum, smallest of maximum, largest of maximum. The centroid uses every rule and cannot reach the extremes.
  • Mamdani: fuzzy set consequents, aggregate then defuzzify. Sugeno (TSK): function consequents, weighted average, cheaper, differentiable, and the form used when rules are learned.
  • Used where no good equation model exists but an operator's rules do, and where smooth behaviour matters: washing machines, air conditioners, autofocus, transmissions, cement kilns.
munotes.in197

Fuzzification, the Rule Base and Defuzzification

Test yourself

1. Name the four stages of a fuzzy inference system and say what each converts. Fuzzification turns each crisp input into grades of membership of its linguistic terms. Rule evaluation computes each rule's firing strength and clips its output set. Aggregation combines the clipped output sets into one fuzzy set. Defuzzification converts that set into a single crisp value.

2. How is a rule's firing strength computed, and why that operation? As the minimum of the memberships of its antecedent conditions, because a conjunction is no stronger than its weakest part, and minimum is the standard fuzzy intersection.

3. Why does a fuzzy rule system need no conflict resolution? Because every rule fires on every input, to a degree between 0 and 1, and all their contributions are aggregated in proportion. No rule has to be chosen over another, which is the difference from a crisp production system.

4. In this chapter's run, why did the rule "if warm and high then fast" fire at 0.286 rather than 0.857? Because the firing strength is the minimum of its conditions. The temperature was warm to only 0.286 while the humidity was high to 0.857, so the weaker condition sets the strength.

5. What is the centroid method, and what is its main defect? It defuzzifies by taking the centre of gravity of the aggregated fuzzy set, so every rule that fired influences the result and the output moves continuously. Its main defect is that it cannot reach the extremes of the output range, which is why the worked controller saturates at 84.47 per cent rather than 100.

6. Distinguish the Mamdani method from the Sugeno method. In Mamdani a rule's consequent is a fuzzy set, and the clipped sets are aggregated and then defuzzified, usually by the centroid. In Sugeno a rule's consequent is a function of the inputs, often a constant, and the output is the weighted average of the rules' values weighted by their firing strengths, which is cheaper and differentiable.

7. State the condition under which fuzzy control is the right choice, and when it is not. It suits a system that is hard to model with equations but for which a human operator's rules of thumb are available, and where smooth rather than abrupt behaviour is wanted. Where an accurate mathematical model of the system exists, classical control theory gives better results and should be used.

Contents This chapter on its own page

munotes.in198

Chapter Thirty-Seven

Why an Agent Needs Probability

Syllabus topic Module 1, "Probabilistic reasoning"

In one line

Probability is what an agent uses when it must act and does not know, and it works by putting a number on each thing that might be true rather than refusing to answer.

In the wording a student can write in an examination: probabilistic reasoning represents an agent's degree of belief in a proposition as a number between 0 and 1. A random variable takes one of a set of mutually exclusive, exhaustive values; an atomic event is a complete assignment to every variable; and a probability distribution assigns a number to each value of a variable, summing to 1. A belief held before any evidence is a prior; one held after evidence is a posterior or conditional probability.

Where the logic stopped

The Knowledge-Based Agent left the pit world in this state: square 1,2 provably safe, and squares 2,2, 3,1 and 3,2 unknown. The knowledge base was right to say unknown, and the agent still has to move.

Three things it could do, and two are unacceptable.

Refuse to move. Sound, and it never finds the gold.

Treat unknown as safe. Unsound, and about half the time fatal.

Prefer the square least likely to hold a pit. This needs a number on "likely", which is the whole of this row.

Probability does not replace the logic; it extends it. Everything the logic proved stays proved: 1,2 has probability 0 of a pit and 1,1 and 2,1 likewise. What probability adds is an answer where the logic had none.

Why logic cannot be patched to do this

A student's first instinct is to write a rule with exceptions, and it is worth seeing exactly why that fails, because it is the standard motivating argument.

Try for all s, BreezeFree(neighbour of s) implies Safe(s). That is true, and it only covers squares next to a visited breeze-free square.

Try for all s, NoEvidenceOfPit(s) implies Safe(s). That is false: a square with no evidence either way can hold a pit.

So weaken it: Safe(s) unless one of a list of exceptions. Now the list has to be complete, and it cannot be: there is always another way a square could turn out dangerous. This is the qualification problem, and it is the reason a purely logical agent in a real environment is either wrong or silent.

Probability sidesteps it. Instead of a rule that must be exceptionless, it reports a degree of belief, which can be revised when evidence arrives and never claims more than it has.

What the number means

This is worth being clear about because students often assume the wrong reading, and a paper can ask.

A probability in AI is a degree of belief, not a claim about the world's own randomness. The pit either is or is not in square 2,2; nothing about it is random. What is uncertain is the agent's knowledge. This reading is called the Bayesian or subjective view, and it is what makes probability usable for a deterministic world an agent cannot see.

munotes.in199

Why an Agent Needs Probability

The contrasting reading, the frequentist view, takes a probability to be a long-run relative frequency, which cannot be applied to a one-off unrepeatable fact like this particular square. Both views use the same arithmetic, so nothing in this book depends on the choice; but the Bayesian reading is what lets an agent have a belief about a unique situation.

And a probability is always relative to the evidence. There is no such thing as the probability of a pit in 2,2 full stop; there is its probability given what the agent has perceived. Write the evidence down, and when it changes the number changes.

The vocabulary, defined once

TermMeaning
Random variablea quantity with a set of possible values, written with a capital: Cavity, Weather
Domainthe set of values. Boolean, discrete or continuous
Atomic event, or possible worlda complete assignment to every variable. They are mutually exclusive and exhaustive
Probability distributionthe numbers for all values of one variable, and they sum to 1
Joint distributionthe numbers for every combination of several variables
Full joint distributionthe joint over all the variables. It determines everything
Prior, or unconditionala belief before evidence, P(Cavity)
Posterior, or conditionala belief after evidence, P(Cavity given Toothache)
Evidencewhat the agent has observed

A Boolean random variable is written Cavity for Cavity = true and not Cavity for false, which is the convention this book uses throughout.

The axioms

Three, and everything else is derived from them.

0 <= P(a) <= 1 for every proposition a

P(true) = 1 and P(false) = 0

P(a or b) = P(a) + P(b) - P(a and b)

The third is the inclusion-exclusion rule, and the subtraction is the part students forget: without it, anything counted in both a and b is counted twice. When a and b cannot both hold, that term is 0 and the rule simplifies to addition, which is the special case usually remembered.

Two immediate consequences, each worth knowing as a fact in its own right:

P(not a) = 1 - P(a)

sum over all values v of P(X = v) = 1

The second says the distribution of a single variable must add to exactly 1, and it is the quickest check on any answer: a set of probabilities for the values of one variable that does not sum to 1 is wrong.

munotes.in200

Why an Agent Needs Probability

Conditional probability and the product rule

The central definition of the row.

P(a | b) = P(a and b) / P(b) provided P(b) > 0

Read it in words: restrict attention to the worlds where b holds, and ask what fraction of them also have a. The division by P(b) is the restriction, and it is why the definition needs P(b) to be non-zero: you cannot condition on something that cannot happen.

Rearranged, it is the product rule, and this form is used far more often:

P(a and b) = P(a | b) * P(b)

= P(b | a) * P(a)

The two lines are equal because a and b is the same proposition as b and a. Setting them equal to each other and dividing is the entire derivation of Bayes theorem, and it is done in two lines in Bayes Theorem.

Why probability suits a rational agent

A paper may ask why a rational agent should use probability rather than some other calculus of belief, and there is a real answer.

An agent's beliefs can be used to place bets. If they violate the axioms above, a set of bets can be constructed that the agent will accept and that loses money in every possible outcome. This is a Dutch book, and the theorem that it can always be built against an agent whose beliefs break the axioms is due to de Finetti.

So the axioms are not a convention chosen for convenience: an agent whose degrees of belief violate them is demonstrably irrational, in the concrete sense that it can be made to lose whatever happens. And combined with The Utility-Based Agent, this closes the argument of the whole of Module 1: probability gives the degrees of belief, utility gives the values, and maximum expected utility gives the action.

The connection to the rest of the book

Three links worth stating explicitly, because two of them are cross-module.

To MU's third row. Logic's unknown becomes a number. A sentence entailed by the knowledge base has probability 1, its negation 0, and an unknown sentence something in between. Logic is the extreme case of probability.

To Module 2's fourth row. Markov Decision Processes uses exactly this machinery, with probabilities on the outcomes of actions instead of on the state of the world.

To Module 2's second row. The Naive Bayes Classifier is this row's Bayes theorem plus one independence assumption, and nothing else. That is the single sharpest cross-module link in the paper and the likeliest Q.3.

Distinctions

LogicProbability
A sentence istrue, false or unknownassigned a number in the interval
When evidence arrivesmore sentences are entailedevery number is revised
Can it act under ignorancenoyes
Handles exceptionsbadly, the qualification problemnaturally
The other is a special caseprobability with 0 and 1 only
munotes.in201

Why an Agent Needs Probability

PriorPosterior
Before or after evidencebeforeafter
WrittenP(a)P(a given e)
In the pit worldprobability of a pit anywheregiven the breezes felt
Bayesian, subjectiveFrequentist
A probability isa degree of beliefa long-run relative frequency
Applies to a unique eventyesno
Arithmeticthe samethe same

What it does not mean

A probability is not a claim that the world is random. The pit is where it is. What is uncertain is the agent's knowledge.

There is no probability without evidence. Every number is conditional on what the agent knows, and it changes when that changes.

Probability does not overturn what the logic proved. Proved safe means probability 0 of a pit, and probability is only needed where the logic said unknown.

A distribution does not merely sum to about 1. It sums to exactly 1, and any answer that does not is wrong.

The or rule is not simple addition. P(a or b) = P(a) + P(b) - P(a and b), and the subtraction is dropped only when the two cannot both hold.

You cannot condition on an impossibility. P(a | b) requires P(b) to be greater than zero.

Quick revision

  • Probabilistic reasoning puts a degree of belief between 0 and 1 on each proposition, so an agent can act where logic says unknown.
  • Logic cannot be patched with exceptions: the list can never be completed, which is the qualification problem.
  • Vocabulary: random variable, domain, atomic event (a complete assignment, mutually exclusive and exhaustive), distribution (sums to 1), joint and full joint distribution, prior, posterior, evidence.
  • Axioms: 0 <= P(a) <= 1; P(true) = 1, P(false) = 0; P(a or b) = P(a) + P(b) - P(a and b). Hence P(not a) = 1 - P(a) and a distribution sums to 1.
  • Conditional probability: P(a | b) = P(a and b) / P(b), needing P(b) > 0. Product rule: P(a and b) = P(a | b) P(b) = P(b | a) P(a). Setting those two equal gives Bayes theorem.
  • A probability is a degree of belief, always relative to evidence. The Bayesian reading applies to unique events; the frequentist reading does not.
  • A Dutch book can be built against any agent whose beliefs violate the axioms, so the axioms are a requirement of rationality and not a convention.
  • Links: logic is probability restricted to 0 and 1; Markov decision processes put these probabilities on action outcomes; naive Bayes is Bayes theorem plus one independence assumption.
munotes.in202

Why an Agent Needs Probability

Test yourself

1. Why does a knowledge-based agent need probability at all? Because a logical knowledge base returns unknown for anything not entailed, and an agent still has to act. Refusing to move is useless and treating unknown as safe is unsound, so the agent needs a graded belief in order to prefer the least dangerous option.

2. What is the qualification problem? That a useful logical rule about the real world needs a list of exceptions which can never be completed, so the rule is either false or so hedged as to be useless. Probability avoids it by reporting a degree of belief that can be revised rather than a rule that must hold without exception.

3. State the three axioms of probability and derive one consequence. Every probability lies between 0 and 1; a certainly true proposition has probability 1 and a certainly false one 0; and P(a or b) equals P(a) plus P(b) minus P(a and b). Taking b as not a in the third, P(a or not a) is 1 and P(a and not a) is 0, so P(not a) is 1 minus P(a).

4. Define conditional probability and explain the division in words. P(a | b) is P(a and b) divided by P(b), defined when P(b) is greater than 0. Dividing restricts attention to the worlds in which b holds and asks what fraction of those also have a.

5. Give the product rule in both of its forms and say what follows from setting them equal. P(a and b) equals P(a | b) times P(b), and also P(b | a) times P(a), since a and b is the same proposition as b and a. Setting the two expressions equal and dividing gives Bayes theorem.

6. Does a probability in AI mean the world is random? Explain with the pit world. No. The pit is in a definite square and nothing about it is random. What is uncertain is the agent's knowledge, so a probability is a degree of belief, which is the Bayesian reading and is what allows a belief about a unique, unrepeatable situation.

7. What is a Dutch book, and why does it matter here? A set of bets that an agent will accept and that loses money in every possible outcome. It can always be constructed against an agent whose degrees of belief violate the probability axioms, so obeying the axioms is a requirement of rationality rather than a matter of convention.

Contents This chapter on its own page

munotes.in203

Chapter Thirty-Eight

The Joint Distribution and Inference by Enumeration

Syllabus topic Module 1, "Probabilistic reasoning"

In one line

The full joint distribution is one number for every way the world could be, and every probability question can be answered by adding up the right rows of it.

In the wording a student can write in an examination: the full joint probability distribution assigns a probability to every atomic event, that is to every complete assignment of values to all the variables. It determines the answer to every probabilistic query about those variables. A query is answered by marginalisation, summing over the variables not mentioned; by conditioning, dividing by the probability of the evidence; and by normalisation, scaling a set of unnormalised numbers so that they sum to 1. The method is called inference by enumeration.

The table

Three Boolean variables about a dental patient: whether they have a Cavity, whether they have a Toothache, and whether the dentist's steel probe Catches in the tooth. Eight atomic events, eight numbers.

# The full joint distribution, and the three operations done ON it: marginalise,
# condition, normalise. Three binary variables, so eight rows that fit on a page.
from itertools import product

VARS = ["Cavity", "Toothache", "Catch"]
# P(Cavity, Toothache, Catch), the numbers used throughout this chapter
JOINT = {
    (True,  True,  True):  0.108, (True,  True,  False): 0.012,
    (True,  False, True):  0.072, (True,  False, False): 0.008,
    (False, True,  True):  0.016, (False, True,  False): 0.064,
    (False, False, True):  0.144, (False, False, False): 0.576,
}

def tf(b):
    return "T" if b else "F"

print("the FULL JOINT DISTRIBUTION over three binary variables")
print("  Cavity | Toothache | Catch | probability")
print("  -------|-----------|-------|------------")
for key in sorted(JOINT, reverse=True):
    print("     %s   |     %s     |   %s   |    %.3f"
          % (tf(key[0]), tf(key[1]), tf(key[2]), JOINT[key]))
print("  %38s %.3f" % ("total", sum(JOINT.values())))
print()
print("it has 2**3 = 8 rows, of which 7 are free: the last is fixed by the total.")
print()

def marginal(**fixed):
    """Sum over every variable not fixed: MARGINALISATION."""
    total = 0.0
    for key, p in JOINT.items():
        row = dict(zip(VARS, key))
        if all(row[v] == val for v, val in fixed.items()):
            total += p
    return total

print("MARGINALISATION: add up the rows that agree on what you care about")
print("  P(Cavity = T)              = %.3f" % marginal(Cavity=True))
print("  P(Toothache = T)           = %.3f" % marginal(Toothache=True))
print("  P(Cavity = T, Toothache=T) = %.3f" % marginal(Cavity=True, Toothache=True))
print()
print("CONDITIONING: divide by the probability of what you were told")
num = marginal(Cavity=True, Toothache=True)
den = marginal(Toothache=True)
print("  P(Cavity=T | Toothache=T) = %.3f / %.3f = %.3f" % (num, den, num / den))
print()
print("NORMALISATION: compute both numerators, then make them add to 1")
a = marginal(Cavity=True, Toothache=True)
b = marginal(Cavity=False, Toothache=True)
print("  unnormalised: %.3f and %.3f, which sum to %.3f" % (a, b, a + b))
print("  normalised:   %.3f and %.3f, which sum to %.1f"
      % (a / (a + b), b / (a + b), (a + b) / (a + b)))
print()
print("how big does the joint table get? 2**n rows for n binary variables:")
for n in (3, 10, 20, 30, 64):
    print("   %2d variables: %d rows" % (n, 2 ** n))
munotes.in204

The Joint Distribution and Inference by Enumeration

the FULL JOINT DISTRIBUTION over three binary variables
  Cavity | Toothache | Catch | probability
  -------|-----------|-------|------------
     T   |     T     |   T   |    0.108
     T   |     T     |   F   |    0.012
     T   |     F     |   T   |    0.072
     T   |     F     |   F   |    0.008
     F   |     T     |   T   |    0.016
     F   |     T     |   F   |    0.064
     F   |     F     |   T   |    0.144
     F   |     F     |   F   |    0.576
                                   total 1.000

it has 2**3 = 8 rows, of which 7 are free: the last is fixed by the total.

MARGINALISATION: add up the rows that agree on what you care about
  P(Cavity = T)              = 0.200
  P(Toothache = T)           = 0.200
  P(Cavity = T, Toothache=T) = 0.120

CONDITIONING: divide by the probability of what you were told
  P(Cavity=T | Toothache=T) = 0.120 / 0.200 = 0.600

NORMALISATION: compute both numerators, then make them add to 1
  unnormalised: 0.120 and 0.080, which sum to 0.200
  normalised:   0.600 and 0.400, which sum to 1.0

how big does the joint table get? 2**n rows for n binary variables:
    3 variables: 8 rows
   10 variables: 1024 rows
   20 variables: 1048576 rows
   30 variables: 1073741824 rows
   64 variables: 18446744073709551616 rows

The three operations

Marginalisation, also called summing out. To get the probability of something that does not mention every variable, add up every row that agrees with it.

P(Cavity) = sum over t, c of P(Cavity, Toothache = t, Catch = c)

= 0.108 + 0.012 + 0.072 + 0.008 = 0.200

The four rows added are the four with Cavity = T, and summing them removes Toothache and Catch from the answer. The variables summed over are said to be marginalised out, and the resulting smaller distribution is a marginal distribution.

Conditioning. To use evidence, marginalise both the numerator and the denominator and divide.

P(Cavity | Toothache) = P(Cavity, Toothache) / P(Toothache)

= 0.120 / 0.200 = 0.600

Read the two numbers. The prior probability of a cavity is 0.200; after a toothache it is 0.600. One symptom has tripled the belief, and that number came from nothing but eight numbers and two additions.

Normalisation. Often the denominator is a nuisance, and there is a way round it. Compute the unnormalised numbers for every value of the query variable and then scale them to sum to 1.

munotes.in205

The Joint Distribution and Inference by Enumeration

unnormalised: cavity 0.120, no cavity 0.080

they sum to 0.200, which IS P(Toothache)

normalised: 0.600 and 0.400

The normalising constant is the probability of the evidence, and computing it as a sum over the query variable's values means it never has to be computed separately. That is why it is conventionally written as a constant alpha and left until the end, and it is exactly what Inference in a Bayesian Network does.

The recipe

Every query, in one procedure, and this is the answer to "describe inference by enumeration".

  1. Fix the query variable and the evidence variables with their observed values.
  2. The remaining variables are the hidden variables.
  3. For each value of the query variable, sum the joint over every combination of the hidden variables, with the evidence held fixed.
  4. Normalise those sums so they add to 1.
P(Query | evidence) = alpha * sum over hidden of P(Query, evidence, hidden)

alpha is whatever makes the result sum to 1, and it never needs a separate calculation.

Why this cannot be the real method

Read the last block of the output. Three variables give 8 rows and it is a page of a book. Sixty-four give over 18 million million million.

Two separate problems, and both matter.

Space. The table has 2**n entries for n Boolean variables. At 30 variables that is a thousand million numbers; a medical domain with a few hundred symptoms is beyond any storage that will ever exist.

Where the numbers come from. Even if the table could be stored, somebody has to supply 2n - 1 independent numbers. This is the worse problem. Nobody can state the probability of "cavity and no toothache and probe catches and patient is left handed and it is Tuesday". The numbers are not merely numerous, they are unobtainable**.

So inference by enumeration over the full joint is the definition of what a correct answer is, and it is not an implementation. The next two chapters are how the table is never built: Conditional Independence shows what makes it compressible, and Bayesian Networks is the compression.

What the joint distribution does give you

Do not dismiss it. Two things make it worth teaching rather than merely mentioning.

It is complete. Any query at all about these variables is answerable from it, including queries with several query variables, several evidence variables, and disjunctions. No other representation in this row is complete in that sense without reconstructing it.

It is the standard against which every other method is checked. When Inference in a Bayesian Network computes an answer, its correctness means agreement with what enumeration over the implied joint would give. The book's own programs are checked that way.

munotes.in206

The Joint Distribution and Inference by Enumeration

Distinctions

MarginalisationConditioning
Doessums out variables you do not care aboutrestricts to worlds matching the evidence
Arithmeticadditiondivision
Resulta smaller distributiona distribution given the evidence
PriorPosterior, in the worked example
P(Cavity)0.200
P(Cavity given Toothache)0.600
The changeone symptom tripled the belief
The normalising constantComputing P(evidence) separately
Isthe sum over the query variable's valuesa second marginalisation
Needednever, as a separate stepavoidable
Writtenalpha

What it does not mean

The joint distribution is not a list of conditional probabilities. It is one number per complete assignment, and the conditionals are computed from it.

Marginalising is not averaging. It is summing. The rows are mutually exclusive, so their probabilities add.

Enumeration is not an algorithm anybody uses on a real problem. It is the definition of the right answer and the standard for checking one.

The table's difficulty is not only its size. The deeper problem is that nobody can supply the numbers, because an atomic event over many variables is too specific for anyone to have a belief about.

Normalising does not change the answer. It converts a set of proportions into probabilities, and the ratios are already correct before it.

Quick revision

  • The full joint distribution gives one probability per atomic event, and determines every query. For n Boolean variables it has 2n entries, of which 2n - 1 are free.
  • Marginalisation sums out the variables not mentioned. P(Cavity) = 0.108 + 0.012 + 0.072 + 0.008 = 0.200.
  • Conditioning divides. P(Cavity | Toothache) = 0.120 / 0.200 = 0.600: one symptom tripled the prior of 0.200.
  • Normalisation: compute the unnormalised number for each value of the query variable and scale to sum to 1. The scaling factor is P(evidence), so it never needs computing separately, and is written alpha.
  • The recipe: P(Query | evidence) = alpha * sum over hidden variables of P(Query, evidence, hidden).
  • It cannot be the real method. 30 variables give over a thousand million entries and 64 give over 18 million million million. And the worse problem is that nobody can supply that many numbers, because an atomic event is too specific to have a belief about.
  • It is still the definition of a correct answer and the standard against which a Bayesian network's inference is checked.

Test yourself

1. Define the full joint distribution and say what it determines. It assigns a probability to every atomic event, that is to every complete assignment of values to all the variables. It determines the answer to every probabilistic query over those variables.

2. Compute P(Cavity) from the eight numbers in this chapter and say what operation you used. Add the four rows with Cavity true: 0.108 plus 0.012 plus 0.072 plus 0.008, which is 0.200. The operation is marginalisation, summing out Toothache and Catch.

munotes.in207

The Joint Distribution and Inference by Enumeration

3. Compute P(Cavity | Toothache) and comment on the result. P(Cavity and Toothache) is 0.108 plus 0.012, which is 0.120, and P(Toothache) is 0.108 plus 0.012 plus 0.016 plus 0.064, which is 0.200. The quotient is 0.600. The prior was 0.200, so a single symptom has tripled the belief.

4. What is the normalising constant, and why does it never need separate computation? It is the probability of the evidence. Computing the unnormalised number for every value of the query variable and requiring them to sum to 1 fixes the constant automatically, because those unnormalised numbers already sum to the probability of the evidence.

5. Give the general recipe for inference by enumeration. Fix the query variable and the evidence with its observed values; the rest are hidden. For each value of the query variable, sum the joint distribution over every combination of hidden variable values with the evidence held fixed. Then normalise the results to sum to 1.

6. Give the two reasons the full joint distribution cannot be used in practice, and say which is worse. Its size, 2**n entries, which is over a thousand million at 30 Boolean variables. And the fact that somebody must supply that many independent numbers. The second is worse, because no expert can state a belief about an atomic event specifying the value of every variable at once.

7. If enumeration is unusable, why is it in the syllabus? Because it defines what a correct answer is, and it is the standard against which every practical method is checked. A Bayesian network's inference is correct precisely when it agrees with enumeration over the joint distribution the network implies.

Contents This chapter on its own page

munotes.in208

Chapter Thirty-Nine

Bayes Theorem

Syllabus topic Module 1, "Bayes theorem"

In one line

Bayes theorem turns the probability of a symptom given a disease, which is what a laboratory can measure, into the probability of the disease given the symptom, which is what a patient wants to know.

In the wording a student can write in an examination: Bayes theorem states that for propositions a and b with P(b) greater than 0,

P(a | b) = P(b | a) * P(a) / P(b)

Here P(a) is the prior, P(b | a) the likelihood, P(b) the evidence or normalising constant, and P(a | b) the posterior. The theorem is used when the likelihood is easy to obtain and the posterior is what is wanted, which is the usual situation in diagnosis.

The derivation, in two lines

It is worth being able to produce, because a paper can ask for it and it takes twenty seconds.

The product rule from Why an Agent Needs Probability gives the same quantity two ways:

P(a and b) = P(a | b) * P(b)

P(a and b) = P(b | a) * P(a)

So the right-hand sides are equal. Divide both by P(b):

P(a | b) P(b) = P(b | a) P(a)

P(a | b) = P(b | a) * P(a) / P(b)

That is the whole proof. Bayes theorem is not a new assumption; it is the product rule written twice and rearranged, which is why it cannot fail and why anyone who rejects it has rejected the axioms.

The four names, and why the theorem is worth having

TermNameIn a diagnosis
P(a)the priorhow common the disease is, the base rate
P(b given a)the likelihoodhow often the test is positive in people who have it
P(b)the evidence, or normalising constanthow often the test is positive at all
P(a given b)the posteriorthe answer: does this patient have it

The point of the theorem is the direction. A laboratory can measure P(positive | disease) by testing people known to have the disease. Nobody can directly measure P(disease | positive), because that depends on how common the disease is in the population being tested. Bayes theorem is the bridge, and the base rate is the toll.

The denominator is usually computed by cases rather than looked up:

P(b) = P(b | a) P(a) + P(b | not a) P(not a)

This is the law of total probability, and it says: the test comes out positive either because the patient has the disease and it was detected, or because they do not and it misfired. Adding the two is the only way to get P(b) from what a laboratory can measure.

munotes.in209

Bayes Theorem

Three worked problems

# Bayes theorem, worked on three problems. The BASE RATE TRAP is the third and it
# is the one every examiner sets.
def bayes(prior, sens, spec, name, positive="positive"):
    """prior = P(cause); sens = P(test+ | cause); spec = P(test- | not cause)."""
    fp = 1 - spec                          # false positive rate
    joint_yes = prior * sens               # has it AND tests positive
    joint_no = (1 - prior) * fp            # has it not AND tests positive
    evidence = joint_yes + joint_no
    post = joint_yes / evidence
    print(name)
    print("   %-34s = %.4f" % ("P(cause)", prior))
    print("   %-34s = %.3f   the sensitivity" % ("P(%s | cause)" % positive, sens))
    print("   %-34s = %.3f   1 - specificity" % ("P(%s | no cause)" % positive, fp))
    print("   %-34s = %.6f" % ("P(cause) * P(+ | cause)", joint_yes))
    print("   %-34s = %.6f" % ("P(no cause) * P(+ | no cause)", joint_no))
    print("   %-34s = %.6f" % ("P(%s), the total" % positive, evidence))
    print("   %-34s = %.6f   %.2f%%" % ("P(cause | %s)" % positive, post, 100 * post))
    print()
    return post

bayes(0.001, 0.99, 0.99,
      "A DISEASE TEST. 1 person in 1000 has it. The test is 99% accurate both ways.")
bayes(0.02, 0.95, 0.90,
      "A MACHINE FAULT. 2% of parts are faulty. The scanner catches 95% and\n"
      "wrongly flags 10% of good parts.", "flagged")
bayes(0.30, 0.98, 0.95,
      "A SPAM FILTER. 30% of mail is spam. The filter catches 98% and wrongly\n"
      "flags 5% of good mail.", "marked spam")

print("THE BASE RATE TRAP, in one sentence:")
print("  the first test is 99% accurate and a positive result still leaves the")
print("  patient more likely NOT to have the disease than to have it, because")
print("  the healthy are a thousand times more numerous. Out of 100,000 people:")
n = 100000
ill = int(n * 0.001)
well = n - ill
tp = round(ill * 0.99)
fp = round(well * 0.01)
print("    %6d have it,      of whom %4d test positive" % (ill, tp))
print("    %6d do not,       of whom %4d test positive" % (well, fp))
print("    so %d positives in all, and only %d of them are ill: %.2f%%"
      % (tp + fp, tp, 100.0 * tp / (tp + fp)))
A DISEASE TEST. 1 person in 1000 has it. The test is 99% accurate both ways.
   P(cause)                           = 0.0010
   P(positive | cause)                = 0.990   the sensitivity
   P(positive | no cause)             = 0.010   1 - specificity
   P(cause) * P(+ | cause)            = 0.000990
   P(no cause) * P(+ | no cause)      = 0.009990
   P(positive), the total             = 0.010980
   P(cause | positive)                = 0.090164   9.02%

A MACHINE FAULT. 2% of parts are faulty. The scanner catches 95% and
wrongly flags 10% of good parts.
   P(cause)                           = 0.0200
   P(flagged | cause)                 = 0.950   the sensitivity
   P(flagged | no cause)              = 0.100   1 - specificity
   P(cause) * P(+ | cause)            = 0.019000
   P(no cause) * P(+ | no cause)      = 0.098000
   P(flagged), the total              = 0.117000
   P(cause | flagged)                 = 0.162393   16.24%

A SPAM FILTER. 30% of mail is spam. The filter catches 98% and wrongly
flags 5% of good mail.
   P(cause)                           = 0.3000
   P(marked spam | cause)             = 0.980   the sensitivity
   P(marked spam | no cause)          = 0.050   1 - specificity
   P(cause) * P(+ | cause)            = 0.294000
   P(no cause) * P(+ | no cause)      = 0.035000
   P(marked spam), the total          = 0.329000
   P(cause | marked spam)             = 0.893617   89.36%

THE BASE RATE TRAP, in one sentence:
  the first test is 99% accurate and a positive result still leaves the
  patient more likely NOT to have the disease than to have it, because
  the healthy are a thousand times more numerous. Out of 100,000 people:
       100 have it,      of whom   99 test positive
     99900 do not,       of whom  999 test positive
    so 1098 positives in all, and only 99 of them are ill: 9.02%
munotes.in210

Bayes Theorem

The base rate trap, which is the examinable part

Read the first block. The test is 99 per cent accurate in both directions, the patient has tested positive, and the probability that they have the disease is 9.02 per cent. They are about ten times more likely to be well than ill.

This is not a paradox and the test is not bad. The arithmetic at the foot of the output is the whole explanation, and it is the form to use when explaining it to anybody:

Out of 100,000 people, 100 have the disease and 99,900 do not. Of the 100, the test correctly flags 99. Of the 99,900, the test wrongly flags one per cent, which is 999. So there are 1,098 positive results and only 99 of them are true. 99 out of 1,098 is 9.02 per cent.

The false positives outnumber the true positives eleven to one, because the healthy group is a thousand times larger. A one per cent error rate on a group a thousand times bigger produces ten times more errors than the whole of the small group.

The name of the mistake. Ignoring the prior and answering 99 per cent is called the base rate fallacy. It is the commonest error on this topic, it is made by doctors and lawyers as well as students, and the way to avoid it is to compute the denominator by cases as the law of total probability requires.

And note the comparison across the three problems. The same structure with a base rate of 0.001 gives 9 per cent, with 0.02 gives 16 per cent, and with 0.30 gives 89 per cent. The prior does most of the work, and the third case is why spam filters are usable while rare-disease screening is hard.

munotes.in211

Bayes Theorem

Two more things the theorem gives

The odds form, which is quicker for a sequence of evidence and is worth knowing.

posterior odds = prior odds * likelihood ratio

where the likelihood ratio is P(b | a) / P(b | not a)

For the first problem: prior odds are 1 to 999, the likelihood ratio is 0.99 divided by 0.01, that is 99, so the posterior odds are 99 to 999, which is 99 out of 1,098. The same answer with no division, and the normalising constant disappears entirely. This is also why a second independent positive test helps so much: multiply by 99 again.

Sequential updating. The posterior after one piece of evidence is the prior for the next. Beliefs are revised piece by piece, and the order does not matter. It requires the pieces of evidence to be conditionally independent given the cause, which is the next chapter and is the assumption The Naive Bayes Classifier is named for.

Where the priors come from

An honest section, because a paper can ask and because the answer is sometimes uncomfortable.

From data, when there is data: the prevalence of a disease, the proportion of faulty parts, the fraction of mail that is spam. This is the usual case and the numbers are then defensible.

From an expert's judgement, when there is not. This is legitimate under the Bayesian reading in Why an Agent Needs Probability and it is also where a system can be criticised.

From a deliberately uninformative choice, such as assigning equal probability to each alternative, when nothing is known. That is itself an assumption and not a neutral position: "equally likely" is a claim.

And the practical reassurance: with enough evidence the posterior becomes insensitive to the prior, because the likelihood ratios accumulate. With little evidence the prior dominates, which is exactly the rare-disease case.

Distinctions

PriorLikelihoodPosterior
SymbolP(a)P(b given a)P(a given b)
Measured byhow common the cause istesting known casesBayes theorem
In the first problem0.0010.990.0902
P(positive given disease)P(disease given positive)
Isthe sensitivity, a property of the testthe answer the patient wants
Depends on the base ratenoyes
In the first problem0.990.0902
Confusing them isthe base rate fallacy
SensitivitySpecificity
IsP(positive given disease)P(negative given no disease)
Measurescatching the illnot alarming the well
In the first problem0.990.99
munotes.in212

Bayes Theorem

What it does not mean

Bayes theorem is not an extra assumption. It is the product rule written two ways and rearranged, so it follows from the axioms alone.

P(a | b) is not P(b | a). Swapping them is the base rate fallacy, and in the first problem the two differ by a factor of eleven.

A 99 per cent accurate test does not give a 99 per cent answer. It gives 9 per cent when the disease affects one person in a thousand.

The result is not evidence that the test is useless. It multiplied the belief from 0.001 to 0.090, a factor of 90. For a rare disease that is exactly why screening is followed by a second, different test.

The denominator is not usually looked up. It is computed by cases, using the law of total probability.

A prior is not optional. Leaving it out is not neutrality; it is assuming a base rate of one half, which in the first problem is wrong by a factor of 500.

Quick revision

  • Bayes theorem: P(a | b) = P(b | a) * P(a) / P(b). Derived in two lines from the product rule written both ways.
  • Names: P(a) prior, P(b | a) likelihood, P(b) evidence or normalising constant, P(a | b) posterior.
  • Law of total probability for the denominator: P(b) = P(b|a)P(a) + P(b|not a)P(not a).
  • The base rate trap. A 99 per cent accurate test, a positive result, a disease affecting 1 in 1,000: the answer is 9.02 per cent. Out of 100,000 people, 99 true positives against 999 false ones.
  • The base rate fallacy is answering 99 per cent, that is confusing P(disease | positive) with P(positive | disease).
  • The same structure at base rates 0.001, 0.02 and 0.30 gives 9 per cent, 16 per cent and 89 per cent. The prior does most of the work.
  • Odds form: posterior odds equal prior odds times the likelihood ratio P(b|a) / P(b|not a). 1 to 999 times 99 gives 99 to 999. No division, and no normalising constant.
  • Sequential updating: today's posterior is tomorrow's prior, provided the pieces of evidence are conditionally independent given the cause.
  • Priors come from data, from expert judgement, or from a deliberately uninformative choice, which is itself an assumption.

Test yourself

1. State Bayes theorem and derive it. P(a | b) equals P(b | a) times P(a), divided by P(b). The product rule gives P(a and b) as both P(a|b)P(b) and P(b|a)P(a); equating those and dividing by P(b) gives the theorem.

2. Name the four quantities in the theorem. P(a) is the prior, P(b | a) the likelihood, P(b) the evidence or normalising constant, and P(a | b) the posterior.

munotes.in213

Bayes Theorem

3. A disease affects 1 person in 1,000. A test detects 99 per cent of cases and wrongly flags 1 per cent of healthy people. A patient tests positive. What is the probability they have the disease? The numerator is 0.001 times 0.99, which is 0.00099. The other term is 0.999 times 0.01, which is 0.00999. The total is 0.01098, so the posterior is 0.00099 divided by 0.01098, that is 0.0902, about 9 per cent.

4. Explain that answer by counting people. In 100,000 people, 100 have the disease and 99 of them test positive. Of the 99,900 who do not, one per cent, that is 999, test positive. So 1,098 people test positive and only 99 of them are ill, which is 9.02 per cent. The healthy group is a thousand times larger, so its small error rate produces ten times more positives than the entire ill group.

5. What is the base rate fallacy? Answering the question P(disease | positive) with the value of P(positive | disease), that is ignoring how common the disease is. In the example above it gives 99 per cent instead of 9 per cent.

6. Give the odds form of the theorem and apply it to the disease problem. Posterior odds equal prior odds times the likelihood ratio, the likelihood ratio being P(b|a) divided by P(b | not a). Here the prior odds are 1 to 999 and the ratio is 0.99 over 0.01, that is 99, so the posterior odds are 99 to 999, giving 99 out of 1,098.

7. The same test structure at base rates of 0.001, 0.02 and 0.30 gives posteriors of 9, 16 and 89 per cent. What does that show? That the prior does most of the work. A test of fixed quality is decisive when the condition is common and nearly uninformative when it is rare, which is why spam filtering works well and why screening for a rare disease needs a second, independent test.

Contents This chapter on its own page

munotes.in214

Chapter Forty

Conditional Independence

Syllabus topic Module 1, "Conditional independence"

In one line

Two things can depend on each other only because they share a cause, and once you know the cause they stop telling you anything about each other.

In the wording a student can write in an examination: two variables X and Y are conditionally independent given Z if, for every value of Z,

P(X, Y | Z) = P(X | Z) * P(Y | Z)

equivalently P(X | Y, Z) = P(X | Z): once Z is known, Y adds nothing about X. Absolute independence is the case with no Z, P(X, Y) = P(X) P(Y). Conditional independence is the property that makes a large joint distribution factorise, and so is what makes probabilistic reasoning practical.

The two definitions, and why the second is the useful one

P(X, Y | Z) = P(X | Z) * P(Y | Z)

P(X | Y, Z) = P(X | Z)

The two are equivalent, and the second is worth reading aloud: given Z, telling me Y does not change what I believe about X. That is what conditional independence means operationally, and it is what licenses leaving Y out of a calculation.

And note what conditional independence is not. X and Y may be strongly dependent and still conditionally independent given Z. Those two facts are consistent, and the next section shows both holding on the same numbers.

Both properties, on the same eight numbers

A toothache and a probe catching in a tooth are obviously related. And the relation is entirely due to the cavity that causes both: given that a patient has a cavity, whether the probe catches tells you nothing further about whether they have a toothache.

# Conditional independence, checked arithmetically on the dentist joint, and then
# COUNTED: how many numbers it saves.
from itertools import product
VARS = ["Cavity", "Toothache", "Catch"]
JOINT = {
    (True,  True,  True):  0.108, (True,  True,  False): 0.012,
    (True,  False, True):  0.072, (True,  False, False): 0.008,
    (False, True,  True):  0.016, (False, True,  False): 0.064,
    (False, False, True):  0.144, (False, False, False): 0.576,
}
def p(**fixed):
    return sum(v for k, v in JOINT.items()
               if all(dict(zip(VARS, k))[a] == b for a, b in fixed.items()))
def cond(q, **given):
    num = p(**{**q, **given})
    den = p(**given)
    return num / den

print("are Toothache and Catch INDEPENDENT? test P(T,C) == P(T) * P(C)")
lhs = p(Toothache=True, Catch=True)
rhs = p(Toothache=True) * p(Catch=True)
print("   P(T,C) = %.4f   P(T) * P(C) = %.4f * %.4f = %.4f   equal? %s"
      % (lhs, p(Toothache=True), p(Catch=True), rhs, abs(lhs - rhs) < 1e-9))
print()
print("are they CONDITIONALLY independent GIVEN Cavity?")
print("   test P(T,C | cav) == P(T | cav) * P(C | cav), for each value of Cavity")
for cav in (True, False):
    l = cond({"Toothache": True, "Catch": True}, Cavity=cav)
    r = cond({"Toothache": True}, Cavity=cav) * cond({"Catch": True}, Cavity=cav)
    print("   Cavity = %-5s   %.6f   against   %.6f   equal? %s"
          % (cav, l, r, abs(l - r) < 1e-9))
print()
print("so they are DEPENDENT, and CONDITIONALLY INDEPENDENT given the cause.")
print("both facts are true at once, and that is the whole point.")
print()
print("what it saves. n symptoms, each conditionally independent given the cause:")
print("   n | full joint, free numbers | with conditional independence")
for n in (2, 5, 10, 20, 30):
    full = 2 ** (n + 1) - 1
    naive = 1 + 2 * n
    print("  %2d | %24d | %28d" % (n, full, naive))
print()
print("30 symptoms: %d numbers instead of %d. That reduction IS the naive Bayes"
      % (1 + 2 * 30, 2 ** 31 - 1))
print("classifier of Module 2, and it is what a Bayesian network generalises.")
munotes.in215

Conditional Independence

are Toothache and Catch INDEPENDENT? test P(T,C) == P(T) * P(C)
   P(T,C) = 0.1240   P(T) * P(C) = 0.2000 * 0.3400 = 0.0680   equal? False

are they CONDITIONALLY independent GIVEN Cavity?
   test P(T,C | cav) == P(T | cav) * P(C | cav), for each value of Cavity
   Cavity = True    0.540000   against   0.540000   equal? True
   Cavity = False   0.020000   against   0.020000   equal? True

so they are DEPENDENT, and CONDITIONALLY INDEPENDENT given the cause.
both facts are true at once, and that is the whole point.

what it saves. n symptoms, each conditionally independent given the cause:
   n | full joint, free numbers | with conditional independence
   2 |                        7 |                            5
   5 |                       63 |                           11
  10 |                     2047 |                           21
  20 |                  2097151 |                           41
  30 |               2147483647 |                           61

30 symptoms: 61 numbers instead of 2147483647. That reduction IS the naive Bayes
classifier of Module 2, and it is what a Bayesian network generalises.

Read the first two blocks together.

They are not independent. P(T, C) is 0.1240 and P(T) P(C) is 0.0680, nearly a factor of two apart. A toothache makes it substantially more likely that the probe will catch.

They ARE conditionally independent given the cavity, and exactly so, at both values of Cavity. Given a cavity, P(T, C) is 0.540 and the product of the two conditionals is also 0.540.

The interpretation is the sentence to remember: the dependence between the two symptoms is entirely explained by the cause. Once you know whether there is a cavity, one symptom tells you nothing more about the other. The cavity is said to screen off one from the other.

Why this is the key to the whole row

Read the count. Thirty symptoms sharing one cause needs 2,147,483,647 free numbers in a full joint distribution, and 61 if each symptom is conditionally independent of the others given the cause.

munotes.in216

Conditional Independence

Where the 61 comes from: one number for the prior on the cause, and for each of the 30 symptoms two numbers, its probability given the cause and given no cause. One plus sixty.

That reduction, from exponential to linear, is the whole reason probabilistic AI is possible. It is worth stating in three forms because each appears in a different part of this paper.

FormWhere
A joint distribution over a cause and conditionally independent effects factorises into a prior times one conditional per effectthis chapter
A network in which each variable depends only on its parents needs only its own small tableBayesian Networks
A classifier that assumes the features are conditionally independent given the class needs only one count per feature per classThe Naive Bayes Classifier

All three are this one property. A student who understands it here understands the naive Bayes classifier before reaching it.

The three ways a dependence can arise

MU asks for conditional independence, and it is much easier to spot in a described problem if the three patterns are known. They come back in Bayesian Networks as the three shapes of a three-node network.

Common cause. A causes both B and C. Then B and C are dependent, and conditionally independent given A. The cavity case, and the standard example.

Chain. A causes B, which causes C. Then A and C are dependent, and conditionally independent given B. Rain causes a wet road, which causes an accident: once you know the road is wet, learning that it rained tells you nothing more about the accident.

Common effect, also called a collider. A and C both cause B. Here it goes the other way round: A and C are independent, and become dependent once B is known. This is the one that surprises everybody and it is examinable.

The common-effect case, worked in words. A burglary and an earthquake can each set off an alarm, and they have nothing to do with each other. Now the alarm sounds. Learning that there was an earthquake makes a burglary less likely, because the earthquake already explains the alarm. Knowing the effect has made two independent causes dependent, and the phenomenon is called explaining away.

PatternShapeWithout knowing the middleKnowing the middle
Common causeB back to A forward to Cdependentindependent
ChainA to B to Cdependentindependent
Common effectA forward to B back from Cindependentdependent

Two of the three patterns are blocked by knowing the middle variable, and the third is opened by it. That asymmetry is exactly what makes reading independence off a graph a real skill, and it is what the d-separation rules in Bayesian Networks formalise.

munotes.in217

Conditional Independence

How to establish conditional independence in practice

A paper may ask where the assumption comes from, and the honest answer has three parts.

From causal knowledge. If the cause is known to produce each symptom by an independent mechanism, they are conditionally independent given it. This is a claim about the world and it is the usual justification.

From data, by checking the arithmetic as the program above does. With finite data the equality never holds exactly, so this becomes a statistical test rather than a check, and it is easy to get wrong.

By assumption, knowingly. This is what The Naive Bayes Classifier does: it assumes every feature is conditionally independent of the others given the class, which is almost always false. The classifier works anyway, and why it works despite a false assumption is discussed in its own chapter. The honest position is that the assumption is a modelling choice and its falsity is known.

Distinctions

IndependentConditionally independent given Z
TestP(X,Y) = P(X)P(Y)P(X,Y given Z) = P(X given Z)P(Y given Z), for every value of Z
In the dentist exampleno: 0.1240 against 0.0680yes: 0.540 against 0.540
Implies the othernono
Both can hold at onceyes, and both can fail
Common causeChainCommon effect
Examplecavity to toothache and catchrain to wet road to accidentburglary and earthquake to alarm
Unconditionallydependentdependentindependent
Given the middleindependentindependentdependent
Name of the surpriseexplaining away
Full joint, 30 effectsWith conditional independence
Free numbers2,147,483,64761
Growthexponentiallinear
Where usednowhereBayesian networks, naive Bayes

What it does not mean

Conditional independence does not imply independence. The dentist variables are conditionally independent given the cavity and strongly dependent without it.

Independence does not imply conditional independence. A burglary and an earthquake are independent and become dependent once the alarm is known.

It is not a property of two variables alone. It is a three-place relation: X and Y given Z. Changing Z changes the answer.

Checking it on data does not establish it. With finite data the equality is never exact, so the check is a statistical test with all the usual difficulties.

Naive Bayes does not assume the features really are independent. It assumes conditional independence knowing the assumption is false, and the consequences are examined in its own chapter.

Knowing more does not always create more independence. Knowing a common effect destroys independence between its causes. Two of the three patterns are blocked by evidence in the middle; the third is opened by it.

munotes.in218

Conditional Independence

Quick revision

  • Conditionally independent given Z: P(X, Y | Z) = P(X | Z) P(Y | Z) for every value of Z. Equivalently P(X | Y, Z) = P(X | Z): given Z, Y adds nothing about X.
  • A pair can be dependent and conditionally independent at once. Toothache and Catch: P(T,C) is 0.1240 against P(T)P(C) of 0.0680, so dependent; given the cavity, 0.540 against 0.540, so conditionally independent. The cause screens off one from the other.
  • The count. Thirty effects sharing a cause: 2,147,483,647 free numbers in the joint, 61 with conditional independence. One for the prior plus two per effect. Exponential becomes linear.
  • Three patterns: common cause (dependent, independent given the middle), chain (the same), common effect (independent, and dependent once the middle is known, which is explaining away).
  • Established from causal knowledge, from data as a statistical test, or by assumption knowingly, which is what naive Bayes does.
  • The same property appears as a factorised joint here, as a network of small tables in Bayesian Networks, and as the naive Bayes assumption in Module 2.

Test yourself

1. Give both definitions of conditional independence and read the second in words. P(X, Y | Z) equals P(X | Z) times P(Y | Z) for every value of Z. Equivalently P(X | Y, Z) equals P(X | Z), which says that once Z is known, learning Y does not change the belief about X.

2. Show that toothache and catch are dependent but conditionally independent given a cavity. P(T, C) is 0.1240 while P(T) times P(C) is 0.200 times 0.340, which is 0.0680, so they are dependent. Given a cavity, P(T, C | cavity) is 0.540 and P(T | cavity) times P(C | cavity) is also 0.540, and similarly for no cavity, so they are conditionally independent given the cavity.

3. How many free numbers does a joint distribution over one cause and thirty conditionally independent effects need, and how many does the full joint need? Sixty-one: one for the prior on the cause and two for each effect, its probability given the cause and given no cause. The full joint over thirty-one Boolean variables needs 2 to the power 31 minus 1, which is 2,147,483,647.

4. Name the three patterns by which variables can be related, and say what happens in each when the middle variable is observed. Common cause, where the two effects are dependent and become independent given the cause. A chain, where the ends are dependent and become independent given the middle. And a common effect, where the two causes are independent and become dependent once the effect is known.

munotes.in219

Conditional Independence

5. What is explaining away? Give an example. When two independent causes share an effect, observing the effect makes them dependent, so learning that one occurred reduces belief in the other. A burglary and an earthquake can each set off an alarm; once the alarm has sounded, learning that there was an earthquake makes a burglary less likely because the earthquake already accounts for the alarm.

6. Where does the assumption of conditional independence usually come from? From causal knowledge, when the cause is known to produce each effect by a separate mechanism. Otherwise from a statistical test on data, which is inexact with finite samples, or by deliberate assumption as in naive Bayes, where the assumption is known to be false and adopted anyway.

7. Why is this chapter the bridge between the joint distribution and Bayesian networks? Because the joint distribution is unusable at scale, and conditional independence is precisely the property that lets it factorise into small pieces. A Bayesian network is that factorisation drawn as a graph: each variable needs only a table conditioned on its parents, which is why exponential storage becomes linear.

Contents This chapter on its own page

munotes.in220

Chapter Forty-One

Bayesian Networks

Syllabus topic Module 1, "Bayesian Networks"

In one line

A Bayesian network draws the causes as arrows into their effects, and then each variable needs only a small table saying how it depends on its own parents.

In the wording a student can write in an examination: a Bayesian network is a directed acyclic graph whose nodes are random variables and in which an arrow from X to Y means X is a parent of Y. Each node carries a conditional probability table giving P(node | its parents) for every combination of parent values. The network represents the full joint distribution by the chain rule for Bayesian networks:

P(x1, x2, ..., xn) = product over i of P(xi | parents of xi)

and the conditional independence it asserts is that each variable is conditionally independent of its non-descendants given its parents.

What the graph claims

An arrow is not a claim about causation as such, and it is not a claim about correlation either. The precise claim is the one in the definition, and getting it right is worth marks: a variable is conditionally independent of its non-descendants given its parents.

Read it as an instruction: to predict a variable, its parents are all you need. Anything else that is not downstream of it adds nothing once the parents are known. The network is a set of statements of the form "given these, forget everything else", and each such statement is what removes rows from the joint table.

In practice arrows are drawn from cause to effect, because that direction produces the sparsest graph and the easiest tables to fill in. That is a modelling convention with a good reason, not part of the definition. A network with the arrows reversed can represent the same distribution, and will usually need far more numbers.

The four-node network

The standard example. A Burglary or an Earthquake can set off an Alarm, and if the alarm sounds a neighbour may Call.

NodeParentsIts table gives
Burglarynoneone number: the prior
Earthquakenoneone number
AlarmBurglary, Earthquakefour numbers, one per combination of parents
CallAlarmtwo numbers

Note what the graph says by what it does not contain. There is no arrow between Burglary and Earthquake: they are independent. There is no arrow from Burglary to Call: a burglary affects the call only through the alarm. That is the conditional independence, and it is what lets Call's table have two numbers instead of eight.

The chain rule, and one joint entry read off the network

# A Bayesian network: the graph, the conditional probability tables, the chain
# rule that reads a joint entry off it, and inference by enumeration.
from itertools import product

# The four-node network. Each node: its parents, and P(node = True | parents).
NET = {
    "Burglary":  ([],                           {(): 0.001}),
    "Earthquake": ([],                          {(): 0.002}),
    "Alarm":     (["Burglary", "Earthquake"],   {(True, True): 0.95,
                                                 (True, False): 0.94,
                                                 (False, True): 0.29,
                                                 (False, False): 0.001}),
    "Call":      (["Alarm"],                    {(True,): 0.90, (False,): 0.05}),
}
ORDER = ["Burglary", "Earthquake", "Alarm", "Call"]

def p_true(node, assignment):
    parents, table = NET[node]
    key = tuple(assignment[p] for p in parents)
    return table[key]

def p_node(node, value, assignment):
    t = p_true(node, assignment)
    return t if value else 1 - t

def joint(assignment):
    """The CHAIN RULE: multiply each node's probability given its parents."""
    out = 1.0
    for node in ORDER:
        out *= p_node(node, assignment[node], assignment)
    return out

print("the network")
for node in ORDER:
    parents, table = NET[node]
    print("   %-10s parents: %s" % (node, ", ".join(parents) if parents else "none"))
print()
print("how many numbers does it need, against the full joint table?")
need = sum(2 ** len(NET[n][0]) for n in ORDER)
print("   the network: %d numbers" % need)
print("   the full joint over 4 binary variables: 2**4 - 1 = %d free numbers" % (2 ** 4 - 1))
print()
print("ONE JOINT ENTRY by the chain rule: burglary, no earthquake, alarm, call")
a = {"Burglary": True, "Earthquake": False, "Alarm": True, "Call": True}
terms = []
out = 1.0
for node in ORDER:
    v = p_node(node, a[node], a)
    terms.append("%.5f" % v)
    out *= v
print("   " + " * ".join(terms) + " = %.9f" % out)
print()
print("INFERENCE BY ENUMERATION: P(Burglary | Call = True)")
tot = {True: 0.0, False: 0.0}
for b, e, al in product([True, False], repeat=3):
    a = {"Burglary": b, "Earthquake": e, "Alarm": al, "Call": True}
    tot[b] += joint(a)
print("   unnormalised: burglary %.9f, no burglary %.9f" % (tot[True], tot[False]))
s = tot[True] + tot[False]
print("   P(Call = True)                     = %.9f" % s)
print("   P(Burglary = True  | Call = True)   = %.6f   %.3f%%"
      % (tot[True] / s, 100 * tot[True] / s))
print("   P(Burglary = False | Call = True)   = %.6f" % (tot[False] / s))
print()
print("the prior was 0.001, so one telephone call has multiplied the")
print("probability of a burglary by about %.0f times, and it is still only %.1f%%."
      % ((tot[True] / s) / 0.001, 100 * tot[True] / s))
munotes.in221

Bayesian Networks

the network
   Burglary   parents: none
   Earthquake parents: none
   Alarm      parents: Burglary, Earthquake
   Call       parents: Alarm

how many numbers does it need, against the full joint table?
   the network: 8 numbers
   the full joint over 4 binary variables: 2**4 - 1 = 15 free numbers

ONE JOINT ENTRY by the chain rule: burglary, no earthquake, alarm, call
   0.00100 * 0.99800 * 0.94000 * 0.90000 = 0.000844308

INFERENCE BY ENUMERATION: P(Burglary | Call = True)
   unnormalised: burglary 0.000849017, no burglary 0.051289959
   P(Call = True)                     = 0.052138976
   P(Burglary = True  | Call = True)   = 0.016284   1.628%
   P(Burglary = False | Call = True)   = 0.983716

the prior was 0.001, so one telephone call has multiplied the
probability of a burglary by about 16 times, and it is still only 1.6%.
munotes.in222

Bayesian Networks

Three things in that output.

The joint entry is read off the graph by multiplication. The probability of a burglary, no earthquake, the alarm sounding and a call is 0.001 0.998 0.94 * 0.90, which is 0.000844308. Each factor is one node's own number, looked up with its parents' values, and the multiplication is the chain rule.

The network needs 8 numbers where the joint needs 15. On four variables that is a modest saving. The saving grows with the graph's sparsity: a network of n Boolean variables in which no node has more than k parents needs at most n * 2k numbers against 2n - 1. At 30 variables with at most 3 parents each, that is 240 numbers against over a thousand million.

The answer to the query is 1.6 per cent. The prior was 0.1 per cent, so one telephone call multiplied the belief by about sixteen. And it is still small, which is the base rate effect of Bayes Theorem appearing again: burglaries are rare, false alarms are not, and one call is weak evidence.

Where the numbers come from, and why the direction matters

This is the practical argument for drawing arrows from cause to effect, and a paper can ask for it.

The tables the network needs are of the form P(effect | its causes). Those are exactly the numbers a person can estimate: how often does the alarm sound when there is a burglary and no earthquake? An engineer can answer that from the alarm's design, and it does not change when the neighbourhood's burglary rate changes.

Reverse an arrow and you need P(burglary | alarm), which depends on the burglary rate, the earthquake rate and the alarm's reliability all at once. It is a diagnostic number rather than a causal one, it is much harder to estimate, and it changes whenever anything else does.

So the causal direction gives numbers that are local, stable and obtainable, which is the real reason Bayesian networks are usable at all. The arithmetic does not care; the person filling in the tables does.

Reading independence off the graph

The three patterns from Conditional Independence are the three shapes a three-node network can take, and knowing them lets independence be read from the picture.

In the networkShapeUnconditionallyGiven the middle
Burglary and Call, through Alarma chaindependentindependent given Alarm
Two symptoms of one causea common cause, or forkdependentindependent given the cause
Burglary and Earthquake, into Alarma common effect, a colliderindependentdependent given Alarm
munotes.in223

Bayesian Networks

Explaining away, in this network. Burglary and Earthquake are independent: no arrow joins them. Now suppose the alarm is known to be sounding. Learning that there was an earthquake makes a burglary less likely, because the earthquake accounts for the alarm. Evidence at a common effect creates a dependence between causes that had none, and this is the one pattern that behaves the opposite way from the other two.

The general rule that decides all cases at once is called d-separation, and it is not on MU's label; the three patterns above are what a paper asks for and they cover every question likely to be set.

Building one

A paper may ask how a network is constructed, and there is a procedure.

  1. Choose the variables, and an ordering in which causes come before effects.
  2. For each variable in that order, choose as parents the smallest set of earlier variables that it directly depends on, that is the smallest set given which it is conditionally independent of the other earlier ones.
  3. Fill in its conditional probability table.

Step 1 matters more than it looks. A bad ordering produces a correct network with far more arrows: order the burglary example as Call, Alarm, Burglary, Earthquake and the graph acquires extra edges and needs more numbers, while representing the same distribution. Causes first gives the sparsest graph, which is the same point as the direction argument above.

And the network is acyclic by construction, because each node's parents come earlier in the ordering. A cycle would make the chain rule meaningless.

Distinctions

Bayesian networkFull joint distribution
Storesone small table per nodeone number per atomic event
Numbers needed, 4 binary variables815
Numbers needed, 30 variables, at most 3 parentsabout 240over a thousand million
Completeyes, it determines the jointyes
Its numbers are obtainableyes, they are local and causalno
Causal directionDiagnostic direction
Tables giveP(effect given causes)P(cause given effects)
Estimable by a personyeshard
Stable when other rates changeyesno
Graph sparsitysparserdenser
Chain and common causeCommon effect
Unconditionallydependentindependent
Given the middle nodeindependentdependent
The phenomenonexplaining away

What it does not mean

An arrow is not a claim that causation has been proved. The formal content is the conditional independence: a variable is independent of its non-descendants given its parents.

A missing arrow is a claim, and a strong one. The absence of an arrow from Burglary to Call says a burglary affects the call only through the alarm. Missing arrows are where a network's assumptions live.

munotes.in224

Bayesian Networks

The network is not an approximation of the joint distribution. It represents it exactly. What it drops are the numbers the conditional independences make redundant.

More arrows are not better. A fully connected network is correct and needs as many numbers as the joint, so it buys nothing. The value is in what is absent.

Independent causes do not stay independent. Given a shared effect they become dependent, which is explaining away.

A cycle is not merely inelegant. The chain rule has no meaning on a cyclic graph, which is why the graph must be acyclic.

Quick revision

  • A Bayesian network is a directed acyclic graph of random variables; each node has a conditional probability table for P(node | parents).
  • Chain rule: P(x1..xn) = product of P(xi | parents of xi). The claim it makes is that each variable is conditionally independent of its non-descendants given its parents.
  • The burglary network: Burglary and Earthquake with no parents, Alarm with both as parents, Call with Alarm. 8 numbers against the joint's 15.
  • One joint entry: 0.001 0.998 0.94 * 0.90 = 0.000844308.
  • P(Burglary | Call) is 1.628 per cent, against a prior of 0.1 per cent: one call multiplies the belief about sixteen times and it is still small.
  • Scale: n Boolean variables with at most k parents each need at most n * 2k numbers. 30 variables, 3 parents: about 240 against over a thousand million.**
  • Arrows go from cause to effect because that makes the tables P(effect | causes), which are local, stable and obtainable. The diagnostic direction needs numbers nobody can estimate and gives a denser graph.
  • Reading independence: chain and common cause are blocked by the middle; a common effect is opened by it, which is explaining away.
  • Building one: order the variables with causes first, give each the smallest set of earlier parents it depends on, then fill the table. A bad ordering gives a correct but denser network.

Test yourself

1. Define a Bayesian network and state the chain rule for it. A directed acyclic graph whose nodes are random variables, each carrying a conditional probability table for the node given its parents. The joint distribution is the product over all nodes of the probability of each node given its parents.

2. What conditional independence does the graph assert? That each variable is conditionally independent of its non-descendants given its parents. Equivalently, to predict a variable, its parents are all that is needed.

munotes.in225

Bayesian Networks

3. How many numbers does the four-node burglary network need, and how many does the full joint over the same variables need? Eight: one each for Burglary and Earthquake, four for Alarm with its two parents, and two for Call. The full joint over four Boolean variables needs 2 to the power 4 minus 1, which is 15.

4. Compute the probability of a burglary, no earthquake, the alarm sounding and a call. Multiply each node's probability given its parents: 0.001 times 0.998 times 0.94 times 0.90, which is 0.000844308.

5. Why are arrows drawn from cause to effect rather than the other way? Because the tables then hold numbers of the form P(effect | causes), which a person can estimate from the mechanism and which do not change when other rates in the domain change. The reverse direction needs diagnostic numbers that depend on everything at once, and it produces a denser graph.

6. What is explaining away, and where does it occur in this network? When two independent causes share an effect, observing the effect makes them dependent. In this network Burglary and Earthquake are independent, but once the alarm is known to be sounding, learning of an earthquake reduces the probability of a burglary, because the earthquake already accounts for the alarm.

7. Describe how a Bayesian network is constructed, and say what a bad variable ordering costs. Choose the variables and order them with causes before effects. For each in turn, take as parents the smallest set of earlier variables on which it directly depends, and fill in its conditional probability table. A bad ordering still gives a correct network, but with more arrows and therefore more numbers to supply, and the numbers themselves become harder to estimate.

Contents This chapter on its own page

munotes.in226

Chapter Forty-Two

Inference in a Bayesian Network

Syllabus topic Module 1, "Bayesian Networks"

In one line

To answer a question of a Bayesian network, add up the probabilities of all the complete worlds that agree with the evidence, and then normalise; and to do it without visiting every world, sum out one variable at a time.

In the wording a student can write in an examination: exact inference in a Bayesian network computes P(query | evidence) by summing the joint distribution over the hidden variables and normalising. Inference by enumeration does so directly and takes time exponential in the number of variables. Variable elimination does the same sums in a better order, keeping intermediate results as factors, and is far cheaper on a sparse network. Exact inference in a general Bayesian network is NP-hard, so approximate methods based on sampling are used on large networks.

The query, and the recipe

The same four-node network as Bayesian Networks. A neighbour telephones. How likely is a burglary?

P(Burglary | Call = true) = alpha * sum over Earthquake, Alarm of P(Burglary, Earthquake, Alarm, Call = true)

Three roles, and naming them correctly is worth marks. Burglary is the query variable. Call is the evidence variable, fixed at the value observed. Earthquake and Alarm are the hidden variables, and they are summed out. alpha is the normalising constant from The Joint Distribution and Inference by Enumeration, which never needs computing separately.

Both methods, run

# Inference in a Bayesian network, two ways on the SAME query, so the second can
# be checked against the first: enumeration, and variable elimination.
from itertools import product

NET = {
    "Burglary":   ([],                         {(): 0.001}),
    "Earthquake": ([],                         {(): 0.002}),
    "Alarm":      (["Burglary", "Earthquake"], {(True, True): 0.95, (True, False): 0.94,
                                                (False, True): 0.29, (False, False): 0.001}),
    "Call":       (["Alarm"],                  {(True,): 0.90, (False,): 0.05}),
}
ORDER = ["Burglary", "Earthquake", "Alarm", "Call"]

def p_node(node, value, a):
    parents, table = NET[node]
    t = table[tuple(a[p] for p in parents)]
    return t if value else 1 - t

def enumerate_query(query, evidence):
    """Sum the joint over every assignment to the hidden variables."""
    hidden = [v for v in ORDER if v != query and v not in evidence]
    out = {}
    for qv in (True, False):
        total = 0.0
        for vals in product([True, False], repeat=len(hidden)):
            a = dict(evidence)
            a[query] = qv
            a.update(dict(zip(hidden, vals)))
            prod = 1.0
            for node in ORDER:
                prod *= p_node(node, a[node], a)
            total += prod
        out[qv] = total
    s = out[True] + out[False]
    return {k: v / s for k, v in out.items()}, s

# --- variable elimination: a factor is a dict from an assignment of its own
# variables to a number, and the two operations are POINTWISE PRODUCT and SUM OUT.
def make_factor(node, evidence):
    parents, _ = NET[node]
    vs = parents + [node]
    free = [v for v in vs if v not in evidence]
    f = {}
    for vals in product([True, False], repeat=len(free)):
        a = dict(evidence)
        a.update(dict(zip(free, vals)))
        f[tuple(a[v] for v in free)] = p_node(node, a[node], a)
    return free, f

def product_factors(f1, f2):
    (v1, t1), (v2, t2) = f1, f2
    out_vars = v1 + [v for v in v2 if v not in v1]
    out = {}
    for vals in product([True, False], repeat=len(out_vars)):
        a = dict(zip(out_vars, vals))
        k1 = tuple(a[v] for v in v1)
        k2 = tuple(a[v] for v in v2)
        out[vals] = t1[k1] * t2[k2]
    return out_vars, out

def sum_out(var, f):
    vs, table = f
    i = vs.index(var)
    keep = vs[:i] + vs[i + 1:]
    out = {}
    for vals in product([True, False], repeat=len(keep)):
        total = 0.0
        for v in (True, False):
            key = vals[:i] + (v,) + vals[i:]
            total += table[key]
        out[vals] = total
    return keep, out

def eliminate(query, evidence, order):
    factors = [make_factor(n, evidence) for n in ORDER]
    for var in order:
        touching = [f for f in factors if var in f[0]]
        factors = [f for f in factors if var not in f[0]]
        acc = touching[0]
        for f in touching[1:]:
            acc = product_factors(acc, f)
        factors.append(sum_out(var, acc))
        print("   eliminated %-11s %d factor(s) multiplied, %d remain"
              % (var, len(touching), len(factors)))
    acc = factors[0]
    for f in factors[1:]:
        acc = product_factors(acc, f)
    vs, table = acc
    i = vs.index(query)
    out = {}
    for vals, val in table.items():
        out[vals[i]] = out.get(vals[i], 0.0) + val
    s = out[True] + out[False]
    return {k: v / s for k, v in out.items()}

print("query: P(Burglary | Call = True)")
print()
print("BY ENUMERATION, summing the joint over Earthquake and Alarm")
post, evid = enumerate_query("Burglary", {"Call": True})
print("   P(Call = True)  = %.9f" % evid)
print("   P(Burglary=T | Call=T) = %.9f" % post[True])
print("   P(Burglary=F | Call=T) = %.9f" % post[False])
print()
print("BY VARIABLE ELIMINATION, eliminating Earthquake then Alarm")
post2 = eliminate("Burglary", {"Call": True}, ["Earthquake", "Alarm"])
print("   P(Burglary=T | Call=T) = %.9f" % post2[True])
print("   P(Burglary=F | Call=T) = %.9f" % post2[False])
print()
print("the two agree to 9 decimal places:", abs(post[True] - post2[True]) < 1e-9)
print()
print("and a second piece of evidence, an earthquake on the news:")
post3, _ = enumerate_query("Burglary", {"Call": True, "Earthquake": True})
print("   P(Burglary=T | Call=T, Earthquake=T) = %.9f" % post3[True])
print("   it FELL from %.6f to %.6f: the earthquake EXPLAINS AWAY the alarm."
      % (post[True], post3[True]))
munotes.in227

Inference in a Bayesian Network

query: P(Burglary | Call = True)

BY ENUMERATION, summing the joint over Earthquake and Alarm
   P(Call = True)  = 0.052138976
   P(Burglary=T | Call=T) = 0.016283730
   P(Burglary=F | Call=T) = 0.983716270

BY VARIABLE ELIMINATION, eliminating Earthquake then Alarm
   eliminated Earthquake  2 factor(s) multiplied, 3 remain
   eliminated Alarm       2 factor(s) multiplied, 2 remain
   P(Burglary=T | Call=T) = 0.016283730
   P(Burglary=F | Call=T) = 0.983716270

the two agree to 9 decimal places: True

and a second piece of evidence, an earthquake on the news:
   P(Burglary=T | Call=T, Earthquake=T) = 0.002886613
   it FELL from 0.016284 to 0.002887: the earthquake EXPLAINS AWAY the alarm.
munotes.in228

Inference in a Bayesian Network

Reading the answer

A burglary is 1.63 per cent likely. The prior was 0.1 per cent, so the telephone call multiplied the belief by about sixteen, and it remains small because burglaries are rare and false alarms are not. That is the base rate effect of Bayes Theorem in a network.

And the two methods agree to nine decimal places, which is how this book establishes that a probabilistic program is right. Enumeration and variable elimination share no code beyond the network's tables, and they do the sums in different orders; agreeing to nine places is strong evidence that neither has a sign error or a missing term. Proof-reading a probability calculation catches almost nothing, and this is what replaces it.

Explaining away, as a number

Conditional Independence and Bayesian Networks both described explaining away in words. Here it is measured.

What is knownP(Burglary)
nothing0.001000
a telephone call0.016284
a telephone call, and an earthquake on the news0.002887

The call raised the belief sixteen-fold. The earthquake then cut it by more than five-sixths, back to nearly the prior.

And nothing about the burglary changed. Burglary and Earthquake have no arrow between them and are independent in the network. What changed is that the alarm now has another explanation, so it no longer needs a burglary. Evidence about one cause of a shared effect has reduced belief in another cause, which is the pattern that cannot happen in the chain or common-cause shapes.

Why enumeration is wasteful, and what elimination fixes

Enumeration multiplies out the whole product for every assignment to the hidden variables, so it recomputes the same sub-products repeatedly. On this network the factor for Call given Alarm is looked up once per assignment to Burglary and Earthquake, although it does not depend on either.

Variable elimination removes the repetition. A factor is a table over some subset of the variables. Two operations:

  • Pointwise product: multiply two factors, entry by entry, over the union of their variables.
  • Summing out: remove one variable from a factor by adding over its values.

The algorithm: make one factor per node, then repeatedly pick a hidden variable, multiply together every factor that mentions it, sum it out of the product, and put the result back. When the hidden variables are gone, multiply what is left and normalise.

In the run, eliminating Earthquake multiplied 2 factors and left 3; eliminating Alarm multiplied 2 and left 2. Each intermediate result is computed once and reused.

munotes.in229

Inference in a Bayesian Network

The elimination order matters, and a great deal. A good order keeps the intermediate factors small; a bad one can produce a factor over almost every variable, at which point elimination is no better than enumeration. Finding the best order is itself NP-hard, and practical systems use heuristics such as eliminating the variable that produces the smallest new factor. The largest factor an order produces is the induced width, and the cost is exponential in it rather than in the number of variables, which is why a sparse network is cheap and a densely connected one is not.

The complexity, stated honestly

Exact inference in a general Bayesian network is NP-hard, so no algorithm can be fast on every network. Two useful facts qualify that.

On a polytree, a network whose underlying undirected graph has no loops, exact inference is linear in the size of the network. The burglary network is a polytree.

On a general network the cost is exponential in the induced width of the elimination order, not in the number of variables. Many real networks are sparse enough that this is small, which is why exact inference is used in practice more often than the NP-hardness result would suggest.

Where it is not enough, approximate inference by sampling is used, and MU does not set it; the names are worth one line each so they are not a mystery. Rejection sampling generates whole worlds from the network and discards those disagreeing with the evidence, which is correct and wasteful when the evidence is unlikely. Likelihood weighting fixes the evidence and weights each sample by how probable that evidence was. Markov chain Monte Carlo walks from one world to a neighbouring one, and the fraction of time it spends in worlds satisfying the query converges to the answer.

Module 1, in one page

This is the last chapter of the module, and MU's Q.3 crosses into Module 2, so the seam is worth marking.

MU's rowWhat it gives the agentWhere Module 2 takes it
Agents and environmentsthe frame: percept, action, performance measure, and five architecturesthe learning agent is the frame for all of Module 2
Problem solving and searchhow to choose an action when the world is known and predictableGradient Descent is search over parameters instead of over states
Knowledge and logichow to represent what is true, and derive moreDecision Tree Learning produces rules of exactly this kind, learned rather than told
Reasoning under uncertaintydegrees of belief, Bayes theorem, networksThe Naive Bayes Classifier is this row with one assumption; HMMs are this row over time; MDPs are this row over actions
munotes.in230

Inference in a Bayesian Network

The single sentence that joins the two modules: Module 1 assumes somebody supplied the model, and Module 2 is how the model is obtained from data. Search needs a transition model; logic needs rules; a Bayesian network needs its tables. Learning with Complete Data fills in those tables by counting, and The EM Algorithm fills them in when some of the data is missing.

Distinctions

EnumerationVariable elimination
Recomputes sub-productsyes, repeatedlyno, each is computed once
Data structurenone beyond the networkfactors
Operationsmultiply and add inlinepointwise product and summing out
Costexponential in the number of variablesexponential in the induced width
Same answeryesyes, agreeing to nine decimal places here
Query variableEvidence variableHidden variable
In this queryBurglaryCallEarthquake, Alarm
What happens to itthe answer is a distribution over itfixed at the observed valuesummed out
PolytreeGeneral network
Undirected graph has loopsnoyes
Exact inferencelinear in the network sizeexponential in the induced width
The burglary network isa polytree

What it does not mean

The answer 1.6 per cent does not mean the call was uninformative. It multiplied the belief sixteen-fold. It is small because the prior was very small.

Variable elimination does not give a different answer. It gives the same answer with less work, which is why the agreement to nine places is the check.

The elimination order is not a detail. A bad order makes elimination as expensive as enumeration, and choosing the best order is itself NP-hard.

NP-hard does not mean impossible in practice. The cost is exponential in the induced width, and real networks are often sparse enough for that to be small.

Explaining away is not a failure of the network. It is a correct consequence of the probabilities, and it is the behaviour that makes a network better than a set of independent rules.

Sampling methods are not approximations of the model. They approximate the answer to a query about an exact model, which is a different thing.

Quick revision

  • P(query | evidence) = alpha * sum over hidden variables of the joint. Query, evidence and hidden variables; the hidden ones are summed out; alpha is fixed by normalising.
  • On the burglary network, P(Burglary | Call) is 0.016284, from a prior of 0.001: a sixteen-fold increase that is still only 1.6 per cent.
  • Two algorithms, one answer, nine decimal places. That agreement is how a probabilistic program is checked here, not proof-reading.
  • Explaining away, measured: 0.001000 with nothing known, 0.016284 after a call, 0.002887 after a call and an earthquake. Nothing about the burglary changed; the alarm acquired another explanation.
  • Variable elimination: a factor is a table over some variables; the operations are pointwise product and summing out. Multiply every factor mentioning the chosen variable, sum it out, put the result back.
  • The elimination order decides the cost. The largest factor produced is the induced width, and the cost is exponential in that. Choosing the best order is NP-hard.
  • Exact inference is NP-hard in general, linear on a polytree. The burglary network is a polytree.
  • Approximate methods: rejection sampling, likelihood weighting, Markov chain Monte Carlo.
  • Module 1 assumes the model was supplied; Module 2 is how the model comes from data.
munotes.in231

Inference in a Bayesian Network

Test yourself

1. Write the general expression for a query in a Bayesian network and name the three kinds of variable. P(query | evidence) is alpha times the sum over the hidden variables of the joint distribution with the evidence fixed. The query variable is the one asked about, the evidence variables are fixed at their observed values, and the hidden variables are summed out.

2. What is P(Burglary | Call = true) in this chapter's network, and how should the number be read? 0.016284, that is about 1.6 per cent. The prior was 0.001, so the call multiplied the belief about sixteen-fold; it remains small because burglaries are rare and the alarm produces false alarms.

3. How does this book establish that the answer is right? By computing it twice with two algorithms that share no code beyond the network's tables, enumeration and variable elimination, and comparing to nine decimal places. Proof-reading a probability calculation would not catch a missing term or a wrong sign.

4. Give the numbers that demonstrate explaining away, and explain them. The probability of a burglary is 0.001 with nothing known, 0.016284 after the telephone call, and 0.002887 once an earthquake is also known about. The earthquake gives the alarm another explanation, so the alarm no longer requires a burglary, even though burglary and earthquake are independent in the network.

5. Describe variable elimination and its two operations. Make one factor per node. Then repeatedly choose a hidden variable, multiply together all the factors that mention it by pointwise product, sum that variable out of the product, and put the result back among the factors. When all hidden variables are gone, multiply the remaining factors and normalise.

6. Why does the elimination order matter, and what quantity measures the cost? Because a bad order produces large intermediate factors, in the worst case over nearly all the variables, at which point no work has been saved. The largest factor an order produces gives the induced width, and the cost is exponential in that rather than in the number of variables.

munotes.in232

Inference in a Bayesian Network

7. State the complexity of exact inference, with the one case where it is easy. It is NP-hard in a general Bayesian network. On a polytree, a network whose underlying undirected graph contains no loops, it is linear in the size of the network. The four-node burglary network is a polytree.

Contents This chapter on its own page

munotes.in233

Module II

Machine learning, supervised models, probabilistic and latent variable models, unsupervised and reinforcement learning, and responsible AI

munotes.in

Chapter Forty-Three

What Machine Learning Is

Syllabus topic Module 2, "Introduction of Machine Learning"

In one line

Machine learning is writing a program that gets better at a task by looking at examples, instead of being told the rule.

In the wording a student can write in an examination: machine learning is the study of algorithms that improve their performance at a task through experience. The standard definition, due to Tom Mitchell, is that a program learns from experience E with respect to a task T and a performance measure P if its performance at T, as measured by P, improves with E. A model is the thing learned; training is the process of fitting it to data; and generalisation, performing well on data not seen during training, is the only thing that matters.

Where this module sits

The Learning Agent gave the frame and it is worth restating, because Module 2 is one box of it.

ComponentWhat it doesWhich of MU's labels
Performance elementchooses actionsall of Module 1
Criticsays how well it did, against a fixed standardthe three forms of learning are three kinds of critic
Learning elementchanges the performance elementall the rest of Module 2
Problem generatorsuggests informative actionsexploration, in Q-Learning

So machine learning is not a separate subject bolted on. It is the answer to Module 1's last environment property, unknown: if the agent does not know the laws it is operating under, it has to find them out, and finding them out from experience is learning.

Mitchell's definition, and why it is worth the three letters

a program learns from experience E with respect to task T and measure P

if its performance at T, measured by P, improves with E

The value of the definition is that it forces three things to be named before anything is built, and a paper often asks for them on a given example.

ExampleT, the taskP, the measureE, the experience
Spam filterclassify a message as spam or notfraction classified correctly, with a heavy penalty for losing wanted maila mailbox of messages already labelled
Handwriting recognitionread a digit from an imagefraction of digits read correctlyimages of digits with their true values
Predicting markspredict a mark from hours studiedaverage squared error of the predictionpast students' hours and marks
Playing draughtschoose a movefraction of games wongames played against itself

The measure is not optional and it is not obvious. A spam filter measured on plain accuracy will learn to mark everything as not-spam if 97 per cent of mail is legitimate, and score 97 per cent. Evaluating a Model is where this is taken properly, and it is licensed by MU's own Course Outcome 3.

munotes.in234

What Machine Learning Is

How it differs from Module 1

Module 1Module 2
The model isgiven by the designerlearned from data
The question iswhat should I dowhat is the pattern
Correct meansthe answer follows from the modelit generalises to unseen data
Fails whenthe model is wrongthe data is unrepresentative, or the model memorises
Needsa specificationexamples

The single sentence that joins the modules: Module 1 assumes somebody supplied the model, and Module 2 is how the model is obtained from data. Search needs a transition model; logic needs rules; a Bayesian network needs its tables. Learning with Complete Data fills in those tables by counting.

When to use it, and when not to

A paper can ask this, and the honest answer is a rule with three conditions.

Use machine learning when the rule is not known, or is too complicated to write down, or changes over time; and examples are available; and some errors are tolerable.

Do not use it when the rule is known and simple. Nobody should learn a model to decide whether a number is even. Nobody should learn the rules of chess. A program that can be written in ten lines should be written in ten lines, and a learned model in its place is slower, larger, less reliable and impossible to explain.

And do not use it when errors are not tolerable and cannot be checked. A learned model is right most of the time and gives no warning when it is not, which is the substance of MU's Responsible AI row.

The smallest honest learner

Marks against hours studied, for eight students. Fit the straight line that minimises the squared error, then use it.

# The smallest honest learner: fit a straight line to marks against hours studied,
# by least squares, and then predict. Twenty lines, no library.
DATA = [(2, 32), (3, 41), (4, 48), (5, 56), (6, 61), (7, 72), (8, 77), (9, 85)]

def fit(points):
    """Least squares: the line y = a + b*x that minimises the squared error."""
    n = len(points)
    mx = sum(x for x, _ in points) / n
    my = sum(y for _, y in points) / n
    sxy = sum((x - mx) * (y - my) for x, y in points)
    sxx = sum((x - mx) ** 2 for x, _ in points)
    b = sxy / sxx
    a = my - b * mx
    return a, b

a, b = fit(DATA)
print("training data: hours studied against marks out of 100")
for x, y in DATA:
    print("   %d hours -> %d marks" % (x, y))
print()
print("the fitted line: marks = %.3f + %.3f * hours" % (a, b))
print()
print("hours | actual | predicted | error")
total = 0.0
for x, y in DATA:
    pred = a + b * x
    err = y - pred
    total += err * err
    print("  %3d | %6d | %9.2f | %+6.2f" % (x, y, pred, err))
print("  mean squared error on the training data: %.3f" % (total / len(DATA)))
print()
print("and the point of it: a prediction for hours nobody studied")
for x in (1, 10, 12):
    print("   %2d hours -> %.1f marks" % (x, a + b * x))
print()
print("the last one is EXTRAPOLATION beyond the range of the data, and the")
print("model cannot know that marks stop at 100: at 12 hours it predicts %.1f." % (a + b * 12))
munotes.in235

What Machine Learning Is

training data: hours studied against marks out of 100
   2 hours -> 32 marks
   3 hours -> 41 marks
   4 hours -> 48 marks
   5 hours -> 56 marks
   6 hours -> 61 marks
   7 hours -> 72 marks
   8 hours -> 77 marks
   9 hours -> 85 marks

the fitted line: marks = 17.881 + 7.476 * hours

hours | actual | predicted | error
    2 |     32 |     32.83 |  -0.83
    3 |     41 |     40.31 |  +0.69
    4 |     48 |     47.79 |  +0.21
    5 |     56 |     55.26 |  +0.74
    6 |     61 |     62.74 |  -1.74
    7 |     72 |     70.21 |  +1.79
    8 |     77 |     77.69 |  -0.69
    9 |     85 |     85.17 |  -0.17
  mean squared error on the training data: 1.060

and the point of it: a prediction for hours nobody studied
    1 hours -> 25.4 marks
   10 hours -> 92.6 marks
   12 hours -> 107.6 marks

the last one is EXTRAPOLATION beyond the range of the data, and the
model cannot know that marks stop at 100: at 12 hours it predicts 107.6.

Everything Module 2 is about is visible in twenty lines.

The model is the two numbers, 17.881 and 7.476. Not the data: once fitted, the eight rows can be thrown away and the line still predicts.

Nothing was told to the program about studying. It does not know that hours cause marks, or which way round the relation should go. It found the line that fits.

The point is the last block. Nobody studied for 1, 10 or 12 hours, and the model answers anyway. Generalisation is the whole purpose: a model that only repeats its training data is a lookup table and has learned nothing.

And the last row is the honest warning. At 12 hours it predicts 107.6 marks. The model has no idea that a mark cannot exceed 100, because nobody told it and no training example was near 12 hours. Extrapolating beyond the range of the data is where a learned model fails silently, and it does so confidently.

munotes.in236

What Machine Learning Is

The three ingredients of any learning method

Every method in this module is these three choices, and naming them makes the module a single subject rather than a list of algorithms.

IngredientWhat it isIn the example above
The hypothesis spacethe set of models the method is willing to considerall straight lines
The loss functionhow badly a particular model fitssquared error
The optimisationhow the best model in the space is foundthe closed-form least-squares formula

A method is not better than another in general; it makes different choices here. A decision tree's hypothesis space is all trees; a neural network's is all settings of its weights. The Statistical Learning Framework states this properly, and it is worth knowing from the first chapter so the methods can be compared rather than merely collected.

Vocabulary

Defined once, and used unchanged for the rest of the module.

  • Instance or example: one row of data.
  • Feature or attribute: one measured quantity of an instance. Hours studied here.
  • Label or target: the answer being learned, where there is one. Marks here.
  • Training set: the examples the model is fitted to. Test set: examples held back to measure generalisation.
  • Model or hypothesis: what the learning produces.
  • Parameter: a number the model learns, such as 7.476. Hyperparameter: a number the designer chooses before learning, such as the degree of a polynomial.
  • Inference or prediction: using a fitted model on a new instance. Not the same "inference" as Module 1's logical inference, and the clash is unfortunate and standard.

Distinctions

Machine learningA program written by hand
The rule comes fromdataa person
Suitsa rule too complex to write, or unknown, or changinga known, simple, stable rule
Failssilently, on data unlike the training setvisibly, as a bug
Explains itselfonly with extra workyes, it is the code
ParameterHyperparameter
Chosen bythe learning algorithm, from datathe designer, before learning
Examplethe slope 7.476the degree of the polynomial
Tuned usingthe training seta validation set, never the test set
Training errorGeneralisation
Measured onthe data fitted todata never seen
Can be made zerousually, yesno
What mattersnot thisthis

What it does not mean

Machine learning is not the whole of AI. Module 1 contains no learning at all, and a minimax chess program learns nothing.

The model is not the data. It is a summary of it, and the data can be discarded after training.

munotes.in237

What Machine Learning Is

A low training error is not success. A model can fit its training data perfectly and be useless, which is Overfitting and Underfitting.

A learned model does not know when it is out of its depth. At 12 hours the line predicts 107.6 marks with no hesitation.

Learning does not discover causes. The line does not say hours cause marks. A model fitted to marks against shoe size would fit just as willingly.

"Inference" here is not Module 1's inference. Here it means using a fitted model to predict; there it meant deriving what follows from a knowledge base.

Quick revision

  • Machine learning: algorithms that improve at a task with experience. Mitchell: a program learns from experience E with respect to task T and measure P if its performance at T, measured by P, improves with E.
  • It is the learning element of The Learning Agent, and the answer to Module 1's unknown environment.
  • Module 1 assumes the model was supplied; Module 2 is how the model comes from data.
  • Use it when the rule is unknown, too complex, or changing; examples exist; and some errors are tolerable. Do not use it for a rule you can write in ten lines.
  • The worked line: marks = 17.881 + 7.476 * hours. The model is the two numbers; the data can be discarded.
  • Generalisation is the point. At 12 hours it predicts 107.6 marks, because nobody told it a mark stops at 100 and no example was near 12 hours. Extrapolation is where a learned model fails silently.
  • Three ingredients of any method: the hypothesis space, the loss function, the optimisation.
  • Vocabulary: instance, feature, label, training and test set, model, parameter (learned) against hyperparameter (chosen), prediction.

Test yourself

1. Give Mitchell's definition of learning and apply it to a spam filter. A program learns from experience E with respect to a task T and a performance measure P if its performance at T, as measured by P, improves with E. For a spam filter: the task is classifying a message as spam or not; the measure is the fraction classified correctly with a heavy penalty for losing wanted mail; and the experience is a mailbox of messages already labelled.

2. How does Module 2 relate to Module 1? It is the learning element of the learning agent introduced in Module 1. Module 1 assumes a model was supplied, whether a transition model, a set of rules or a set of probability tables, and Module 2 is how such a model is obtained from data. It is the response to an environment being unknown.

munotes.in238

What Machine Learning Is

3. When should machine learning not be used? When the rule is known and simple enough to write directly, since a learned model is then slower, larger, less reliable and harder to explain. And when errors cannot be tolerated and cannot be checked, since a learned model fails silently.

4. In the worked example, what exactly is the model, and what can be discarded? The model is the two numbers 17.881 and 7.476, the intercept and the slope. Once they are fitted the eight training rows can be discarded and the model still predicts.

5. The model predicts 107.6 marks for 12 hours of study. What has gone wrong, and what is the general lesson? Nothing has gone wrong inside the model; it has extrapolated beyond the range of its data. It was never told that a mark cannot exceed 100 and no training example was near 12 hours. The lesson is that a learned model fails silently and confidently outside the region its data covered.

6. Name the three ingredients of any learning method, with the example's values. The hypothesis space, here all straight lines; the loss function, here squared error; and the optimisation procedure, here the closed-form least-squares formula.

7. Distinguish a parameter from a hyperparameter, and say which data is used to set each. A parameter is a number the learning algorithm fits from the training data, such as the slope. A hyperparameter is chosen by the designer before learning, such as the degree of a polynomial, and is tuned on a validation set held out from the training data, never on the test set.

Contents This chapter on its own page

munotes.in239

Chapter Forty-Four

Supervised Learning

Syllabus topic Module 2, "supervised"

In one line

Supervised learning is learning from examples where somebody has already written down the right answer.

In the wording a student can write in an examination: supervised learning infers a function from a labelled training set, a collection of pairs in which each input is accompanied by the correct output. Formally, given examples of an unknown function, the learner returns a hypothesis approximating it. Where the output is a continuous number the task is regression; where it is one of a finite set of classes it is classification.

The shape of the problem

Four things, and a paper asking you to set up a supervised problem wants all four.

PartWhat it isIn the example
The inputa vector of features describing one instancehours studied
The labelthe correct output for that instancethe mark, or pass and fail
The training setmany input and label pairseight students
The hypothesis spacethe functions the learner may choose fromall straight lines, or all thresholds

The word supervised names the labels. A supervisor has already looked at each example and written the answer beside it, and that is the experience the learner gets. It is the most informative kind of feedback in the module and the most expensive to obtain.

Both kinds of answer, on one dataset

# Supervised learning, both kinds of answer, on the SAME eight students: predict
# the mark (regression) and predict pass or fail (classification).
DATA = [(2, 32), (3, 41), (4, 48), (5, 56), (6, 61), (7, 72), (8, 77), (9, 85)]
PASS_MARK = 50

def fit_line(points):
    n = len(points)
    mx = sum(x for x, _ in points) / n
    my = sum(y for _, y in points) / n
    b = (sum((x - mx) * (y - my) for x, y in points)
         / sum((x - mx) ** 2 for x, _ in points))
    return my - b * mx, b

a, b = fit_line(DATA)
print("REGRESSION: the label is a NUMBER, the mark.")
print("   model: marks = %.3f + %.3f * hours" % (a, b))
for h in (3.5, 6.5, 9.5):
    print("   %.1f hours -> %.1f marks" % (h, a + b * h))
print()
print("CLASSIFICATION: the label is a CLASS, pass or fail.")
labelled = [(x, "pass" if y >= PASS_MARK else "fail") for x, y in DATA]
print("   the training set, relabelled:")
print("      " + "  ".join("%d:%s" % (x, c) for x, c in labelled))
# the simplest possible classifier: one threshold on hours, chosen to make the
# fewest mistakes on the training data
best = None
for t in [i + 0.5 for i in range(1, 10)]:
    wrong = sum(1 for x, c in labelled
                if (c == "pass") != (x >= t))
    if best is None or wrong < best[1]:
        best = (t, wrong)
t, wrong = best
print("   model: pass if hours >= %.1f. it gets %d of %d training rows right."
      % (t, len(labelled) - wrong, len(labelled)))
for h in (3.5, 6.5, 9.5):
    print("   %.1f hours -> %s" % (h, "pass" if h >= t else "fail"))
print()
print("SAME data, SAME feature, two different tasks, and two different models.")
print("the difference is entirely in what the LABEL is.")
print()
print("and the two are related: the regression model, thresholded at %d marks," % PASS_MARK)
print("is itself a classifier. it says pass when %.3f + %.3f * hours >= %d," % (a, b, PASS_MARK))
print("that is when hours >= %.3f, so it agrees with the classifier above." % ((PASS_MARK - a) / b))
munotes.in240

Supervised Learning

REGRESSION: the label is a NUMBER, the mark.
   model: marks = 17.881 + 7.476 * hours
   3.5 hours -> 44.0 marks
   6.5 hours -> 66.5 marks
   9.5 hours -> 88.9 marks

CLASSIFICATION: the label is a CLASS, pass or fail.
   the training set, relabelled:
      2:fail  3:fail  4:fail  5:pass  6:pass  7:pass  8:pass  9:pass
   model: pass if hours >= 4.5. it gets 8 of 8 training rows right.
   3.5 hours -> fail
   6.5 hours -> pass
   9.5 hours -> pass

SAME data, SAME feature, two different tasks, and two different models.
the difference is entirely in what the LABEL is.

and the two are related: the regression model, thresholded at 50 marks,
is itself a classifier. it says pass when 17.881 + 7.476 * hours >= 50,
that is when hours >= 4.296, so it agrees with the classifier above.

One dataset, two tasks, and the only thing that changed is the label. The regression model is two numbers; the classification model is one. Neither is more supervised than the other.

And the closing paragraph is the connection worth carrying forward: a regression model with a threshold on its output is a classifier. The line predicts 50 marks at 4.296 hours, and the threshold classifier chose 4.5; they disagree only in the gap between two training points where nothing tells them apart. The Artificial Neuron and the Perceptron is exactly this idea with more features.

Where the labels come from, and what they cost

This is the practical limit of supervised learning and a paper can ask for it.

Labels are expensive. Somebody has to supply them. A medical image dataset needs a radiologist's time per image; a translation dataset needs a translator. This is the bottleneck, and it is the same bottleneck that defeated expert systems in Rule-Based Systems and Expert Systems, in a new form: there, the expert had to state the rule; here, the expert has to label the cases. The advantage is that labelling is far easier than rule-stating, which is precisely why machine learning displaced the earlier approach.

munotes.in241

Supervised Learning

Sometimes labels are free. Where the answer arrives later of its own accord, the labels cost nothing: whether a loan was repaid, whether a user clicked, what the next word in a sentence turned out to be. This is often called self-supervision when the label is taken from the data itself, and it is why language models can be trained on text with no annotator at all.

And labels can be wrong. A training set carries the mistakes and the opinions of whoever made it. A model fitted to it reproduces them faithfully, which is the mechanism behind most of Bias and Fairness in AI Models.

Inductive bias, which makes learning possible at all

A section worth its place because it answers "why can a learner say anything about a case it has not seen".

Eight training points and infinitely many functions pass through all eight. The learner chose a straight line, and the reason it did is that its hypothesis space contained only straight lines. Any restriction of that kind is called an inductive bias: the assumptions a learner makes beyond the data.

Without an inductive bias, no generalisation is possible. A learner willing to consider every function has no reason to prefer one that continues smoothly over one that returns zero everywhere off the training set. It would fit the training data perfectly and predict nothing. This is the substance of the no free lunch theorem: averaged over all possible problems, no learning algorithm beats any other, so every method's success comes from its assumptions matching the problem.

So a paper asking "what assumption does this method make" always has an answer. A straight line assumes the relation is linear. A decision tree assumes it is a series of axis-aligned splits. A k-nearest-neighbour model assumes nearby inputs have similar labels.

The assumption the data must satisfy

One more, and it is the one most often violated in practice.

Supervised learning assumes the training examples and the future cases are drawn from the same distribution, and usually that they are independent draws. The standard abbreviation is i.i.d., independent and identically distributed.

When the assumption fails, the model fails, and it fails without warning:

  • A spam filter trained on last year's mail meets this year's spam, which was written to defeat last year's filters. The distribution shifted.
  • A model of examination marks trained on one college's students is used at another with different teaching. The population differs.
  • The What Machine Learning Is line predicted 107.6 marks at 12 hours, which is outside the range the training data covered at all.
munotes.in242

Supervised Learning

Evaluating a Model measures generalisation by holding data back, and that measurement is only meaningful if the held-back data was drawn from the same distribution as the future cases. It is a real assumption, not a formality.

Where supervised learning sits among the three forms

SupervisedUnsupervisedReinforcement
The critic givesthe right answer for each casenothinga reward, possibly delayed
Data islabelled pairsunlabelled instancesexperience of acting
Cost of the datahigh, someone must labellowthe cost of acting in the world
Feedback isimmediate and exactabsentdelayed and partial
MU's models in itk-NN, decision trees, naive Bayes, SVM, neural networks, ensemblesclustering, association rulesMDPs and Q-learning

Most of MU's Module 2 is supervised, which reflects practice: it is the form with the most reliable methods and the clearest measure of success.

Distinctions

RegressionClassification
The label isa continuous numberone of a finite set of classes
Example herethe markpass or fail
Model heretwo numbers, a lineone number, a threshold
Scored bysquared errorfraction correct, and better measures
SupervisedUnsupervised
Labelspresentabsent
Success ismeasurable against the labelsmuch harder to define
Costlabellingnone
Inductive biasOverfitting
Isthe assumptions beyond the datafitting the noise as though it were signal
Too littleno generalisation at all
Too muchthe truth is not in the hypothesis space

What it does not mean

Supervised does not mean a person watches it learn. It means the training data carries the correct answers.

The two tasks are not different fields. They share the machinery; only the label's type differs, and a thresholded regression is a classifier.

Labels are not necessarily correct. They carry the opinions and mistakes of whoever wrote them, and the model reproduces both.

A learner with no assumptions is not more general. It cannot generalise at all, which is the no free lunch result.

Held-out data does not measure generalisation unconditionally. It does so only if it was drawn from the same distribution as the future cases.

More features are not automatically better. They enlarge the hypothesis space, which needs more data, and that is the curse of dimensionality met in k-NN for Regression, and What Limits the Method.

Quick revision

  • Supervised learning infers a function from a labelled training set of input and correct-output pairs. Continuous output: regression. A class: classification.
  • The four parts: input features, label, training set, hypothesis space.
  • On one dataset: the regression model is marks = 17.881 + 7.476 * hours; the classifier is pass if hours >= 4.5. Only the label changed.
  • A regression model with a threshold is a classifier. The line reaches 50 marks at 4.296 hours.
  • Labels are the bottleneck. Sometimes free (self-supervision, where the answer arrives later), often expensive, and sometimes wrong, which is where model bias begins.
  • Inductive bias is the assumption beyond the data, and without one no generalisation is possible (no free lunch). A line assumes linearity; a tree assumes axis-aligned splits; k-NN assumes nearby inputs have similar labels.
  • The data assumption: training and future cases are drawn from the same distribution, usually i.i.d. It fails under distribution shift, a different population, or extrapolation.
  • Most of MU's Module 2 is supervised.
munotes.in243

Supervised Learning

Test yourself

1. Define supervised learning and name its two kinds of task. Learning a function from a training set of input and correct-output pairs. Where the output is a continuous number the task is regression; where it is one of a finite set of classes it is classification.

2. In this chapter one dataset produced two models. What differed? Only the label. With the mark as label the learner fitted a line, marks = 17.881 + 7.476 * hours. With pass or fail as label it fitted a single threshold, pass if hours >= 4.5. The inputs and the training instances were identical.

3. Explain how a regression model can serve as a classifier. By thresholding its output. The fitted line reaches 50 marks at 4.296 hours, so predicting pass whenever the line's output is at least 50 is a classifier, and it agrees with the separately fitted threshold everywhere except in the gap between two training points.

4. What is the practical limitation of supervised learning, and give one case where it does not apply. That labels must be supplied, which usually costs expert time and is the bottleneck of the approach. It does not apply where the answer arrives by itself: whether a loan was repaid, whether a user clicked, or what the next word of a text turned out to be.

5. What is inductive bias, and why is it necessary? The assumptions a learner makes beyond the data, embodied in the set of hypotheses it is willing to consider. It is necessary because infinitely many functions fit any finite training set, so without a restriction there is no reason to prefer one, and no generalisation is possible. This is the substance of the no free lunch result.

6. State the assumption supervised learning makes about the data, and give two ways it fails. That the training examples and the future cases come from the same distribution, usually as independent draws. It fails under distribution shift, as when a spam filter meets spam written to defeat it, and when the model is applied to a different population, or extrapolated beyond the range the training data covered.

munotes.in244

Supervised Learning

7. How do the three forms of learning differ in the feedback they receive? Supervised learning receives the correct answer for each case. Unsupervised learning receives no feedback at all, only the instances. Reinforcement learning receives a reward, which says how good an outcome was but not what the right action would have been, and which may arrive long after the action.

Contents This chapter on its own page

munotes.in245

Chapter Forty-Five

Unsupervised Learning

Syllabus topic Module 2, "unsupervised"

In one line

Unsupervised learning is looking for structure in data that nobody has labelled, so there is no right answer to be checked against.

In the wording a student can write in an examination: unsupervised learning infers structure from a training set of unlabelled instances. There is no target output and no critic, so success cannot be measured against a correct answer; the learner is instead judged by whether the structure it finds is useful or meaningful. The principal tasks are clustering, association rule mining, dimensionality reduction and anomaly detection.

What it means to have no labels

The definition is easiest to see as what is missing from Supervised Learning.

SupervisedUnsupervised
Each example carriesan input and its correct outputan input only
The learner is askedpredict the outputfind structure
Error isthe difference from the labelnot defined
Success ismeasurable, exactlya judgement, usually
The criticsupplies the answerdoes not exist

The third and fourth rows are the whole difficulty. With no label there is no error to minimise, so there is no obvious objective and no obvious way to tell a good result from a bad one. Every unsupervised method therefore has to invent an objective, and different inventions give different answers on the same data. Hierarchical Clustering, and Judging a Clustering is where that is taken seriously.

The four things it is used for

A paper asking what unsupervised learning does wants these, and an example of each.

Clustering. Group the instances so that those in a group are more like each other than like those in other groups. Segmenting students by study pattern; grouping news articles by topic. Clustering and k-Means is MU's label for it.

Association rule mining. Find which things occur together. Which items are bought in the same basket. Support, Confidence and Lift and The Apriori Algorithm are MU's labels.

Dimensionality reduction. Describe each instance with fewer numbers while losing as little as possible. A hundred measurements of a student reduced to three that capture most of the variation, which makes everything downstream cheaper and often works better. Not on MU's label; named here because it is one of the four and a paper may ask for the list.

Anomaly detection. Find the instances unlike the rest. A transaction unlike any the cardholder has made before. It is unsupervised precisely because nobody has a labelled set of every kind of fraud that might be invented tomorrow.

Why it is worth doing when it cannot be scored

Three honest reasons, and they are why the row exists at all.

The data is there and the labels are not. Almost all data is unlabelled. A shop's till records exist whether or not anyone has classified the baskets. Using them requires a method that does not need labels.

munotes.in246

Unsupervised Learning

It is a step before supervised learning. Clustering can suggest what the classes should be; dimensionality reduction can shrink the input to something a supervised model can learn from with the data available. Much practical unsupervised work is preparation rather than an end in itself.

The structure itself is the answer. A shop wanting to know which products sell together is not predicting anything. Support, Confidence and Lift produces the answer directly.

What makes it hard, stated plainly

Three difficulties, and a paper can ask for any of them.

There is no correct answer to compare with. Two clusterings of the same customers, one by spending and one by region, can both be defensible. Which is better depends on what the clustering is for, and the algorithm was not told.

A structure is always found. Run k-means asking for four clusters on data with no groups in it at all, and it returns four clusters. The method cannot report that there was nothing there. That is the single most dangerous property of unsupervised learning and it is why Hierarchical Clustering, and Judging a Clustering insists on asking whether a clustering means anything before using it.

The number of groups is usually a hyperparameter. k-means must be told k. Choosing it is a judgement, and the standard devices, the elbow and the silhouette, are measurements rather than proofs.

Semi-supervised and self-supervised, named once

Neither is on MU's label and both come up, so one line each prevents confusion.

Semi-supervised learning uses a small labelled set together with a large unlabelled one. The unlabelled data reveals the shape of the input distribution, and the few labels say which part of it is which. It suits exactly the common situation where labels are expensive and raw data is free.

Self-supervised learning manufactures labels from the data itself: hide a word in a sentence and predict it, hide part of an image and predict that. The data was unlabelled and the task is then supervised, so it is a way of turning an unsupervised situation into a supervised one. It is how modern language models are trained, and it is worth knowing that the distinction between supervised and unsupervised is about the data, not about the machinery.

Distinctions

ClusteringClassification
Classes arediscoveredgiven in advance by the labels
Dataunlabelledlabelled
Right answernone to check againstthe label
Resultgroups with no namesa prediction of a known class
UnsupervisedSemi-supervisedSelf-supervised
Labelsnonea fewmade from the data itself
Then trained asunsupervisedboth togethersupervised
Anomaly detectionClassification of fraud
Needs examples of the bad classnoyes
Handles a kind never seen beforeyesno
Defines abnormal asunlike the restlike the labelled bad examples
munotes.in247

Unsupervised Learning

What it does not mean

Unsupervised does not mean unguided. The method's objective, its distance measure and its number of groups are all chosen by the designer, and they decide the answer.

No labels does not mean no assumptions. k-means assumes clusters are roughly round and of similar size. Change the assumption and the groups change.

Finding clusters does not mean clusters exist. The algorithm returns k groups whether or not the data has any.

It is not a weaker form of supervised learning. It answers different questions. "Which products sell together" has no label to predict.

Self-supervised learning is not unsupervised. The data is unlabelled and the task manufactured from it is supervised.

Quick revision

  • Unsupervised learning finds structure in unlabelled data. No critic, no target, no error to minimise, so each method must invent an objective.
  • Four tasks: clustering, association rule mining, dimensionality reduction, anomaly detection.
  • Why it is used: most data is unlabelled; it is a preparation step for supervised learning; and sometimes the structure is the answer.
  • Three difficulties: no correct answer to compare with; a structure is always found, even in data with none; and the number of groups is a hyperparameter.
  • Semi-supervised: a few labels with much unlabelled data. Self-supervised: labels manufactured from the data, after which the task is supervised.
  • Clustering discovers the classes; classification is given them.
  • Anomaly detection needs no examples of the bad class, which is why it handles kinds of fraud nobody has seen.

Test yourself

1. Define unsupervised learning and say what is missing compared with supervised learning. Learning structure from a training set of unlabelled instances. What is missing is the label on each example, so there is no target output, no critic, and no error that can be computed against a correct answer.

2. Name the four principal unsupervised tasks with an example of each. Clustering, such as grouping students by study pattern. Association rule mining, such as finding which products are bought together. Dimensionality reduction, such as describing each student with three numbers instead of a hundred. And anomaly detection, such as flagging a transaction unlike any the cardholder has made.

3. Why is unsupervised learning hard to evaluate? Because there is no correct answer to compare against. Two different groupings of the same data can both be defensible, and which is better depends on the purpose, which the algorithm was never told.

4. What is the most dangerous property of clustering, and what follows from it? That a structure is always found. Asked for four clusters in data with no groups at all, the algorithm returns four clusters and cannot report that there was nothing there. It follows that a clustering must be judged before it is used, not merely computed.

munotes.in248

Unsupervised Learning

5. Give three reasons unsupervised learning is worth doing despite the difficulty of scoring it. Most data is unlabelled, so a method that needs no labels is the only one available. It often serves as preparation for supervised learning, by suggesting classes or by reducing the input. And sometimes the structure found is itself the answer, as when a shop wants to know which products sell together.

6. Distinguish clustering from classification. Clustering discovers groups in unlabelled data and the groups have no names. Classification predicts one of a set of classes fixed in advance by the labels in the training data, and its accuracy can be measured against those labels.

7. Is self-supervised learning a form of unsupervised learning? Explain. The data is unlabelled, so the situation is unsupervised, but a label is manufactured from the data itself, such as hiding a word and predicting it. The task that is then trained is supervised. The distinction between supervised and unsupervised concerns whether labels were supplied with the data, not the machinery used afterwards.

Contents This chapter on its own page

munotes.in249

Chapter Forty-Six

Reinforcement Learning: The Third Form

Syllabus topic Module 2, "reinforcement"

In one line

Reinforcement learning is learning from a score rather than from an answer: the agent is told how well it did, not what it should have done.

In the wording a student can write in an examination: in reinforcement learning an agent interacts with an environment, taking actions in states and receiving a numerical reward. It is not told the correct action; it must discover which actions yield the most reward by trying them. Two features distinguish it: the reward may be delayed, so an action's value depends on consequences far in the future, which is the credit assignment problem; and the agent's actions determine what data it sees, so it must balance exploration against exploitation.

What the feedback is

The difference from the other two forms is entirely in what the critic says, and it is worth stating three times over.

The agent does something, and the critic saysThe form
"the right answer was 7"supervised
nothing at allunsupervised
"that was worth 3 points"reinforcement

A reward says how good the outcome was, not what should have been done instead. That is a much weaker signal than a label. Told that a chess move scored badly, the agent does not learn which move was better; it learns only that this one was poor, and must try others to find out.

The two things that make it a different problem

The reward is delayed. A move in chess is followed by fifty more before the game is won or lost, and only then does a reward arrive. Which of the fifty deserves the credit? That is the credit assignment problem, and it does not arise in supervised learning at all, where the label arrives with the example.

The agent generates its own data. A supervised learner is handed a training set. A reinforcement learner sees only the consequences of the actions it chose, so a good action never tried is never learned about. It must sometimes take an action it believes is worse, purely to find out. That is the exploration against exploitation problem from The Learning Agent, and Q-Learning is where it becomes a concrete rule.

Where it fits, and where it does not

A paper can ask when reinforcement learning is the right choice, and the answer has conditions.

It suits a problem where the right action is not known but the outcome can be scored, where the agent can act repeatedly and cheaply, and where actions have consequences that unfold over time. Games, control, scheduling, resource allocation.

It does not suit a problem where acting is expensive or dangerous, because it learns by trying and its early attempts are bad. A reinforcement learner cannot be let loose on a real patient, a real vehicle or a real power station to find out what happens. The standard answer is a simulator, and the standard failure is that the simulator differs from reality in some way that matters.

munotes.in250

Reinforcement Learning: The Third Form

The three forms, in one table

This is the answer to MU's Forms of learning (supervised, unsupervised, reinforcement) label, and it is the table to reproduce.

SupervisedUnsupervisedReinforcement
The critic givesthe correct outputnothinga numerical reward
Datalabelled pairsunlabelled instancesexperience the agent generated
Feedback timingimmediatenonepossibly much delayed
The agent chooses its own datanonoyes
Central difficultyobtaining labelsno way to score a resultcredit assignment, and exploration
Goalpredict the labelfind structuremaximise total reward over time
MU's methodsk-NN, trees, naive Bayes, SVM, networks, ensemblesclustering, association rulesMDPs, Q-learning

And the one-line version worth memorising: supervised learning is told the answer, unsupervised learning is told nothing, and reinforcement learning is told the score.

Its relation to Module 1

The cross-module link, and a likely Q.3.

The Utility-Based Agent maximised expected utility over outcomes whose probabilities it was given. Reinforcement learning is that agent when nobody gave it the probabilities or the utilities: it must estimate both from experience. Markov Decision Processes sets out the problem when the model IS known, and Q-Learning solves it when it is not.

So reinforcement learning is not a third kind of prediction. It is a decision problem, and it is the only part of Module 2 that inherits directly from Module 1's agent framework rather than from its data.

Distinctions

A rewardA label
Sayshow good the outcome waswhat the correct output was
Tells you the right actionnoyes
Can arrive lateyesno
Fromthe environmentan annotator
Reinforcement learningSupervised learning
Who chose the datathe agent, by actingsomebody else, in advance
A good action never tried isnever learnedirrelevant, the data is fixed
Needs explorationyesno
Credit assignmentExploration against exploitation
The problemwhich of many past actions earned this rewardtake the best known action, or an informative one
Becausethe reward is delayedthe agent generates its own data
Solved in this book bythe value of a state, Markov Decision Processesepsilon-greedy, Q-Learning

What it does not mean

A reward is not a label. It scores an outcome and does not name a correct action.

Reinforcement learning is not trial and error without structure. It estimates the value of states and actions, and the estimate is what improves.

Delayed reward is not a minor complication. It is the defining difficulty, and the reason a whole row of MU's syllabus is given to it.

munotes.in251

Reinforcement Learning: The Third Form

Exploration is not noise. It is a deliberate, sometimes costly choice to act suboptimally in order to learn.

It is not always applicable. Where acting is expensive or dangerous it cannot learn by trying, and a simulator is needed, with all the risk of the simulator being wrong.

Quick revision

  • Reinforcement learning: an agent acts in states, receives a numerical reward, and must discover which actions yield the most reward over time.
  • The reward says how good, not what was right. A much weaker signal than a label.
  • Two defining difficulties: credit assignment, because the reward is delayed; and exploration against exploitation, because the agent generates its own data.
  • Supervised is told the answer, unsupervised is told nothing, reinforcement is told the score. Three kinds of critic.
  • Suits problems where the right action is unknown but the outcome can be scored and acting is cheap and repeatable. Unsuitable where acting is dangerous or expensive; a simulator is then used, and may differ from reality.
  • It is The Utility-Based Agent with the probabilities and utilities unknown. Markov Decision Processes is the known-model case, Q-Learning the unknown one.
  • It is a decision problem, not a prediction problem, and the only part of Module 2 inheriting from Module 1's agent framework.

Test yourself

1. Define reinforcement learning and say what the agent receives. An agent takes actions in states of an environment and receives a numerical reward. It is not told the correct action; it must discover by trying which actions yield the greatest total reward over time.

2. How does a reward differ from a label? A label states the correct output for an example. A reward states how good an outcome was, without saying which action would have been better, and it may arrive long after the action that earned it.

3. What is the credit assignment problem, and why does it not arise in supervised learning? When a reward arrives after a long sequence of actions, it is not clear which of them deserves the credit or blame. It does not arise in supervised learning because the correct output arrives with each example, so the feedback is attached to the case it concerns.

4. Why must a reinforcement learner explore? Because it sees only the consequences of the actions it takes, so an action it never tries is never learned about. Occasionally acting against its current belief is the only way to discover something better.

5. Give the three forms of learning in terms of the critic. Supervised learning has a critic that supplies the correct answer. Unsupervised learning has no critic at all. Reinforcement learning has a critic that supplies a numerical reward, which says how good the outcome was and nothing more.

munotes.in252

Reinforcement Learning: The Third Form

6. When is reinforcement learning unsuitable, and what is the usual workaround? When acting is expensive or dangerous, because the method learns by trying and its early attempts are poor. The usual workaround is to train in a simulator, with the standing risk that the simulator differs from reality in a way that matters.

7. How does reinforcement learning relate to the utility-based agent of Module 1? The utility-based agent maximises expected utility using probabilities and utilities it was given. Reinforcement learning is the same objective when neither has been given, so both must be estimated from experience. Markov decision processes handle the case where the model is known, and Q-learning the case where it is not.

Contents This chapter on its own page

munotes.in253

Chapter Forty-Seven

Parametric and Nonparametric Models

Syllabus topic Module 2, "Parametric vs Nonparametric"

In one line

A parametric model boils the data down to a fixed handful of numbers and then throws the data away; a nonparametric model keeps the data and consults it every time.

In the wording a student can write in an examination: a parametric model summarises the training data in a fixed, finite number of parameters chosen before the data is seen; the size of the model does not grow with the amount of data. A nonparametric model has a number of parameters that grows with the training set, so it retains more of the data and can represent a wider range of functions. The distinction is about how model complexity relates to data size, not about whether parameters exist.

The two on one dataset

Eight students, hours studied against marks.

The parametric model is the straight line of What Machine Learning Is: marks = 17.881 + 7.476 * hours. Two numbers. Fit them, discard the eight rows, and the model still predicts.

The nonparametric model is nearest neighbour: to predict for a new number of hours, find the closest student in the training set and return their mark. No numbers are fitted at all, and the whole training set is the model.

# Parametric against nonparametric, on the SAME eight students, with the memory
# and the prediction cost of each COUNTED rather than described.
DATA = [(2, 32), (3, 41), (4, 48), (5, 56), (6, 61), (7, 72), (8, 77), (9, 85)]

def fit_line(points):
    n = len(points)
    mx = sum(x for x, _ in points) / n
    my = sum(y for _, y in points) / n
    b = (sum((x - mx) * (y - my) for x, y in points)
         / sum((x - mx) ** 2 for x, _ in points))
    return my - b * mx, b

a, b = fit_line(DATA)

def parametric(h):
    """Two numbers. The data is not consulted."""
    return a + b * h, 0                       # (prediction, rows examined)

def nonparametric(h):
    """The whole training set IS the model. Every row is examined."""
    best = min(DATA, key=lambda row: abs(row[0] - h))
    return float(best[1]), len(DATA)

print("the parametric model is two numbers: %.3f and %.3f" % (a, b))
print("the nonparametric model is all %d rows of the training data" % len(DATA))
print()
print(" hours | parametric | rows read | nonparametric | rows read")
for h in (2.0, 4.5, 6.5, 9.0, 12.0):
    p, pr = parametric(h)
    q, qr = nonparametric(h)
    print("  %4.1f | %10.1f | %9d | %13.1f | %9d" % (h, p, pr, q, qr))
print()
print("what each costs, as the training set grows:")
print("   n rows | parametric: numbers stored | nonparametric: numbers stored")
for n in (8, 100, 10000, 1000000):
    print("  %7d | %26d | %29d" % (n, 2, 2 * n))
print()
print("and the cost of ONE prediction:")
print("   parametric:    2 multiplications, whatever n is")
print("   nonparametric: n comparisons, growing with the data")
print()
print("at 12 hours the parametric model says %.1f, which is impossible," % parametric(12.0)[0])
print("and the nonparametric model says %.1f, the nearest student it has."
      % nonparametric(12.0)[0])
print("neither is right. they are wrong in DIFFERENT ways, and that is the trade.")
munotes.in254

Parametric and Nonparametric Models

the parametric model is two numbers: 17.881 and 7.476
the nonparametric model is all 8 rows of the training data

 hours | parametric | rows read | nonparametric | rows read
   2.0 |       32.8 |         0 |          32.0 |         8
   4.5 |       51.5 |         0 |          48.0 |         8
   6.5 |       66.5 |         0 |          61.0 |         8
   9.0 |       85.2 |         0 |          85.0 |         8
  12.0 |      107.6 |         0 |          85.0 |         8

what each costs, as the training set grows:
   n rows | parametric: numbers stored | nonparametric: numbers stored
        8 |                          2 |                            16
      100 |                          2 |                           200
    10000 |                          2 |                         20000
  1000000 |                          2 |                       2000000

and the cost of ONE prediction:
   parametric:    2 multiplications, whatever n is
   nonparametric: n comparisons, growing with the data

at 12 hours the parametric model says 107.6, which is impossible,
and the nonparametric model says 85.0, the nearest student it has.
neither is right. they are wrong in DIFFERENT ways, and that is the trade.

What each is wrong about

Read the last two lines of the output, because they are the honest comparison.

At 12 hours, beyond anything in the data, the parametric model extrapolates its line and predicts a mark above 100, which is impossible. The nonparametric model returns the mark of the nearest student it has, 85 at 9 hours, and refuses to extrapolate at all.

Neither is right, and they are wrong in opposite directions. The line assumes the relation continues; the neighbour assumes nothing beyond its data and therefore says nothing new. That is the trade in one example, and it is worth more than any list of properties.

The trade, set out

ParametricNonparametric
Number of parametersfixed, chosen in advancegrows with the data
Training data after fittingcan be discardedmust be kept
Memoryconstantproportional to n
Training costusually higher, an optimisationoften nothing at all
Prediction costconstant and smallgrows with n
Assumes a form for the functionyes, and it may be wrongno
With little databetter: the assumption substitutes for dataworse: too few neighbours to trust
With a great deal of datalimited by its own formbetter: it can represent anything
Biashigh, if the form is wronglow
Variancelowhigh
Extrapolatesyes, confidently and often wronglyno
Examples in MU's listlinear models, naive Bayes, a neural network of fixed sizek-NN, a decision tree grown to fit, kernel SVM
munotes.in255

Parametric and Nonparametric Models

The two rows on bias and variance are the connection to the next chapter. A parametric model's fixed form is exactly a restriction on its hypothesis space, so it has high bias and low variance. A nonparametric model has almost no restriction, so low bias and high variance. Bias and Variance measures both.

The misconception in the name

Nonparametric does not mean "has no parameters". k-nearest neighbours has a parameter, k. A decision tree has one parameter per split, and often many. A kernel SVM has one weight per support vector.

What the word actually means is that the number of parameters is not fixed in advance: it grows with the training set, so the model's capacity grows as more data arrives. The precise reading of the term is "not characterised by a fixed, finite set of parameters", and a paper that asks you to define it wants exactly that.

A second, related misreading: nonparametric does not mean assumption-free. k-NN assumes that nearby inputs have similar outputs, which is a strong assumption and is false wherever the function jumps. Every method has an inductive bias, as Supervised Learning established.

Which to choose

A paper asking "when would you use each" expects the conditions, not a preference.

Choose parametric when the data is limited, when the form of the relation is known or can be assumed with confidence, when prediction must be fast or must run on a small device, when the model must be inspected or explained, and when the fitted model has to be transported without the data.

Choose nonparametric when there is plenty of data, when the form of the relation is unknown or clearly not simple, when training must be cheap or the model must absorb new examples continuously, and when accuracy matters more than prediction speed.

And the honest middle. Most of MU's models can be pushed either way. A decision tree is nonparametric when grown freely and effectively parametric when its depth is capped. A neural network of fixed architecture is parametric; adding layers as data arrives makes it nonparametric. The distinction is about how capacity relates to data, so it is a property of how a method is used as much as of the method.

Distinctions

ParametricNonparametric
Model sizefixedgrows with n
Keeps the training datanoyes
Assumes a functional formyesno
Bias and variancehigh bias, low variancelow bias, high variance
munotes.in256

Parametric and Nonparametric Models

"Nonparametric" as commonly misreadWhat it means
Has no parametersnot fixed in NUMBER in advance
Makes no assumptionsstill has an inductive bias, such as nearby means similar
Instance-based, or lazyModel-based, or eager
Training doesalmost nothingthe work
Prediction doesthe workalmost nothing
Examplek-NNa fitted line
Usuallynonparametricparametric

What it does not mean

Nonparametric does not mean without parameters. It means the number of them is not fixed in advance.

Nonparametric does not mean without assumptions. k-NN assumes nearby inputs have similar labels.

Parametric does not mean simple. A neural network with a billion weights is parametric, because the count was fixed before training.

Neither is better. With little data the parametric model's assumption is an advantage; with a great deal of data it becomes the limit.

The distinction is not fixed per algorithm. A depth-capped decision tree behaves parametrically; a freely grown one does not.

Keeping the data is not only a memory cost. It is also a privacy and a deployment cost: a nonparametric model cannot be shipped without shipping the training data with it.

Quick revision

  • Parametric: a fixed number of parameters, chosen before seeing the data; the data can be discarded after fitting. Nonparametric: the number of parameters grows with the training set, so the data must be kept.
  • The distinction is about capacity against data size, not about whether parameters exist.
  • On the eight students: the line is two numbers; nearest neighbour is all eight rows, and reads every one for each prediction.
  • At 12 hours the line predicts an impossible mark and the neighbour returns its nearest student's mark. Wrong in opposite directions: one extrapolates, the other refuses to.
  • Parametric: high bias, low variance, better with little data, constant memory and fast prediction. Nonparametric: low bias, high variance, better with much data, memory and prediction cost growing with n.
  • Nonparametric does not mean no parameters (k-NN has k, a tree has one per split) and does not mean no assumptions (k-NN assumes nearby means similar).
  • MU's examples: parametric are linear models, naive Bayes, a fixed neural network; nonparametric are k-NN, a freely grown decision tree, a kernel SVM.
  • Lazy or instance-based methods do nothing at training and the work at prediction; eager methods do the reverse.

Test yourself

1. Define parametric and nonparametric models. A parametric model has a fixed, finite number of parameters chosen before the data is seen, so its size does not grow with the data. A nonparametric model has a number of parameters that grows with the training set, so its capacity increases as more data arrives.

2. On the eight-student example, what is each model, and what does each cost? The parametric model is two numbers, the intercept and the slope, and predicting costs two multiplications whatever the data size. The nonparametric model is all eight rows, it stores two numbers per row, and predicting requires examining every row.

munotes.in257

Parametric and Nonparametric Models

3. At 12 hours of study the two models disagree. What does each do, and what does that show? The line extrapolates and predicts a mark above 100, which is impossible. The nearest neighbour returns the mark of the closest student it has, 85 at nine hours, and cannot go beyond its data. Both are wrong, in opposite ways: one assumes the relation continues, the other assumes nothing at all.

4. Correct the statement "nonparametric models have no parameters". They have parameters, often many: k-nearest neighbours has k, a decision tree has one per split, a kernel support vector machine has a weight per support vector. What is not fixed in advance is the number of them, which grows with the training set.

5. Relate the distinction to bias and variance. A parametric model's fixed form restricts the hypothesis space, giving high bias and low variance. A nonparametric model imposes little restriction, giving low bias and high variance. That is why parametric models are better with little data and nonparametric ones with a great deal.

6. When would you choose a parametric model? When data is limited, when the form of the relation is known or safely assumed, when prediction must be fast or run on a small device, when the model must be explained, or when it must be deployed without shipping the training data.

7. Is a decision tree parametric or nonparametric? Justify. It depends on how it is used. Grown freely until the leaves are pure, it adds parameters as the data grows and is nonparametric. With its depth capped in advance, its size is bounded regardless of the data and it behaves parametrically. The distinction concerns how capacity relates to data size, which is partly a matter of how a method is used.

Contents This chapter on its own page

munotes.in258

Chapter Forty-Eight

Bias and Variance

Syllabus topic Module 2, "variance tradeoff"

In one line

Bias is being wrong in the same direction every time, variance is being wrong in a different direction every time, and you cannot reduce both by changing how flexible the model is.

In the wording a student can write in an examination: for a model fitted to a random training sample, the expected squared error at a point decomposes into three parts:

expected error = bias squared + variance + irreducible noise

Bias is the difference between the average prediction, over many training samples, and the truth; it measures error due to the model's assumptions. Variance is how much the prediction changes from one training sample to another; it measures sensitivity to the particular data. Irreducible noise belongs to the process and no model removes it. Increasing a model's flexibility lowers bias and raises variance, which is the bias-variance tradeoff.

The three parts, in words

A paper asks for these separately, so each gets its own sentence.

Bias is a systematic error. Fit a straight line to data that genuinely curves, and the line is too low in the middle and too high at the ends every single time, whatever sample you give it. The error does not average out over samples, because it is the same error each time.

Variance is an unsystematic error. Fit a degree nine polynomial to twelve points, and it chases the noise in those particular twelve; give it a different twelve and it chases different noise, producing a very different curve. Averaged over samples the errors cancel; on any one sample they do not.

Irreducible noise is the part of the observation that no function of the input could predict. Marks depend on things other than hours studied: how the student slept, which questions came up. No model can reduce this, and a model that appears to has fitted noise, which is the next chapter.

Measuring it

The process is a gentle curve with noise on it. The program draws 200 training samples of twelve points each, fits a polynomial of a given degree to every one, and looks at the predictions all 200 fits make at a single point.

# Bias and variance, MEASURED. The same model family is fitted to many resamples
# of one noisy process, and the two quantities are computed from the fits.
# Read against Geman, Bienenstock and Doursat 1992.
def lcg(seed):
    """A deterministic generator, so the book's printed run is reproducible."""
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

def truth(x):
    """The process being learned: a gentle curve."""
    return 40 + 6.0 * x - 0.30 * x * x

def sample(rng, n=12):
    """n noisy observations of it, at x = 1 .. n."""
    out = []
    for i in range(1, n + 1):
        noise = (rng() + rng() + rng() - 1.5) * 8      # zero-mean, spread 8
        out.append((float(i), truth(i) + noise))
    return out

def fit_poly(points, degree):
    """Least squares by the normal equations, solved with Gaussian elimination."""
    m = degree + 1
    A = [[sum(x ** (i + j) for x, _ in points) for j in range(m)] for i in range(m)]
    b = [sum(y * x ** i for x, y in points) for i in range(m)]
    for c in range(m):                                  # Gaussian elimination
        piv = max(range(c, m), key=lambda r: abs(A[r][c]))
        A[c], A[piv] = A[piv], A[c]
        b[c], b[piv] = b[piv], b[c]
        for r in range(m):
            if r == c or A[c][c] == 0:
                continue
            f = A[r][c] / A[c][c]
            for k in range(c, m):
                A[r][k] -= f * A[c][k]
            b[r] -= f * b[c]
    return [b[i] / A[i][i] if A[i][i] else 0.0 for i in range(m)]

def predict(coef, x):
    return sum(c * x ** i for i, c in enumerate(coef))

TRIALS = 200
AT = 6.5                                   # the point where bias and variance are measured
gen = lcg(2024)
rng = lambda: next(gen)                    # noqa: E731

print("the true process at x = %.1f is %.3f" % (AT, truth(AT)))
print()
print("degree | mean prediction | bias^2  | variance | bias^2 + variance")
print("-------|-----------------|---------|----------|------------------")
for degree in (0, 1, 2, 5, 9):
    preds = []
    for _ in range(TRIALS):
        preds.append(predict(fit_poly(sample(rng), degree), AT))
    mean = sum(preds) / TRIALS
    bias2 = (mean - truth(AT)) ** 2
    var = sum((p - mean) ** 2 for p in preds) / TRIALS
    print("   %d   | %15.3f | %7.3f | %8.3f | %17.3f"
          % (degree, mean, bias2, var, bias2 + var))
print()
print("degree 0 is a flat line: its prediction is far from the truth every time,")
print("so the BIAS is large and the VARIANCE is small.")
print("degree 9 passes through all 12 points: its average is close to the truth,")
print("so the BIAS is small, and it swings wildly from sample to sample.")
print("degree 2 is the shape of the truth, and both are small.")
munotes.in259

Bias and Variance

the true process at x = 6.5 is 66.325

degree | mean prediction | bias^2  | variance | bias^2 + variance
-------|-----------------|---------|----------|------------------
   0   |          62.710 |  13.067 |    1.257 |            14.324
   1   |          62.862 |  11.989 |    1.346 |            13.335
   2   |          66.303 |   0.000 |    3.342 |             3.342
   5   |          66.162 |   0.027 |    5.031 |             5.057
   9   |          66.252 |   0.005 |    8.784 |             8.789

degree 0 is a flat line: its prediction is far from the truth every time,
so the BIAS is large and the VARIANCE is small.
degree 9 passes through all 12 points: its average is close to the truth,
so the BIAS is small, and it swings wildly from sample to sample.
degree 2 is the shape of the truth, and both are small.
munotes.in260

Bias and Variance

Read the two middle columns in opposite directions. Bias squared falls: 13.067, 11.989, 0.000, 0.027, 0.005. Variance rises: 1.257, 1.346, 3.342, 5.031, 8.784. That is the tradeoff, as arithmetic.

Three rows deserve naming.

Degree 0 is a flat line. It predicts about 62.7 whatever sample it is given, and the truth is 66.3. It is wrong by the same amount every time, so its bias is large and its variance is nearly nothing. This is underfitting.

Degree 9 passes through almost every one of the twelve points. Averaged over 200 samples its prediction is 66.252, very close to the truth, so its bias is tiny. But its variance is 8.784, seven times degree 2's: on any single sample it is wildly off, in a direction decided by that sample's noise. This is overfitting.

Degree 2 is the shape of the truth, so its bias is 0.000 to three places and its variance is the smallest that a curve-shaped model can have. Its total, 3.342, is the least of the five. The best model is not the most flexible nor the simplest; it is the one whose flexibility matches the problem.

The decomposition, and where it comes from

A paper may ask for the derivation in outline. Write y = f(x) + e for the true process with zero-mean noise e, and g(x) for the model fitted to one random training sample. The expected squared error at x, over both the noise and the choice of training sample, is

E[(y - g(x))2] = (E[g(x)] - f(x))2 + E[(g(x) - E[g(x)])2] + E[e2]

= bias squared + variance + irreducible noise

The middle step is the standard trick of adding and subtracting E[g(x)] inside the square; the cross term vanishes because E[g(x) - E[g(x)]] is zero, and the noise term separates because the noise is independent of the training sample.

Three things follow and each is examinable. The three parts are non-negative, so none can be traded below zero. The noise term is a property of the process, not of the model, so the best achievable error is not zero. And the decomposition is an expectation over training samples, so bias and variance are not observable on one dataset: you cannot point at a single fitted model and read off its variance.

What changes each

The practical table, and what a question about reducing error is really asking.

munotes.in261

Bias and Variance

To reduceDoCost
Biasa more flexible model; more or better features; a model family matching the problemvariance rises
Variancemore training data; regularization; averaging several models; fewer featuresbias may rise
Noisenothing a model can do; measure better, or add a feature that explains it

More data is the one lever that reduces variance without raising bias, which is why it is always the first answer. It does nothing for bias: a straight line fitted to a curve stays a straight line however many points it sees.

And the two that come later in this module are both variance reductions. Regularization shrinks the fit's freedom. Ensemble Methods, Bagging and the Random Forest averages many high-variance models, so their unsystematic errors cancel; that is exactly why bagging helps a deep tree and does almost nothing for a linear model.

What the dilemma actually says

Geman, Bienenstock and Doursat call it a dilemma rather than a tradeoff, and the stronger word is deliberate. With a fixed amount of data, reducing one raises the other, so error cannot be driven to zero by choosing a cleverer model family alone.

The honest modern qualification, which a good answer mentions: very large models trained on very large datasets have been observed to behave less simply than the classic curve suggests, with test error falling again past the point where the model can fit its training data exactly. This book does not measure that and does not assert it, and MU's label is the classical tradeoff, which the table above demonstrates. The classical account is what is examined and it is correct for the regime a student will work in.

Distinctions

BiasVariance
Error issystematic, the same direction each timeunsystematic, a different direction each time
Caused bythe model's assumptions being wrongsensitivity to the particular sample
Averaging over samplesdoes not remove itremoves it
High when the model istoo rigidtoo flexible
In the table, degree 013.0671.257
In the table, degree 90.0058.784
UnderfittingOverfitting
Biashighlow
Variancelowhigh
Training errorhighlow
Test errorhighhigh
The curemore flexibilityless, or more data
ReducibleIrreducible
Which partsbias and variancethe noise
Belongs tothe modelthe process
Best achievable erroris this, not zero

What it does not mean

Bias here is not social bias. It is the systematic component of statistical error. Bias and Fairness in AI Models is about the other meaning entirely, and the collision of terms is unfortunate and standard.

Variance is not the spread of the data. It is the spread of the MODEL's prediction across different training samples.

You cannot measure either on one dataset. Both are expectations over training samples, which is why the program draws 200 of them.

munotes.in262

Bias and Variance

Low bias is not good on its own. Degree 9 has almost no bias and the second worst total error in the table.

The tradeoff is not a law forbidding improvement. More data reduces variance without raising bias, and a better feature can reduce bias without raising variance. What is fixed is that, with the data you have, tuning flexibility alone moves one against the other.

Zero error is not attainable. The noise term is a property of the process.

Quick revision

  • Expected error = bias squared + variance + irreducible noise. All three non-negative; the noise belongs to the process.
  • Bias: systematic, from the model's assumptions; does not average out. Variance: unsystematic, from sensitivity to the sample; does average out.
  • Measured at one point over 200 resamples: bias squared 13.067, 11.989, 0.000, 0.027, 0.005 for degrees 0, 1, 2, 5, 9, while variance rises 1.257, 1.346, 3.342, 5.031, 8.784. The least total, 3.342, is at degree 2, the shape of the truth.
  • Degree 0 underfits: high bias, low variance. Degree 9 overfits: low bias, high variance.
  • To cut bias: more flexibility, better features. To cut variance: more data, regularization, averaging models, fewer features.
  • More data is the only lever that cuts variance without raising bias. It does nothing for bias.
  • Neither is observable on a single dataset: both are expectations over training samples.
  • Geman and colleagues call it a dilemma: with fixed data, reducing one raises the other.

Test yourself

1. Write the decomposition of expected error and name each term. Expected squared error equals bias squared plus variance plus irreducible noise. Bias is the gap between the average prediction over many training samples and the truth; variance is the spread of the prediction across those samples; the noise is the unpredictable part of the observation, which belongs to the process.

2. Distinguish bias from variance in terms of how the errors behave across samples. A bias error is systematic: the model is wrong in the same direction on every sample, so averaging does not remove it. A variance error is unsystematic: the model is wrong in a different direction on each sample, so averaging over samples removes it while any single sample suffers it.

3. In the measured table, why does degree 0 have a bias squared of 13.067 and a variance of only 1.257? A degree 0 model is a horizontal line at the mean of the sample. It predicts about 62.7 whatever the sample, while the truth at that point is 66.3, so it is wrong by roughly the same amount each time, which is bias. Because it only follows the sample mean it barely moves from sample to sample, which is why its variance is small.

munotes.in263

Bias and Variance

4. Degree 9 has a bias squared of 0.005 and the second worst total error. Explain. Averaged over 200 samples its predictions centre almost exactly on the truth, so it is nearly unbiased. But it fits the noise in whichever twelve points it is given, so on any individual sample its prediction is far away, giving a variance of 8.784 and a total of 8.789.

5. Name three ways to reduce variance and say which of them does not raise bias. More training data, regularization, and averaging several models such as by bagging. More training data is the one that does not raise bias; the other two constrain or smooth the fit and can increase bias.

6. Why can bias and variance not be measured from a single training set? Because both are defined as expectations over the random choice of training sample: bias uses the average prediction across samples, and variance uses the spread across them. With one sample there is one fitted model and no spread to observe, which is why the program draws two hundred.

7. Why is zero expected error impossible, and what is the best achievable? Because the irreducible noise term is a property of the process being observed rather than of the model, and no function of the input can predict it. The best achievable expected error is that noise term, reached when bias and variance are both driven to zero.

Contents This chapter on its own page

munotes.in264

Chapter Forty-Nine

Overfitting and Underfitting

Syllabus topic Module 2, "Overfitting"

In one line

Underfitting is a model too rigid to follow the pattern; overfitting is a model flexible enough to follow the noise as though it were the pattern.

In the wording a student can write in an examination: a model underfits when it is too simple to capture the structure in the data, so both training and test error are high; this is high bias. A model overfits when it fits the particular training sample so closely that it captures its noise, so training error is low while test error is high; this is high variance. Generalisation is performance on data not used in training, and it is the only thing that matters.

Both errors, measured

One training set of twelve points, and 1800 points from the same process that the model never sees. Polynomials of degree 0 to 10 are fitted to the twelve and scored on both.

# Overfitting, measured: fit polynomials of nine degrees to ONE training set and
# report the error on that set and on data the model has never seen.
def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

def truth(x):
    return 40 + 6.0 * x - 0.30 * x * x

def sample(rng, xs):
    return [(x, truth(x) + (rng() + rng() + rng() - 1.5) * 8) for x in xs]

def fit_poly(points, degree):
    m = degree + 1
    A = [[sum(x ** (i + j) for x, _ in points) for j in range(m)] for i in range(m)]
    b = [sum(y * x ** i for x, y in points) for i in range(m)]
    for c in range(m):
        piv = max(range(c, m), key=lambda r: abs(A[r][c]))
        A[c], A[piv] = A[piv], A[c]
        b[c], b[piv] = b[piv], b[c]
        for r in range(m):
            if r == c or A[c][c] == 0:
                continue
            f = A[r][c] / A[c][c]
            for k in range(c, m):
                A[r][k] -= f * A[c][k]
            b[r] -= f * b[c]
    return [b[i] / A[i][i] if A[i][i] else 0.0 for i in range(m)]

def predict(coef, x):
    return sum(c * x ** i for i, c in enumerate(coef))

def mse(coef, points):
    return sum((y - predict(coef, x)) ** 2 for x, y in points) / len(points)

gen = lcg(99)
rng = lambda: next(gen)                               # noqa: E731
train = sample(rng, [float(i) for i in range(1, 13)])       # 12 points
# WARNING: 11 test points is TOO FEW: the test error is then itself noisy and its
# minimum lands in a different place on every run, which hides the U-shape the
# chapter is about. 600 unseen points give a stable measurement.
test = []
for _ in range(50):
    test += sample(rng, [i + 0.25 * k for i in range(1, 13) for k in (0, 1, 2)])

print("12 training points, and %d test points the model never sees." % len(test))
print()
print("degree | training error | test error | verdict")
print("-------|----------------|------------|--------")
best = None
for d in range(0, 11):
    coef = fit_poly(train, d)
    tr, te = mse(coef, train), mse(coef, test)
    if best is None or te < best[1]:
        best = (d, te)
    print("  %2d   | %14.3f | %10.3f |" % (d, tr, te))
print()
print("read the two columns in opposite directions.")
print("  the TRAINING error falls all the way to degree 10: a more flexible model")
print("  always fits the data it was given better. it is not a measure of anything.")
print("  the TEST error falls, reaches its least at degree %d, and then RISES." % best[0])
print()
print("  degree 0 and 1 UNDERFIT: too rigid to follow the curve, so both errors")
print("  are high. degree 8 and above OVERFIT: they have learned the NOISE in the")
print("  12 training points, which the unseen points do not share.")
munotes.in265

Overfitting and Underfitting

12 training points, and 1800 test points the model never sees.

degree | training error | test error | verdict
-------|----------------|------------|--------
   0   |         91.775 |     69.758 |
   1   |         26.603 |     27.998 |
   2   |         10.351 |     17.434 |
   3   |          9.837 |     17.812 |
   4   |          7.913 |     21.725 |
   5   |          7.906 |     21.590 |
   6   |          4.512 |     24.438 |
   7   |          4.395 |     27.636 |
   8   |          2.474 |     47.920 |
   9   |          1.802 |    236.085 |
  10   |          0.373 |   1374.908 |

read the two columns in opposite directions.
  the TRAINING error falls all the way to degree 10: a more flexible model
  always fits the data it was given better. it is not a measure of anything.
  the TEST error falls, reaches its least at degree 2, and then RISES.

  degree 0 and 1 UNDERFIT: too rigid to follow the curve, so both errors
  are high. degree 8 and above OVERFIT: they have learned the NOISE in the
  12 training points, which the unseen points do not share.

The two columns go in opposite directions, and that is the whole chapter.

The training error falls monotonically, 91.775 down to 0.373. It never rises, and it never can: a more flexible model family contains every simpler one, so it can always do at least as well on the data it was fitted to. Training error is therefore not a measure of anything. A model reporting a low training error has reported that it is flexible, not that it is good.

The test error is a U. It falls from 69.758 to 17.434 at degree 2 and then rises, gently at first and then catastrophically: 47.920 at degree 8, 236.085 at degree 9, 1374.908 at degree 10.

munotes.in266

Overfitting and Underfitting

Degree 10 has twelve points and eleven coefficients. It very nearly passes through every one, so its training error is 0.373, and it is worse on unseen data than the flat line that predicted the mean. A model with a training error near zero and a test error eighty times worse than a constant is the clearest picture of overfitting there is.

Reading the two failures

UnderfittingOverfitting
Training errorhighlow
Test errorhighhigh
The two errors areclose togetherfar apart
Bias and variancehigh bias, low variancelow bias, high variance
In the tabledegrees 0 and 1degrees 8, 9, 10
The model has learnedtoo littlethe noise
The curemore flexibility, better featuresless flexibility, more data, regularization

The diagnostic is the gap between the two errors, and it is what a paper wants when it asks how you would tell. Both high and close: underfitting. Training low and test far above it: overfitting. Both low: you are finished.

At degree 2 the errors are 10.351 and 17.434, still not equal. That gap never closes entirely, because the training points were used to choose the fit and the test points were not. A small persistent gap is normal; a large and growing one is the warning.

Why more flexibility eventually hurts

The mechanism, stated once so it can be repeated in an answer.

Each observation is the truth plus noise. A model flexible enough to pass through the observations must reproduce the noise, and the noise in the training sample has nothing to do with the noise anywhere else. So every bit of that fit is not merely useless on new data, it is actively wrong: the curve is bent away from the truth to reach a point that was only there by chance.

And the bending compounds. Between two training points, a high-degree polynomial forced through both swings violently, which is why the test error at degree 10 is not a little worse but eighty times worse. The model is not merely uninformative off the training points; it is confidently wrong.

How overfitting is detected

Three methods, in increasing order of reliability, and a paper may ask for two of them.

A held-out test set. Split the data, fit on one part, measure on the other. This is what the program does. The test set must be used once, to report a final number. Tuning a choice by looking at the test error makes the test set part of the training process, and its error then understates the true error, sometimes badly.

munotes.in267

Overfitting and Underfitting

A validation set. A third split, used for choosing hyperparameters such as the degree, so the test set stays untouched. The right procedure is: fit on training, choose the degree on validation, report on test.

Cross-validation. Split into k folds, train on k - 1 and measure on the remaining one, k times, and average. It uses all the data for both purposes and gives a more stable estimate, at k times the cost. Evaluating a Model sets it out properly.

How overfitting is prevented

Six devices, and every one of them is somewhere else in this module, which is worth noticing.

DeviceWhat it doesWhere in this book
More datathe noise averages out; the model cannot fit all of itBias and Variance
A simpler modelfewer parameters to bendthis chapter
Regularizationpenalise large coefficients, so extreme fits are expensiveRegularization
Early stoppingstop training when validation error starts risingThe Multilayer Network and Backpropagation
Pruningcut back a tree grown too farReading, Drawing and Pruning a Decision Tree
Averaging modelsunsystematic errors cancelEnsemble Methods, Bagging and the Random Forest

And the one that is not on that list: feature selection. Fewer, better features shrink the hypothesis space directly. It is cheap and it is often the largest single improvement available.

Occam's razor, and the honest version of it

The principle usually quoted here is that the simplest hypothesis fitting the data should be preferred. It is a good working rule and it is worth being precise about why.

The justification is not that the world is simple. It is a counting argument: there are far fewer simple hypotheses than complex ones, so a simple hypothesis that fits a large dataset is unlikely to have done so by chance, while among the vast number of complex hypotheses some will fit any dataset by accident.

So the principle is about evidence, not aesthetics, and it has a limit: if the truth is genuinely complicated, the simplest hypothesis fitting the data will be wrong. Degree 0 is the simplest model in the table and it is not the best.

Distinctions

Training errorTest error
Measured onthe data fitted todata never seen
As flexibility risesfalls, alwaysfalls then rises
Useful as a measure of qualitynoyes
In the table at degree 100.3731374.908
Validation setTest set
Used forchoosing hyperparametersthe final report
Used how oftenmany timesonce
If confusedthe reported error is optimistic
Occam's razor, as usually statedIts justification
Prefer the simplest hypothesis that fitsthere are fewer simple hypotheses, so one fitting a large dataset is unlikely to fit by chance
Fails whenthe truth is genuinely complex
munotes.in268

Overfitting and Underfitting

What it does not mean

Low training error is not success. Degree 10 has the lowest training error in the table and by far the worst test error.

Overfitting is not a bug in the algorithm. The fit is the correct least-squares answer. The mistake is choosing a model family too flexible for the data available.

Underfitting is not caused by too little data. It is caused by too little flexibility, and more data does not fix it.

A gap between the two errors is not always overfitting. A small persistent gap is expected, since the training points were used to choose the fit.

The test set is not for tuning. Used more than once it stops measuring generalisation, and the reported figure becomes optimistic.

Simpler is not always better. Occam's razor prefers the simplest hypothesis that fits, and degree 0 does not fit.

Quick revision

  • Underfitting: too rigid, high bias, both errors high and close. Overfitting: too flexible, high variance, training low and test far above it.
  • Measured: training error falls monotonically 91.775 to 0.373; test error falls to 17.434 at degree 2 and rises to 1374.908 at degree 10.
  • Training error is not a measure of quality. A more flexible family always fits its own data at least as well.
  • The diagnostic is the gap between the two errors. A small persistent gap is normal.
  • The mechanism: a model flexible enough to pass through the observations must reproduce their noise, which is unrelated to any other sample, so the curve is bent away from the truth.
  • Detected by a held-out test set (used once), a validation set for choosing hyperparameters, or cross-validation.
  • Prevented by more data, a simpler model, regularization, early stopping, pruning, averaging models, and feature selection.
  • Occam's razor is justified by counting: there are fewer simple hypotheses, so one that fits a large dataset is unlikely to have done so by chance. It fails when the truth is genuinely complex.

Test yourself

1. Define underfitting and overfitting in terms of the two errors. A model underfits when it is too simple to capture the structure, so training and test error are both high and close together. It overfits when it fits the particular training sample so closely that it captures its noise, so training error is low while test error is much higher.

2. Why does the training error never rise as the degree increases? Because a more flexible model family contains every simpler one as a special case, so the best fit within it can never be worse on the data it was fitted to. The training error therefore falls monotonically and measures flexibility rather than quality.

munotes.in269

Overfitting and Underfitting

3. At degree 10 the training error is 0.373 and the test error 1374.908. Explain both numbers. With twelve points and eleven coefficients the polynomial almost passes through every training point, which drives the training error to nearly zero. Doing so requires reproducing the noise in those twelve points, which the unseen points do not share, and the curve swings violently between them, so on new data it is far worse than even the flat line that predicts the mean.

4. How do you tell underfitting from overfitting in practice? By the gap between the two errors. Both high and close together indicates underfitting. A low training error with a test error far above it indicates overfitting. A small persistent gap is normal, since the training data was used to choose the fit.

5. Why must a test set be used only once? Because using it to choose between models makes it part of the training process. The chosen model is then the one that happened to suit that particular held-out sample, and its measured error understates the true error on genuinely new data.

6. Name four ways of preventing overfitting. More training data, a simpler model family, regularization which penalises large coefficients, early stopping when validation error begins to rise, pruning a tree that has been grown too far, averaging several models, and reducing the number of features.

7. State Occam's razor and give its real justification. Prefer the simplest hypothesis consistent with the data. The justification is a counting argument rather than a claim that the world is simple: there are far fewer simple hypotheses than complex ones, so a simple one fitting a large dataset is unlikely to have done so by accident, whereas among the vast number of complex hypotheses some will fit any dataset by chance.

Contents This chapter on its own page

munotes.in270

Chapter Fifty

Regularization

Syllabus topic Module 2, "regularization"

In one line

Regularization adds a charge for using large coefficients, so a fit that has to contort itself to pass through every point becomes too expensive to choose.

In the wording a student can write in an examination: regularization adds a penalty term to the loss function, penalising the complexity of the model rather than its error, so that training minimises

total loss = error on the training data + lambda * penalty(model)

where lambda is a hyperparameter controlling the strength. Ridge regression, or L2 regularization, penalises the sum of the squared coefficients; lasso, or L1, penalises the sum of the absolute values. Regularization reduces variance at the cost of some bias, and so combats overfitting.

The idea

Overfitting and Underfitting ended with six cures and this is the one that does not require throwing anything away.

The usual response to overfitting is to use a smaller model: fewer parameters, fewer features, a lower degree. That works and it is blunt, because the decision has to be made before seeing how the fit behaves.

Regularization does something different. Keep the flexible model, and make the flexible fits expensive. The optimisation then chooses for itself how much of the available flexibility to use, and it uses less where the data does not support more.

Why coefficient size is the right thing to charge for: a curve that passes through every one of twelve scattered points has to swing violently between them, and swinging violently requires enormous coefficients that nearly cancel. Penalising their size makes exactly that kind of fit unaffordable, while a gentle curve with small coefficients pays almost nothing.

It measured

The same degree 10 polynomial, the same twelve training points, at five penalty strengths.

# Regularization: add a penalty on the SIZE of the coefficients, and watch the
# wild degree-10 fit be tamed. Ridge regression, solved by the normal equations.
def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

def truth(x):
    return 40 + 6.0 * x - 0.30 * x * x

def sample(rng, xs):
    return [(x, truth(x) + (rng() + rng() + rng() - 1.5) * 8) for x in xs]

def fit_ridge(points, degree, lam):
    """Least squares plus lam times the sum of squared coefficients."""
    m = degree + 1
    A = [[sum((x / 10.0) ** (i + j) for x, _ in points) + (lam if i == j else 0.0)
          for j in range(m)] for i in range(m)]
    b = [sum(y * (x / 10.0) ** i for x, y in points) for i in range(m)]
    for c in range(m):
        piv = max(range(c, m), key=lambda r: abs(A[r][c]))
        A[c], A[piv] = A[piv], A[c]
        b[c], b[piv] = b[piv], b[c]
        for r in range(m):
            if r == c or A[c][c] == 0:
                continue
            f = A[r][c] / A[c][c]
            for k in range(c, m):
                A[r][k] -= f * A[c][k]
            b[r] -= f * b[c]
    return [b[i] / A[i][i] if A[i][i] else 0.0 for i in range(m)]

def predict(coef, x):
    return sum(c * (x / 10.0) ** i for i, c in enumerate(coef))

def mse(coef, points):
    return sum((y - predict(coef, x)) ** 2 for x, y in points) / len(points)

gen = lcg(99)
rng = lambda: next(gen)                               # noqa: E731
train = sample(rng, [float(i) for i in range(1, 13)])
test = []
for _ in range(50):
    test += sample(rng, [i + 0.25 * k for i in range(1, 13) for k in (0, 1, 2)])

print("a degree 10 polynomial on 12 points, at five penalty strengths.")
print("the penalty is lambda times the sum of the squared coefficients.")
print()
print("  lambda | training error | test error | size of the coefficients")
print("  -------|----------------|------------|-------------------------")
for lam in (0.0, 1e-6, 1e-4, 1e-2, 1.0):
    coef = fit_ridge(train, 10, lam)
    size = sum(c * c for c in coef) ** 0.5
    print("  %6g | %14.3f | %10.3f | %23.1f"
          % (lam, mse(coef, train), mse(coef, test), size))
print()
print("with no penalty the coefficients are enormous and the test error is")
print("ruinous. the penalty makes large coefficients expensive, so the fit stops")
print("using them, and the SAME degree 10 model becomes usable.")
print()
print("the model was never made less flexible. only the fits it is willing to")
print("choose were restricted, which is the whole idea.")
munotes.in271

Regularization

a degree 10 polynomial on 12 points, at five penalty strengths.
the penalty is lambda times the sum of the squared coefficients.

  lambda | training error | test error | size of the coefficients
  -------|----------------|------------|-------------------------
       0 |          0.360 |    757.507 |              51902164.0
   1e-06 |          4.830 |     29.904 |                  1632.7
  0.0001 |          5.952 |     22.463 |                   235.2
    0.01 |          8.672 |     20.213 |                    67.4
       1 |         40.799 |     41.336 |                    47.4

with no penalty the coefficients are enormous and the test error is
ruinous. the penalty makes large coefficients expensive, so the fit stops
using them, and the SAME degree 10 model becomes usable.

the model was never made less flexible. only the fits it is willing to
choose were restricted, which is the whole idea.

Read the last column first, because it is the mechanism. With no penalty the coefficients have a combined size of 51,902,164. They are enormous and they nearly cancel, which is what a curve forced through twelve scattered points has to do. At lambda of 0.01 the size is 67.4, and the test error has gone from 757.507 to 20.213.

munotes.in272

Regularization

Three things in the table are worth naming.

The training error rises as lambda rises, 0.360 to 40.799, and that is correct. Regularization is not supposed to fit the training data better; it is supposed to stop fitting it so well.

The test error falls, reaches its least, and then rises again. 757.507, 29.904, 22.463, 20.213, 41.336. So lambda has its own U-shape, exactly as the degree did in the previous chapter. Too little penalty and the fit overfits; too much and it underfits.

At lambda of 1 the two errors are almost equal, 40.799 and 41.336. That is the signature of underfitting from Overfitting and Underfitting: both high and close together. The penalty has overwhelmed the data.

And the comparison across chapters: the best degree 2 model in the previous chapter scored 17.434. This regularised degree 10 model scores 20.213, close to it, from a model family that without the penalty was eighty times worse than a flat line.

The two penalties

MU's own label is Overfitting & regularization and a paper asks for both by name.

Ridge, or L2. Penalise the sum of the squared coefficients.

loss = sum over i of (y_i - prediction_i)2 + lambda * sum over j of w_j2

It shrinks every coefficient towards zero without reaching zero. It has a closed-form solution, the one the program uses: add lambda down the diagonal of the normal equations. That single line is worth remembering as what ridge regression IS computationally.

Lasso, or L1. Penalise the sum of the absolute values.

loss = sum over i of (y_i - prediction_i)**2 + lambda * sum over j of |w_j|

It drives some coefficients exactly to zero, so it performs feature selection as a side effect: the features whose coefficients vanish are simply dropped. That is its distinctive property and it is the reason to choose it.

Why L1 reaches zero and L2 does not, in one sentence: the squared penalty's gradient is proportional to the coefficient, so it becomes vanishingly weak as the coefficient approaches zero, while the absolute penalty's gradient has constant size all the way in and pushes the coefficient through.

Elastic net uses both together, and is the usual answer when features are correlated, where lasso alone picks one of a correlated group arbitrarily.

Two practical rules that cost marks if forgotten

The intercept is not penalised. Shrinking it towards zero would say the output ought to be near zero, which is a statement about the units the data happens to be measured in and not about complexity.

The features must be standardised first. The penalty charges by coefficient size, and a coefficient's size depends on its feature's units. A feature measured in metres has a coefficient a thousand times larger than the same feature in millimetres, so it would be penalised a thousand times more heavily for no reason at all. Standardising each feature to zero mean and unit spread removes the arbitrariness. The program above divides x by 10 for exactly this reason, so the powers of a number near 1 stay comparable.

munotes.in273

Regularization

Choosing lambda

Lambda is a hyperparameter, so it is chosen the way Overfitting and Underfitting says hyperparameters are chosen: on a validation set or by cross-validation, never on the test set and never on the training error.

The training error cannot choose it, because the training error always prefers lambda equal to zero: that is what the first row of the table shows.

In practice lambda is searched over a wide range on a logarithmic scale, which is why the table's values are 0, 0.000001, 0.0001, 0.01 and 1 rather than 0.1, 0.2, 0.3. The right value can be very small, and a linear search would miss it.

The same idea under other names

Regularization is a family rather than one technique, and recognising it elsewhere is worth a Q.3 answer.

WhereWhat is penalised or restricted
Ridge and lassothe size of the coefficients
Pruning a decision tree, chapter 58the number of leaves
Early stopping, chapter 63how far the weights are allowed to move from their starting point
Dropout in a neural networkreliance on any single unit, by removing units at random during training
A prior in Bayesian estimation, chapter 68a belief about the parameters before the data, which pulls the estimate towards it
Laplace smoothing, chapter 59a zero count, by adding one

The last two rows are worth pausing on. Ridge regression is exactly maximum a posteriori estimation with a normal prior on the coefficients, and lasso with a double-exponential prior. So the penalty is not an arbitrary charge: it is a prior belief that the coefficients are small, expressed as arithmetic. A paper asking for the Bayesian interpretation of regularization wants that sentence.

Distinctions

Ridge, L2Lasso, L1
Penalisesthe sum of squared coefficientsthe sum of absolute values
Coefficients reach exactly zeronoyes
Performs feature selectionnoyes
Closed-form solutionyes, lambda on the diagonalno, needs an iterative method
With correlated featuresshares the weight between thempicks one arbitrarily
Reducing the degreeRegularization
Decidedbefore fittingby the optimisation, given lambda
The model familyis made smalleris unchanged
Flexibilityremovedmade expensive
Lambda too smallLambda too large
Behaviouroverfitsunderfits
Training errorvery lowhigh
Test errorvery highhigh, and close to the training error
In the table757.507 at lambda 041.336 at lambda 1
munotes.in274

Regularization

What it does not mean

Regularization does not improve the training error. It makes it worse on purpose, from 0.360 to 8.672 in the table.

It does not make the model smaller. The degree 10 polynomial still has eleven coefficients; they are merely small. Only lasso removes any of them.

Lambda is not chosen from the training error. The training error always prefers lambda of zero.

It is not a substitute for more data. More data reduces variance without raising bias; regularization trades a little bias for a larger reduction in variance.

Ridge does not set coefficients to zero. It shrinks them towards zero and they arrive only in the limit.

The features must be standardised. Without it the penalty charges by the accident of units.

Quick revision

  • Regularization: minimise training error + lambda * penalty(model), so complex fits become expensive. It trades a little bias for a larger reduction in variance.
  • Mechanism: a curve forced through scattered points needs enormous, nearly cancelling coefficients. Penalising their size makes that fit unaffordable.
  • Measured on the degree 10 polynomial: coefficient size 51,902,164 at lambda 0 with test error 757.507, against size 67.4 at lambda 0.01 with test error 20.213.
  • The training error rises with lambda; the test error is a U, least at lambda 0.01 here.
  • Ridge (L2) penalises squared coefficients, shrinks towards zero without reaching it, has a closed-form solution: add lambda to the diagonal of the normal equations. Lasso (L1) penalises absolute values, drives coefficients exactly to zero, and so performs feature selection. Elastic net uses both.
  • Do not penalise the intercept. Standardise the features first, or the penalty charges by the accident of units.
  • Choose lambda on a validation set or by cross-validation, searched on a logarithmic scale. The training error always prefers zero.
  • The same idea appears as pruning, early stopping, dropout, a prior, and Laplace smoothing. Ridge is exactly maximum a posteriori estimation with a normal prior on the coefficients.

Test yourself

1. Write the regularized loss and say what each part does. Total loss equals the error on the training data plus lambda times a penalty on the model's complexity. The first term pulls the fit towards the data, the penalty pulls it towards simplicity, and lambda sets the exchange rate between them.

2. Why is the size of the coefficients the right thing to penalise? Because a curve that passes through every one of a set of scattered points must swing violently between them, and doing so requires very large coefficients that nearly cancel. Charging for their size makes exactly that kind of fit unaffordable while leaving a gentle fit almost untouched.

munotes.in275

Regularization

3. In the measured table, what happened between lambda 0 and lambda 0.01? The combined size of the coefficients fell from 51,902,164 to 67.4, the training error rose from 0.360 to 8.672, and the test error fell from 757.507 to 20.213. The same degree 10 model went from being eighty times worse than a flat line to being close to the best model of the previous chapter.

4. Distinguish ridge from lasso. Ridge penalises the sum of the squared coefficients, shrinks them all towards zero without any reaching it, and has a closed-form solution obtained by adding lambda to the diagonal of the normal equations. Lasso penalises the sum of the absolute values, drives some coefficients exactly to zero and thereby selects features, and requires an iterative solver.

5. Why does lasso reach exactly zero when ridge does not? Because the gradient of a squared penalty is proportional to the coefficient and so becomes vanishingly weak near zero, while the gradient of an absolute-value penalty keeps a constant size all the way in and pushes the coefficient through to zero.

6. Give the two practical rules that are easy to forget, with reasons. Do not penalise the intercept, because shrinking it towards zero asserts that the output should be near zero, which depends only on the units. And standardise the features before fitting, because a coefficient's size depends on its feature's units, so an unstandardised feature would be penalised according to whether it was measured in metres or millimetres.

7. How is lambda chosen, and why not from the training error? On a validation set or by cross-validation, searched over a wide range on a logarithmic scale. It cannot be chosen from the training error because that always improves as lambda falls, so it would always select lambda of zero, which is the unregularized fit.

Contents This chapter on its own page

munotes.in276

Chapter Fifty-One

Gradient Descent

Syllabus topic Module 2, "Gradient descent"

In one line

Gradient descent finds the lowest point of a curve by repeatedly taking a small step downhill.

In the wording a student can write in an examination: gradient descent minimises a differentiable loss function by iteratively moving each parameter in the direction opposite to the gradient, the vector of partial derivatives. The update rule is

w <- w - rate * gradient

where the learning rate controls the step size. It converges to a global minimum for a convex loss and to a local minimum otherwise. A rate too small converges slowly; a rate too large overshoots and may diverge.

What the derivative is, for this purpose

MU's own word is intuitive, so the calculus is reduced to the one fact needed.

The derivative of a function at a point is the slope of the curve there: how much the output changes for a small change in the input.

  • Positive slope: the curve is going up as you move right, so the low ground is to the left.
  • Negative slope: the curve is going down as you move right, so the low ground is to the right.
  • Zero slope: the curve is flat, so you are at the bottom, the top, or a shelf.

The update rule follows from those three lines and nothing else. Subtract the slope: if the slope is positive, subtracting moves left; if negative, subtracting moves right; if zero, nothing moves. Downhill in both cases, with one rule. That is the whole of the intuition MU asks for.

The gradient is the same idea with several parameters: one partial derivative for each, collected into a vector. Each parameter is moved by its own slope, so each moves in the direction that reduces the loss fastest for it alone.

Four steps by hand, then convergence

The loss is f(w) = (w - 3)**2 + 2, a valley whose lowest point is 2, at w = 3. Its slope is 2(w - 3).

# Gradient descent, worked by hand for four steps and then run to convergence,
# and the learning rate shown too small, right, and too large.
# The loss: f(w) = (w - 3)**2 + 2, whose least value is 2 at w = 3.
def f(w):
    return (w - 3) ** 2 + 2

def slope(w):
    """The derivative, 2(w - 3). At w = 3 it is 0: that is the bottom."""
    return 2 * (w - 3)

print("the loss is f(w) = (w - 3)**2 + 2. its slope is f'(w) = 2(w - 3).")
print("the rule is: w <- w - rate * slope(w).")
print()
print("FOUR STEPS BY HAND, starting at w = 10 with a rate of 0.2")
w = 10.0
print("  step | w before | slope | rate*slope | w after  | loss")
for step in range(1, 5):
    g = slope(w)
    move = 0.2 * g
    nxt = w - move
    print("   %2d  | %8.4f | %5.2f | %10.4f | %8.4f | %8.4f"
          % (step, w, g, move, nxt, f(nxt)))
    w = nxt
print()
print("run on to convergence, printing every fifth step:")
w = 10.0
for step in range(1, 41):
    w -= 0.2 * slope(w)
    if step % 5 == 0:
        print("   step %2d: w = %.6f   loss = %.6f   slope = %+.6f"
              % (step, w, f(w), slope(w)))
print()
print("THE LEARNING RATE decides everything. 30 steps from w = 10:")
print("  rate  | w after 30 steps | loss     | what happened")
for rate in (0.001, 0.05, 0.2, 0.9, 1.0, 1.05):
    w = 10.0
    diverged = False
    for _ in range(30):
        w -= rate * slope(w)
        if abs(w) > 1e12:
            diverged = True
            break
    if diverged:
        note = "DIVERGED, w ran away to infinity"
        print("  %5.3f | %16s | %8s | %s" % (rate, "-", "-", note))
        continue
    err = abs(w - 3)
    if rate == 1.0:
        note = "OSCILLATES between 10 and -4 forever"
    elif err > 7.0:
        note = "OVERSHOOTING, and getting worse every step"
    elif err > 1.0:
        note = "still crawling, nowhere near"
    elif err < 1e-4:
        note = "arrived"
    else:
        note = "close, a few more steps would do it"
    print("  %5.3f | %16.6f | %8.4f | %s" % (rate, w, f(w), note))
print()
print("too small and it never arrives; too large and it overshoots and diverges;")
print("at exactly 1.0 it jumps to the mirror image of where it was, forever.")
munotes.in277

Gradient Descent

the loss is f(w) = (w - 3)**2 + 2. its slope is f'(w) = 2(w - 3).
the rule is: w <- w - rate * slope(w).

FOUR STEPS BY HAND, starting at w = 10 with a rate of 0.2
  step | w before | slope | rate*slope | w after  | loss
    1  |  10.0000 | 14.00 |     2.8000 |   7.2000 |  19.6400
    2  |   7.2000 |  8.40 |     1.6800 |   5.5200 |   8.3504
    3  |   5.5200 |  5.04 |     1.0080 |   4.5120 |   4.2861
    4  |   4.5120 |  3.02 |     0.6048 |   3.9072 |   2.8230

run on to convergence, printing every fifth step:
   step  5: w = 3.544320   loss = 2.296284   slope = +1.088640
   step 10: w = 3.042326   loss = 2.001792   slope = +0.084653
   step 15: w = 3.003291   loss = 2.000011   slope = +0.006583
   step 20: w = 3.000256   loss = 2.000000   slope = +0.000512
   step 25: w = 3.000020   loss = 2.000000   slope = +0.000040
   step 30: w = 3.000002   loss = 2.000000   slope = +0.000003
   step 35: w = 3.000000   loss = 2.000000   slope = +0.000000
   step 40: w = 3.000000   loss = 2.000000   slope = +0.000000

THE LEARNING RATE decides everything. 30 steps from w = 10:
  rate  | w after 30 steps | loss     | what happened
  0.001 |         9.591956 |  45.4539 | still crawling, nowhere near
  0.050 |         3.296738 |   2.0881 | close, a few more steps would do it
  0.200 |         3.000002 |   2.0000 | arrived
  0.900 |         3.008666 |   2.0001 | close, a few more steps would do it
  1.000 |        10.000000 |  51.0000 | OSCILLATES between 10 and -4 forever
  1.050 |       125.145816 | 14921.6003 | OVERSHOOTING, and getting worse every step

too small and it never arrives; too large and it overshoots and diverges;
at exactly 1.0 it jumps to the mirror image of where it was, forever.
munotes.in278

Gradient Descent

The four hand steps are what a paper asks for. At w = 10 the slope is 14, so the step is 0.2 * 14 = 2.8 and w becomes 7.2. The loss falls from 51 to 19.64. Each step the slope is smaller, so the step is smaller, and the descent slows as it approaches the bottom without being told to.

That automatic slowing is the property worth naming. Nothing schedules it: the slope IS the distance from the minimum here, so the step shrinks in proportion. By step 30 w is 3.000002 and the slope is 0.000003.

The learning rate, in both directions

Read the last table, because every row is a different failure or success.

0.001 is too small. After 30 steps w has moved from 10 to 9.59. It is going the right way and will take thousands of steps.

0.2 arrives, to six decimal places, in 30 steps.

1.0 oscillates forever. From w = 10 the slope is 14 and the step is 14, landing at -4. From -4 the slope is -14 and the step takes it back to 10. It never diverges and it never converges; it jumps between the two points forever, and the table shows it exactly back at 10 after 30 steps.

1.05 diverges. Each step overshoots by slightly more than it came, so w grows without bound: 125.1 after 30 steps, and the loss is 14,921.

There is a threshold and for this loss it is exactly 1.0. Below it the method converges; at it the method cycles; above it the method diverges. For a general quadratic loss the threshold is 2 divided by the curvature, and the practical consequence is the one to remember: a loss that is sharply curved in some direction forces a small rate on every direction, which is why real optimisation uses the refinements below.

munotes.in279

Gradient Descent

The three variants, which is what a paper asks for

The loss in machine learning is a sum over the training examples, and the variants differ in how many examples are used per step.

BatchStochastic (SGD)Mini-batch
Examples per stepall of themonea small group, often 32 to 256
Direction of the stepthe exact gradienta very noisy estimatea reasonable estimate
Steps per pass over the data1nn / batch size
Cost per stephightinymoderate
Path to the minimumsmootherraticfairly smooth
Can escape a shallow local minimumnoyes, the noise helpssomewhat
Used in practicerarely, only on small datararely, alonealmost always

The reason mini-batch wins is worth one sentence: a noisy estimate of the gradient computed a hundred times is worth far more than an exact one computed once, because the errors partly cancel while the hundred steps make real progress.

One epoch means one complete pass through the training data. It is the unit training is usually reported in, and it is not the same as a step.

Why it does not always find the best answer

Three honest limits, and a paper can ask for any.

Local minima. On a loss with several valleys, gradient descent settles in whichever one it started above. The loss in this chapter is convex, a single valley, so the starting point does not matter; a neural network's loss is not, and the starting point does matter.

Saddle points and plateaus. Places where the gradient is nearly zero but the point is not a minimum. In many dimensions these are far more common than local minima, and they stall progress without stopping it.

It needs the loss to be differentiable. A loss with a jump in it has no gradient at the jump. This is why classification is usually trained on a smooth surrogate such as cross-entropy rather than directly on the number of mistakes, which is a step function and has zero gradient almost everywhere.

The standard refinements, named

None is on MU's label and all four appear in any library, so one line each.

  • Momentum: add a fraction of the previous step to this one, so the parameter keeps moving in a consistent direction and crosses flat regions faster.
  • AdaGrad, RMSProp: give each parameter its own rate, scaled down for parameters whose gradients have been large, so one sharply curved direction no longer forces a small rate on all of them.
  • Adam: momentum and a per-parameter rate together. It is the usual default.
  • A learning rate schedule: start large and reduce the rate over time, so early steps are fast and later ones settle.
munotes.in280

Gradient Descent

Where it appears in the rest of this book

The cross-chapter list, because this is the one method that recurs.

ChapterWhat gradient descent fits
The Artificial Neuron and the Perceptronthe weights of one unit
The Multilayer Network and Backpropagationevery weight of the network, with the gradient computed by the chain rule
The Soft Margin and the Kernelthe hinge loss, in one standard solver
Maximum Likelihood Estimationthe parameters, when no closed form exists
Q-Learningthe update is a gradient step on a squared temporal-difference error

And the one place it is not used: the straight line of What Machine Learning Is has a closed-form solution, so nothing is iterated. Gradient descent is what you use when there is no formula, and most models in this module have none.

Distinctions

BatchStochastic
Gradient per step fromall examplesone example
Step directionexactnoisy
Progress per passone stepn steps
Escapes shallow minimanoyes
Learning rate too smallToo large
Behaviourconverges, very slowlyovershoots, then diverges
In the table0.001, reached 9.59 after 30 steps1.05, reached 125.1
At exactly the threshold1.0, oscillates forever
Convex lossNon-convex loss
Valleysonemany
Where it converges tothe global minimuma local minimum
Starting point mattersnoyes
Examplethis chapter's, and linear regressiona neural network's

What it does not mean

The gradient does not point at the minimum. It points in the direction of steepest increase at the current point, and the step is the opposite direction. On a long narrow valley that is nearly across the valley rather than along it.

A zero gradient does not mean a minimum. It may be a maximum, a saddle point or a plateau.

A smaller learning rate is not safer in every sense. It cannot diverge, and it may never arrive.

Gradient descent does not need the loss to be the error. It minimises whatever differentiable function it is given, which is how the penalty of Regularization is included: add it to the loss and its gradient joins the step.

Stochastic gradient descent is not an approximation to be apologised for. Its noise helps it escape shallow minima, and many small noisy steps beat one exact one.

It is not always necessary. A closed-form solution, where one exists, is exact and faster.

Quick revision

  • Update rule: w <- w - rate * gradient. Subtracting the slope moves downhill whichever way the slope points.
  • The gradient is the vector of partial derivatives, one per parameter.
  • Four hand steps from w = 10 at rate 0.2: slope 14 gives 7.2, then 5.52, 4.512, 3.9072, with the loss falling 51, 19.64, 8.35, 4.29, 2.82. The steps shrink by themselves because the slope shrinks.
  • Learning rate: 0.001 crawls, 0.2 arrives, 1.0 oscillates between 10 and -4 forever, 1.05 diverges to 125.1. The threshold here is exactly 1.0, and in general 2 / curvature.
  • Variants: batch (all examples, exact, slow), stochastic (one, noisy, fast), mini-batch (a group, and what is actually used). One epoch is one pass over the data.
  • Limits: local minima on a non-convex loss, saddle points and plateaus, and the loss must be differentiable, which is why classification uses a smooth surrogate.
  • Refinements: momentum, AdaGrad and RMSProp, Adam, learning rate schedules.
  • Used to fit the perceptron, a neural network by backpropagation, the hinge loss, maximum likelihood where no closed form exists, and the Q-learning update. Not used where a closed form exists.
munotes.in281

Gradient Descent

Test yourself

1. State the update rule and explain why subtracting the gradient moves downhill. w <- w - rate * gradient. The gradient is the slope, which points uphill: positive slope means the low ground is to the left and negative slope means it is to the right. Subtracting therefore moves left when the slope is positive and right when it is negative, which is downhill in both cases.

2. Work the first two steps for f(w) = (w - 3)2 + 2 from w = 10 with a rate of 0.2.** The slope is 2(w - 3). At w = 10 it is 14, so the step is 2.8 and w becomes 7.2, where the loss is 19.64. At 7.2 the slope is 8.4, so the step is 1.68 and w becomes 5.52, where the loss is 8.3504.

3. Why do the steps get smaller without anything scheduling them? Because the step is the rate times the slope, and the slope shrinks as the minimum is approached. For this loss the slope is exactly twice the distance from the minimum, so the step shrinks in proportion to how far there is still to go.

4. Describe what happens at learning rates of 0.001, 1.0 and 1.05 on this loss. At 0.001 it converges correctly but far too slowly, reaching only 9.59 after thirty steps. At exactly 1.0 it jumps from 10 to minus 4 and back forever, neither converging nor diverging. At 1.05 each step overshoots by more than it came, so the parameter grows without bound, reaching 125.1 after thirty steps.

5. Distinguish batch, stochastic and mini-batch gradient descent, and say which is used. Batch uses every training example for each step, giving the exact gradient at high cost. Stochastic uses one example, giving a very noisy direction very cheaply. Mini-batch uses a small group, giving a reasonable direction at moderate cost, and it is what is used in practice, because many approximate steps make more progress than one exact one.

munotes.in282

Gradient Descent

6. Give three reasons gradient descent may fail to find the best answer. On a non-convex loss it settles in whichever valley it started above, so the starting point decides the result. It stalls at saddle points and plateaus where the gradient is nearly zero but the point is not a minimum. And it requires a differentiable loss, so a loss such as the count of mistakes, which is a step function, cannot be used directly.

7. Why is the straight line of the first chapter not fitted by gradient descent? Because least squares for a linear model has a closed-form solution, which gives the exact answer in one calculation. Gradient descent is for losses with no formula, which is the case for almost every other model in this module.

Contents This chapter on its own page

munotes.in283

Chapter Fifty-Two

Classification and Regression

Syllabus topic Module 2, "Classification vs Regression"

In one line

Regression predicts a number and is wrong by an amount; classification predicts a category and is simply right or wrong.

In the wording a student can write in an examination: in regression the target is a continuous quantity and the model's error is measured as a distance from the true value, usually by mean squared error. In classification the target is one of a finite set of classes and the error is a count of misclassifications. The difference in the type of the target determines the loss function used to fit the model and the measures used to report it.

The same model, scored two ways

# Classification against regression: the same eight students, the same feature,
# and the two SCORED, so the difference in what counts as an error is visible.
DATA = [(2, 32), (3, 41), (4, 48), (5, 56), (6, 61), (7, 72), (8, 77), (9, 85)]
PASS = 50

def fit_line(pts):
    n = len(pts)
    mx = sum(x for x, _ in pts) / n
    my = sum(y for _, y in pts) / n
    b = sum((x - mx) * (y - my) for x, y in pts) / sum((x - mx) ** 2 for x, _ in pts)
    return my - b * mx, b

a, b = fit_line(DATA)
print("REGRESSION errors are SIZES. being out by 2 is twice as bad as by 1.")
print("  hours | true | predicted | error | squared | absolute")
se = ae = 0.0
for x, y in DATA:
    p = a + b * x
    e = y - p
    se += e * e
    ae += abs(e)
    print("   %3d  | %4d | %9.2f | %+5.2f | %7.3f | %8.3f" % (x, y, p, e, e * e, abs(e)))
print("  mean squared error  %.4f     root mean squared error %.4f"
      % (se / len(DATA), (se / len(DATA)) ** 0.5))
print("  mean absolute error %.4f" % (ae / len(DATA)))
print()
print("CLASSIFICATION errors are COUNTS. a prediction is right or it is wrong.")
print("  hours | true  | predicted | correct?")
right = 0
for x, y in DATA:
    true_c = "pass" if y >= PASS else "fail"
    pred_c = "pass" if a + b * x >= PASS else "fail"
    ok = true_c == pred_c
    right += ok
    print("   %3d  | %-5s | %-9s | %s" % (x, true_c, pred_c, "yes" if ok else "NO"))
print("  accuracy %d of %d = %.3f" % (right, len(DATA), right / len(DATA)))
print()
print("the SAME model scored two ways. and the two disagree about what matters:")
worst = max(DATA, key=lambda r: abs(r[1] - (a + b * r[0])))
print("  the worst regression error is at %d hours, out by %.2f marks,"
      % (worst[0], abs(worst[1] - (a + b * worst[0]))))
print("  and the classifier gets that student RIGHT, because %.1f and %.1f are"
      % (worst[1], a + b * worst[0]))
print("  on the same side of the pass mark. a large numeric error can be a")
print("  correct class, and a tiny one can be the wrong class.")
munotes.in284

Classification and Regression

REGRESSION errors are SIZES. being out by 2 is twice as bad as by 1.
  hours | true | predicted | error | squared | absolute
     2  |   32 |     32.83 | -0.83 |   0.694 |    0.833
     3  |   41 |     40.31 | +0.69 |   0.477 |    0.690
     4  |   48 |     47.79 | +0.21 |   0.046 |    0.214
     5  |   56 |     55.26 | +0.74 |   0.545 |    0.738
     6  |   61 |     62.74 | -1.74 |   3.021 |    1.738
     7  |   72 |     70.21 | +1.79 |   3.189 |    1.786
     8  |   77 |     77.69 | -0.69 |   0.477 |    0.690
     9  |   85 |     85.17 | -0.17 |   0.028 |    0.167
  mean squared error  1.0595     root mean squared error 1.0293
  mean absolute error 0.8571

CLASSIFICATION errors are COUNTS. a prediction is right or it is wrong.
  hours | true  | predicted | correct?
     2  | fail  | fail      | yes
     3  | fail  | fail      | yes
     4  | fail  | fail      | yes
     5  | pass  | pass      | yes
     6  | pass  | pass      | yes
     7  | pass  | pass      | yes
     8  | pass  | pass      | yes
     9  | pass  | pass      | yes
  accuracy 8 of 8 = 1.000

the SAME model scored two ways. and the two disagree about what matters:
  the worst regression error is at 7 hours, out by 1.79 marks,
  and the classifier gets that student RIGHT, because 72.0 and 70.2 are
  on the same side of the pass mark. a large numeric error can be a
  correct class, and a tiny one can be the wrong class.

The closing paragraph is the chapter. The prediction that is worst as a number is correct as a class, because 72.0 and 70.2 are both above 50. And the reverse happens too: a student whose true mark is 50.1 and whose prediction is 49.9 is wrong by 0.2 marks and wrongly classified. The two losses disagree about which predictions matter, and that is why the choice of task is not cosmetic.

The loss functions

A paper asking for the difference expects the losses by name.

For regression:

LossFormulaCharacter
Mean squared error, MSEaverage of (true - predicted)**2punishes a large error much more than several small ones; differentiable everywhere; sensitive to outliers
Root mean squared error, RMSEthe square root of MSEin the same units as the target, so it is readable: 1.030 marks here
Mean absolute error, MAEaverage of abs(true - predicted)treats all errors in proportion; robust to outliers; not differentiable at zero
munotes.in285

Classification and Regression

Read the two figures: MSE is 1.060 and MAE is 0.856. MSE is larger because the two errors near 1.8 are squared, and the ranking of models can differ between the two. A paper asking which to use wants: MSE when large errors are disproportionately bad, MAE when an outlier should not dominate.

For classification:

LossWhat it is
Zero-one loss0 if right, 1 if wrong. It is what accuracy counts.
Cross-entropy, or log lossthe negative log of the probability the model gave to the true class. Used for fitting, because zero-one loss has zero gradient almost everywhere and so cannot be optimised by gradient descent.
Hinge lossused by support vector machines, chapter 61

That parenthesis is the reason classification is trained on something other than what it is measured by. Counting mistakes is a step function: change a weight slightly and the count usually does not change at all, so Gradient Descent has nothing to follow. Cross-entropy is a smooth stand-in that falls whenever the model becomes more confident about the right answer.

Why accuracy alone is not enough

The accuracy above is 1.000, which looks conclusive and is not, for two reasons a paper will test.

It was measured on the training data. Overfitting and Underfitting settled that: a score on the data fitted to measures flexibility, not quality.

Accuracy is meaningless when the classes are unbalanced. If 97 per cent of mail is legitimate, a filter that marks everything as legitimate scores 97 per cent and has never caught a single spam message. Evaluating a Model is where this is taken properly, with the confusion matrix, precision and recall, and it is licensed by MU's own Course Outcome 3.

Which task is this, and can it be converted

A paper may give a problem and ask which it is. Two tests.

Is the target ordered and are the gaps meaningful? Marks out of 100: yes, and 60 is genuinely between 55 and 65. Regression. A degree class of first, second, third: ordered, but the gaps are not numeric. That is ordinal data, and it belongs to neither cleanly; treating it as regression asserts that the gaps are equal.

Would being slightly wrong be slightly bad? If predicting 71 instead of 72 is nearly as good as being right, it is regression. If predicting the wrong class is simply wrong however close the two classes are, it is classification.

munotes.in286

Classification and Regression

Converting between them. Supervised Learning showed a regression model with a threshold serving as a classifier, and that is the usual direction. The reverse is rarely sensible: dividing a continuous target into buckets and classifying them throws away the ordering and the magnitudes, and a model told only "high" or "low" cannot say which of two high cases is higher.

The vocabulary of classification

One line each, because they appear in every later chapter.

  • Binary classification: two classes. Pass and fail.
  • Multiclass: more than two, each instance in exactly one. A digit from 0 to 9.
  • Multilabel: each instance may carry several labels at once. An article tagged both sport and politics.
  • Decision boundary: the surface in the input space where the predicted class changes. For the threshold model here it is the single point hours = 4.296.
  • Probabilistic classifier: one that returns a probability per class rather than a bare class, so a threshold can be chosen afterwards. The Naive Bayes Classifier is one.

Distinctions

RegressionClassification
Targeta continuous numberone of a finite set of classes
Error isa sizea count
Fitted by minimisingsquared errorcross-entropy, usually
Reported byRMSE, MAE, and R squaredaccuracy, and better measures
Being slightly wrongis slightly badis simply wrong
In this chapterRMSE 1.030 marksaccuracy 1.000
MSEMAE
Punishes a large errordisproportionatelyin proportion
Outliersdominatedo not
Differentiable everywhereyesno, not at zero
Here1.0600.856
Zero-one lossCross-entropy
Measuresmistakeshow confidently the right class was predicted
Gradientzero almost everywhereuseful
Used forreportingfitting

What it does not mean

The distinction is not about the algorithm. A decision tree, a neural network and k-NN all do both. It is about the type of the target.

A large numeric error is not a wrong classification. The worst-predicted student here is classified correctly, and a student out by 0.2 marks across the pass line would not be.

Accuracy of 1.000 is not proof of anything. It was measured on the training data, and on unbalanced classes accuracy is misleading even on a test set.

Cross-entropy is not what a classifier is judged by. It is what a classifier is fitted by, because the thing it is judged by has no useful gradient.

Bucketing a number is not usually a good way to get a classification problem. It discards the ordering and the magnitudes.

RMSE is not MSE. RMSE is in the units of the target and is what should be quoted to a reader; MSE is what is minimised.

Quick revision

  • Regression: continuous target, error is a size. Classification: a class, error is a count.
  • Regression losses: MSE (squares, so large errors dominate, differentiable), RMSE (same units as the target, 1.030 marks here), MAE (proportional, robust, not differentiable at zero, 0.856 here).
  • Classification losses: zero-one for reporting, cross-entropy for fitting, hinge for SVMs.
  • Zero-one loss has no useful gradient, being a step function, which is why classifiers are fitted on cross-entropy and reported on accuracy.
  • The two losses disagree about which predictions matter. The worst numeric error here, 1.79 marks at 7 hours, is a correct classification; an error of 0.2 marks across the pass line would not be.
  • Accuracy alone is not enough: it was measured on training data here, and on unbalanced classes a useless model scores highly.
  • Deciding which task: is the target ordered with meaningful gaps, and is being slightly wrong slightly bad? Ordinal targets fit neither cleanly.
  • A thresholded regression is a classifier; bucketing a number to make a classification problem throws away information.
  • Vocabulary: binary, multiclass, multilabel, decision boundary, probabilistic classifier.
munotes.in287

Classification and Regression

Test yourself

1. State the difference between classification and regression, and say what follows from it. Regression has a continuous target and its error is the distance from the true value; classification has a categorical target and its error is a count of mistakes. It follows that they use different loss functions for fitting and different measures for reporting.

2. Name three regression losses and say when each is preferred. Mean squared error, preferred when a large error is disproportionately bad and when a differentiable loss is needed. Root mean squared error, which is the same quantity in the units of the target and so is what should be quoted. Mean absolute error, preferred when outliers should not dominate the fit.

3. Why are classifiers fitted on cross-entropy rather than on the number of mistakes? Because the count of mistakes is a step function: a small change in the weights usually leaves it unchanged, so its gradient is zero almost everywhere and gradient descent has nothing to follow. Cross-entropy falls smoothly as the model becomes more confident about the correct class.

4. In this chapter the worst regression error is at 7 hours, and the classifier gets that student right. Explain, and give the reverse case. The predicted mark was 70.2 against a true 72, an error of 1.79 marks, but both are above the pass mark of 50, so the class is correct. The reverse would be a student whose true mark was 50.1 and whose prediction was 49.9: an error of 0.2 marks, and the wrong class.

5. Give two reasons the accuracy of 1.000 reported here proves little. It was measured on the same eight students the model was fitted to, so it measures flexibility rather than generalisation. And accuracy is misleading whenever the classes are unbalanced, since a model that always predicts the common class scores as highly as the class is common.

munotes.in288

Classification and Regression

6. How would you decide whether a problem is classification or regression? Ask whether the target is ordered with meaningful numeric gaps, and whether being slightly wrong is slightly bad. If both, it is regression. If a wrong answer is simply wrong however close, it is classification. Ordinal targets such as degree classes fit neither cleanly, since they are ordered but the gaps are not numeric.

7. Can a regression model be used for classification, and the reverse? A regression model can be thresholded to give a classifier, which is the usual direction and is exactly what this chapter does. The reverse, dividing a continuous target into buckets and classifying them, is rarely sensible because it discards both the ordering and the magnitudes.

Contents This chapter on its own page

munotes.in289

Chapter Fifty-Three

k-Nearest Neighbours

Syllabus topic Module 2, "k-NN"

In one line

To classify something new, find the training examples most like it and let them vote.

In the wording a student can write in an examination: the k-nearest neighbours algorithm classifies a new instance by finding the k training instances closest to it under a distance measure and assigning the majority class among them. It is an instance-based or lazy learner: there is no training phase beyond storing the data, and all the work happens at prediction time. It is nonparametric, since the model is the whole training set.

The algorithm

Five lines, and it is worth writing them out because the whole method is here.

to classify a new point x, given k:
    1. compute the distance from x to EVERY training instance
    2. sort by that distance
    3. take the k closest
    4. count the classes among them
    5. return the class with the most votes    (ties: see below)

There is no step for training. k-NN stores the data and does nothing else until asked. That is why it is called lazy: the work is deferred to prediction, which is the opposite trade from the fitted line of What Machine Learning Is.

The distance measures

MU's label names k-NN without naming a distance, and a paper expects at least two.

MeasureFormula for two pointsCharacter
Euclidean, or L2the square root of the sum of squared differencesstraight-line distance; the default
Manhattan, or L1the sum of absolute differencesdistance along the grid; less affected by one large difference
Minkowskithe p-th root of the sum of p-th powersthe family: p = 2 is Euclidean, p = 1 is Manhattan
Hammingthe number of features that differfor categorical features, where subtraction is meaningless
Cosinethe angle between the two vectorsfor text and other data where direction matters and length does not

A categorical feature has no arithmetic. The difference between Mumbai and Pune is not a number, so Euclidean distance cannot be used on it. Either use Hamming distance, or encode each category as its own 0/1 feature, which is called one-hot encoding.

It worked, by hand and then run

Twelve students, each with hours studied and attendance, and whether they passed. A new student has studied 5 hours with 72 per cent attendance.

# k-nearest neighbours, worked BY HAND on a table the reader can check, then run.
# Twelve students: hours studied, attendance per cent, and whether they passed.
TRAIN = [
    (2, 55, "fail"), (3, 60, "fail"), (3, 80, "fail"), (4, 65, "fail"),
    (4, 85, "pass"), (5, 70, "pass"), (5, 90, "pass"), (6, 60, "pass"),
    (6, 88, "pass"), (7, 75, "pass"), (2, 95, "fail"), (8, 50, "pass"),
]

def euclid(a, b):
    return ((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) ** 0.5

def manhattan(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

def classify(point, k, dist=euclid, show=False):
    scored = sorted(((dist(point, (h, at)), lab) for h, at, lab in TRAIN))
    near = scored[:k]
    votes = {}
    for d, lab in near:
        votes[lab] = votes.get(lab, 0) + 1
    if show:
        for d, lab in near:
            print("      distance %7.3f   %s" % (d, lab))
        print("      votes:", ", ".join("%s %d" % (l, n) for l, n in sorted(votes.items())))
    return max(sorted(votes), key=lambda l: votes[l])

NEW = (5, 72)
print("a new student: %d hours studied, %d%% attendance" % NEW)
print()
print("STEP 1 measure the distance to every training student (Euclidean)")
for h, at, lab in TRAIN:
    print("   (%d, %d) %-5s  distance = sqrt((%d-%d)^2 + (%d-%d)^2) = %7.3f"
          % (h, at, lab, NEW[0], h, NEW[1], at, euclid(NEW, (h, at))))
print()
print("STEP 2 take the k nearest and let them vote")
for k in (1, 3, 5, 7):
    print("   k = %d" % k)
    ans = classify(NEW, k, show=True)
    print("      ANSWER: %s" % ans)
print()
print("THE DISTANCE MEASURE also changes the answer:")
for name, d in (("Euclidean", euclid), ("Manhattan", manhattan)):
    print("   %-10s k=3 -> %s" % (name, classify(NEW, 3, d)))
print()
print("AND THE SCALE MATTERS. attendance runs 50 to 95 and hours 2 to 8, so")
print("attendance dominates the distance. the same student, with hours and")
print("attendance both rescaled to 0..1:")

def scaled(p):
    return ((p[0] - 2) / 6.0, (p[1] - 50) / 45.0)

def classify_scaled(point, k):
    s = scaled(point)
    scored = sorted((euclid(s, scaled((h, at))), lab) for h, at, lab in TRAIN)
    votes = {}
    for d, lab in scored[:k]:
        votes[lab] = votes.get(lab, 0) + 1
    return max(sorted(votes), key=lambda l: votes[l])

for k in (1, 3, 5, 7):
    print("   k = %d  unscaled %-5s   scaled %-5s" % (k, classify(NEW, k), classify_scaled(NEW, k)))
print()
print("on THIS student the two agree. on a student with 2 hours and 75% attendance")
print("they do not, and that is the warning:")
OTHER = (2, 75)
for k in (1, 3, 5):
    print("   k = %d  unscaled %-5s   scaled %-5s"
          % (k, classify(OTHER, k), classify_scaled(OTHER, k)))
print("   unscaled, attendance swamps the distance and the nearest students are")
print("   whoever attended about 75 per cent, several of whom passed. scaled,")
print("   the two hours studied count as much, and 2 hours is the lowest in")
print("   the table, where every student failed.")
munotes.in290

k-Nearest Neighbours

a new student: 5 hours studied, 72% attendance

STEP 1 measure the distance to every training student (Euclidean)
   (2, 55) fail   distance = sqrt((5-2)^2 + (72-55)^2) =  17.263
   (3, 60) fail   distance = sqrt((5-3)^2 + (72-60)^2) =  12.166
   (3, 80) fail   distance = sqrt((5-3)^2 + (72-80)^2) =   8.246
   (4, 65) fail   distance = sqrt((5-4)^2 + (72-65)^2) =   7.071
   (4, 85) pass   distance = sqrt((5-4)^2 + (72-85)^2) =  13.038
   (5, 70) pass   distance = sqrt((5-5)^2 + (72-70)^2) =   2.000
   (5, 90) pass   distance = sqrt((5-5)^2 + (72-90)^2) =  18.000
   (6, 60) pass   distance = sqrt((5-6)^2 + (72-60)^2) =  12.042
   (6, 88) pass   distance = sqrt((5-6)^2 + (72-88)^2) =  16.031
   (7, 75) pass   distance = sqrt((5-7)^2 + (72-75)^2) =   3.606
   (2, 95) fail   distance = sqrt((5-2)^2 + (72-95)^2) =  23.195
   (8, 50) pass   distance = sqrt((5-8)^2 + (72-50)^2) =  22.204

STEP 2 take the k nearest and let them vote
   k = 1
      distance   2.000   pass
      votes: pass 1
      ANSWER: pass
   k = 3
      distance   2.000   pass
      distance   3.606   pass
      distance   7.071   fail
      votes: fail 1, pass 2
      ANSWER: pass
   k = 5
      distance   2.000   pass
      distance   3.606   pass
      distance   7.071   fail
      distance   8.246   fail
      distance  12.042   pass
      votes: fail 2, pass 3
      ANSWER: pass
   k = 7
      distance   2.000   pass
      distance   3.606   pass
      distance   7.071   fail
      distance   8.246   fail
      distance  12.042   pass
      distance  12.166   fail
      distance  13.038   pass
      votes: fail 3, pass 4
      ANSWER: pass

THE DISTANCE MEASURE also changes the answer:
   Euclidean  k=3 -> pass
   Manhattan  k=3 -> pass

AND THE SCALE MATTERS. attendance runs 50 to 95 and hours 2 to 8, so
attendance dominates the distance. the same student, with hours and
attendance both rescaled to 0..1:
   k = 1  unscaled pass    scaled pass
   k = 3  unscaled pass    scaled pass
   k = 5  unscaled pass    scaled pass
   k = 7  unscaled pass    scaled pass

on THIS student the two agree. on a student with 2 hours and 75% attendance
they do not, and that is the warning:
   k = 1  unscaled pass    scaled fail
   k = 3  unscaled pass    scaled fail
   k = 5  unscaled pass    scaled fail
   unscaled, attendance swamps the distance and the nearest students are
   whoever attended about 75 per cent, several of whom passed. scaled,
   the two hours studied count as much, and 2 hours is the lowest in
   the table, where every student failed.
munotes.in291

k-Nearest Neighbours

Every distance is printed with its arithmetic, which is what a by-hand question wants. For the training student at 6 hours and 60 per cent, the distance is the square root of (5-6)2 + (72-60)2, which is the square root of 145, that is 12.042.

Choosing k

k is a hyperparameter and the three things to say about it are these.

Small k is sensitive to noise. At k = 1 a single mislabelled training point creates a small region of wrong predictions around itself. The decision boundary is jagged.

Large k smooths, and eventually destroys. At k equal to the size of the training set, every prediction is the majority class of the whole dataset, whatever the input. The boundary becomes a straight line and then disappears.

munotes.in292

k-Nearest Neighbours

So k controls the bias-variance tradeoff directly. Small k, low bias and high variance. Large k, high bias and low variance. It is the clearest example in this module of the tradeoff being a single dial, and a paper can ask you to say which end is which.

Two practical rules. Choose k by cross-validation, as Overfitting and Underfitting requires of every hyperparameter. And for a two-class problem use an odd k, so a simple majority cannot tie. With more than two classes an odd k does not prevent ties, and the usual tie-breaks are to prefer the class of the single nearest neighbour, or to weight each vote by 1 / distance.

Weighted voting

A refinement a paper may ask for. In plain k-NN the nearest neighbour and the k-th nearest have equal votes, which is odd when one is very close and the other far away.

Distance-weighted k-NN gives each neighbour a vote of 1 / distance, or 1 / distance squared. Close neighbours then dominate, ties become almost impossible, and the method is much less sensitive to k: raising k adds only distant, lightly weighted votes.

What it costs

The complexity table, which is the practical reason k-NN is used less than its simplicity suggests.

k-NNA fitted model
Training timeO(1), just store the dataoften substantial
MemoryO(n * d), the whole datasetthe parameters only
One predictionO(n * d), every row, every featureO(d) or better
Adding one training examplefreeusually a refit

For a million training rows and a hundred features, one prediction reads a hundred million numbers. The standard remedies are spatial index structures such as a k-d tree or a ball tree, which cut the search when the dimension is low; in high dimensions they degrade to examining everything, for the reason in the next chapter.

Why it works at all: Cover and Hart

The theoretical result that makes k-NN respectable, and MU's syllabus mentions the method without it, so knowing it is a distinguishing answer.

Cover and Hart proved in 1967 that as the amount of training data grows without limit, the error rate of the 1-nearest-neighbour rule is at most twice the Bayes error, the least error any classifier could achieve given the true distributions.

Read the conditions, because they are the whole content: it is an asymptotic result, holding in the limit of infinite data, and the bound is on the 1-nearest-neighbour rule specifically. What it says is remarkable all the same: a rule that does no learning at all, given enough data, is within a factor of two of the best possible. With larger k the bound improves and approaches the Bayes error.

munotes.in293

k-Nearest Neighbours

And it explains where k-NN fails. The result needs the neighbours to be genuinely near, which needs the data to be dense. That is exactly what the next chapter shows is impossible in high dimensions.

Distinctions

k-NNA parametric model
Trainingstores the datafits parameters
Calledlazy, instance-basedeager, model-based
Prediction costgrows with nconstant
Data needed at prediction timeall of itnone
Small kLarge k
Boundaryjaggedsmooth
Biaslowhigh
Variancehighlow
Sensitive to a mislabelled pointyesno
At the extremek = 1 copies the nearest labelk = n always predicts the majority class
EuclideanManhattanHamming
Forcontinuous featurescontinuous featurescategorical features
Sensitive to one large differencemorelessnot applicable

What it does not mean

k-NN does not learn anything at training time. It stores the data. All the work is at prediction.

The k neighbours are not a region of fixed size. The region grows or shrinks to contain exactly k points, so it is small where the data is dense and large where it is sparse.

An odd k does not prevent ties in general. It prevents them only for two classes.

Nonparametric does not mean no hyperparameters. k, the distance measure and the scaling are all chosen by the designer.

The Cover and Hart bound does not hold on your dataset. It is asymptotic, in the limit of infinite data.

A categorical feature cannot be given numeric codes and measured with Euclidean distance. Coding Mumbai as 1 and Pune as 2 asserts that Pune is twice Mumbai and that they are one unit apart.

Quick revision

  • k-NN: compute the distance from the new point to every training instance, take the k nearest, and return the majority class. Lazy, instance-based, nonparametric; no training phase.
  • Distances: Euclidean (L2), Manhattan (L1), Minkowski (the family), Hamming (categorical), cosine (text). Categorical features need Hamming or one-hot encoding.
  • k is the bias-variance dial. Small k: jagged boundary, low bias, high variance, sensitive to one bad label. Large k: smooth, high bias, low variance; at k = n it always predicts the majority class.
  • Choose k by cross-validation; use an odd k for two classes. Distance-weighted voting gives each neighbour 1 / distance and makes the method less sensitive to k.
  • Cost: training O(1), memory O(nd), one prediction O(nd). Remedied by a k-d tree or ball tree, which fail in high dimensions.
  • Cover and Hart 1967: as data grows without limit, the 1-nearest-neighbour error is at most twice the Bayes error. Asymptotic, and for k = 1; larger k approaches the Bayes error.
munotes.in294

k-Nearest Neighbours

Test yourself

1. Give the k-NN algorithm in five steps. Compute the distance from the new point to every training instance; sort by distance; take the k closest; count the classes among them; return the class with the most votes, breaking ties by the nearest neighbour or by weighting votes by inverse distance.

2. Why is k-NN called a lazy learner, and what does that cost? Because it does no work at training time beyond storing the data, deferring everything to prediction. It costs memory proportional to the whole dataset and a prediction time proportional to the number of training rows times the number of features.

3. Name three distance measures and say when each is appropriate. Euclidean, the straight-line distance, for continuous features and the usual default. Manhattan, the sum of absolute differences, for continuous features when one large difference should not dominate. Hamming, the count of features that differ, for categorical features where subtraction has no meaning.

4. How does k affect bias and variance? A small k gives a jagged boundary that follows individual points, which is low bias and high variance and is easily upset by one mislabelled example. A large k averages over many points, giving a smooth boundary with high bias and low variance, until at k equal to the dataset size every prediction is the overall majority class.

5. Why use an odd k, and what does that not fix? So that a simple majority vote cannot tie when there are two classes. It does not prevent ties with three or more classes, for which the usual remedies are to fall back on the nearest neighbour's class or to weight votes by inverse distance.

6. State Cover and Hart's result with its conditions. As the training set grows without limit, the error rate of the one-nearest-neighbour rule is at most twice the Bayes error, the least error achievable by any classifier given the true distributions. It is an asymptotic result for k equal to one, and larger k improves the bound towards the Bayes error itself.

7. Why can a categorical feature not simply be numbered and used with Euclidean distance? Because numbering imposes an order and a spacing that do not exist. Coding Mumbai as 1 and Pune as 2 asserts that they are one unit apart and that Pune is in some sense twice Mumbai, both of which are meaningless. Use Hamming distance, or one-hot encode each category as its own indicator feature.

Contents This chapter on its own page

munotes.in295

Chapter Fifty-Four

k-NN for Regression, and What Limits the Method

Syllabus topic Module 2, "K-NN algorithm for classification or regression"

In one line

k-NN predicts a number by averaging its neighbours' numbers, and it is defeated by features on different scales and by having too many features.

In the wording a student can write in an examination: k-NN regression predicts a continuous value for a new instance as the mean (or a distance-weighted mean) of the target values of its k nearest training instances. Its two principal limitations are sensitivity to feature scaling, since a feature with a larger numeric range dominates the distance, and the curse of dimensionality, since in a high-dimensional space the volume grows so fast that all points become roughly equidistant and no neighbour is genuinely near.

Regression with neighbours

The classification rule took a majority vote. The regression rule takes a mean. Everything else is identical.

to predict a value for x, given k:
    find the k training instances nearest to x
    return the MEAN of their target values

The distance-weighted version divides each neighbour's contribution by its distance, so near neighbours count more, and it is the version usually used in practice.

It running, and what happens past the data

# k-NN for REGRESSION (set by the practical, not by a theory label), and the two
# things that limit the method: feature scale, and dimensionality. Both counted.
import math
TRAIN = [(2, 32), (3, 41), (4, 48), (5, 56), (6, 61), (7, 72), (8, 77), (9, 85)]

def knn_regress(h, k):
    near = sorted(TRAIN, key=lambda r: abs(r[0] - h))[:k]
    return sum(y for _, y in near) / k, near

print("REGRESSION with k-NN: average the neighbours' VALUES instead of voting.")
print("  hours | k=1  | k=3   | k=5   | the k=3 neighbours")
for h in (2.5, 4.5, 6.5, 9.5, 12.0):
    p1, _ = knn_regress(h, 1)
    p3, n3 = knn_regress(h, 3)
    p5, _ = knn_regress(h, 5)
    print("  %5.1f | %4.1f | %5.2f | %5.2f | %s"
          % (h, p1, p3, p5, " ".join("%d:%d" % (x, y) for x, y in n3)))
print()
print("  k = 1 is a staircase: it repeats a training value exactly.")
print("  larger k smooths, and at 12 hours EVERY k returns the same thing,")
print("  because the nearest neighbours cannot change beyond the data.")
print()
print("LIMIT 1, THE FEATURE SCALE. two features, one in years and one in rupees.")
A = (3.0, 50000.0)
B = (4.0, 50000.0)
C = (3.0, 50500.0)
print("  A = (3 years, 50000 rupees)")
print("  B = (4 years, 50000 rupees)  one whole year apart")
print("  C = (3 years, 50500 rupees)  one per cent apart in salary")
print("  distance A to B = %.1f      distance A to C = %.1f"
      % (math.dist(A, B), math.dist(A, C)))
print("  so C looks %.0f times further away than B, although B differs by a"
      % (math.dist(A, C) / math.dist(A, B)))
print("  YEAR and C by one per cent. the rupees swamp everything.")
print()
print("LIMIT 2, THE CURSE OF DIMENSIONALITY. how much of a unit cube lies within")
print("0.1 of a face, as the number of dimensions grows?")
print("   dimensions | fraction of the volume NEAR a face | fraction in the middle")
for d in (1, 2, 3, 10, 50, 100):
    middle = 0.8 ** d
    print("   %10d | %33.6f | %21.9f" % (d, 1 - middle, middle))
print()
print("in 100 dimensions essentially EVERY point is near an edge, and the idea")
print("of a nearby neighbour stops meaning anything. to keep the same density of")
print("neighbours as d grows, the data must grow exponentially:")
print("   dimensions | points needed for the same density as 100 points in 1-D")
for d in (1, 2, 3, 5, 10):
    print("   %10d | %d" % (d, 100 ** d))
munotes.in296

k-NN for Regression, and What Limits the Method

REGRESSION with k-NN: average the neighbours' VALUES instead of voting.
  hours | k=1  | k=3   | k=5   | the k=3 neighbours
    2.5 | 32.0 | 40.33 | 47.60 | 2:32 3:41 4:48
    4.5 | 48.0 | 48.33 | 47.60 | 4:48 5:56 3:41
    6.5 | 61.0 | 63.00 | 62.80 | 6:61 7:72 5:56
    9.5 | 85.0 | 78.00 | 70.20 | 9:85 8:77 7:72
   12.0 | 85.0 | 78.00 | 70.20 | 9:85 8:77 7:72

  k = 1 is a staircase: it repeats a training value exactly.
  larger k smooths, and at 12 hours EVERY k returns the same thing,
  because the nearest neighbours cannot change beyond the data.

LIMIT 1, THE FEATURE SCALE. two features, one in years and one in rupees.
  A = (3 years, 50000 rupees)
  B = (4 years, 50000 rupees)  one whole year apart
  C = (3 years, 50500 rupees)  one per cent apart in salary
  distance A to B = 1.0      distance A to C = 500.0
  so C looks 500 times further away than B, although B differs by a
  YEAR and C by one per cent. the rupees swamp everything.

LIMIT 2, THE CURSE OF DIMENSIONALITY. how much of a unit cube lies within
0.1 of a face, as the number of dimensions grows?
   dimensions | fraction of the volume NEAR a face | fraction in the middle
            1 |                          0.200000 |           0.800000000
            2 |                          0.360000 |           0.640000000
            3 |                          0.488000 |           0.512000000
           10 |                          0.892626 |           0.107374182
           50 |                          0.999986 |           0.000014272
          100 |                          1.000000 |           0.000000000

in 100 dimensions essentially EVERY point is near an edge, and the idea
of a nearby neighbour stops meaning anything. to keep the same density of
neighbours as d grows, the data must grow exponentially:
   dimensions | points needed for the same density as 100 points in 1-D
            1 | 100
            2 | 10000
            3 | 1000000
            5 | 10000000000
           10 | 100000000000000000000
munotes.in297

k-NN for Regression, and What Limits the Method

Three readings of the first table.

k = 1 is a staircase. It returns a training value exactly, so its predictions jump from one observed mark to another with nothing in between. That is the highest-variance version of the method.

Larger k smooths. At 6.5 hours, k = 1 gives 61.0, k = 3 gives 63.00 and k = 5 gives 62.80.

At 12 hours every k gives the same answer as at 9.5 hours. Beyond the data the nearest neighbours cannot change, so the prediction is constant for ever. Compare Parametric and Nonparametric Models: the fitted line predicted 107.6 marks there, which is impossible, and k-NN predicts 78.00 for any number of hours above 9. Neither extrapolates correctly, and they fail in opposite ways.

Limit one: the scale of the features

The middle block is the demonstration and it is worth reading twice.

Two features: years of experience, running from about 1 to 10, and salary, running into tens of thousands. Point B differs from A by a whole year of experience. Point C differs by one per cent of salary.

Euclidean distance says A to B is 1.0 and A to C is 500.0. The trivial difference looks five hundred times larger than the substantial one, purely because rupees are numerically bigger than years. Every neighbour k-NN finds will be chosen almost entirely on salary, and the experience column may as well not be there.

The fix is to rescale every feature before measuring any distance, and there are two standard ways.

MethodFormulaResult
Min-max scaling, or normalisationsubtract the minimum, divide by the rangeevery feature lies in 0 to 1
Standardisation, or the z-scoresubtract the mean, divide by the standard deviationevery feature has mean 0 and spread 1

Min-max is bounded and is upset by a single extreme value, which stretches the range and squashes everything else. Standardisation is unbounded and is not. And the scaling must be computed on the TRAINING data only and then applied unchanged to the test data. Computing it over everything lets information about the test set leak into training, which is called data leakage and makes the reported error optimistic.

k-Nearest Neighbours showed the same effect changing an answer: a student with 2 hours and 75 per cent attendance is classified pass on the raw features and fail once both are scaled to 0 to 1.

Limit two: the curse of dimensionality

The third block, and it is the deeper of the two limits because rescaling cannot fix it.

munotes.in298

k-NN for Regression, and What Limits the Method

Read the volume table. In one dimension, the middle 80 per cent of a unit interval holds 80 per cent of the length. In three dimensions, the central cube holds 0.512. In 10 dimensions, 0.107. In 100 dimensions it holds about one part in a hundred thousand million, so essentially every point lies near a face.

Two consequences, and each is fatal to the idea of a neighbour.

Everything is far away. As dimensions grow, the distance from a point to its nearest neighbour and to its farthest neighbour become almost the same. If the nearest point is barely nearer than the farthest, the word nearest has stopped meaning anything.

The data required grows exponentially. The last table: to keep the same density of neighbours as 100 points give in one dimension needs 10,000 in two, a million in three, and 10 to the power 20 in ten dimensions. No dataset is that large, so in high dimensions the k nearest neighbours of a point are simply the k least distant of a sparse scatter, and they are not near it in any useful sense.

The remedies, and a paper asking what to do about it wants these three. Feature selection: keep the features that matter, which is the cheapest and often the best. Dimensionality reduction: project onto fewer dimensions that preserve most of the variation. Change the method: use a model that does not rely on distances, such as a decision tree, which examines one feature at a time.

When k-NN is the right choice

Despite the two limits, it remains a reasonable first method, and a paper may ask when.

Use it when the data is low-dimensional, when the decision boundary is irregular and no simple form suits it, when training must be instantaneous or new examples arrive continuously, and as a baseline: it is quick to implement and any more elaborate method should beat it.

Do not use it when there are many features, when prediction must be fast, when the dataset is too large to hold in memory, or when the training data cannot be kept for reasons of privacy or deployment.

Distinctions

k-NN classificationk-NN regression
Combines the neighbours bya majority votea mean
Outputa classa number
Tiespossible, broken by nearest or by weightingnot applicable
Set byMU's theory labelthe practical, not the theory label
Min-max scalingStandardisation
Formulasubtract the min, divide by the rangesubtract the mean, divide by the spread
Range afterwardsexactly 0 to 1unbounded, mean 0
Upset by one extreme valueyes, badlymuch less
Feature scaleDimensionality
The problemone feature dominates the distanceall distances become similar
Fixed byrescalingfewer features, or another method
Fixable at allyes, completelyno, only mitigated
munotes.in299

k-NN for Regression, and What Limits the Method

What it does not mean

k-NN regression is not interpolation between neighbours. It returns their mean, so its prediction is a flat step inside each neighbourhood rather than a sloping line.

Rescaling does not cure the curse of dimensionality. It cures the scale problem. In high dimensions every rescaled feature contributes to distances that are all much the same.

The curse is not about computation. The search can be made fast; the trouble is that the answer stops being meaningful.

The scaling must not be computed over the whole dataset. Computing it on training and test together is data leakage.

Beyond the range of the data, k-NN is not conservative in a useful way. It returns the same value for ever, which is wrong in a different way from extrapolating a line.

More features are not more information for this method. Each extra feature dilutes the distance and makes the neighbours less relevant.

Quick revision

  • k-NN regression: the prediction is the mean of the k nearest neighbours' targets, or a distance-weighted mean. Set by the practical, not by a theory label.
  • k = 1 is a staircase repeating training values; larger k smooths. Beyond the data the prediction is constant for ever: 78.00 at 12 hours as at 9.5.
  • Feature scale. Experience in years against salary in rupees: one year apart is a distance of 1.0 and one per cent of salary apart is 500.0. The larger-ranged feature decides every neighbour.
  • Fix by min-max scaling (0 to 1, upset by one extreme value) or standardisation (mean 0, spread 1). Compute it on the training data only, or you have data leakage.
  • The curse of dimensionality. The middle 80 per cent of a unit cube holds 0.512 of the volume in 3 dimensions and about one part in a hundred thousand million in 100. Nearest and farthest distances converge, and the data needed for the same density grows exponentially: 10 to the power 20 points in ten dimensions.
  • Remedies: feature selection, dimensionality reduction, or a method that does not use distances, such as a decision tree.
  • Use k-NN for low-dimensional data, irregular boundaries, instant training, and as a baseline.

Test yourself

1. How does k-NN regression differ from k-NN classification? Only in how the neighbours are combined: classification takes a majority vote of their classes, regression takes the mean of their target values, or a mean weighted by inverse distance.

2. What does k-NN regression predict for an input beyond the range of the training data, and how does that compare with a fitted line? It returns the mean of the same k nearest neighbours for every such input, so the prediction is constant for ever: 78.00 marks for 12 hours of study as for 9.5. A fitted line extrapolates instead, predicting 107.6 marks, which is impossible. Both are wrong, in opposite ways.

munotes.in300

k-NN for Regression, and What Limits the Method

3. Explain the feature scale problem with the salary example. With features of years of experience and salary in rupees, two points differing by one whole year of experience are at Euclidean distance 1.0, while two differing by one per cent of a fifty thousand rupee salary are at distance 500. The feature with the larger numeric range determines every neighbour, regardless of which feature matters.

4. Name the two standard rescaling methods and say how they differ. Min-max scaling subtracts the minimum and divides by the range, putting every feature in 0 to 1, but a single extreme value stretches the range and squashes everything else. Standardisation subtracts the mean and divides by the standard deviation, giving mean 0 and unit spread, and is much less disturbed by an extreme value.

5. Why must the scaling be computed on the training data only? Because computing it over the training and test data together lets information about the test set influence the training, which is data leakage. The reported error then understates the true error on genuinely new data.

6. State the curse of dimensionality and give two of its consequences for k-NN. That volume grows so fast with the number of dimensions that data becomes hopelessly sparse. The distance from a point to its nearest and to its farthest neighbour become almost equal, so nearest loses its meaning; and the amount of data required to keep the same density of neighbours grows exponentially, reaching 10 to the power 20 points in ten dimensions for what 100 points give in one.

7. Give three responses to the curse of dimensionality. Feature selection, keeping only the features that matter, which is the cheapest and often the most effective. Dimensionality reduction, projecting onto fewer dimensions that preserve most of the variation. Or changing to a method that does not depend on distances, such as a decision tree, which examines one feature at a time.

Contents This chapter on its own page

munotes.in301

Chapter Fifty-Five

Entropy and Information Gain

Syllabus topic Module 2, "Decision Trees"

In one line

Entropy measures how mixed up a set of answers is, and information gain measures how much a question unmixes it.

In the wording a student can write in an examination: the entropy of a set S with respect to a class label is

H(S) = - sum over classes c of p(c) * log2(p(c))

where p(c) is the proportion of S in class c. It is measured in bits, is 0 when every instance has the same class, and is maximal when the classes are equally represented. The information gain of splitting S on an attribute A is the entropy before the split minus the weighted average entropy of the parts after it:

Gain(S, A) = H(S) - sum over values v of A of (|S_v| / |S|) * H(S_v)

Entropy, in words before formulas

Entropy answers one question: if I pick an instance from this set at random, how surprised will I be by its class?

  • If every instance is yes, the answer is certain, there is no surprise, and the entropy is 0.
  • If half are yes and half no, the answer is a coin toss, the surprise is as large as it can be for two classes, and the entropy is exactly 1 bit.
  • Anything between is between.

The unit is the bit, and it is the same bit as in information theory: the entropy is the average number of yes-or-no questions needed to determine an instance's class, if the questions are asked as efficiently as possible.

The measure, and why the logarithm

H(S) = - sum over c of p(c) * log2(p(c))

Three features of that formula are worth being able to justify.

The minus sign. A probability is at most 1, so its logarithm is at most 0. The minus makes the result non-negative.

The base 2. It makes the unit the bit. Base e gives nats and base 10 gives bans; nothing else changes, and for choosing a split the base is irrelevant because it scales every candidate equally.

The weighting by p(c). The term -log2(p(c)) is the surprise of seeing class c: rare classes are surprising, and a class of probability 1 has surprise 0. Multiplying by p(c) and adding gives the average surprise, which is what entropy is.

A class with p(c) = 0 contributes nothing, by the convention that 0 * log(0) is 0, which is the limit.

It computed

# Entropy and information gain, computed on a 14-row table the reader can check.
# The question: will a student attend the lecture?
import math

ROWS = [
    # weather, distance, friend going, early, attend
    ("rain",  "far",   "no",  "yes", "no"),
    ("rain",  "far",   "no",  "no",  "no"),
    ("clear", "far",   "no",  "yes", "yes"),
    ("humid", "near",  "no",  "yes", "yes"),
    ("humid", "near",  "yes", "yes", "yes"),
    ("humid", "near",  "yes", "no",  "no"),
    ("clear", "near",  "yes", "no",  "yes"),
    ("rain",  "near",  "no",  "yes", "no"),
    ("rain",  "near",  "yes", "yes", "yes"),
    ("humid", "far",   "yes", "yes", "yes"),
    ("rain",  "far",   "yes", "no",  "yes"),
    ("clear", "far",   "yes", "no",  "yes"),
    ("clear", "near",  "no",  "no",  "yes"),
    ("humid", "far",   "no",  "no",  "no"),
]
COLS = ["weather", "distance", "friend", "early"]
TARGET = 4

def entropy(rows):
    if not rows:
        return 0.0
    total = len(rows)
    out = 0.0
    for label in set(r[TARGET] for r in rows):
        p = sum(1 for r in rows if r[TARGET] == label) / total
        out -= p * math.log2(p)
    return out

def split(rows, col):
    values = {}
    for r in rows:
        values.setdefault(r[col], []).append(r)
    return values

def gain(rows, col):
    before = entropy(rows)
    after = sum(len(part) / len(rows) * entropy(part)
                for part in split(rows, col).values())
    return before - after, before, after

print("ENTROPY measures how mixed a set of labels is. In bits:")
print("   a set that is | entropy")
for yes, no in ((14, 0), (13, 1), (10, 4), (9, 5), (7, 7)):
    n = yes + no
    e = 0.0
    for c in (yes, no):
        if c:
            e -= (c / n) * math.log2(c / n)
    print("   %2d yes, %2d no | %.4f" % (yes, no, e))
print("   a pure set has entropy 0. an even split has entropy exactly 1.")
print()
yes = sum(1 for r in ROWS if r[TARGET] == "yes")
print("the 14 rows: %d attend, %d do not." % (yes, len(ROWS) - yes))
print("entropy of the whole set = %.4f bits" % entropy(ROWS))
print()
print("INFORMATION GAIN of splitting on each attribute:")
for i, name in enumerate(COLS):
    g, before, after = gain(ROWS, i)
    parts = split(ROWS, i)
    print("   %-9s" % name)
    for v in sorted(parts):
        part = parts[v]
        y = sum(1 for r in part if r[TARGET] == "yes")
        print("      %-6s %2d rows (%d yes, %d no)  entropy %.4f  weight %d/%d"
              % (v, len(part), y, len(part) - y, entropy(part), len(part), len(ROWS)))
    print("      weighted entropy after = %.4f" % after)
    print("      GAIN = %.4f - %.4f = %.4f" % (before, after, g))
print()
best = max(range(len(COLS)), key=lambda i: gain(ROWS, i)[0])
print("the root of the tree is %s, with the largest gain, %.4f bits."
      % (COLS[best], gain(ROWS, best)[0]))
munotes.in302

Entropy and Information Gain

ENTROPY measures how mixed a set of labels is. In bits:
   a set that is | entropy
   14 yes,  0 no | 0.0000
   13 yes,  1 no | 0.3712
   10 yes,  4 no | 0.8631
    9 yes,  5 no | 0.9403
    7 yes,  7 no | 1.0000
   a pure set has entropy 0. an even split has entropy exactly 1.

the 14 rows: 9 attend, 5 do not.
entropy of the whole set = 0.9403 bits

INFORMATION GAIN of splitting on each attribute:
   weather
      clear   4 rows (4 yes, 0 no)  entropy 0.0000  weight 4/14
      humid   5 rows (3 yes, 2 no)  entropy 0.9710  weight 5/14
      rain    5 rows (2 yes, 3 no)  entropy 0.9710  weight 5/14
      weighted entropy after = 0.6935
      GAIN = 0.9403 - 0.6935 = 0.2467
   distance
      far     7 rows (4 yes, 3 no)  entropy 0.9852  weight 7/14
      near    7 rows (5 yes, 2 no)  entropy 0.8631  weight 7/14
      weighted entropy after = 0.9242
      GAIN = 0.9403 - 0.9242 = 0.0161
   friend
      no      7 rows (3 yes, 4 no)  entropy 0.9852  weight 7/14
      yes     7 rows (6 yes, 1 no)  entropy 0.5917  weight 7/14
      weighted entropy after = 0.7885
      GAIN = 0.9403 - 0.7885 = 0.1518
   early
      no      7 rows (4 yes, 3 no)  entropy 0.9852  weight 7/14
      yes     7 rows (5 yes, 2 no)  entropy 0.8631  weight 7/14
      weighted entropy after = 0.9242
      GAIN = 0.9403 - 0.9242 = 0.0161

the root of the tree is weather, with the largest gain, 0.2467 bits.
munotes.in303

Entropy and Information Gain

Follow the weather calculation, because that is the one a paper sets.

The 14 rows are 9 yes and 5 no, so the entropy before any split is

H = -(9/14)log2(9/14) - (5/14)log2(5/14) = 0.9403 bits

Splitting on weather gives three parts:

ValueRowsyesnoEntropyWeight
clear4400.00004/14
humid5320.97105/14
rain5230.97105/14

weighted entropy after = (4/14)0 + (5/14)0.9710 + (5/14)*0.9710 = 0.6935

Gain(weather) = 0.9403 - 0.6935 = 0.2467 bits

The clear branch has entropy 0. Every one of those four students attends, so that branch is settled and needs no further question. That is what a useful split looks like.

And the four gains together: weather 0.2467, friend 0.1518, distance 0.0161, early 0.0161. Distance and early are almost worthless here: splitting on either leaves the parts nearly as mixed as the whole. Weather is the root because it is the question that unmixes the most.

Three properties a paper can ask you to prove

Each is one line and each is examinable.

Gain is never negative. The weighted average entropy of the parts cannot exceed the entropy of the whole. Splitting can only reduce disorder or leave it unchanged.

Gain is 0 exactly when the split is useless, that is when every part has the same class proportions as the whole, so knowing the attribute tells you nothing about the class.

Maximum entropy for k equally likely classes is log2(k). Two classes: 1 bit. Four classes: 2 bits. This matters, because it means entropies for problems with different numbers of classes are not directly comparable.

munotes.in304

Entropy and Information Gain

The defect of information gain, and its two repairs

Information gain is biased towards attributes with many values, and this is the single most important criticism of it. Quinlan says so himself in the 1986 paper.

The extreme case makes it obvious. Add a roll number column, unique to each student. Splitting on it gives 14 parts of one row each, every one pure, so the weighted entropy after is 0 and the gain is the full 0.9403 bits, the largest possible. Information gain would choose roll number as the root, producing a tree that is perfect on the training data and completely useless: it has memorised the students, not learned the pattern.

Two standard repairs, and a paper asking about the defect wants at least one.

Gain ratio, Quinlan's own answer in C4.5. Divide the gain by the split information, the entropy of the sizes of the parts themselves:

SplitInfo(S, A) = - sum over v of (|S_v|/|S|) * log2(|S_v|/|S|)

GainRatio(S, A) = Gain(S, A) / SplitInfo(S, A)

An attribute with many small parts has a large split information, so dividing penalises it. It over-corrects when one part is tiny, making the split information near zero and the ratio huge, so implementations only consider attributes whose plain gain is at least average.

The Gini impurity, used by CART and by most modern libraries:

Gini(S) = 1 - sum over c of p(c)**2

It measures the probability of misclassifying an instance labelled by drawing a class at random from the set's own distribution. It is 0 for a pure set and 0.5 for a two-class even split, so it behaves like entropy without the logarithm, which makes it cheaper to compute. In practice the two choose the same split almost always; the choice between them is not where the accuracy comes from.

Continuous attributes

The 14 rows have only categorical attributes, and MU's models include continuous ones, so a paper may ask.

A continuous attribute such as marks is handled by turning it into a binary question: marks <= t for some threshold t. The threshold is chosen by sorting the values, considering each midpoint between consecutive distinct values, and taking whichever gives the largest gain. It is exhaustive and it is cheap, because only the midpoints where the class actually changes can ever be best.

A continuous attribute may be used more than once on a path, with different thresholds, unlike a categorical one, which is exhausted by the split.

Distinctions

EntropyInformation gain
Measureshow mixed one set ishow much a split unmixes it
Ofa single seta set and an attribute
Range0 to log2(k)0 to the entropy before
Best value0, pureas large as possible
munotes.in305

Entropy and Information Gain

EntropyGini impurity
Formulaminus the sum of p log2 p1 minus the sum of p squared
Pure set00
Two-class even split10.5
Uses a logarithmyesno, cheaper
Used byID3, C4.5CART, and most libraries
Information gainGain ratio
Biased towards many-valued attributesyes, badlycorrected
Divides bythe split information
Its own defectover-corrects when a part is tiny

What it does not mean

Entropy is not error. A set that is 90 per cent yes has entropy 0.469 and would be classified with 10 per cent error. They are different quantities and both are used.

A gain of 0 does not mean the attribute is irrelevant to the class in general. It means it is uninformative for this set, and it may become informative further down the tree after other splits.

The highest gain is not always the best split. The roll-number example has the highest possible gain and is worthless.

Entropy does not depend on the order of the rows or on which class is called positive. It depends only on the proportions.

The logarithm base is not a modelling choice. It sets the unit and scales every candidate equally, so it never changes which split is chosen.

Gini is not a weaker measure. It almost always chooses the same split and is cheaper to compute.

Quick revision

  • Entropy: H(S) = -sum p(c) log2 p(c), in bits. 0 for a pure set, 1 for a two-class even split, maximum log2(k) for k equal classes.
  • Information gain: entropy before minus the weighted average entropy of the parts. Never negative; zero exactly when the parts have the same class mix as the whole.
  • On the 14 rows: entropy 0.9403. Gains: weather 0.2467, friend 0.1518, distance 0.0161, early 0.0161. Weather is the root, and its clear branch has entropy 0.0000.
  • Information gain is biased towards attributes with many values. A unique roll number gives the maximum possible gain and a worthless tree.
  • Repairs: gain ratio, dividing by the split information (Quinlan's C4.5), which over-corrects when a part is tiny; and the Gini impurity, 1 - sum p squared, used by CART, cheaper and almost always agreeing.
  • Continuous attributes become binary questions x <= t, with t chosen by trying the midpoints between consecutive distinct values, and may be split on more than once along a path.

Test yourself

1. Define entropy and give its value for a pure set and for a two-class even split. The entropy of a set is minus the sum over classes of the proportion times its base-two logarithm, measured in bits. It is 0 for a set whose instances all share one class, and exactly 1 for a set evenly divided between two classes.

munotes.in306

Entropy and Information Gain

2. Compute the entropy of a set of 14 instances, 9 of one class and 5 of the other. Minus nine fourteenths times the log to base two of nine fourteenths, minus five fourteenths times the log of five fourteenths, which is 0.9403 bits.

3. Define information gain and compute it for the weather attribute on those 14 rows. Gain is the entropy before the split minus the weighted average entropy of the parts. Weather splits the rows into 4 clear with entropy 0, 5 humid with entropy 0.9710, and 5 rain with entropy 0.9710. The weighted entropy after is four fourteenths times 0 plus five fourteenths times 0.9710 twice, that is 0.6935, so the gain is 0.9403 minus 0.6935, which is 0.2467 bits.

4. Why can information gain never be negative, and when is it zero? Because splitting a set cannot increase the weighted average disorder of its parts. It is zero exactly when every part has the same class proportions as the whole, so learning the attribute's value tells you nothing about the class.

5. State the principal defect of information gain and give an example. It is biased towards attributes with many distinct values. A unique identifier such as a roll number splits fourteen rows into fourteen pure parts, giving the maximum possible gain of 0.9403 bits, and produces a tree that has memorised the training data and learned nothing.

6. Give two corrections for that defect. Gain ratio, which divides the gain by the split information, the entropy of the part sizes, so that an attribute with many small parts is penalised. And the Gini impurity, one minus the sum of the squared class proportions, used by CART, which is cheaper to compute and in practice selects almost the same splits.

7. How is a continuous attribute handled? It is converted into a binary question of the form x is at most t. The threshold is chosen by sorting the observed values and evaluating the gain at each midpoint between consecutive distinct values, taking the best. Unlike a categorical attribute, a continuous one may be used again further down the same path with a different threshold.

Contents This chapter on its own page

munotes.in307

Chapter Fifty-Six

Decision Tree Learning

Syllabus topic Module 2, "Decision Trees"

In one line

A decision tree asks the most informative question first, splits the data on the answer, and repeats on each part until the answers agree.

In the wording a student can write in an examination: decision tree learning constructs a tree in which each internal node tests one attribute, each branch corresponds to a value of that attribute, and each leaf carries a class label. The standard algorithm, ID3, is greedy and recursive: at each node it selects the attribute of highest information gain, partitions the instances by that attribute's values, and recurses on each partition, stopping when the instances at a node all share a class, when no attributes remain, or when the partition is empty.

The algorithm

ID3(examples, attributes):
    if every example has the same class: return a LEAF with that class
    if attributes is empty: return a LEAF with the MAJORITY class
    A = the attribute of greatest information gain;  make a node testing A
    for each value v of A:  part = the examples with A = v
        if part is empty: attach a LEAF with examples' majority class
        else attach ID3(part, attributes without A)
    return the node

Three stopping conditions, and all three are examinable. The examples agree, so nothing is left to ask. The attributes are exhausted, so no question remains and the majority is the best available answer. Or the partition is empty, which happens when a value of A occurs nowhere in this branch, and the parent's majority is used.

The attribute used at a node is removed from the list. Splitting on it again in the same branch would gain nothing, since every example in the branch now shares its value. That is true only for a categorical attribute; a continuous one tested as x <= t may be tested again with a different threshold.

Building it, with the gain at every node

# ID3: build the whole tree from the 14 rows, printing the gain at every node,
# and then turn the tree into rules. Read against Quinlan 1986.
import math

ROWS = [
    ("rain",  "far",   "no",  "yes", "no"),
    ("rain",  "far",   "no",  "no",  "no"),
    ("clear", "far",   "no",  "yes", "yes"),
    ("humid", "near",  "no",  "yes", "yes"),
    ("humid", "near",  "yes", "yes", "yes"),
    ("humid", "near",  "yes", "no",  "no"),
    ("clear", "near",  "yes", "no",  "yes"),
    ("rain",  "near",  "no",  "yes", "no"),
    ("rain",  "near",  "yes", "yes", "yes"),
    ("humid", "far",   "yes", "yes", "yes"),
    ("rain",  "far",   "yes", "no",  "yes"),
    ("clear", "far",   "yes", "no",  "yes"),
    ("clear", "near",  "no",  "no",  "yes"),
    ("humid", "far",   "no",  "no",  "no"),
]
COLS = ["weather", "distance", "friend", "early"]
TARGET = 4

def entropy(rows):
    if not rows:
        return 0.0
    out = 0.0
    for label in set(r[TARGET] for r in rows):
        p = sum(1 for r in rows if r[TARGET] == label) / len(rows)
        out -= p * math.log2(p)
    return out

def split(rows, col):
    d = {}
    for r in rows:
        d.setdefault(r[col], []).append(r)
    return d

def gain(rows, col):
    return entropy(rows) - sum(len(p) / len(rows) * entropy(p)
                               for p in split(rows, col).values())

def majority(rows):
    counts = {}
    for r in rows:
        counts[r[TARGET]] = counts.get(r[TARGET], 0) + 1
    return max(sorted(counts), key=lambda k: counts[k])

def build(rows, available, depth=0, why=""):
    pad = "   " + "   " * depth
    labels = set(r[TARGET] for r in rows)
    if len(labels) == 1:                       # STOP: the rows agree
        leaf = labels.pop()
        print("%s%s-> LEAF %s   (%d rows, all agree)" % (pad, why, leaf, len(rows)))
        return leaf
    if not available:                          # STOP: no attributes left
        leaf = majority(rows)
        print("%s%s-> LEAF %s   (%d rows, no attributes left, majority)"
              % (pad, why, leaf, len(rows)))
        return leaf
    best = max(available, key=lambda c: gain(rows, c))
    g = gain(rows, best)
    print("%s%ssplit on %-9s gain %.4f   (%d rows, entropy %.4f)"
          % (pad, why, COLS[best], g, len(rows), entropy(rows)))
    tree = {}
    rest = [c for c in available if c != best]
    for value in sorted(split(rows, best)):
        part = split(rows, best)[value]
        tree[value] = build(part, rest, depth + 1, "%s = %s  " % (COLS[best], value))
    return (COLS[best], tree)

print("building the tree from %d rows, entropy %.4f" % (len(ROWS), entropy(ROWS)))
print()
tree = build(ROWS, list(range(len(COLS))))
print()

def rules(node, path=None):
    """Every root-to-leaf path, as an IF ... THEN rule."""
    path = path or []
    if isinstance(node, str):
        return [(" and ".join(path) if path else "always", node)]
    col, branches = node
    out = []
    for value in sorted(branches):
        out += rules(branches[value], path + ["%s is %s" % (col, value)])
    return out

print("THE SAME TREE AS RULES, which is how it is read aloud:")
for cond, then in rules(tree):
    print("   IF %-46s THEN attend = %s" % (cond, then))
print()

def classify(node, row):
    while not isinstance(node, str):
        col, branches = node
        node = branches[row[COLS.index(col)]]
    return node

wrong = sum(1 for r in ROWS if classify(tree, r) != r[TARGET])
print("the tree gets %d of %d training rows right." % (len(ROWS) - wrong, len(ROWS)))
leaves = len(rules(tree))
print("it has %d leaves, for %d training rows." % (leaves, len(ROWS)))
munotes.in308

Decision Tree Learning

building the tree from 14 rows, entropy 0.9403

   split on weather   gain 0.2467   (14 rows, entropy 0.9403)
      weather = clear  -> LEAF yes   (4 rows, all agree)
      weather = humid  split on early     gain 0.9710   (5 rows, entropy 0.9710)
         early = no  -> LEAF no   (2 rows, all agree)
         early = yes  -> LEAF yes   (3 rows, all agree)
      weather = rain  split on friend    gain 0.9710   (5 rows, entropy 0.9710)
         friend = no  -> LEAF no   (3 rows, all agree)
         friend = yes  -> LEAF yes   (2 rows, all agree)

THE SAME TREE AS RULES, which is how it is read aloud:
   IF weather is clear                               THEN attend = yes
   IF weather is humid and early is no               THEN attend = no
   IF weather is humid and early is yes              THEN attend = yes
   IF weather is rain and friend is no               THEN attend = no
   IF weather is rain and friend is yes              THEN attend = yes

the tree gets 14 of 14 training rows right.
it has 5 leaves, for 14 training rows.
munotes.in309

Decision Tree Learning

Follow the three levels.

The root splits on weather, gain 0.2467, the largest of the four as Entropy and Information Gain computed.

The clear branch stops immediately. All four of those students attend, so the first stopping condition fires: a leaf, with no further question.

The humid branch splits on early with a gain of 0.9710, which is the whole of that branch's entropy, so both of its parts are pure. The rain branch does the same on friend.

The tree is three levels deep with five leaves and it classifies all fourteen training rows correctly, and neither distance nor one of the other attributes appears at all. ID3 uses an attribute only where it is the most informative question available, and two of the four are never worth asking.

Why the greedy choice is not guaranteed best

ID3 takes the attribute of highest gain at each node, without looking ahead, and never revisits a choice. That is what greedy means, and it has two consequences a paper can ask about.

The tree found may not be the smallest tree that fits. A pair of attributes that are individually uninformative can be jointly decisive: the exclusive-or of two attributes has zero gain on each of them separately, so ID3 will not choose either first, although splitting on one and then the other classifies the data perfectly.

Finding the smallest consistent tree is NP-hard, which is why every practical algorithm is greedy. So the greediness is not laziness; it is the only tractable option, and the price is that the tree is a good one rather than the best one.

ID3 also performs no backtracking: once a split is made it is never undone. A poor early choice is carried by every branch beneath it.

The tree as rules

Read the second block of output. Every root-to-leaf path is an IF ... THEN rule, and the five paths give five rules that cover every case exactly once.

That correspondence is the reason decision trees are the most interpretable model in MU's list, and it is the answer to any question about why they are preferred where an explanation is needed. Rule-Based Systems and Expert Systems had to be given its rules by an expert; a decision tree learns the same kind of rules from data. It is the direct answer to the knowledge acquisition bottleneck that chapter records.

munotes.in310

Decision Tree Learning

The rules are mutually exclusive and exhaustive by construction, so unlike a hand-written rule base there is no conflict set and no need for a conflict-resolution strategy.

What ID3 cannot do, and what came after it

Quinlan's own 1986 paper is explicit about the limitations, and naming the successor is worth a mark.

Limitation of ID3What C4.5 and CART do
Only categorical attributesC4.5 handles continuous ones with x <= t thresholds
Gain is biased towards many-valued attributesC4.5 uses gain ratio; CART uses Gini
No handling of missing valuesC4.5 sends a fraction of the instance down each branch, weighted by how common that value is
No pruning, so it overfits noisy dataC4.5 prunes; CART uses cost-complexity pruning
Only classificationCART also does regression, with the mean at each leaf and variance in place of entropy

CART produces strictly binary trees, splitting on A = v against A != v even for categorical attributes, where ID3 gives a branch per value. That difference matters: a many-valued attribute fragments an ID3 tree into small parts very quickly, and CART does not.

The fragmentation problem

Worth its own paragraph because it is the practical failure of the method and it explains why the next chapter is about pruning.

Every split divides the data. After three splits on three-valued attributes, 14 rows have become 27 potential parts, most of them holding one row or none. A decision made on one or two rows is not a decision, it is an accident, and the tree will assert it with complete confidence.

That is why practical implementations impose a minimum number of instances at a node before a split is allowed, and why Reading, Drawing and Pruning a Decision Tree is a chapter rather than a remark.

Distinctions

Internal nodeLeaf
Holdsa test on one attributea class label
Has childrenone per value of the attributenone
Created whensome attribute has positive gain and the rows disagreethe rows agree, or no attribute is left
ID3C4.5CART
Split measureinformation gaingain ratioGini
Continuous attributesnoyesyes
Missing valuesnoyes, fractionallyyes, by surrogate splits
Pruningnoyesyes, cost-complexity
Branches per nodeone per valueone per valuealways two
Regressionnonoyes
A decision treeA hand-written rule base
Rules come fromdataan expert
Conflict resolutionnot needed, the rules are exclusiverequired
Answers the knowledge acquisition bottleneckyesit is the bottleneck
munotes.in311

Decision Tree Learning

What it does not mean

ID3 does not find the smallest tree. It is greedy, and finding the smallest consistent tree is NP-hard.

An attribute absent from the tree is not irrelevant. It was simply never the best question at any node where it remained available.

A pure leaf is not evidence that the tree is right. Purity on two rows is easily an accident, which is what fragmentation means.

Removing an attribute after use is not always correct. It is correct for a categorical attribute, whose value is fixed in the branch, and not for a continuous one tested by a threshold.

The tree's perfect training accuracy is not a result. Overfitting and Underfitting settled that, and the next chapter measures what it costs.

Decision trees are not restricted to classification. CART fits regression trees, with the mean at each leaf and variance reduction in place of information gain.

Quick revision

  • ID3: at each node choose the attribute of greatest information gain, split on its values, recurse. Greedy, recursive, no backtracking.
  • Three stopping conditions: the rows agree; no attributes remain, so take the majority; or the partition is empty, so take the parent's majority.
  • A used categorical attribute is removed from the branch; a continuous one may be reused with a different threshold.
  • The 14-row tree: root weather (gain 0.2467), clear a pure leaf, humid split on early and rain on friend, both with gain 0.9710. Five leaves, 14 of 14 correct, and two attributes never used.
  • Greedy is not optimal: exclusive-or gives zero gain on each attribute alone, and finding the smallest consistent tree is NP-hard.
  • Every root-to-leaf path is an IF ... THEN rule, mutually exclusive and exhaustive, needing no conflict resolution. That is why trees are the most interpretable model in MU's list, and it answers the knowledge acquisition bottleneck.
  • ID3's limits: categorical only, gain biased, no missing values, no pruning, classification only. C4.5 adds thresholds, gain ratio, missing values and pruning; CART uses Gini, is always binary, and does regression.
  • Fragmentation: each split divides the data, so deep nodes decide on one or two rows, which is why a minimum node size and pruning are needed.

Test yourself

1. Give the ID3 algorithm. If every example has the same class, return a leaf with it. If no attributes remain, return a leaf with the majority class. Otherwise select the attribute of greatest information gain, make a node testing it, and for each of its values recurse on the examples with that value, using the remaining attributes; an empty partition becomes a leaf with the parent's majority class.

munotes.in312

Decision Tree Learning

2. Name the three stopping conditions. All the examples at the node share one class; the list of attributes is exhausted, so the majority class is used; or the partition for some value is empty, in which case the parent's majority class is used.

3. Describe the tree built from the 14 rows. The root splits on weather with a gain of 0.2467. The clear branch is a pure leaf predicting attend. The humid branch splits on early with a gain of 0.9710, giving two pure leaves, and the rain branch splits on friend, also with gain 0.9710, giving two more. The tree has five leaves and classifies all fourteen training rows correctly, without ever using distance.

4. Why is a greedy algorithm used when it is not guaranteed to find the best tree? Because finding the smallest tree consistent with the data is NP-hard, so no tractable algorithm can guarantee optimality. Greedy selection gives a good tree at reasonable cost, and the price is illustrated by the exclusive-or of two attributes, on which each attribute alone has zero gain although the pair is decisive.

5. Explain the relationship between a decision tree and a rule base. Each root-to-leaf path is an IF-THEN rule whose conditions are the tests along the path. The resulting rules are mutually exclusive and exhaustive, so unlike a hand-written rule base no conflict-resolution strategy is needed. The important difference is that the rules are learned from data rather than supplied by an expert, which answers the knowledge acquisition bottleneck.

6. Give four limitations of ID3 and say how its successors address them. It handles only categorical attributes, which C4.5 fixes with threshold tests. Its gain measure is biased towards many-valued attributes, which C4.5 addresses with gain ratio and CART with the Gini index. It has no treatment of missing values, which C4.5 handles by sending fractions of an instance down several branches. And it does not prune, so it overfits noisy data, which both successors correct.

7. What is fragmentation, and what follows from it? Every split divides the data among its branches, so after a few splits the parts contain very few instances. A decision made on one or two rows is an accident rather than evidence, yet the tree asserts it with full confidence. It follows that practical implementations require a minimum number of instances before allowing a split, and that the tree must be pruned.

Contents This chapter on its own page

munotes.in313

Chapter Fifty-Seven

Reading, Drawing and Pruning a Decision Tree

Syllabus topic Module 2, "Visualize and interpret the generated decision tree"

In one line

A tree is read by following one path from the root, drawn with the test at each node and the class at each leaf, and pruned by cutting back branches that fit noise rather than pattern.

In the wording a student can write in an examination: a decision tree is interpreted by tracing the path from the root to a leaf, the tests along that path being the conjunction of conditions under which the leaf's class is predicted. A fully grown tree overfits noisy data, so it is pruned: pre-pruning stops growth early by a criterion such as a maximum depth or a minimum number of instances at a node, and post-pruning grows the tree fully and then removes subtrees whose removal does not worsen, or improves, performance on held-out data.

Reading a tree

Three things to be able to say about any tree put in front of you, and a paper asks for all three.

Trace one instance. Start at the root, read the test, follow the branch matching that instance's value, and repeat until a leaf. The leaf's label is the prediction. Nothing else in the tree is consulted.

Read a path as a rule. The tests along a root-to-leaf path are joined by and. From the tree of Decision Tree Learning: IF weather is rain AND friend is yes THEN attend = yes.

Read the root as the most important question. The attribute at the root had the greatest information gain over the whole dataset, so it is the single question that best separates the classes. Attributes nearer the root are more influential in general; that is an ordering of influence, not a measurement of it, and quoting a tree's structure as a measure of feature importance is a common overstatement.

Drawing one

A paper asks for a drawn tree, and the conventions are worth following exactly.

  • The root at the top, growing downwards.
  • Each internal node labelled with the attribute name only, not the test.
  • Each branch labelled with the value it corresponds to.
  • Each leaf labelled with the class, drawn as a box or underlined to distinguish it from an internal node.
  • Useful additions when marks allow: the number of instances reaching each node, and the class counts at each leaf, which is how anyone can check the tree against the table.

The 14-row tree of the previous chapter, as a paper would want it written out:

PathRowsPrediction
weather = clear4yes
weather = humid, early = no2no
weather = humid, early = yes3yes
weather = rain, friend = no3no
weather = rain, friend = yes2yes
munotes.in314

Reading, Drawing and Pruning a Decision Tree

Five leaves for fourteen rows. Look at the row counts: two leaves rest on two rows each. On real data that is not evidence, and the next section is what to do about it.

Pruning, measured

The true rule is known: attend if the weather is clear or a friend is going. Fifteen per cent of the training labels are then flipped, so the tree has genuine noise to overfit. 120 rows to train on, 400 held out to judge.

# Pruning, MEASURED. A tree grown to purity on noisy data, then cut back, with
# the training and validation accuracy at every size. Set by the practical's
# "Visualize and interpret the generated decision tree".
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(31)
rnd = lambda: next(gen)                                   # noqa: E731

# The TRUE rule is simple: attend if the weather is clear, or a friend is going.
# 15 per cent of the labels are then flipped, which is the noise a tree can fit.
WEATHER = ["clear", "humid", "rain"]
YESNO = ["yes", "no"]

def make(n):
    rows = []
    for _ in range(n):
        w = WEATHER[int(rnd() * 3)]
        d = YESNO[int(rnd() * 2)]
        f = YESNO[int(rnd() * 2)]
        e = YESNO[int(rnd() * 2)]
        label = "yes" if (w == "clear" or f == "yes") else "no"
        if rnd() < 0.15:
            label = "no" if label == "yes" else "yes"      # the noise
        rows.append((w, d, f, e, label))
    return rows

COLS = ["weather", "distance", "friend", "early"]
TARGET = 4
train, validate = make(120), make(400)

def entropy(rows):
    if not rows:
        return 0.0
    out = 0.0
    for lab in set(r[TARGET] for r in rows):
        p = sum(1 for r in rows if r[TARGET] == lab) / len(rows)
        out -= p * math.log2(p)
    return out

def split(rows, c):
    d = {}
    for r in rows:
        d.setdefault(r[c], []).append(r)
    return d

def gain(rows, c):
    return entropy(rows) - sum(len(p) / len(rows) * entropy(p)
                               for p in split(rows, c).values())

def majority(rows):
    counts = {}
    for r in rows:
        counts[r[TARGET]] = counts.get(r[TARGET], 0) + 1
    return max(sorted(counts), key=lambda k: counts[k])

def build(rows, avail, depth, limit):
    if len(set(r[TARGET] for r in rows)) == 1 or not avail or depth == limit:
        return majority(rows)
    best = max(avail, key=lambda c: gain(rows, c))
    if gain(rows, best) <= 0:
        return majority(rows)
    rest = [c for c in avail if c != best]
    parts = split(rows, best)
    return (COLS[best], majority(rows),
            {v: build(parts[v], rest, depth + 1, limit) for v in sorted(parts)})

def classify(node, row):
    while not isinstance(node, str):
        col, fallback, branches = node
        v = row[COLS.index(col)]
        if v not in branches:
            return fallback
        node = branches[v]
    return node

def accuracy(tree, rows):
    return sum(1 for r in rows if classify(tree, r) == r[TARGET]) / len(rows)

def leaves(node):
    if isinstance(node, str):
        return 1
    return sum(leaves(b) for b in node[2].values())

print("the TRUE rule: attend if the weather is clear OR a friend is going.")
print("15 per cent of the labels are then flipped. 120 training rows, 400 for")
print("validation. the tree is grown to a depth limit, and the limit varied:")
print()
print("  depth | leaves | training accuracy | validation accuracy")
print("  ------|--------|-------------------|--------------------")
best = None
for limit in (1, 2, 3, 4, 99):
    t = build(train, list(range(len(COLS))), 0, limit)
    tr, va = accuracy(t, train), accuracy(t, validate)
    if best is None or va > best[1]:
        best = (limit, va, leaves(t))
    shown = "full" if limit == 99 else "%d" % limit
    print("  %5s | %6d | %17.3f | %19.3f" % (shown, leaves(t), tr, va))
print()
print("the training accuracy never falls as the depth grows, and here it stops")
print("improving at depth 2: the extra splits buy nothing even on the data they")
print("were fitted to. the validation accuracy PEAKS at depth %s with %d leaves"
      % (best[0], best[2]))
print("and then FALLS, which is the signature of overfitting.")
print()
print("the full tree has learned the flipped labels, which the validation set")
print("does not share. cutting it back to %d leaves is PRUNING, and it makes" % best[2])
print("the tree both smaller and BETTER.")
print()
print("and the best it could possibly do: the true rule itself, on the same")
print("validation set, scores %.3f, because 15 per cent of those labels are"
      % (sum(1 for r in validate
             if ("yes" if (r[0] == "clear" or r[2] == "yes") else "no") == r[TARGET])
         / len(validate)))
print("flipped too. no tree can beat that, and the pruned tree is close to it.")
munotes.in315

Reading, Drawing and Pruning a Decision Tree

the TRUE rule: attend if the weather is clear OR a friend is going.
15 per cent of the labels are then flipped. 120 training rows, 400 for
validation. the tree is grown to a depth limit, and the limit varied:

  depth | leaves | training accuracy | validation accuracy
  ------|--------|-------------------|--------------------
      1 |      2 |             0.708 |               0.713
      2 |      6 |             0.842 |               0.853
      3 |     12 |             0.842 |               0.810
      4 |     22 |             0.842 |               0.810
   full |     22 |             0.842 |               0.810

the training accuracy never falls as the depth grows, and here it stops
improving at depth 2: the extra splits buy nothing even on the data they
were fitted to. the validation accuracy PEAKS at depth 2 with 6 leaves
and then FALLS, which is the signature of overfitting.

the full tree has learned the flipped labels, which the validation set
does not share. cutting it back to 6 leaves is PRUNING, and it makes
the tree both smaller and BETTER.

and the best it could possibly do: the true rule itself, on the same
validation set, scores 0.853, because 15 per cent of those labels are
flipped too. no tree can beat that, and the pruned tree is close to it.
munotes.in316

Reading, Drawing and Pruning a Decision Tree

Read the two accuracy columns.

The full tree has 22 leaves for 120 training rows, so an average leaf rests on five instances and many rest on one. It scores 0.842 on training and 0.810 on validation.

The depth-2 tree has 6 leaves and scores 0.842 on training, exactly the same, and 0.853 on validation, which is better.

And 0.853 is the best any model could do. The true rule itself, applied to the same validation set, scores 0.853, because 15 per cent of those labels were flipped too. The pruned tree has reached the ceiling. The sixteen extra leaves of the full tree bought nothing on the training data and cost 0.043 on new data: they are the flipped labels, memorised.

That is the whole case for pruning in three numbers: same training accuracy, better validation accuracy, a quarter of the size.

The two kinds of pruning

Pre-pruning, or early stoppingPost-pruning
Whenduring growthafter the tree is fully grown
Howrefuse to splitremove a subtree and replace it with a leaf
Criteriamaximum depth; minimum instances at a node; minimum gain; a statistical testreduced-error pruning; cost-complexity pruning; rule post-pruning
Costcheap, one passmore work, the full tree is built first
Riskthe horizon effect: a split that looks useless may enable a decisive one below itnone of that kind
Usually preferrednoyes

The horizon effect is why post-pruning is preferred, and it is worth naming because it is the same effect as in Games as Search. The exclusive-or of two attributes has zero gain on each one alone, so a pre-pruning rule that stops when the gain is small will stop immediately and never discover that splitting twice classifies everything. Post-pruning cannot make that mistake, because the tree is grown first and the decision to cut is made with the subtree's actual performance in hand.

The three post-pruning methods, in one line each.

Reduced-error pruning. Take each internal node in turn, replace its subtree with a leaf holding the majority class, and keep the change if the accuracy on a validation set does not fall. Repeat until no further cut helps. It is simple and it needs data set aside.

Cost-complexity pruning, used by CART. Score each candidate tree by error + alpha * (number of leaves), and choose alpha by cross-validation. That is exactly the shape of Regularization: a penalty on complexity added to the loss, with a strength chosen on held-out data.

munotes.in317

Reading, Drawing and Pruning a Decision Tree

Rule post-pruning, used by C4.5. Convert the tree to rules, one per path; then for each rule, try dropping each condition and keep the drop if the rule's estimated accuracy does not fall; then sort the surviving rules by accuracy. It is the most flexible, because a condition can be removed from one rule while remaining in another, which no tree operation can do.

Interpreting a tree honestly

Three cautions, and a viva asks about them.

A tree is not stable. Change a few training rows and a different attribute may win at the root, giving a completely different-looking tree with much the same accuracy. So do not present a particular tree's structure as a discovered fact about the world. That instability is also exactly what Ensemble Methods, Bagging and the Random Forest exploits: high variance is what averaging cures.

Depth in the tree is not importance. The root won the gain contest over the whole dataset; an attribute deep in one branch may matter enormously within that branch.

A leaf's confidence is its row count. A leaf holding 40 rows of which 38 are yes is worth believing; a leaf holding 1 row is not, and both are printed with the same certainty by the classifier. Always draw the counts.

Distinctions

Pre-pruningPost-pruning
Actswhile growingafter growing
Suffers the horizon effectyesno
Needs the full tree builtnoyes
Typical criterionmax depth, min instances per nodevalidation accuracy, or error + alpha * leaves
Reduced-error pruningCost-complexity pruningRule post-pruning
Judged byvalidation accuracyerror + alpha * leavesper-rule accuracy
Used bygeneralCARTC4.5
Can drop one condition from one rule onlynonoyes
A fully grown treeThe pruned tree here
Leaves226
Training accuracy0.8420.842
Validation accuracy0.8100.853
Against the true rule's own 0.8530.043 shortequal

What it does not mean

Pruning does not always reduce training accuracy. Here it did not change it at all: the sixteen extra leaves earned nothing even on the data they were fitted to.

A smaller tree is not automatically better. The depth-1 tree has 2 leaves and scores 0.713. Pruning has an optimum, like every other flexibility dial.

Pre-pruning is not simply a cheaper post-pruning. It can stop before a decisive pair of splits, which post-pruning cannot.

The root attribute is not proven to be the most important. It won a greedy contest on this particular sample, and a small change in the data can change it.

A pure leaf is not a confident leaf. Purity on one row means nothing. Draw the counts.

munotes.in318

Reading, Drawing and Pruning a Decision Tree

Pruning is not specific to trees. It is Regularization in a different representation: cost-complexity pruning is a penalty on the number of leaves.

Quick revision

  • Reading: trace root to leaf; the path's tests joined by and form a rule; the root is the single most separating question for this dataset.
  • Drawing: root at the top, attribute name at each internal node, value on each branch, class in a box at each leaf, and the instance counts, because a leaf's confidence is its row count.
  • Measured: the full tree has 22 leaves, training 0.842, validation 0.810. The depth-2 tree has 6 leaves, training 0.842, validation 0.853. 0.853 is what the TRUE rule itself scores, so the pruned tree has reached the ceiling and the extra sixteen leaves were memorised noise.
  • Pre-pruning stops growth by max depth, minimum instances, or minimum gain. It suffers the horizon effect: exclusive-or has zero gain on either attribute alone.
  • Post-pruning grows fully and cuts back: reduced-error (keep a cut if validation accuracy does not fall), cost-complexity (error + alpha * leaves, CART, and it is regularization), rule post-pruning (C4.5, drops a condition from one rule only).
  • Cautions: a tree is unstable under small data changes, depth is not importance, and a pure leaf on one row is worthless.

Test yourself

1. How do you read a prediction out of a decision tree? Start at the root, apply its test to the instance, follow the branch matching the result, and repeat until reaching a leaf. The leaf's label is the prediction; no other part of the tree is consulted.

2. What should a drawn tree show besides the attributes and classes, and why? The number of instances reaching each node and the class counts at each leaf, because a leaf's trustworthiness depends entirely on how many rows support it. A leaf resting on one row is asserted with the same confidence as one resting on forty.

3. Give the three numbers that make the case for pruning in this chapter. The full tree has 22 leaves with training accuracy 0.842 and validation accuracy 0.810. The pruned tree has 6 leaves with the same training accuracy of 0.842 and a validation accuracy of 0.853. So pruning made the tree a quarter of the size, lost nothing on training, and gained 0.043 on unseen data.

4. Why is 0.853 significant in that table? Because it is what the true rule itself scores on the same validation set, since fifteen per cent of those labels were flipped. No model can do better, so the pruned tree has reached the ceiling and the full tree's extra leaves were memorised noise.

munotes.in319

Reading, Drawing and Pruning a Decision Tree

5. Distinguish pre-pruning from post-pruning and say which is preferred. Pre-pruning refuses to split during growth, by a criterion such as maximum depth or minimum gain; post-pruning grows the tree fully and then replaces subtrees with leaves. Post-pruning is preferred because pre-pruning suffers the horizon effect: a split with no immediate gain may enable a decisive one below it, and exclusive-or is the standard example.

6. Describe reduced-error pruning and cost-complexity pruning. Reduced-error pruning replaces each internal node's subtree with a leaf holding the majority class and keeps the change if accuracy on a validation set does not fall, repeating until no cut helps. Cost-complexity pruning scores candidate trees by their error plus alpha times the number of leaves and chooses alpha by cross-validation, which is exactly regularization applied to tree size.

7. Why should a particular tree's structure not be presented as a fact about the world? Because trees are unstable: changing a few training rows can change which attribute wins at the root and produce a very different-looking tree of similar accuracy. The structure reflects a greedy contest on one sample, and that same instability is what ensemble methods later exploit.

Contents This chapter on its own page

munotes.in320

Chapter Fifty-Eight

The Naive Bayes Classifier

Syllabus topic Module 2, "Naive Bayes"

In one line

Naive Bayes computes the probability of each class given the evidence by multiplying the evidence together as if the pieces were independent, which they are not, and it works anyway.

In the wording a student can write in an examination: the naive Bayes classifier assigns to an instance with features x1 ... xn the class c maximising

P(c | x1..xn) proportional to P(c) * product over i of P(xi | c)

This follows from Bayes theorem together with the naive assumption that the features are conditionally independent given the class. The denominator P(x1..xn) is the same for every class and so is dropped. Laplace smoothing adds a constant to every count to prevent an unobserved feature value from forcing the whole product to zero.

It is Module 1, twice

The derivation is three lines and uses nothing not already proved.

Start from Bayes theorem, Bayes Theorem:

P(c | x1..xn) = P(x1..xn | c) * P(c) / P(x1..xn)

Drop the denominator. It does not depend on c, so it cannot change which class is largest; it is the normalising constant of that chapter.

Apply conditional independence, Conditional Independence. If the features are conditionally independent given the class, the joint likelihood factorises:

P(x1..xn | c) = product over i of P(xi | c)

so P(c | x1..xn) proportional to P(c) * product over i of P(xi | c)

There is nothing else in the method. No optimisation, no iteration, no hyperparameter except the smoothing constant. Training is counting, which is why it is the fastest classifier in MU's list.

And the saving is the one Conditional Independence counted: with 30 binary features the full joint needs 2,147,483,647 numbers and this needs 61.

It worked, with every fraction printed

# The naive Bayes classifier: worked BY HAND on the 14 rows, with every
# probability printed, and the zero-frequency problem shown and then fixed.
ROWS = [
    ("rain",  "far",   "no",  "yes", "no"),
    ("rain",  "far",   "no",  "no",  "no"),
    ("clear", "far",   "no",  "yes", "yes"),
    ("humid", "near",  "no",  "yes", "yes"),
    ("humid", "near",  "yes", "yes", "yes"),
    ("humid", "near",  "yes", "no",  "no"),
    ("clear", "near",  "yes", "no",  "yes"),
    ("rain",  "near",  "no",  "yes", "no"),
    ("rain",  "near",  "yes", "yes", "yes"),
    ("humid", "far",   "yes", "yes", "yes"),
    ("rain",  "far",   "yes", "no",  "yes"),
    ("clear", "far",   "yes", "no",  "yes"),
    ("clear", "near",  "no",  "no",  "yes"),
    ("humid", "far",   "no",  "no",  "no"),
]
COLS = ["weather", "distance", "friend", "early"]
TARGET = 4
VALUES = [sorted({r[i] for r in ROWS}) for i in range(len(COLS))]

def counts(cls, col, val):
    n = sum(1 for r in ROWS if r[TARGET] == cls)
    k = sum(1 for r in ROWS if r[TARGET] == cls and r[col] == val)
    return k, n

def cond(cls, col, val, alpha):
    """P(feature = val | class), with Laplace smoothing by alpha."""
    k, n = counts(cls, col, val)
    return (k + alpha) / (n + alpha * len(VALUES[col]))

def predict(case, alpha, show=False):
    scores = {}
    for cls in ("yes", "no"):
        prior = sum(1 for r in ROWS if r[TARGET] == cls) / len(ROWS)
        p = prior
        if show:
            print("   class %s" % cls)
            print("      P(%s) = %d/%d = %.4f"
                  % (cls, sum(1 for r in ROWS if r[TARGET] == cls), len(ROWS), prior))
        for i, v in enumerate(case):
            c = cond(cls, i, v, alpha)
            k, n = counts(cls, i, v)
            p *= c
            if show:
                print("      P(%s = %s | %s) = (%d + %g)/(%d + %g*%d) = %.4f"
                      % (COLS[i], v, cls, k, alpha, n, alpha, len(VALUES[i]), c))
        scores[cls] = p
        if show:
            print("      product = %.8f" % p)
    total = scores["yes"] + scores["no"]
    return scores, (scores["yes"] / total if total else 0.0)

CASE = ("rain", "near", "yes", "no")
print("a new student: weather %s, distance %s, friend going %s, early lecture %s"
      % CASE)
print()
print("WITHOUT smoothing (alpha = 0):")
scores, p_yes = predict(CASE, 0.0, show=True)
print("   unnormalised: yes %.8f   no %.8f" % (scores["yes"], scores["no"]))
print("   P(attend = yes) = %.8f / (%.8f + %.8f) = %.4f"
      % (scores["yes"], scores["yes"], scores["no"], p_yes))
print("   ANSWER: %s" % ("yes" if p_yes > 0.5 else "no"))
print()
print("THE ZERO-FREQUENCY PROBLEM. no student who ATTENDED had weather 'x', an")
print("unseen value, so P(weather = x | yes) would be 0/9 = 0, and the WHOLE")
print("product becomes 0 no matter how strong the other evidence is.")
print("the same happens for any value never seen with a class. check 'clear':")
for cls in ("yes", "no"):
    k, n = counts(cls, 0, "clear")
    print("   P(weather = clear | %s) = %d/%d = %.4f  %s"
          % (cls, k, n, k / n, "<- ZERO, and it wipes out the product" if k == 0 else ""))
print()
print("WITH Laplace smoothing (alpha = 1): add 1 to every count, and add")
print("alpha times the number of possible values to every denominator.")
for cls in ("yes", "no"):
    k, n = counts(cls, 0, "clear")
    print("   P(weather = clear | %s) = (%d+1)/(%d+1*3) = %.4f"
          % (cls, k, n, cond(cls, 0, "clear", 1.0)))
print()
print("the smoothed prediction for a student in CLEAR weather, near, no friend,")
print("early lecture:")
C2 = ("clear", "near", "no", "yes")
for alpha in (0.0, 1.0):
    s, p = predict(C2, alpha)
    print("   alpha = %.0f:  P(yes) = %.4f   -> %s" % (alpha, p, "yes" if p > 0.5 else "no"))
munotes.in321

The Naive Bayes Classifier

a new student: weather rain, distance near, friend going yes, early lecture no

WITHOUT smoothing (alpha = 0):
   class yes
      P(yes) = 9/14 = 0.6429
      P(weather = rain | yes) = (2 + 0)/(9 + 0*3) = 0.2222
      P(distance = near | yes) = (5 + 0)/(9 + 0*2) = 0.5556
      P(friend = yes | yes) = (6 + 0)/(9 + 0*2) = 0.6667
      P(early = no | yes) = (4 + 0)/(9 + 0*2) = 0.4444
      product = 0.02351558
   class no
      P(no) = 5/14 = 0.3571
      P(weather = rain | no) = (3 + 0)/(5 + 0*3) = 0.6000
      P(distance = near | no) = (2 + 0)/(5 + 0*2) = 0.4000
      P(friend = yes | no) = (1 + 0)/(5 + 0*2) = 0.2000
      P(early = no | no) = (3 + 0)/(5 + 0*2) = 0.6000
      product = 0.01028571
   unnormalised: yes 0.02351558   no 0.01028571
   P(attend = yes) = 0.02351558 / (0.02351558 + 0.01028571) = 0.6957
   ANSWER: yes

THE ZERO-FREQUENCY PROBLEM. no student who ATTENDED had weather 'x', an
unseen value, so P(weather = x | yes) would be 0/9 = 0, and the WHOLE
product becomes 0 no matter how strong the other evidence is.
the same happens for any value never seen with a class. check 'clear':
   P(weather = clear | yes) = 4/9 = 0.4444
   P(weather = clear | no) = 0/5 = 0.0000  <- ZERO, and it wipes out the product

WITH Laplace smoothing (alpha = 1): add 1 to every count, and add
alpha times the number of possible values to every denominator.
   P(weather = clear | yes) = (4+1)/(9+1*3) = 0.4167
   P(weather = clear | no) = (0+1)/(5+1*3) = 0.1250

the smoothed prediction for a student in CLEAR weather, near, no friend,
early lecture:
   alpha = 0:  P(yes) = 1.0000   -> yes
   alpha = 1:  P(yes) = 0.8319   -> yes
munotes.in322

The Naive Bayes Classifier

The arithmetic a paper wants. For the class yes: the prior is 9/14, and the four conditional probabilities are read straight off the table by counting. Their product is 0.02351558. The same for no gives 0.01028571. Normalising, P(yes) is 0.6957, so the answer is yes.

Note that the two products do not sum to 1 before normalising. They are P(class) * P(evidence | class), which is the joint, and normalising by their sum divides by P(evidence). That is the normalising constant of Bayes Theorem computed without ever being named.

The zero-frequency problem

Read the middle block. Among the five students who did not attend, none had clear weather, so P(weather = clear | no) is 0/5 = 0.

One zero destroys everything. The product for no becomes exactly 0, whatever the other three features say, so the classifier reports P(yes) = 1.0000: absolute certainty from one missing count. That is not confidence, it is an artefact, and it would occur on any feature value that happens not to appear with a class in a finite sample.

munotes.in323

The Naive Bayes Classifier

Laplace smoothing is the fix and it is one line:

P(xi = v | c) = (count + alpha) / (n_c + alpha * number of possible values of xi)

With alpha = 1, P(weather = clear | no) becomes (0 + 1)/(5 + 3) = 0.1250 instead of 0, and the same student's prediction falls from the absurd 1.0000 to a sensible 0.8319. Same answer, honest confidence.

The denominator must add alpha times the number of possible values, not alpha once, or the smoothed probabilities for a feature no longer sum to 1. And this is Regularization again: smoothing is a prior pulling every estimate towards uniform, and alpha = 1 is exactly a uniform prior on each feature's distribution. It is the same device as The Learning Agent used to stop an early run of failures producing an estimate of zero.

The three standard variants

MU writes Naive Bayes without qualification, and a paper may ask which kind.

VariantFeatures areP(xi given c) is
Multinomialcounts, such as how often a word occursproportional to the count, smoothed
Bernoullipresent or absenta probability of presence, and absence is also evidence
Gaussiancontinuous numbersa normal density with the mean and variance of that feature within that class

Multinomial and Bernoulli differ in a way that matters for text: Bernoulli explicitly scores a word's absence, multinomial ignores it. For short documents Bernoulli usually wins; for long ones multinomial does.

Gaussian naive Bayes is how continuous features are handled without discretising them: estimate the mean and variance of each feature within each class from the training data, and use the normal density. That is two numbers per feature per class, so it remains linear in the number of features.

Why a false assumption gives a good classifier

The assumption is almost always false. In text, New and York are strongly dependent given any class. In the 14 rows, weather and distance may well be related. And the classifier works. A paper asking why expects this answer.

The probabilities are wrong; the ordering is often right. Classification needs only the largest class, not a correct probability. Dependent features count their shared evidence more than once, which pushes the winning class's product further ahead, and the winner usually does not change.

So the correct statement is precise: naive Bayes is a good classifier and a bad probability estimator. Its outputs are notoriously overconfident, clustering near 0 and 1. Anything that uses the probability as a number, such as ranking by risk or setting a threshold on expected cost, should not use naive Bayes without recalibrating it.

munotes.in324

The Naive Bayes Classifier

Two more practical reasons it survives: it needs very little data, since each estimate is a one-dimensional count rather than a joint; and it is immune to the curse of dimensionality that defeats k-NN in k-NN for Regression, and What Limits the Method, because it never computes a distance.

Two implementation points that cost marks

Underflow. Multiplying a hundred probabilities gives a number too small for a computer to represent, and it becomes 0. The fix is to work with logarithms: maximise log P(c) + sum of log P(xi | c), which turns the product into a sum and cannot underflow. Every real implementation does this.

A feature value never seen at all, in any class, contributes the same factor to every class and so cannot affect the comparison. It is usually simply skipped.

Distinctions

Naive BayesBayes theorem
Isa classifiera theorem
Extra assumptionconditional independence of the featuresnone
Exactnoyes
A good classifierA good probability estimator
Needsthe right class to be largestthe number to be right
Naive Bayes isyesno, it is overconfident
MultinomialBernoulliGaussian
Featurescountspresent or absentcontinuous
Scores absencenoyesnot applicable
Parameters per feature per classoneonetwo, mean and variance
No smoothingLaplace smoothing
An unseen value givesprobability 0, wiping out the producta small positive probability
Confidence here1.0000, from one missing count0.8319
It isa bug waiting for a finite samplea uniform prior, that is regularization

What it does not mean

Naive does not mean simple-minded. It names the independence assumption specifically.

The assumption is not usually true, and the classifier is not claiming it is. It is claiming that the ordering of the classes survives the approximation.

The output probability is not a probability you should act on numerically. It is overconfident. Use it to choose a class, not to price a risk.

Smoothing is not a fudge. It is a uniform prior, and it is the same device as the ridge penalty of Regularization.

A zero probability is not evidence of impossibility. It is evidence that the value did not occur in a finite sample.

Multiplying the probabilities directly is not how it is implemented. Logarithms are used, to avoid underflow.

Quick revision

  • P(c | x) proportional to P(c) * product of P(xi | c). Bayes theorem, drop the denominator, and assume the features are conditionally independent given the class.
  • Training is counting. No optimisation, no iteration. With 30 binary features it needs 61 numbers where the full joint needs 2,147,483,647.
  • Worked: prior 9/14, four conditionals counted off the table, product 0.02351558 against 0.01028571, giving P(yes) = 0.6957.
  • Zero frequency: P(weather = clear | no) = 0/5 = 0 makes the whole product 0, so the classifier reports 1.0000. One missing count produces absolute certainty.
  • Laplace smoothing: (count + alpha) / (n + alpha * number of values). With alpha = 1 the estimate becomes 0.1250 and the confidence falls from 1.0000 to 0.8319. It is a uniform prior, that is regularization.
  • Variants: multinomial (counts), Bernoulli (presence, and absence is evidence), Gaussian (continuous, mean and variance per feature per class).
  • A good classifier and a bad probability estimator. The assumption is false, the probabilities are overconfident, and the class ordering usually survives.
  • Implementation: use logarithms, or the product underflows to zero.
munotes.in325

The Naive Bayes Classifier

Test yourself

1. Derive the naive Bayes rule from Bayes theorem. Bayes theorem gives P(c | x) as P(x | c) times P(c) divided by P(x). The denominator is the same for every class and cannot change which is largest, so it is dropped. Assuming the features are conditionally independent given the class, P(x | c) factorises into the product of P(xi | c), giving P(c | x) proportional to P(c) times that product.

2. Compute the prediction for a student in rain, near, with a friend going, no early lecture. For yes: prior 9/14 times the four conditionals, giving 0.02351558. For no: prior 5/14 times its conditionals, giving 0.01028571. Normalising, P(yes) is 0.6957, so the prediction is that the student attends.

3. What is the zero-frequency problem, and what does it do to the output? If a feature value never occurs with a class in the training data, its conditional probability is exactly zero, and multiplying by it makes the entire product zero however strong the other evidence. In this chapter no non-attending student had clear weather, so the classifier reports a probability of 1.0000, absolute certainty produced by one missing count.

4. State Laplace smoothing and apply it to that case. Estimate each conditional as the count plus alpha, divided by the class count plus alpha times the number of possible values of that feature. With alpha of 1, P(weather = clear | no) becomes one over eight, that is 0.1250, instead of zero, and the classifier's confidence falls from 1.0000 to 0.8319.

5. Name the three variants of naive Bayes and say what each suits. Multinomial, for count features such as word frequencies. Bernoulli, for presence-or-absence features, which also scores a feature's absence as evidence and suits short documents. Gaussian, for continuous features, modelling each with a normal distribution whose mean and variance are estimated per class.

munotes.in326

The Naive Bayes Classifier

6. The independence assumption is usually false. Why does the classifier still work? Because classification needs only the correct class to have the largest score, not a correct probability. Dependent features double-count their shared evidence, which exaggerates the leading class's score but usually does not change which class leads. The correct summary is that it is a good classifier and a poor probability estimator, since its outputs are systematically overconfident.

7. Why are logarithms used in an implementation? Because multiplying many probabilities produces a number too small to represent, which becomes zero and destroys the comparison. Taking logarithms turns the product into a sum of logarithms, which cannot underflow, and the class with the largest sum is the same as the class with the largest product.

Contents This chapter on its own page

munotes.in327

Chapter Fifty-Nine

Support Vector Machines: The Margin

Syllabus topic Module 2, "SVM"

In one line

When many lines separate the data, a support vector machine picks the one with the most clear space on either side.

In the wording a student can write in an examination: a support vector machine is a linear classifier that chooses, among all hyperplanes separating the training classes, the one with the greatest margin, the perpendicular distance to the nearest training instances. Those nearest instances are the support vectors, and the solution depends only on them. It is therefore called a maximum margin classifier, and the principle is justified by structural risk minimisation: a larger margin corresponds to a smaller capacity and so to a better expected generalisation.

The problem the margin solves

Supervised Learning fitted a threshold at 4.5 hours and observed that the training data could not choose between 4.3 and 4.5. The same difficulty in two dimensions is the starting point here.

Six points, three of each class, plainly separable. Many lines separate them, and every one classifies all six correctly, so the training error cannot choose. A support vector machine chooses by a second criterion: the width of the corridor the line sits in.

And the justification is not aesthetic. A line squeezed against one class will misclassify a new point that falls just past it, and new points do fall just past lines. The widest corridor is the choice that tolerates the most movement in the data before an error occurs.

The definitions

For a line (in general, a hyperplane) written w . x + b = 0:

the signed distance from a point x to it is (w . x + b) / ||w||

A point is classified by the sign of w . x + b, so a training point with label y in {+1, -1} is correct exactly when y * (w . x + b) > 0.

The margin is the distance from the hyperplane to the nearest training point of either class. Some texts call that the half margin and use "margin" for the full corridor, which is twice it. Say which you mean; this book uses the distance to the nearest point.

The support vectors are the training points at exactly that distance. Everything else is irrelevant to the answer, which is the property demonstrated below.

Measured

# The margin, COMPUTED. Two candidate separating lines on the same six points,
# the margin of each measured, and the support vectors identified.
import math
POS = [(3, 3), (4, 4), (4, 2)]          # class +1
NEG = [(1, 1), (0, 2), (1, 0)]          # class -1
POINTS = [(p, +1) for p in POS] + [(p, -1) for p in NEG]

def margin(w, b):
    """The distance from the nearest point to the line w.x + b = 0, and which."""
    norm = math.hypot(*w)
    best = None
    for (x, y), label in POINTS:
        signed = (w[0] * x + w[1] * y + b) / norm
        if label * signed <= 0:
            return None, None, "MISCLASSIFIES (%g, %g)" % (x, y)
        d = abs(signed)
        if best is None or d < best[0] - 1e-12:
            best = (d, [(x, y)])
        elif abs(d - best[0]) < 1e-9:
            best[1].append((x, y))
    return best[0], best[1], "separates all six"

CANDIDATES = [
    ("A:  x + y = 4        ", (1.0, 1.0), -4.0),
    ("B:  x + y = 3        ", (1.0, 1.0), -3.0),
    ("C:  x + y = 2.5      ", (1.0, 1.0), -2.5),
    ("D:  x = 2            ", (1.0, 0.0), -2.0),
    ("E:  x + 0.2y = 2.2   ", (1.0, 0.2), -2.2),
]
print("six points. class +1 at %s" % ", ".join(str(p) for p in POS))
print("           class -1 at %s" % ", ".join(str(p) for p in NEG))
print()
print("candidate line          | margin  | verdict | the nearest points")
for name, w, b in CANDIDATES:
    m, sv, note = margin(w, b)
    if m is None:
        print("%s | %7s | %-24s |" % (name, "-", note))
    else:
        print("%s | %7.4f | %-24s | %s"
              % (name, m, note, " ".join(str(p) for p in sv)))
print()
best = max((c for c in CANDIDATES if margin(c[1], c[2])[0] is not None),
           key=lambda c: margin(c[1], c[2])[0])
m, sv, _ = margin(best[1], best[2])
print("the LARGEST margin is %s with %.4f." % (best[0].strip(), m))
print("its nearest points are %s: these are the SUPPORT VECTORS."
      % " and ".join(str(p) for p in sv))
print()
print("why the largest: every candidate above separates the six points equally")
print("well, 6 of 6 correct, so the training error cannot choose between them.")
print("the margin can. a line squeezed against one class generalises worse,")
print("because a new point a little way past it is misclassified.")
print()
print("MOVING A NON-SUPPORT POINT CHANGES NOTHING. take (4, 4), which is not a")
print("support vector, and move it to (9, 9):")
POS[1] = (9, 9)
POINTS = [(p, +1) for p in POS] + [(p, -1) for p in NEG]
m2, sv2, _ = margin(best[1], best[2])
print("   margin is still %.4f, and the support vectors are still %s."
      % (m2, " and ".join(str(p) for p in sv2)))
print("   the model depends ONLY on the support vectors. the other points could")
print("   be deleted and the same line would be found.")
munotes.in328

Support Vector Machines: The Margin

six points. class +1 at (3, 3), (4, 4), (4, 2)
           class -1 at (1, 1), (0, 2), (1, 0)

candidate line          | margin  | verdict | the nearest points
A:  x + y = 4         |  1.4142 | separates all six        | (3, 3) (4, 2) (1, 1) (0, 2)
B:  x + y = 3         |  0.7071 | separates all six        | (1, 1) (0, 2)
C:  x + y = 2.5       |  0.3536 | separates all six        | (1, 1) (0, 2)
D:  x = 2             |  1.0000 | separates all six        | (3, 3) (1, 1) (1, 0)
E:  x + 0.2y = 2.2    |  0.9806 | separates all six        | (1, 1)

the LARGEST margin is A:  x + y = 4 with 1.4142.
its nearest points are (3, 3) and (4, 2) and (1, 1) and (0, 2): these are the SUPPORT VECTORS.

why the largest: every candidate above separates the six points equally
well, 6 of 6 correct, so the training error cannot choose between them.
the margin can. a line squeezed against one class generalises worse,
because a new point a little way past it is misclassified.

MOVING A NON-SUPPORT POINT CHANGES NOTHING. take (4, 4), which is not a
support vector, and move it to (9, 9):
   margin is still 1.4142, and the support vectors are still (3, 3) and (4, 2) and (1, 1) and (0, 2).
   the model depends ONLY on the support vectors. the other points could
   be deleted and the same line would be found.
munotes.in329

Support Vector Machines: The Margin

Read the margin column: 1.4142, 0.7071, 0.3536, 1.0000, 0.9806. Every one of the five lines separates all six points, and they differ by a factor of four in how much room they leave. Line A, x + y = 4, is the widest at 1.4142, which is the square root of 2.

Its support vectors are the four points at exactly that distance: (3,3) and (4,2) on one side, (1,1) and (0,2) on the other. The corridor touches two points of each class, which is what a maximal margin solution looks like.

And the last block is the property that names the method. Move (4,4) to (9,9), five units away. The margin is unchanged at 1.4142 and the support vectors are unchanged. A point that is not a support vector could be deleted entirely and the same line would be found. That is why it is called a support vector machine: the support vectors support the solution and nothing else contributes.

The optimisation

A paper may ask for the problem as it is posed, and it is worth being able to state.

Rescale w and b so that the nearest points satisfy |w . x + b| = 1. That is always possible and it fixes an arbitrary scaling. The margin is then 1 / ||w||, so maximising the margin is minimising ||w||, and it is conventional to minimise half its square because that is smooth:

munotes.in330

Support Vector Machines: The Margin

minimise 0.5 * ||w||**2

subject to y_i * (w . x_i + b) >= 1 for every training point i

This is a convex quadratic programme: a quadratic objective with linear constraints. Convex is the word that matters. It has exactly one minimum, so unlike a neural network's loss there is no local minimum to get stuck in and no dependence on initialisation. Any correct solver finds the same answer every time, and that reproducibility is one of the method's real advantages.

The constraint can be read directly: every point must be on the correct side and at least one unit of the rescaled distance away. Points satisfying it with equality are the support vectors.

The dual, and why it is mentioned

The problem is usually solved in its dual form, with one variable alpha_i per training point rather than one per feature. Three consequences, and a paper may ask for the third.

Most alpha_i are zero. They are non-zero exactly at the support vectors, which is where the sparsity comes from.

The number of variables is the number of training points, not the number of features, so the method copes with very high-dimensional data.

The data appears only as inner products x_i . x_j. That single fact is what makes The Soft Margin and the Kernel possible: replace the inner product with a kernel and the whole method works in a different space without ever going there.

Why the widest margin generalises better

The justification is not merely the intuitive one, and naming the principle is worth a mark.

Cortes and Vapnik's framework is structural risk minimisation. The capacity of a set of classifiers is measured by the VC dimension, and for separating hyperplanes with a margin the capacity falls as the margin grows. A bound on the expected error combines the training error with a term that grows with capacity, so maximising the margin minimises the bound.

In the language of Bias and Variance: a larger margin is a smaller hypothesis space, which is lower variance. Maximising the margin is regularization, imposed geometrically. And it is the same 0.5 * ||w||**2 that appears as the ridge penalty in Regularization, which is not a coincidence.

Where support vector machines stand

A paper asking when to use one expects these.

Strengths. Effective when the number of features exceeds the number of instances, which defeats most methods. Sparse: only the support vectors are kept. Convex, so the answer is unique and reproducible. And with a kernel, it handles non-linear boundaries without changing the algorithm.

Weaknesses. Training is between quadratic and cubic in the number of instances, so it does not scale to very large datasets. It produces no probability, only a side of the boundary; probabilities require a separate calibration step. Choosing a kernel and its parameters is a real burden. And the features must be scaled, for the same reason as in k-NN for Regression, and What Limits the Method: a feature with a large numeric range dominates the inner product.

munotes.in331

Support Vector Machines: The Margin

Distinctions

A separating lineThe maximum margin line
Number of themusually infinitely manyone
Chosen bythe training error, which cannot choosethe margin
On the six pointsfive candidates, all 6 of 6 correctx + y = 4, margin 1.4142
A support vectorAny other training point
Distance to the boundaryexactly the margingreater
Its alpha in the dualnon-zerozero
Deleting itchanges the solutionchanges nothing
Moving it further awaychanges the solutionchanges nothing
SVMLogistic regression
Depends onthe support vectors onlyevery training point
Outputsa side of the boundarya probability
Losshingecross-entropy
Optimisationconvex quadratic programmeconvex, iterative

What it does not mean

A support vector is not a vector in the machine-learning sense of a feature vector only. It is a training instance that lies on the margin, and the name is historical.

Maximising the margin is not the same as minimising the training error. All five candidate lines had zero training error.

The margin is not the corridor's full width. It is the distance to the nearest point, half the corridor, and texts differ.

The solution does not use most of the data. Two of six points here contribute nothing, and on a large dataset the fraction that contributes is often tiny.

Convexity is not merely convenient. It means there is no initialisation to choose and no local minimum, so the answer is unique and reproducible.

An SVM does not produce a probability. The distance to the boundary is not one, and turning it into one needs a separate calibration.

Quick revision

  • An SVM chooses, among separating hyperplanes, the one of greatest margin, the distance to the nearest training point. Those nearest points are the support vectors.
  • Classification is by the sign of w . x + b; a point is correct when y * (w . x + b) > 0.
  • Measured on six points: five separating lines with margins 1.4142, 0.7071, 0.3536, 1.0000, 0.9806, all with zero training error. The widest is x + y = 4, with four support vectors.
  • Moving a non-support point from (4,4) to (9,9) changes nothing: same margin, same support vectors. The solution depends only on the support vectors.
  • The problem: minimise 0.5 * ||w||2 subject to y_i (w . x_i + b) >= 1. A convex quadratic programme**, so one minimum, no initialisation, a reproducible answer.
  • In the dual, one variable per training point, non-zero only at support vectors, and the data appears only as inner products, which is what makes the kernel possible.
  • Justified by structural risk minimisation: a larger margin is a smaller capacity. In the language of Module 2, it is regularization imposed geometrically, and 0.5 * ||w||**2 is the ridge penalty.
  • Strengths: more features than instances, sparse, convex, kernels. Weaknesses: scales poorly in the number of instances, gives no probability, needs kernel choice, and needs the features scaled.
munotes.in332

Support Vector Machines: The Margin

Test yourself

1. Define the margin and the support vectors. The margin is the perpendicular distance from the separating hyperplane to the nearest training instance of either class. The support vectors are the training instances lying at exactly that distance.

2. Why can the training error not choose between separating lines, and what does an SVM use instead? Because every separating line classifies all the training points correctly, so they all have zero training error. An SVM chooses the one with the greatest margin, on the ground that a line squeezed against one class misclassifies a new point that falls slightly past it.

3. In this chapter, what happened when a non-support point was moved five units away? Nothing. The margin remained 1.4142 and the support vectors were unchanged. The solution depends only on the support vectors, so any other training point could be deleted and the same line would be found.

4. State the optimisation problem an SVM solves and name its type. Minimise half the squared norm of w, subject to y_i times (w . x_i + b) being at least 1 for every training point. It is a convex quadratic programme: a quadratic objective with linear constraints.

5. Why does convexity matter here? Because a convex problem has exactly one minimum, so there is no local minimum to be trapped in and no starting point to choose. Any correct solver returns the same answer every time, which makes the method reproducible in a way that a neural network is not.

6. What property of the dual formulation makes kernels possible? In the dual the training data appears only through inner products between pairs of instances. Replacing that inner product with a kernel function computes the inner product in some other space, so the method operates there without the mapping ever being carried out.

7. Give two strengths and two weaknesses of support vector machines. They work when the number of features exceeds the number of instances, and they are sparse, since only the support vectors are retained; they are also convex and so reproducible. Against that, training scales poorly with the number of instances, they output a side of the boundary rather than a probability, the kernel and its parameters must be chosen, and the features must be scaled first.

Contents This chapter on its own page

munotes.in333

Chapter Sixty

The Soft Margin and the Kernel

Syllabus topic Module 2, "SVM"

In one line

The soft margin lets a few points be on the wrong side for a price, and the kernel lets a straight line in a space you never build curve in the space you have.

In the wording a student can write in an examination: the soft margin introduces a slack variable for each training instance, permitting it to violate the margin, and minimises 0.5 ||w||2 + C (sum of the slacks), where the hyperparameter C sets the cost of a violation. The kernel trick replaces every inner product in the dual formulation with a kernel function K(x, z), which equals the inner product of the images of x and z under some mapping into a higher-dimensional feature space**, so a linear boundary there corresponds to a non-linear boundary in the original space and the mapping is never computed.

Problem one: no line separates the data

Support Vector Machines: The Margin required a hyperplane satisfying y_i (w . x_i + b) >= 1 for every point. On real data no such hyperplane exists, for two quite different reasons.

Noise. A mislabelled or unusual instance sits among the other class. The true boundary is a line; one point is on the wrong side of it.

Genuine non-linearity. The classes are separated by a curve, not a line, however clean the data. Exclusive-or is the smallest example.

These need different repairs, and confusing them is a common error. The soft margin handles the first; the kernel handles the second. A kernel applied to noisy data overfits it; a soft margin applied to a curved boundary underfits.

The soft margin

Introduce a slack s_i >= 0 for each instance and weaken the constraint:

y_i * (w . x_i + b) >= 1 - s_i

Read the slack: s_i = 0 means the point respects the margin; 0 < s_i < 1 means it is inside the corridor but still on the correct side; s_i > 1 means it is misclassified. Then minimise

0.5 * ||w||**2 + C * sum of s_i

Two terms pulling opposite ways. The first wants a wide margin. The second wants few violations. C is the exchange rate, and it is the single most important hyperparameter of the method.

Written as an unconstrained loss, the same thing is the hinge loss:

loss = 0.5 * ||w||**2 + C * sum of max(0, 1 - y_i (w . x_i + b))

Note what the hinge charges for: being on the wrong side, and being correct but inside the corridor. That is why the error count and the loss do not move together, as the measurement below shows.

munotes.in334

The Soft Margin and the Kernel

Problem two: exclusive-or, and the mapping

# The soft margin and the kernel. Exclusive-or cannot be separated by any line;
# mapped to three dimensions it can. And the kernel trick computed BOTH ways.
import itertools, math

XOR = [((0, 0), -1), ((1, 1), -1), ((0, 1), +1), ((1, 0), +1)]
print("EXCLUSIVE-OR: (0,0) and (1,1) are one class, (0,1) and (1,0) the other.")
print("can ANY straight line w1*x + w2*y + b = 0 separate them? search a grid:")
found = 0
for w1 in [i / 2.0 for i in range(-8, 9)]:
    for w2 in [i / 2.0 for i in range(-8, 9)]:
        for b in [i / 2.0 for i in range(-8, 9)]:
            if all(lab * (w1 * x + w2 * y + b) > 0 for (x, y), lab in XOR):
                found += 1
print("   lines tried: %d      lines that separate: %d"
      % (17 ** 3, found))
print("   none. exclusive-or is NOT linearly separable, which is what defeated")
print("   the perceptron of the previous chapter.")
print()
print("MAP IT UP. send (x, y) to (x, y, x*y), a third dimension:")
for (x, y), lab in XOR:
    print("   (%d, %d) class %+d  ->  (%d, %d, %d)" % (x, y, lab, x, y, x * y))
print("   now the PLANE  x + y - 2*(x*y) = 0.5  separates them:")
for (x, y), lab in XOR:
    v = x + y - 2 * (x * y) - 0.5
    print("      (%d, %d, %d)  value %+.1f  side %+d   correct: %s"
          % (x, y, x * y, v, 1 if v > 0 else -1, lab == (1 if v > 0 else -1)))
print()
print("THE KERNEL TRICK. a polynomial kernel of degree 2 computes the inner")
print("product in the mapped space WITHOUT building it. take two points:")
A, B = (2.0, 3.0), (4.0, 1.0)

def phi(p):
    """The explicit degree-2 map, six numbers for two."""
    x, y = p
    return (x * x, y * y, math.sqrt(2) * x * y,
            math.sqrt(2) * x, math.sqrt(2) * y, 1.0)

explicit = sum(a * b for a, b in zip(phi(A), phi(B)))
kernel = (A[0] * B[0] + A[1] * B[1] + 1.0) ** 2
print("   A = %s   B = %s" % (A, B))
print("   phi(A) = (%s)" % ", ".join("%.4f" % v for v in phi(A)))
print("   phi(B) = (%s)" % ", ".join("%.4f" % v for v in phi(B)))
print("   explicit inner product of the two 6-vectors : %.6f" % explicit)
print("   the kernel (A.B + 1)**2, on the ORIGINAL 2  : %.6f" % kernel)
print("   the same number, and the second never built the six numbers.")
print()
print("THE SOFT MARGIN. one +1 point is placed INSIDE the -1 group, so no line")
print("separates the seven at all. C decides how much a violation costs.")
POS = [(3, 3), (4, 4), (4, 2), (0, 1)]        # (0,1) is the intruder
NEG = [(1, 1), (0, 2), (1, 0)]
PTS = [(p, +1) for p in POS] + [(p, -1) for p in NEG]

def hinge_objective(w, b, C):
    """0.5*|w|^2 + C * sum of hinge losses. The SVM's own objective."""
    reg = 0.5 * (w[0] ** 2 + w[1] ** 2)
    loss = sum(max(0.0, 1 - lab * (w[0] * x + w[1] * y + b)) for (x, y), lab in PTS)
    return reg + C * loss, reg, loss

print("   the intruder is (0, 1), labelled +1, surrounded by the -1 points.")
print("   C      | best objective | 0.5|w|^2 | total hinge loss | errors")
for C in (0.01, 0.05, 0.2, 1.0, 5.0):
    best = None
    for w1 in [i / 10.0 for i in range(-30, 31)]:
        for w2 in [i / 10.0 for i in range(-30, 31)]:
            for b in [i / 10.0 for i in range(-50, 51)]:
                obj, reg, loss = hinge_objective((w1, w2), b, C)
                if best is None or obj < best[0]:
                    err = sum(1 for (x, y), lab in PTS
                              if lab * (w1 * x + w2 * y + b) <= 0)
                    best = (obj, reg, loss, err, (w1, w2), b)
    print("   %6g | %14.4f | %8.4f | %16.4f | %d of 7"
          % (C, best[0], best[1], best[2], best[3]))
print()
print("   read the two middle columns against each other. as C rises, half the")
print("   squared norm rises 0.0000, 0.0250, 0.1700, 0.2500, which means the")
print("   MARGIN SHRINKS; and the hinge loss falls 6.0, 4.7, 2.7, 2.5, which")
print("   means the violations are being paid down. that is the whole trade.")
print()
print("   the error count is NOT monotonic, and it is not supposed to be: the")
print("   objective minimises the hinge loss, which charges for being close to")
print("   the boundary as well as for being on the wrong side of it.")
print()
print("   C is the regularization dial of chapter 50 with 1/C in place of lambda:")
print("   large C means little regularization, a narrow margin, few violations.")
munotes.in335

The Soft Margin and the Kernel

EXCLUSIVE-OR: (0,0) and (1,1) are one class, (0,1) and (1,0) the other.
can ANY straight line w1*x + w2*y + b = 0 separate them? search a grid:
   lines tried: 4913      lines that separate: 0
   none. exclusive-or is NOT linearly separable, which is what defeated
   the perceptron of the previous chapter.

MAP IT UP. send (x, y) to (x, y, x*y), a third dimension:
   (0, 0) class -1  ->  (0, 0, 0)
   (1, 1) class -1  ->  (1, 1, 1)
   (0, 1) class +1  ->  (0, 1, 0)
   (1, 0) class +1  ->  (1, 0, 0)
   now the PLANE  x + y - 2*(x*y) = 0.5  separates them:
      (0, 0, 0)  value -0.5  side -1   correct: True
      (1, 1, 1)  value -0.5  side -1   correct: True
      (0, 1, 0)  value +0.5  side +1   correct: True
      (1, 0, 0)  value +0.5  side +1   correct: True

THE KERNEL TRICK. a polynomial kernel of degree 2 computes the inner
product in the mapped space WITHOUT building it. take two points:
   A = (2.0, 3.0)   B = (4.0, 1.0)
   phi(A) = (4.0000, 9.0000, 8.4853, 2.8284, 4.2426, 1.0000)
   phi(B) = (16.0000, 1.0000, 5.6569, 5.6569, 1.4142, 1.0000)
   explicit inner product of the two 6-vectors : 144.000000
   the kernel (A.B + 1)**2, on the ORIGINAL 2  : 144.000000
   the same number, and the second never built the six numbers.

THE SOFT MARGIN. one +1 point is placed INSIDE the -1 group, so no line
separates the seven at all. C decides how much a violation costs.
   the intruder is (0, 1), labelled +1, surrounded by the -1 points.
   C      | best objective | 0.5|w|^2 | total hinge loss | errors
     0.01 |         0.0600 |   0.0000 |           6.0000 | 3 of 7
     0.05 |         0.2600 |   0.0250 |           4.7000 | 4 of 7
      0.2 |         0.7100 |   0.1700 |           2.7000 | 1 of 7
        1 |         2.7500 |   0.2500 |           2.5000 | 1 of 7
        5 |        12.7500 |   0.2500 |           2.5000 | 1 of 7

   read the two middle columns against each other. as C rises, half the
   squared norm rises 0.0000, 0.0250, 0.1700, 0.2500, which means the
   MARGIN SHRINKS; and the hinge loss falls 6.0, 4.7, 2.7, 2.5, which
   means the violations are being paid down. that is the whole trade.

   the error count is NOT monotonic, and it is not supposed to be: the
   objective minimises the hinge loss, which charges for being close to
   the boundary as well as for being on the wrong side of it.

   C is the regularization dial of chapter 50 with 1/C in place of lambda:
   large C means little regularization, a narrow margin, few violations.
munotes.in336

The Soft Margin and the Kernel

Read the three blocks.

Exclusive-or. Four thousand nine hundred and thirteen candidate lines were tried and none separates the four points. This is not a failure of search; it is a theorem, and it is the problem that stopped the perceptron of The Artificial Neuron and the Perceptron.

The mapping. Send (x, y) to (x, y, xy). The four points become four points in three dimensions, and the plane x + y - 2xy = 0.5 separates them. A linear boundary in the new space is a non-linear boundary in the old one: back in two dimensions, that plane is the curve x + y - 2xy = 0.5.

munotes.in337

The Soft Margin and the Kernel

The trick. phi sends a two-dimensional point to six numbers. The inner product of phi(A) and phi(B) is 144.000000. The kernel (A . B + 1)2, computed on the original two numbers, is 144.000000. The same number, and the second never built the six.** That is the kernel trick entire: since Support Vector Machines: The Margin showed the dual uses the data only through inner products, replacing every inner product with K runs the whole algorithm in the six-dimensional space at the cost of arithmetic on two numbers.

The soft margin. As C rises from 0.01 to 5, 0.5 ||w||2 rises 0.0000, 0.0250, 0.1700, 0.2500, so the margin shrinks; and the hinge loss falls 6.0, 4.7, 2.7, 2.5, so the violations are paid down**. The error count is not monotonic, which is honest: the objective minimises the hinge loss, and the hinge charges for being near the boundary as well as for being past it.

The standard kernels

A paper asks for these three by name.

KernelK(x, z)Feature space
Linearx . zthe original one; no mapping
Polynomial of degree d(x . z + c)**dall monomials up to degree d; finite
Radial basis function, RBF or Gaussianexp(-gamma * dist(x, z)**2), the squared distanceinfinite dimensional
Sigmoidtanh(a * x . z + r)resembles a neural network; not always a valid kernel

The RBF kernel's feature space has infinitely many dimensions, and a boundary is still found in it in finite time, because the algorithm never enters that space. That is the sharpest statement of what the trick buys and a paper likes it.

gamma controls the reach of each training point. Large gamma makes each point influence only its immediate neighbourhood, giving a wiggly boundary and overfitting; small gamma makes the boundary smooth and can underfit. So an RBF SVM has two hyperparameters, C and gamma, and they are tuned together on a grid by cross-validation. That is the usual answer to "how is an SVM tuned".

What makes a function a kernel

Not every two-argument function is one, and the condition has a name.

Mercer's condition. K is a valid kernel if it is symmetric and the matrix K(x_i, x_j) formed from any finite set of points is positive semi-definite. If that holds, some mapping phi exists for which K is the inner product, and it need not be written down.

Two useful consequences. Kernels can be combined: the sum of two kernels is a kernel, and so is a positive multiple, and so is a product. And a kernel can be defined on objects that are not vectors at all, such as strings, trees or graphs, which is how SVMs are applied to text and to molecules.

munotes.in338

The Soft Margin and the Kernel

Choosing between them

A paper asking which kernel to use expects a rule rather than a preference.

Linear when the number of features is large, especially larger than the number of instances, as in text. The data is usually already separable in such a space and a non-linear kernel only overfits.

RBF as the general-purpose default when the number of features is moderate and the boundary is unknown. It is the usual first choice.

Polynomial when interactions of a known degree are expected, for example when the effect of two features together matters.

And the practical warning from k-NN for Regression, and What Limits the Method: scale the features first. The RBF kernel measures a distance, and the polynomial an inner product, so a feature with a large numeric range dominates both, exactly as it dominates a nearest-neighbour search.

Distinctions

Soft marginKernel
Fixesnoise: a few points on the wrong sidenon-linearity: a curved boundary
Addsslack variables and Ca kernel function, and its parameters
Wrongly appliedto a curved boundary, it underfitsto noisy data, it overfits
Small CLarge C
Marginwidenarrow
Violations toleratedmanyfew
Regularizationstrongweak
Riskunderfittingoverfitting
The explicit mappingThe kernel
Builds the new coordinatesyesno
Cost for a degree-2 map of 2 features6 numbers per point2, and one multiplication
For an RBFimpossible, infinitely manyone exponential
Both give144.000000144.000000

What it does not mean

The kernel does not map the data. It computes what the inner product would be if the data had been mapped. Nothing is ever mapped.

A kernel is not a distance. It is an inner product in some space; the RBF kernel is built from a distance but is not one.

The soft margin is not a way of handling curved boundaries. It handles violations of a linear boundary.

C is not the margin. It is the price of violating it, and 1/C behaves as the regularization strength lambda.

Not every function of two arguments is a kernel. Mercer's condition must hold.

A non-linear kernel is not always better. With more features than instances, a linear kernel usually wins, because the data is already separable and a richer kernel only fits noise.

Quick revision

  • Soft margin: allow y_i (w . x_i + b) >= 1 - s_i with slack s_i >= 0, and minimise 0.5 ||w||2 + C * sum of s_i. Equivalently the hinge loss**, which charges for being inside the corridor as well as past the boundary.
  • C is the exchange rate. Measured: as C rises, 0.5||w||2 rises 0.0000 to 0.2500, so the margin shrinks, while the hinge loss falls 6.0 to 2.5. 1/C plays the part of lambda** in Regularization.
  • Exclusive-or: 4,913 candidate lines tried, 0 separate it. Mapped to (x, y, xy), the plane x + y - 2xy = 0.5 does.
  • The kernel trick, both ways: the inner product of two explicit 6-vectors is 144.000000, and (A . B + 1)2 on the original two numbers is 144.000000**. The dual uses the data only through inner products, so replacing them with K runs the algorithm in the mapped space without entering it.
  • Kernels: linear, polynomial (x.z + c)d, RBF exp(-gamma ||x - z||2) whose feature space is infinite dimensional, and sigmoid.
  • RBF has two hyperparameters, C and gamma, tuned together by cross-validation. Large gamma overfits, small gamma underfits.
  • Mercer's condition: symmetric and positive semi-definite. Kernels can be summed and multiplied, and defined on strings, trees and graphs.
  • Scale the features first. And the soft margin fixes noise, the kernel fixes curvature; swapping them is the standard mistake.
munotes.in339

The Soft Margin and the Kernel

Test yourself

1. What does the soft margin change, and what does C control? It replaces the requirement that every point satisfy the margin with the weaker requirement y_i (w . x_i + b) at least 1 - s_i for a non-negative slack, and adds C times the sum of the slacks to the objective. C is the price of a violation: it sets the exchange rate between a wide margin and few violations.

2. Write the SVM objective as an unconstrained loss and say what the hinge charges for. Half the squared norm of w, plus C times the sum over instances of the maximum of zero and 1 - y_i (w . x_i + b). The hinge charges both for being on the wrong side of the boundary and for being on the correct side but inside the margin corridor.

3. In this chapter's measurement, what happened as C rose? Half the squared norm rose from 0.0000 to 0.2500, meaning the margin shrank, while the total hinge loss fell from 6.0 to 2.5, meaning violations were paid down. The error count was not monotonic, because the objective minimises the hinge loss rather than the count.

4. Show that exclusive-or is not linearly separable, and give a mapping that fixes it. Searching 4,913 candidate lines over a grid of weights and offsets finds none that separates the four points. Mapping (x, y) to (x, y, xy) places the points in three dimensions, where the plane x + y - 2xy = 0.5 separates them; back in two dimensions that plane is a curve.

munotes.in340

The Soft Margin and the Kernel

5. State the kernel trick and give the numerical demonstration from this chapter. The dual formulation uses the training data only through inner products, so replacing each inner product with a kernel function computes the inner product in some mapped space without performing the mapping. Here the explicit degree-two map sends two numbers to six, and the inner product of the two six-vectors is 144.000000, which is exactly what the kernel (A . B + 1) squared gives from the original two numbers.

6. Name three kernels and say what is remarkable about one of them. Linear, x . z. Polynomial, (x . z + c) to the power d. And the radial basis function, the exponential of minus gamma times the squared distance. The last is remarkable because its feature space has infinitely many dimensions, and a boundary is still found in it in finite time, because the algorithm never enters that space.

7. When would you use a linear kernel rather than an RBF one? When the number of features is large, especially larger than the number of instances, as in text classification. The data is then usually already separable in the original space, and a richer kernel would fit noise rather than structure.

Contents This chapter on its own page

munotes.in341

Chapter Sixty-One

The Artificial Neuron and the Perceptron

Syllabus topic Module 2, "single-layer"

In one line

An artificial neuron adds up its inputs with weights, and fires if the total passes a threshold; one of them can learn any rule that a straight line can separate, and no others.

In the wording a student can write in an examination: an artificial neuron computes a weighted sum of its inputs plus a bias, and passes the result through an activation function. A perceptron is a single such neuron with a threshold activation, giving output 1 when w . x + b >= 0 and 0 otherwise. The perceptron learning rule updates w <- w + rate (target - output) x on each misclassified example, and the perceptron convergence theorem guarantees that this terminates in finitely many steps if the data is linearly separable.

The neuron

Three parts, and a paper asks for all three.

PartWhat it is
Weights wone per input, learned; how much that input counts
Bias ba learned constant; how easy the neuron is to fire
Activationa function applied to the weighted sum, which decides the output

z = w1x1 + w2x2 + ... + wn*xn + b

output = activation(z)

The quantity z is called the net input or the pre-activation. The bias is often written as an extra input fixed at 1 with its own weight, which makes the formula uniform; the two descriptions are identical.

The activation functions

MU's label names only single-layer, and a paper about neurons asks for these.

FunctionFormulaOutput rangeNote
Step, or threshold1 if z >= 0, else 0{0, 1}the original perceptron; not differentiable, so gradient descent cannot be used
Sigmoid, or logistic1 / (1 + exp(-z))(0, 1)smooth, so backpropagation works; reads as a probability
tanh(e^z - e^-z)/(e^z + e^-z)(-1, 1)centred on zero, which usually trains faster
ReLUmax(0, z)[0, infinity)cheap, and the default in a deep network

The step function is why the perceptron needed its own learning rule. Its derivative is zero everywhere it exists, so Gradient Descent has nothing to follow. Replacing the step with a sigmoid is exactly what makes the next chapter possible, and it is the single most important change between the two.

Training it, by hand

# The perceptron: one artificial neuron, trained BY HAND on AND until it
# converges, and then shown failing on exclusive-or. Read against Rosenblatt 1958.
AND = [((0, 0), 0), ((0, 1), 0), ((1, 0), 0), ((1, 1), 1)]
XOR = [((0, 0), 0), ((0, 1), 1), ((1, 0), 1), ((1, 1), 0)]

def step(z):
    return 1 if z >= 0 else 0

def train(data, name, rate=0.5, epochs=12, show=False):
    w = [0.0, 0.0]
    b = 0.0
    for epoch in range(1, epochs + 1):
        errors = 0
        for (x1, x2), target in data:
            z = w[0] * x1 + w[1] * x2 + b
            out = step(z)
            err = target - out
            if err:
                errors += 1
                if show:
                    print("      (%d,%d) target %d  z = %.1f*%d + %.1f*%d + %.1f = %.1f"
                          % (x1, x2, target, w[0], x1, w[1], x2, b, z))
                    print("            output %d, error %+d, so w <- w + %.1f*%d*x"
                          % (out, err, rate, err))
                w[0] += rate * err * x1
                w[1] += rate * err * x2
                b += rate * err
                if show:
                    print("            now w = (%.1f, %.1f)  b = %.1f" % (w[0], w[1], b))
        if show:
            print("   end of epoch %d: %d error(s), w = (%.1f, %.1f), b = %.1f"
                  % (epoch, errors, w[0], w[1], b))
        if errors == 0:
            return w, b, epoch
    return w, b, None

print("ONE NEURON: output = step(w1*x1 + w2*x2 + b), where step(z) is 1 if z >= 0.")
print("the LEARNING RULE: on an error, w <- w + rate * (target - output) * x.")
print()
print("TRAINING ON AND, starting from w = (0, 0), b = 0, rate 0.5")
w, b, ep = train(AND, "AND", show=True)
print()
print("converged after %d epoch(s): w = (%.1f, %.1f), b = %.1f" % (ep, w[0], w[1], b))
print("   the rule it learned: fire when %.1f*x1 + %.1f*x2 + %.1f >= 0"
      % (w[0], w[1], b))
print("   check it:")
for (x1, x2), t in AND:
    z = w[0] * x1 + w[1] * x2 + b
    print("      (%d,%d) -> z = %+.1f -> %d   target %d   %s"
          % (x1, x2, z, step(z), t, "ok" if step(z) == t else "WRONG"))
print()
print("NOW EXCLUSIVE-OR, the same neuron, the same rule, 100 epochs:")
w2, b2, ep2 = train(XOR, "XOR", epochs=100)
print("   converged?", "yes" if ep2 else "NO, still making errors after 100 epochs")
print("   final w = (%.1f, %.1f), b = %.1f" % (w2[0], w2[1], b2))
for (x1, x2), t in XOR:
    z = w2[0] * x1 + w2[1] * x2 + b2
    print("      (%d,%d) -> %d   target %d   %s"
          % (x1, x2, step(z), t, "ok" if step(z) == t else "WRONG"))
print()
print("it cannot converge, and no amount of training will help: one neuron draws")
print("ONE straight line, and exclusive-or needs a boundary that is not one.")
print()
print("WHICH OF THE 16 TWO-INPUT BOOLEAN FUNCTIONS CAN ONE NEURON LEARN?")
ok = bad = 0
for bits in range(16):
    data = [((x1, x2), (bits >> i) & 1)
            for i, (x1, x2) in enumerate([(0, 0), (0, 1), (1, 0), (1, 1)])]
    _, _, e = train(data, "f%d" % bits, epochs=200)
    if e:
        ok += 1
    else:
        bad += 1
        print("   function %2d cannot be learned: %s"
              % (bits, " ".join("%d%d->%d" % (a, b_, t) for (a, b_), t in data)))
print("   %d of 16 learned, %d not. the two that fail are exclusive-or and its" % (ok, bad))
print("   negation, which is why Minsky and Papert's 1969 objection mattered.")
munotes.in342

The Artificial Neuron and the Perceptron

ONE NEURON: output = step(w1*x1 + w2*x2 + b), where step(z) is 1 if z >= 0.
the LEARNING RULE: on an error, w <- w + rate * (target - output) * x.

TRAINING ON AND, starting from w = (0, 0), b = 0, rate 0.5
      (0,0) target 0  z = 0.0*0 + 0.0*0 + 0.0 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (0.0, 0.0)  b = -0.5
      (1,1) target 1  z = 0.0*1 + 0.0*1 + -0.5 = -0.5
            output 0, error +1, so w <- w + 0.5*1*x
            now w = (0.5, 0.5)  b = 0.0
   end of epoch 1: 2 error(s), w = (0.5, 0.5), b = 0.0
      (0,0) target 0  z = 0.5*0 + 0.5*0 + 0.0 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (0.5, 0.5)  b = -0.5
      (0,1) target 0  z = 0.5*0 + 0.5*1 + -0.5 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (0.5, 0.0)  b = -1.0
      (1,1) target 1  z = 0.5*1 + 0.0*1 + -1.0 = -0.5
            output 0, error +1, so w <- w + 0.5*1*x
            now w = (1.0, 0.5)  b = -0.5
   end of epoch 2: 3 error(s), w = (1.0, 0.5), b = -0.5
      (0,1) target 0  z = 1.0*0 + 0.5*1 + -0.5 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (1.0, 0.0)  b = -1.0
      (1,0) target 0  z = 1.0*1 + 0.0*0 + -1.0 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (0.5, 0.0)  b = -1.5
      (1,1) target 1  z = 0.5*1 + 0.0*1 + -1.5 = -1.0
            output 0, error +1, so w <- w + 0.5*1*x
            now w = (1.0, 0.5)  b = -1.0
   end of epoch 3: 3 error(s), w = (1.0, 0.5), b = -1.0
      (1,0) target 0  z = 1.0*1 + 0.5*0 + -1.0 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (0.5, 0.5)  b = -1.5
      (1,1) target 1  z = 0.5*1 + 0.5*1 + -1.5 = -0.5
            output 0, error +1, so w <- w + 0.5*1*x
            now w = (1.0, 1.0)  b = -1.0
   end of epoch 4: 2 error(s), w = (1.0, 1.0), b = -1.0
      (0,1) target 0  z = 1.0*0 + 1.0*1 + -1.0 = 0.0
            output 1, error -1, so w <- w + 0.5*-1*x
            now w = (1.0, 0.5)  b = -1.5
   end of epoch 5: 1 error(s), w = (1.0, 0.5), b = -1.5
   end of epoch 6: 0 error(s), w = (1.0, 0.5), b = -1.5

converged after 6 epoch(s): w = (1.0, 0.5), b = -1.5
   the rule it learned: fire when 1.0*x1 + 0.5*x2 + -1.5 >= 0
   check it:
      (0,0) -> z = -1.5 -> 0   target 0   ok
      (0,1) -> z = -1.0 -> 0   target 0   ok
      (1,0) -> z = -0.5 -> 0   target 0   ok
      (1,1) -> z = +0.0 -> 1   target 1   ok

NOW EXCLUSIVE-OR, the same neuron, the same rule, 100 epochs:
   converged? NO, still making errors after 100 epochs
   final w = (-0.5, 0.0), b = 0.0
      (0,0) -> 1   target 0   WRONG
      (0,1) -> 1   target 1   ok
      (1,0) -> 0   target 1   WRONG
      (1,1) -> 0   target 0   ok

it cannot converge, and no amount of training will help: one neuron draws
ONE straight line, and exclusive-or needs a boundary that is not one.

WHICH OF THE 16 TWO-INPUT BOOLEAN FUNCTIONS CAN ONE NEURON LEARN?
   function  6 cannot be learned: 00->0 01->1 10->1 11->0
   function  9 cannot be learned: 00->1 01->0 10->0 11->1
   14 of 16 learned, 2 not. the two that fail are exclusive-or and its
   negation, which is why Minsky and Papert's 1969 objection mattered.
munotes.in343

The Artificial Neuron and the Perceptron

The learning rule read in words. If the output was right, change nothing. If the target was 1 and the output 0, the error is +1, so add the input to the weights, making the neuron more likely to fire on inputs like this one. If the target was 0 and the output 1, the error is -1, so subtract. Note that an input of 0 changes its weight by nothing: only the inputs that were actually on are held responsible, which is the whole of the rule's sense.

munotes.in344

The Artificial Neuron and the Perceptron

AND converges in six epochs to w = (1.0, 0.5), b = -1.5, that is: fire when x1 + 0.5 x2 >= 1.5. Only (1,1) reaches 1.5, and it reaches it exactly.

The convergence theorem, with its condition

If the training data is linearly separable, the perceptron learning rule finds a separating weight vector in a finite number of updates. That is the perceptron convergence theorem and it is remarkable: no learning rate schedule, no local minima, and the bound does not depend on the number of training examples.

The condition is everything. If the data is not linearly separable the rule never terminates: it cycles, changing weights for ever, and there is no signal from inside the algorithm to say which case you are in. The run on exclusive-or above is that behaviour: a hundred epochs, still wrong on half the rows.

munotes.in345

The Artificial Neuron and the Perceptron

That is also a practical problem, since it means the algorithm cannot be run to completion on real data and must be stopped by a limit on epochs, returning whatever weights it happened to hold.

The limit, counted

The last block of the output is the argument that ended the first era of neural networks, and it is settled by exhaustive search rather than by assertion.

There are 16 Boolean functions of two inputs. A single neuron learns 14 of them. The two it cannot are function 6, exclusive-or, and function 9, its negation.

The reason is geometric and is worth stating precisely: a neuron computes w . x + b >= 0, which is a half-plane. The points it outputs 1 for must all lie on one side of a straight line. For exclusive-or, (0,1) and (1,0) must be on one side and (0,0) and (1,1) on the other, and those two pairs interleave along every direction, so no line does it. The Soft Margin and the Kernel proves the same thing by searching 4,913 candidate lines.

Minsky and Papert set this out in 1969, and funding and interest in neural networks collapsed for over a decade afterwards. The objection was correct about a single layer and, as the next chapter shows, not about networks; what was missing was a way to train more than one layer, which arrived with backpropagation.

What one neuron is, in other language

Three connections worth making, because they show that the perceptron is not an isolated curiosity.

It is a linear classifier, the same object as the SVM of Support Vector Machines: The Margin. The difference is which separating line is chosen: the perceptron takes any line that works, and the SVM takes the one of greatest margin. On the six points of that chapter, the perceptron would have been satisfied with any of the five candidates.

With a sigmoid activation and cross-entropy loss it is logistic regression, which is the standard linear classifier of statistics. The only change is the activation.

It is the building block of everything in the next two chapters. A multilayer network is these neurons in layers, and a deep network is many layers of them.

Distinctions

Step activationSigmoid activation
Output0 or 1anything between
Differentiablenoyes
Trained bythe perceptron rulegradient descent
Gives a confidencenoyes
munotes.in346

The Artificial Neuron and the Perceptron

PerceptronSupport vector machine
Choosesany separating linethe maximum margin one
On non-separable datanever terminatesthe soft margin handles it
Convex problemnot posed as oneyes
Linearly separableNot
Perceptron ruleconverges in finite stepscycles for ever
ExampleAND, OR, NAND, 14 of 16exclusive-or and its negation
The algorithm can tell whichno

What it does not mean

A perceptron is not a model of a biological neuron. It is a caricature: real neurons spike in time, have thousands of inputs and do not compute a weighted sum in this way.

The learning rule is not gradient descent. The step activation has no useful gradient; the rule is its own thing, and its convergence proof is separate.

Failure to converge is not slow convergence. On non-separable data it never terminates, and no amount of patience helps.

14 of 16 is not "mostly works". The two it fails on are the interesting ones, and exclusive-or is the smallest example of the structure a single layer cannot represent.

Minsky and Papert were not wrong. They were right about a single layer. What did not follow, and what was widely inferred, was that networks of them were equally limited.

The bias is not optional. Without it the boundary must pass through the origin, and even AND becomes unlearnable.

Quick revision

  • Neuron: z = w . x + b, then an activation. Weights, bias and activation are the three parts.
  • Activations: step (not differentiable, the original), sigmoid (smooth, makes backpropagation possible), tanh (zero-centred), ReLU (cheap, the deep default).
  • Perceptron learning rule: w <- w + rate (target - output) x, applied on an error. An input of 0 changes nothing.
  • On AND it converges in six epochs to w = (1.0, 0.5), b = -1.5.
  • Convergence theorem: if the data is linearly separable, it terminates in finitely many updates. If not, it cycles for ever, and the algorithm cannot tell you which case you are in.
  • Exactly 2 of the 16 two-input Boolean functions cannot be learned: exclusive-or and its negation. A neuron computes a half-plane, and those two pairs interleave.
  • Minsky and Papert 1969 made this argument and the field collapsed for a decade. They were right about one layer.
  • One neuron is a linear classifier: the SVM picks the widest line, the perceptron any line. With a sigmoid and cross-entropy it is logistic regression.

Test yourself

1. Describe an artificial neuron. It computes a weighted sum of its inputs plus a bias, and passes that net input through an activation function to produce its output. The weights and bias are learned; the activation is chosen by the designer.

munotes.in347

The Artificial Neuron and the Perceptron

2. Give the perceptron learning rule and read it in words. w <- w + rate (target - output) x, applied whenever an example is misclassified. If the target was 1 and the output 0 the weights of the inputs that were on are increased, making the neuron more likely to fire on similar inputs; if the target was 0 and the output 1 they are decreased; an input of zero changes its own weight by nothing.

3. State the perceptron convergence theorem with its condition, and say what happens when the condition fails. If the training data is linearly separable, the rule finds a separating weight vector after finitely many updates. If it is not separable the rule never terminates but cycles indefinitely, and nothing in the algorithm distinguishes the two cases, so it must be stopped by an epoch limit.

4. Exactly how many of the sixteen two-input Boolean functions can one neuron learn, and which fail? Fourteen. The two that fail are exclusive-or and its negation, which this chapter establishes by training a perceptron on all sixteen.

5. Why can a single neuron not compute exclusive-or? Because it outputs 1 exactly on one side of a straight line, that is on a half-plane. Exclusive-or requires (0,1) and (1,0) to be separated from (0,0) and (1,1), and those two pairs interleave along every direction, so no line puts one pair on each side.

6. Why did the step activation require a special learning rule? Because its derivative is zero wherever it exists, so gradient descent has no slope to follow. Replacing it with a smooth activation such as the sigmoid is what allows the gradient-based training of the next chapter.

7. How does a perceptron differ from a support vector machine? Both are linear classifiers. The perceptron stops at any separating line, so its answer depends on the order the examples were presented and on the starting weights. A support vector machine solves a convex problem for the line of greatest margin, so its answer is unique, and its soft margin handles data that is not separable, which defeats the perceptron entirely.

Contents This chapter on its own page

munotes.in348

Chapter Sixty-Two

The Multilayer Network and Backpropagation

Syllabus topic Module 2, "Feed Forward Backpropagation"

In one line

Stack neurons in layers, and train them by computing the error at the output and passing it backwards through the weights to find how much each earlier weight was to blame.

In the wording a student can write in an examination: a multilayer feedforward network, or multilayer perceptron, arranges neurons in an input layer, one or more hidden layers and an output layer, each unit connected only to units in the next layer. Backpropagation trains it by gradient descent: a forward pass computes the output and the loss, and a backward pass applies the chain rule to compute the loss's partial derivative with respect to every weight, propagating a quantity delta from each layer to the one before it.

Why a hidden layer changes everything

The Artificial Neuron and the Perceptron established that one neuron draws one straight line, and that exclusive-or needs something else.

A hidden layer gives the network its own intermediate features. Each hidden unit draws its own line; the output unit then combines their answers. For exclusive-or, one hidden unit can learn x1 OR x2 and another NOT (x1 AND x2), and the output unit can take their conjunction, which is exactly exclusive-or. The hidden layer is not extra capacity in a vague sense: it is a learned re-representation of the input, and the output layer is a linear classifier on those new features rather than on the originals.

That is the same idea as the kernel of The Soft Margin and the Kernel, arrived at differently. A kernel maps to a fixed space chosen by the designer; a hidden layer learns the mapping from the data.

The universal approximation theorem

A network with one hidden layer of sufficiently many units, with a non-linear activation, can approximate any continuous function on a bounded region to any desired accuracy.

Read the conditions, because the theorem is routinely overstated. It says such a network exists; it says nothing about finding it by training, nothing about how many units are needed, which may be astronomically many, and nothing about generalising beyond the training data. The honest summary: representability is not the problem, and never was. Trainability is. That is why depth matters in practice although one layer suffices in theory, which is What Deep Learning Is.

The two passes

Naming them is worth marks and the order is the algorithm.

Forward pass. For each layer in turn, compute each unit's net input as the weighted sum of the previous layer's outputs plus its bias, and apply the activation. Finish with the loss at the output.

Backward pass. Compute delta at the output, then at each earlier layer in turn, each delta being the weighted sum of the deltas above it times the derivative of that unit's own activation. The gradient for a weight is then delta at its destination times the output at its source, and the weight is moved against it.

munotes.in349

The Multilayer Network and Backpropagation

delta at an output unit = (output - target) * activation'(output)

delta at a hidden unit = (sum over k of delta_k weight to k) activation'(its own output)

gradient for a weight = delta at the destination * output at the source

The middle line is backpropagation. A hidden unit's share of the blame is the blame of the units it feeds, weighted by how strongly it feeds them. Everything else is bookkeeping.

One update, entirely by hand

# Feed forward backpropagation, set by the practical. ONE weight update worked
# fully by hand with every number printed, then the same network trained to
# solve exclusive-or. Read against Rumelhart, Hinton and Williams 1986.
import math

def sigmoid(z):
    return 1.0 / (1.0 + math.exp(-z))

def dsigmoid(a):
    """The derivative, written in terms of the OUTPUT: a * (1 - a)."""
    return a * (1.0 - a)

# --- PART 1: one update, by hand, on a 2-2-1 network with chosen weights ------
w1 = [[0.15, 0.20], [0.25, 0.30]]     # input -> hidden, w1[h][i]
b1 = [0.35, 0.35]
w2 = [0.40, 0.45]                     # hidden -> output
b2 = 0.60
x = [0.05, 0.10]
target = 0.01
rate = 0.5

print("A 2-2-1 NETWORK. input %s, target %.2f, learning rate %.1f" % (x, target, rate))
print("   w1 = %s   b1 = %s" % (w1, b1))
print("   w2 = %s   b2 = %.2f" % (w2, b2))
print()
print("STEP 1 FORWARD PASS")
h_in = [w1[j][0] * x[0] + w1[j][1] * x[1] + b1[j] for j in (0, 1)]
h = [sigmoid(z) for z in h_in]
for j in (0, 1):
    print("   hidden %d: z = %.2f*%.2f + %.2f*%.2f + %.2f = %.6f   a = sigmoid(z) = %.8f"
          % (j + 1, w1[j][0], x[0], w1[j][1], x[1], b1[j], h_in[j], h[j]))
o_in = w2[0] * h[0] + w2[1] * h[1] + b2
o = sigmoid(o_in)
print("   output:   z = %.2f*%.8f + %.2f*%.8f + %.2f = %.8f"
      % (w2[0], h[0], w2[1], h[1], b2, o_in))
print("             a = sigmoid(z) = %.8f" % o)
print()
print("STEP 2 THE ERROR")
err = 0.5 * (target - o) ** 2
print("   E = 0.5 * (target - output)^2 = 0.5 * (%.2f - %.8f)^2 = %.8f"
      % (target, o, err))
print()
print("STEP 3 THE DELTA AT THE OUTPUT")
delta_o = (o - target) * dsigmoid(o)
print("   delta = (output - target) * output * (1 - output)")
print("         = (%.8f - %.2f) * %.8f * %.8f = %.8f"
      % (o, target, o, 1 - o, delta_o))
print()
print("STEP 4 THE GRADIENT FOR ONE WEIGHT, AND ITS UPDATE")
grad_w2_0 = delta_o * h[0]
new_w2_0 = w2[0] - rate * grad_w2_0
print("   dE/dw2[0] = delta * hidden1 = %.8f * %.8f = %.8f"
      % (delta_o, h[0], grad_w2_0))
print("   w2[0] <- %.2f - %.1f * %.8f = %.8f" % (w2[0], rate, grad_w2_0, new_w2_0))
print()
print("STEP 5 THE DELTA AT A HIDDEN UNIT: the error SENT BACK")
delta_h0 = delta_o * w2[0] * dsigmoid(h[0])
print("   delta_hidden1 = delta_output * w2[0] * hidden1 * (1 - hidden1)")
print("                 = %.8f * %.2f * %.8f * %.8f = %.8f"
      % (delta_o, w2[0], h[0], 1 - h[0], delta_h0))
grad_w1_00 = delta_h0 * x[0]
print("   dE/dw1[0][0] = delta_hidden1 * x1 = %.8f * %.2f = %.8f"
      % (delta_h0, x[0], grad_w1_00))
print("   w1[0][0] <- %.2f - %.1f * %.8f = %.8f"
      % (w1[0][0], rate, grad_w1_00, w1[0][0] - rate * grad_w1_00))
print()
print("that is backpropagation: the delta at a unit is the weighted sum of the")
print("deltas above it, times the derivative of its own activation.")
print()

# --- PART 2: the same architecture, trained on exclusive-or ------------------
def lcg(seed):
    v = seed
    while True:
        v = (1664525 * v + 1013904223) % (2 ** 32)
        yield v / 2 ** 32

gen = lcg(5)
rnd = lambda: (next(gen) - 0.5) * 2.0                  # noqa: E731

XOR = [([0.0, 0.0], 0.0), ([0.0, 1.0], 1.0), ([1.0, 0.0], 1.0), ([1.0, 1.0], 0.0)]
H = 3
W1 = [[rnd() for _ in range(2)] for _ in range(H)]
B1 = [rnd() for _ in range(H)]
W2 = [rnd() for _ in range(H)]
B2 = rnd()
RATE = 0.9

def forward(inp):
    hs = [sigmoid(sum(W1[j][i] * inp[i] for i in range(2)) + B1[j]) for j in range(H)]
    out = sigmoid(sum(W2[j] * hs[j] for j in range(H)) + B2)
    return hs, out

print("TRAINING THE SAME KIND OF NETWORK ON EXCLUSIVE-OR, %d hidden units:" % H)
print("   epoch |  total error | outputs for 00, 01, 10, 11")
for epoch in range(1, 20001):
    total = 0.0
    for inp, t in XOR:
        hs, out = forward(inp)
        total += 0.5 * (t - out) ** 2
        d_out = (out - t) * dsigmoid(out)
        d_h = [d_out * W2[j] * dsigmoid(hs[j]) for j in range(H)]
        for j in range(H):
            W2[j] -= RATE * d_out * hs[j]
        B2 -= RATE * d_out
        for j in range(H):
            for i in range(2):
                W1[j][i] -= RATE * d_h[j] * inp[i]
            B1[j] -= RATE * d_h[j]
    if epoch in (1, 100, 1000, 5000, 10000, 20000):
        outs = " ".join("%.4f" % forward(inp)[1] for inp, _ in XOR)
        print("   %5d | %12.8f | %s" % (epoch, total, outs))
print()
print("the four outputs are near 0, 1, 1, 0, which is exclusive-or. ONE neuron")
print("could not do it; three hidden units and a second layer can.")
munotes.in350

The Multilayer Network and Backpropagation

A 2-2-1 NETWORK. input [0.05, 0.1], target 0.01, learning rate 0.5
   w1 = [[0.15, 0.2], [0.25, 0.3]]   b1 = [0.35, 0.35]
   w2 = [0.4, 0.45]   b2 = 0.60

STEP 1 FORWARD PASS
   hidden 1: z = 0.15*0.05 + 0.20*0.10 + 0.35 = 0.377500   a = sigmoid(z) = 0.59326999
   hidden 2: z = 0.25*0.05 + 0.30*0.10 + 0.35 = 0.392500   a = sigmoid(z) = 0.59688438
   output:   z = 0.40*0.59326999 + 0.45*0.59688438 + 0.60 = 1.10590597
             a = sigmoid(z) = 0.75136507

STEP 2 THE ERROR
   E = 0.5 * (target - output)^2 = 0.5 * (0.01 - 0.75136507)^2 = 0.27481108

STEP 3 THE DELTA AT THE OUTPUT
   delta = (output - target) * output * (1 - output)
         = (0.75136507 - 0.01) * 0.75136507 * 0.24863493 = 0.13849856

STEP 4 THE GRADIENT FOR ONE WEIGHT, AND ITS UPDATE
   dE/dw2[0] = delta * hidden1 = 0.13849856 * 0.59326999 = 0.08216704
   w2[0] <- 0.40 - 0.5 * 0.08216704 = 0.35891648

STEP 5 THE DELTA AT A HIDDEN UNIT: the error SENT BACK
   delta_hidden1 = delta_output * w2[0] * hidden1 * (1 - hidden1)
                 = 0.13849856 * 0.40 * 0.59326999 * 0.40673001 = 0.01336792
   dE/dw1[0][0] = delta_hidden1 * x1 = 0.01336792 * 0.05 = 0.00066840
   w1[0][0] <- 0.15 - 0.5 * 0.00066840 = 0.14966580

that is backpropagation: the delta at a unit is the weighted sum of the
deltas above it, times the derivative of its own activation.

TRAINING THE SAME KIND OF NETWORK ON EXCLUSIVE-OR, 3 hidden units:
   epoch |  total error | outputs for 00, 01, 10, 11
       1 |   0.55569127 | 0.4755 0.4694 0.4587 0.4579
     100 |   0.53977321 | 0.5127 0.5243 0.4795 0.4880
    1000 |   0.00715226 | 0.0588 0.9478 0.9287 0.0540
    5000 |   0.00065242 | 0.0174 0.9832 0.9792 0.0169
   10000 |   0.00029712 | 0.0117 0.9886 0.9860 0.0114
   20000 |   0.00014072 | 0.0080 0.9921 0.9904 0.0079

the four outputs are near 0, 1, 1, 0, which is exclusive-or. ONE neuron
could not do it; three hidden units and a second layer can.
munotes.in351

The Multilayer Network and Backpropagation

The five steps are the by-hand question. Follow them once and the algorithm is yours.

Step 1 computes both hidden activations and then the output, 0.75136507. Step 2 gives the squared error. Step 3 computes the output delta, (output - target) output (1 - output), which is the chain rule: the derivative of the loss with respect to the output, times the derivative of the activation with respect to its net input.

Step 4 is the gradient for one weight: delta * the activation at the source. That single line is why the algorithm is cheap. Every weight's gradient is a product of two numbers already computed.

munotes.in352

The Multilayer Network and Backpropagation

Step 5 is the backward pass proper. The hidden unit's delta is the output delta, times the weight connecting them, times the hidden unit's own activation derivative. w2[0] appears twice and it appears for two different reasons: once as the weight being updated, and once as the path along which the blame travels back. Confusing those two roles is the commonest error in the topic.

And note what the second training run shows: the error after 100 epochs is 0.53977321, barely below its starting 0.55569127, and after 1000 it is 0.00715226. Backpropagation on this problem spends a long time apparently doing nothing and then solves it suddenly. That is normal and it is why a training curve is watched rather than a single number.

Why the sigmoid, and why its derivative is convenient

dsigmoid above is written a (1 - a), in terms of the output rather than the input. That is not a shortcut, it is a property of the sigmoid: its derivative at z equals sigmoid(z) (1 - sigmoid(z)).

So the forward pass has already computed everything the backward pass needs. No activation is recomputed and nothing is stored beyond each unit's output. That efficiency is part of why the sigmoid was the standard activation for two decades.

What goes wrong

Four failures, each with a name, and a paper can ask for any.

Local minima. The loss is not convex, so gradient descent settles wherever it started above. Different random initial weights give different results, which is why a network is often trained several times. And it is the sharpest contrast with Support Vector Machines: The Margin, whose convex problem has one answer.

The vanishing gradient. The sigmoid's derivative is at most 0.25, so a delta passed back through n layers is multiplied by at most 0.25n. Through ten layers that is less than one part in a million: the early layers barely move. This is why deep networks were untrainable for years, and why ReLU, whose derivative is 1 for positive inputs, replaced the sigmoid.**

Saturation. A sigmoid unit whose net input is large in either direction has an output near 0 or 1 and a derivative near zero, so it stops learning even in a shallow network. Keeping the inputs and the initial weights small avoids it.

Overfitting. A network with many weights has enormous capacity. The cures are those of Regularization: a weight penalty, early stopping on a validation set, and dropout, which removes units at random during training so no unit can be relied on.

The initial weights must be small and random, and this is worth stating because it is an easy mistake. Initialise every weight to zero and all the hidden units compute the same thing, receive the same delta, and stay identical for ever. The random initialisation is what breaks the symmetry.

munotes.in353

The Multilayer Network and Backpropagation

Architecture, briefly

A paper may ask how a network is specified.

The input layer has one unit per feature; the output layer one unit for regression or for binary classification, and one per class with a softmax for multiclass. The hidden layers are the designer's choice, and they are hyperparameters tuned like any other.

Two practical points. Scale the inputs, for the same reason as in every distance-based and penalised method. And use a smooth loss: squared error for regression, cross-entropy for classification, because as Classification and Regression explained the count of mistakes has no gradient.

Distinctions

Forward passBackward pass
Computesactivations, then the lossdeltas, then gradients
Directioninput to outputoutput to input
Usesthe weightsthe same weights, and the stored activations
Perceptron ruleBackpropagation
Activationstepany differentiable one
Layersoneany number
Is gradient descentnoyes
Convergesprovably, if separableto a local minimum
One hidden layer, in theoryIn practice
Can approximate any continuous functionyesthe theorem is about existence
Says how many unitsnomay be astronomically many
Says training will find itnoit usually will not

What it does not mean

Backpropagation is not a learning algorithm. It computes the gradient. Gradient Descent does the learning, and any gradient method may be used with it.

The universal approximation theorem does not say one layer is enough. It says one layer can represent the function. It says nothing about finding it, about how wide it must be, or about generalisation.

A local minimum is not a bug. It is a property of a non-convex loss, which is why initialisation matters and why networks are trained more than once.

The vanishing gradient is not slow learning. The early layers receive almost no signal, so they barely change at all.

Weights must not be initialised to zero. All hidden units would then be identical for ever; the random initialisation breaks that symmetry.

More hidden units are not better. They add capacity and therefore variance, and the cures are those of Regularization.

Quick revision

  • Multilayer feedforward network: input, one or more hidden layers, output. The hidden layer is a learned re-representation of the input, and the output layer is a linear classifier on it.
  • Universal approximation: one hidden layer with enough units can approximate any continuous function on a bounded region. Existence only: nothing about how many units, about training finding it, or about generalisation.
  • Forward pass: activations then loss. Backward pass: deltas then gradients.
  • delta at the output = (output - target) activation'(output); delta at a hidden unit = (sum of delta_k w_k) activation'(its output); gradient = delta at the destination output at the source.
  • The sigmoid's derivative is a * (1 - a), in terms of the output, so the forward pass has already computed everything the backward pass needs.
  • Trained on exclusive-or with 3 hidden units: total error 0.55569127 at epoch 1, 0.53977321 at 100, 0.00715226 at 1000, 0.00014072 at 20,000, with outputs near 0, 1, 1, 0. The plateau then sudden drop is normal.
  • Failures: local minima (non-convex, so initialisation matters), vanishing gradient (sigmoid derivative at most 0.25, so 0.25n through n layers, which is why ReLU replaced it), saturation, and overfitting** (weight penalty, early stopping, dropout).
  • Initialise small and random: zeros leave every hidden unit identical for ever.
munotes.in354

The Multilayer Network and Backpropagation

Test yourself

1. What does a hidden layer add, and why does it solve exclusive-or? It gives the network intermediate features of its own, each hidden unit drawing its own boundary and the output layer combining them. For exclusive-or one hidden unit can represent x1 or x2 and another not (x1 and x2), and the output unit's conjunction of those is exclusive-or, which no single boundary in the original inputs can express.

2. State the universal approximation theorem and its limitations. A network with one hidden layer of sufficiently many units and a non-linear activation can approximate any continuous function on a bounded region to any accuracy. It asserts only that such a network exists; it does not say how many units are needed, does not say training will find it, and says nothing about performance outside the training data.

3. Give the three backpropagation formulas. The delta at an output unit is the derivative of the loss with respect to the output times the derivative of the activation, which for a squared loss and a sigmoid is (output - target) output (1 - output). The delta at a hidden unit is the sum over the units it feeds of their deltas times the connecting weights, times its own activation derivative. The gradient for a weight is the delta at its destination times the activation at its source.

4. Why is the sigmoid's derivative convenient? Because it can be written as a * (1 - a) in terms of the unit's own output, which the forward pass has already computed. No activation needs recomputing during the backward pass and nothing beyond each unit's output need be stored.

5. What is the vanishing gradient problem and what caused it to matter? The sigmoid's derivative never exceeds 0.25, so a delta passed back through n layers is multiplied by at most 0.25 to the power n, which through ten layers is less than one part in a million. The early layers therefore receive almost no signal and barely learn, which made deep networks untrainable until activations such as ReLU, whose derivative is one for positive inputs, replaced the sigmoid.

munotes.in355

The Multilayer Network and Backpropagation

6. Why must the initial weights be small and random rather than zero? Because with all weights equal every hidden unit computes the same function, receives the same delta and is updated identically, so they remain identical for ever and the network has the capacity of a single unit. The random initialisation breaks that symmetry.

7. In this chapter's training run the error was 0.5397 after 100 epochs and 0.0072 after 1000. What does that pattern show? That backpropagation on this problem spends a long period making almost no apparent progress and then improves suddenly. It shows why training must be judged from a curve over many epochs rather than from a single measurement, and why stopping early on an apparent lack of progress can be a mistake.

Contents This chapter on its own page

munotes.in356

Chapter Sixty-Three

What Deep Learning Is

Syllabus topic Module 2, "concept of deep learning"

In one line

Deep learning is a neural network with many layers, in which each layer learns features from the layer below, so the features are learned instead of designed.

In the wording a student can write in an examination: deep learning is machine learning with artificial neural networks of many hidden layers. Its defining property is representation learning: rather than being given features designed by a person, the network learns a hierarchy of representations, each layer composing the features of the one beneath into something more abstract. The same backpropagation trains it; what changed to make deep networks practical was more data, more computation, and a set of specific technical remedies.

What depth actually buys

The Multilayer Network and Backpropagation recorded the universal approximation theorem: one hidden layer of enough units can approximate any continuous function. So depth is not required for representability, and a paper asking why depth matters is asking for a different answer.

Depth buys efficiency of representation. Certain functions need exponentially many units in one layer and only polynomially many when the layers are stacked. A deep network expresses a composition of simple steps; a shallow one must enumerate the whole result.

And it buys a hierarchy. In a network trained on images, the early layers respond to edges, the middle layers to parts, the later layers to whole objects. Nobody designed that progression: each layer's features are composed from those below it because that is the cheapest way for the network to reduce its loss.

That is the claim worth being careful about. The hierarchy is a well-attested property of trained image networks; this book has not measured it and does not assert it as a general law. What is safe to say, and what a paper wants, is the principle: the features are learned rather than designed.

The change that actually happened

A paper often asks why deep learning succeeded when neural networks had been known since the 1950s. The honest answer has four parts and none of them is a new idea about networks.

What changedWhy it mattered
Dataa network with millions of weights needs a great many examples, and digital data became abundant
Computationthe graphics processor turned out to do exactly the matrix arithmetic a network needs, thousands of times in parallel
ActivationsReLU in place of the sigmoid removed the vanishing gradient of The Multilayer Network and Backpropagation
Techniquebetter initialisation, normalisation between layers, dropout, and optimisers such as Adam made deep networks trainable in practice

Backpropagation did not change. It is the algorithm of 1986, applied to larger networks on larger data with better activations. Saying that a new learning algorithm was discovered is a common and wrong answer.

munotes.in357

What Deep Learning Is

What was given up

Every advantage in the previous section was paid for, and naming the costs is what separates an informed answer from an enthusiastic one.

Data. Deep networks need far more labelled data than any other method in MU's list. The Naive Bayes Classifier works on a few hundred rows; a deep network on a few hundred rows will simply memorise them.

Computation. Training a large network costs a great deal of electricity and time, and that cost is concentrated in the few organisations that can afford it.

Opacity. This is the one that matters for the rest of this syllabus. A decision tree's path is a rule a person can read; Reading, Drawing and Pruning a Decision Tree turned one into five sentences. A network's decision lives in millions of weights and cannot be read at all. Transparency and Explainability is where MU takes that up, and it is the direct cost of this chapter's subject.

Brittleness. A network can be extremely accurate on data like its training data and fail strangely on data slightly unlike it, with no warning and with high confidence. That is the same failure What Machine Learning Is showed with a straight line predicting 107.6 marks, and it does not become milder with depth.

Hyperparameters. The number of layers, their widths, the activations, the learning rate, the regularization and the initialisation are all choices, and the results depend on them.

The architectures, named once

MU sets the concept, not the architectures, so each gets one line and a paper wanting more than that is asking beyond the label.

  • Convolutional network (CNN): units look at a small patch of the input and the same weights are reused across the whole image, so the number of weights does not grow with the image and a feature learned in one place is available everywhere. For images and anything with a grid structure.
  • Recurrent network (RNN), and LSTM: the network has a loop, so its state carries information from one step of a sequence to the next. For sequences, and the direct relative of Hidden Markov Models, which does the same job with an explicit probabilistic state.
  • Transformer: processes a whole sequence at once and learns which positions to attend to. It is the architecture behind current language models.
  • Autoencoder: trained to reproduce its own input through a narrow middle layer, which forces that layer to be a compressed representation. It is unsupervised, and it is the bridge to Unsupervised Learning.

Where it fits among MU's models

The comparison a Q.3 would ask for.

Deep networkDecision treeNaive BayesSVMk-NN
Data neededa great dealmoderatevery littlemoderatemoderate
Features designed bythe networka persona persona person, or a kernela person
Interpretablenoyespartlypartlyby example
Training costhighlownegligiblemoderate to highnone
Best whereimages, speech, language, very large datarules matter and must be readtext, small datamany features, few rowslow dimensions
munotes.in358

What Deep Learning Is

A deep network is not the default choice. On a table of a few hundred rows with a dozen features, which is what most real problems look like, a tree or an ensemble of trees will usually match or beat it, train in a second, and be readable. Deep learning earns its cost where the input is raw and high-dimensional and the data is abundant, which is exactly the case for images, audio and text.

What this book can and cannot show

An honest limit, stated rather than concealed. Every program in this book is plain Python run on three interpreters, and a deep network large enough to demonstrate representation learning cannot be trained that way in a chapter. What this book does show is the whole mechanism at a scale a reader can check: The Multilayer Network and Backpropagation computes one weight update by hand to eight decimal places and then trains a network to do what one neuron provably cannot. A deep network is that, repeated, with more layers and more data. Nothing conceptual is missing; scale is.

And Using an AI Library Responsibly is where the reader is shown what a library call does in terms of these chapters, with the same honesty about what is not installed on the machine this book was checked on.

Distinctions

Shallow networkDeep network
Hidden layersonemany
Can approximate any continuous functionyes, in theoryyes
Units needed for some functionsexponentially manypolynomially many
Featuresstill a single transformationa hierarchy
Feature engineeringRepresentation learning
Features come froma person's knowledge of the domainthe network, from data
Needs domain expertiseyesless
Needs datalessmuch more
Transfers to a new problemrarelyoften, by reusing early layers
What changed by 1986What changed by 2012
The algorithmbackpropagation was publishedunchanged
Datascarceabundant
Computationscarcethe graphics processor
ActivationsigmoidReLU

What it does not mean

Deep does not mean better. On small tabular data a tree or an ensemble usually wins, trains in a second and can be read.

Deep learning is not a new learning algorithm. It is backpropagation, from 1986, on more data with better activations.

The universal approximation theorem does not make depth pointless. One layer can represent the function; it may need exponentially many units and training may not find it.

munotes.in359

What Deep Learning Is

Learned features are not interpretable features. They are effective and they are not readable, which is the cost Transparency and Explainability addresses.

More layers are not automatically better. Depth adds capacity, and capacity without data is overfitting.

Accuracy on a benchmark is not reliability in use. A network can be excellent on data like its training data and fail without warning on data slightly unlike it.

Quick revision

  • Deep learning: neural networks with many hidden layers, whose defining property is representation learning, a hierarchy of features learned rather than designed.
  • Depth is not needed for representability, by the universal approximation theorem. It buys efficiency: some functions need exponentially many units in one layer and polynomially many when stacked.
  • Four things changed, and none of them is the algorithm: data, computation (the graphics processor), ReLU in place of the sigmoid, and technique (initialisation, normalisation, dropout, Adam).
  • The costs: much more data, much more computation, opacity, brittleness, and many hyperparameters.
  • Architectures, one line each: CNN (shared weights over patches, for grids), RNN and LSTM (a loop carrying state, for sequences, the relative of HMMs), transformer (attends over a whole sequence), autoencoder (reproduces its input through a narrow layer, unsupervised).
  • Not the default choice. On a few hundred rows with a dozen features a tree or an ensemble usually wins. Deep learning earns its cost on raw, high-dimensional input with abundant data.
  • This book shows the mechanism at a checkable scale and says plainly that it cannot show the scale.

Test yourself

1. Define deep learning and name its defining property. Machine learning with neural networks of many hidden layers. Its defining property is representation learning: the network learns a hierarchy of features from the data instead of being given features designed by a person.

2. If one hidden layer can approximate any continuous function, why does depth matter? Because the theorem concerns representability, not efficiency or trainability. Some functions require exponentially many units in a single layer and only polynomially many when the computation is composed across several, and a deep network's features are built from those beneath them rather than enumerated.

3. Why did deep learning succeed when neural networks had been known for decades? Because of abundant data, the graphics processor providing the parallel matrix arithmetic networks need, the ReLU activation removing the vanishing gradient, and practical technique such as better initialisation, normalisation, dropout and modern optimisers. The learning algorithm itself, backpropagation, did not change.

4. Give four costs of deep learning. It needs far more labelled data than any other method in this syllabus; training is computationally expensive; the resulting model is opaque and cannot be read as a rule; it is brittle, failing confidently on data slightly unlike its training data; and it has many hyperparameters whose values change the result.

munotes.in360

What Deep Learning Is

5. Name three deep architectures and say what each suits. A convolutional network, which reuses the same weights across small patches and suits images and other grid data. A recurrent network or LSTM, which carries state along a sequence and suits sequential data, playing the role that hidden Markov models play probabilistically. And a transformer, which attends across a whole sequence at once and underlies current language models.

6. When would you not use a deep network? On a modest table of a few hundred rows with a dozen designed features, where a decision tree or an ensemble of trees will usually match or beat it, train almost instantly, and be readable. Deep learning earns its cost when the input is raw and high-dimensional, such as images, audio or text, and the data is abundant.

7. What does the opacity of a deep network cost, and where does this syllabus address it? It costs the ability to explain a decision. A decision tree's path is a rule a person can read, while a network's decision is distributed across millions of weights. MU addresses this in the Responsible AI row, under transparency and explainability, and it is the direct consequence of choosing a learned representation over a designed one.

Contents This chapter on its own page

munotes.in361

Chapter Sixty-Four

Ensemble Methods, Bagging and the Random Forest

Syllabus topic Module 2, "Ensemble methods"

In one line

Train many models on slightly different data, let them vote, and their unsystematic errors cancel while their agreement survives.

In the wording a student can write in an examination: an ensemble method combines the predictions of several models, called base learners or weak learners, to obtain a prediction better than any of them alone. Bagging, short for bootstrap aggregating, trains each base learner on a bootstrap sample, a sample of the same size drawn with replacement, and combines them by majority vote for classification or by averaging for regression. A random forest is bagging applied to decision trees with the additional restriction that each split may consider only a random subset of the features.

Why voting works, and when it does not

The arithmetic first, because it makes the condition visible.

Suppose n voters each answer correctly with probability p, independently. The majority is correct when more than half are, which is a sum of binomial terms. The first block of the program computes it.

At p = 0.55, one voter is right 55 times in 100 and a hundred and one voters are right 84 times in 100. At p = 0.60, a hundred and one voters reach 98.

And at p = 0.45 the same arithmetic runs the other way: one voter is right 45 times in 100, and a hundred and one voters are right 16. A committee of members worse than chance is far worse than any one of them. That is the condition everyone omits: the base learner must be better than guessing, or the ensemble makes it worse.

And the deeper condition: the calculation assumes the voters are independent. Models trained on the same data are not, so real ensembles gain far less than the table promises. Everything in the rest of this chapter is a device for making the models more different, because difference is what the arithmetic is really paying for.

Bagging and the random forest, measured

# Ensembles, MEASURED: why many weak models beat one, then bagging and a random
# forest built over the decision tree of chapter 56, on the same test set.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

print("WHY VOTING WORKS, as arithmetic. n independent voters, each right with")
print("probability p. the majority is right with probability:")

def majority_right(n, p):
    total = 0.0
    need = n // 2 + 1
    for k in range(need, n + 1):
        total += math.comb(n, k) * p ** k * (1 - p) ** (n - k)
    return total

print("   voters |  p=0.55  |  p=0.60  |  p=0.45")
for n in (1, 5, 11, 51, 101):
    print("   %6d | %8.4f | %8.4f | %8.4f"
          % (n, majority_right(n, 0.55), majority_right(n, 0.60), majority_right(n, 0.45)))
print()
print("   at p above 0.5 the majority races to certainty. at p BELOW 0.5 it races")
print("   to zero: a committee of voters worse than chance is worse than one of")
print("   them. and the whole table assumes the voters are INDEPENDENT.")
print()

# ---- the data: the same noisy problem as the pruning chapter ----------------
gen = lcg(77)
rnd = lambda: next(gen)                                   # noqa: E731
# EIGHT features of which only TWO matter. The six irrelevant ones are what
# make the trees DIFFER from one another, and difference is what averaging needs.
WEATHER = ["clear", "humid", "rain"]
YESNO = ["yes", "no"]
COLS = ["weather", "friend", "noise1", "noise2", "noise3", "noise4", "noise5", "noise6"]
TARGET = len(COLS)

def make(n):
    rows = []
    for _ in range(n):
        w = WEATHER[int(rnd() * 3)]
        f = YESNO[int(rnd() * 2)]
        junk = [YESNO[int(rnd() * 2)] for _ in range(6)]
        lab = "yes" if (w == "clear" or f == "yes") else "no"
        if rnd() < 0.20:
            lab = "no" if lab == "yes" else "yes"
        rows.append(tuple([w, f] + junk + [lab]))
    return rows

train, test = make(60), make(600)

def entropy(rows):
    if not rows:
        return 0.0
    out = 0.0
    for lab in set(r[TARGET] for r in rows):
        p = sum(1 for r in rows if r[TARGET] == lab) / len(rows)
        out -= p * math.log2(p)
    return out

def split(rows, c):
    d = {}
    for r in rows:
        d.setdefault(r[c], []).append(r)
    return d

def gain(rows, c):
    return entropy(rows) - sum(len(p) / len(rows) * entropy(p)
                               for p in split(rows, c).values())

def majority(rows):
    counts = {}
    for r in rows:
        counts[r[TARGET]] = counts.get(r[TARGET], 0) + 1
    return max(sorted(counts), key=lambda k: counts[k])

def build(rows, avail, features_per_split=None):
    if len(set(r[TARGET] for r in rows)) == 1 or not avail:
        return majority(rows)
    pool = avail
    if features_per_split and len(avail) > features_per_split:
        pool = [avail[int(rnd() * len(avail))] for _ in range(features_per_split)]
        pool = list(dict.fromkeys(pool)) or avail
    best = max(pool, key=lambda c: gain(rows, c))
    if gain(rows, best) <= 0:
        return majority(rows)
    parts = split(rows, best)
    rest = [c for c in avail if c != best]
    return (COLS[best], majority(rows),
            {v: build(parts[v], rest, features_per_split) for v in sorted(parts)})

def classify(node, row):
    while not isinstance(node, str):
        col, fallback, branches = node
        v = row[COLS.index(col)]
        if v not in branches:
            return fallback
        node = branches[v]
    return node

def accuracy(pred, rows):
    return sum(1 for r in rows if pred(r) == r[TARGET]) / len(rows)

def bootstrap(rows):
    """A sample of the same size, drawn WITH replacement."""
    return [rows[int(rnd() * len(rows))] for _ in range(len(rows))]

print("60 training rows, 600 test rows, EIGHT features of which only two matter,")
print("and 20 per cent of the labels flipped.")
print()
print("A SINGLE FULL TREE grown to purity:")
one = build(train, list(range(len(COLS))))
print("   accuracy %.4f" % accuracy(lambda r: classify(one, r), test))
print()
def vote(trees):
    def f(row):
        counts = {}
        for t in trees:
            c = classify(t, row)
            counts[c] = counts.get(c, 0) + 1
        return max(sorted(counts), key=lambda k: counts[k])
    return f

print("BAGGING: each tree on its own BOOTSTRAP sample, then a majority vote.")
print("the column that matters is the LAST: what one tree of the committee")
print("scores on average, against what the committee scores together.")
print()
print("   trees | one tree, on average | the committee | the gain")
for n_trees in (5, 25, 101, 301):
    bag = [build(bootstrap(train), list(range(len(COLS)))) for _ in range(n_trees)]
    solo = sum(accuracy(lambda r, t=t: classify(t, r), test) for t in bag) / n_trees
    together = accuracy(vote(bag), test)
    print("   %5d | %20.4f | %13.4f | %+8.4f"
          % (n_trees, solo, together, together - solo))
print()
print("RANDOM FOREST: the same, but each split may only consider 3 of the 8")
print("features, chosen at random, which makes the trees LESS ALIKE.")
print()
print("   trees | one tree, on average | the forest   | the gain")
for n_trees in (5, 25, 101, 301):
    forest = [build(bootstrap(train), list(range(len(COLS))), 3) for _ in range(n_trees)]
    solo = sum(accuracy(lambda r, t=t: classify(t, r), test) for t in forest) / n_trees
    together = accuracy(vote(forest), test)
    print("   %5d | %20.4f | %13.4f | %+8.4f"
          % (n_trees, solo, together, together - solo))
print()
print("the true rule itself scores %.4f on this test set, since 20 per cent of"
      % (sum(1 for r in test
             if ("yes" if (r[0] == "clear" or r[1] == "yes") else "no") == r[TARGET])
         / len(test)))
print("its labels were flipped. that is the ceiling.")
print()
print("BOOTSTRAP: sampling 60 rows WITH replacement leaves about 1/e of them out.")
n = 60
left_out = (1 - 1.0 / n) ** n
print("   P(a given row is NOT chosen in n draws) = (1 - 1/%d)^%d = %.4f" % (n, n, left_out))
print("   1/e = %.4f, so about 36.8%% of rows are unused by each tree and are" % (1 / math.e))
print("   available as a free test set for it: the OUT-OF-BAG estimate.")
munotes.in362

Ensemble Methods, Bagging and the Random Forest

WHY VOTING WORKS, as arithmetic. n independent voters, each right with
probability p. the majority is right with probability:
   voters |  p=0.55  |  p=0.60  |  p=0.45
        1 |   0.5500 |   0.6000 |   0.4500
        5 |   0.5931 |   0.6826 |   0.4069
       11 |   0.6331 |   0.7535 |   0.3669
       51 |   0.7641 |   0.9265 |   0.2359
      101 |   0.8438 |   0.9791 |   0.1562

   at p above 0.5 the majority races to certainty. at p BELOW 0.5 it races
   to zero: a committee of voters worse than chance is worse than one of
   them. and the whole table assumes the voters are INDEPENDENT.

60 training rows, 600 test rows, EIGHT features of which only two matter,
and 20 per cent of the labels flipped.

A SINGLE FULL TREE grown to purity:
   accuracy 0.6933

BAGGING: each tree on its own BOOTSTRAP sample, then a majority vote.
the column that matters is the LAST: what one tree of the committee
scores on average, against what the committee scores together.

   trees | one tree, on average | the committee | the gain
       5 |               0.6653 |        0.6717 |  +0.0063
      25 |               0.6768 |        0.7150 |  +0.0382
     101 |               0.6648 |        0.7150 |  +0.0502
     301 |               0.6657 |        0.7133 |  +0.0476

RANDOM FOREST: the same, but each split may only consider 3 of the 8
features, chosen at random, which makes the trees LESS ALIKE.

   trees | one tree, on average | the forest   | the gain
       5 |               0.6290 |        0.6867 |  +0.0577
      25 |               0.6482 |        0.7367 |  +0.0885
     101 |               0.6279 |        0.7300 |  +0.1021
     301 |               0.6436 |        0.7450 |  +0.1014

the true rule itself scores 0.8067 on this test set, since 20 per cent of
its labels were flipped. that is the ceiling.

BOOTSTRAP: sampling 60 rows WITH replacement leaves about 1/e of them out.
   P(a given row is NOT chosen in n draws) = (1 - 1/60)^60 = 0.3648
   1/e = 0.3679, so about 36.8% of rows are unused by each tree and are
   available as a free test set for it: the OUT-OF-BAG estimate.
munotes.in363

Ensemble Methods, Bagging and the Random Forest

Read the last column of both tables.

munotes.in364

Ensemble Methods, Bagging and the Random Forest

Bagging: one tree of the committee averages 0.6657, and 301 of them together score 0.7133. The gain is +0.0476.

Random forest: one tree averages 0.6436, which is worse than a bagged tree, and 301 of them together score 0.7450, which is better. The gain is +0.1014, more than twice as large.

Read that again, because it is the most counter-intuitive fact in the chapter and the likeliest examination question. Restricting each split to three of the eight features makes every individual tree worse. It makes the forest better. Diversity is worth more than individual accuracy, because averaging removes exactly the errors that differ between models and cannot remove the ones they share.

And the ceiling: the true rule itself scores 0.8067 on this test set, since 20 per cent of its labels were flipped. The forest at 0.7450 has closed about two thirds of the gap between a single tree and the best achievable.

munotes.in365

Ensemble Methods, Bagging and the Random Forest

Why bagging works, in the language of chapter 48

Bias and Variance gives the mechanism exactly, and a paper asking why bagging helps wants this.

Averaging n independent estimates divides their variance by n and leaves their bias unchanged. So:

Bagging reduces variance and does nothing for bias. It therefore helps a high-variance, low-bias model a great deal, and a high-bias model not at all.

Which is why bagging is applied to fully grown decision trees. A deep tree is the highest-variance model in MU's list: Reading, Drawing and Pruning a Decision Tree showed that changing a few rows changes the whole structure. Bagging a linear regression achieves almost nothing, because a linear model has low variance already and its bias is untouched.

And the trees in a bagged forest are deliberately NOT pruned. Pruning reduces variance, which is the ensemble's job; leaving the trees deep keeps their bias low and lets the vote handle the variance. That surprises students who have just learned to prune.

The bootstrap, and what it gives free

A bootstrap sample of n rows is drawn with replacement, so some rows appear twice or more and some not at all.

P(a given row is never chosen in n draws) = (1 - 1/n)**n -> 1/e = 0.3679

The program computes 0.3648 at n = 60. So each tree never sees about 36.8 per cent of the training data, and those rows are a ready-made test set for that tree. Averaging each tree's accuracy on its own unused rows gives the out-of-bag estimate, which is a validation score obtained without holding any data back at all. It is one of the most useful properties of the method and a paper may ask for it by name.

The random forest's second source of difference

Bagging makes the trees differ by giving them different rows. A random forest also gives them different columns: at each split, only a random subset of the features may be considered, conventionally about the square root of their number for classification.

The reason is specific and worth stating. With one strongly predictive feature, every bagged tree will split on it at the root, so the trees are correlated however the rows are resampled, and correlated errors do not cancel. Forcing most splits to ignore it breaks that correlation.

Two further benefits fall out. The out-of-bag estimate is still available. And feature importance can be measured, by shuffling one feature's values and seeing how much the out-of-bag accuracy falls; that is a measurement, unlike the position-in-the-tree heuristic that Reading, Drawing and Pruning a Decision Tree warned against.

The three ways to combine models

A paper asking for the ensemble family wants these three distinguished.

munotes.in366

Ensemble Methods, Bagging and the Random Forest

BaggingBoostingStacking
Models are trainedin parallel, independentlyin sequence, each on the previous ones' mistakesin parallel, then a model learns how to combine them
Each seesa bootstrap samplethe whole set, reweightedthe whole set
Combined byequal vote or averageweighted votea learned combiner
Reducesvariancebias, mainlyboth
Base learner should below bias, high variance: a deep treehigh bias, low variance: a stumpanything
Overfits easilynomore easilyyes, needs care
Chapterthis oneBoosting and AdaBoostnot on MU's label

Bagging and boosting want opposite base learners, and that single row is the cleanest way to hold them apart: bagging averages away the variance of strong learners, boosting accumulates weak ones into a strong one.

Distinctions

A single treeA bagged forest
Variancehighmuch lower
Biaslowthe same
Interpretableyes, as rulesno, 301 trees are not rules
Prunedshould bedeliberately not
BaggingRandom forest
Rowsbootstrap samplebootstrap sample
Features at a splitalla random subset
Individual treebetter, 0.6657worse, 0.6436
The committee0.71330.7450
Voters better than chanceVoters worse than chance
p = 0.55, 101 of them0.8438
p = 0.45, 101 of them0.1562
The committee ismuch better than onemuch worse than one

What it does not mean

An ensemble is not automatically better. If the base learner is worse than chance, the ensemble is far worse. The arithmetic runs both ways.

Bagging does not reduce bias. It divides variance and leaves bias alone, which is why it does little for a linear model.

More trees do not overfit. Adding trees to a bagged forest cannot make it worse; it converges. What overfits is each individual tree, and the vote is the cure.

The trees in a bagged forest should not be pruned. Pruning is variance reduction, which is the ensemble's job.

Restricting the features does not make the forest worse. It makes each tree worse and the forest better, which is the chapter's central measurement.

An ensemble is not interpretable. Three hundred trees are not a set of rules, and the interpretability that Reading, Drawing and Pruning a Decision Tree prized is the price paid here.

Quick revision

  • Ensemble: combine several base learners. Bagging trains each on a bootstrap sample (drawn with replacement) and combines by majority vote or average.
  • The voting arithmetic runs both ways: 101 voters at p = 0.55 reach 0.8438; at p = 0.45 they reach 0.1562. The base learner must be better than chance, and the voters must be different.
  • Measured: bagging, one tree 0.6657, committee 0.7133, gain +0.0476. Random forest, one tree 0.6436, forest 0.7450, gain +0.1014.
  • The forest's trees are individually WORSE and collectively BETTER. Diversity beats individual accuracy.
  • Mechanism: averaging n independent estimates divides variance by n and leaves bias unchanged. So bagging suits a high-variance, low-bias model, which is a fully grown tree, and those trees are deliberately not pruned.
  • Bootstrap: (1 - 1/n)n tends to 1/e = 0.3679, so each tree misses about 36.8 per cent of the rows, giving the out-of-bag** estimate free.
  • A random forest adds a random subset of features per split, about the square root of their number, to break the correlation a single strong feature would create. It also gives a measured feature importance by shuffling.
  • Bagging is parallel and reduces variance and wants strong learners; boosting is sequential and reduces bias and wants weak ones; stacking learns the combiner.
munotes.in367

Ensemble Methods, Bagging and the Random Forest

Test yourself

1. Define bagging. Bootstrap aggregating: train each base learner on its own bootstrap sample, a sample of the same size drawn with replacement from the training data, then combine them by majority vote for classification or by averaging for regression.

2. Under what condition does an ensemble help, and what happens when it fails? Each base learner must be better than chance, and they must make different errors. If the learners are worse than chance the majority is far worse than any one of them: 101 voters each right 45 times in 100 are right only 16 times in 100.

3. Why does bagging suit decision trees in particular? Because averaging divides variance by the number of models and leaves bias unchanged, so it helps a low-bias high-variance model most. A fully grown decision tree is the highest-variance model in this syllabus, since changing a few training rows changes its whole structure, while a linear model has low variance already and gains almost nothing.

4. Should the trees in a bagged forest be pruned? Justify. No. Pruning reduces variance, which is exactly what the vote is there to do, and it would raise the bias that the ensemble cannot fix. The trees are left fully grown so their bias stays low and the vote handles the variance.

5. What is the out-of-bag estimate and where does it come from? Drawing n rows with replacement leaves each particular row unchosen with probability (1 - 1/n) to the power n, which tends to 1/e, about 36.8 per cent. Each tree therefore never sees about a third of the training data, and its accuracy on those unused rows, averaged over the trees, is a validation estimate obtained without holding any data back.

munotes.in368

Ensemble Methods, Bagging and the Random Forest

6. How does a random forest differ from plain bagging, and why? At each split it may consider only a random subset of the features, conventionally about the square root of their number. Without it, a single strongly predictive feature would be chosen at the root of every tree however the rows were resampled, so the trees would be correlated and their errors would not cancel.

7. In this chapter's measurement, the random forest's individual trees were worse than the bagged ones and its committee was better. Explain. Restricting the features available at each split prevents each tree from using the best feature every time, so each tree is individually less accurate. It also makes the trees far less alike, and averaging removes exactly the errors that differ between models while leaving those they share. Diversity is therefore worth more than individual accuracy: the gain rose from +0.0476 to +0.1014.

Contents This chapter on its own page

munotes.in369

Chapter Sixty-Five

Boosting and AdaBoost

Syllabus topic Module 2, "Boosting"

In one line

Train a weak model, find what it got wrong, make those cases matter more, train another, and add up their votes with a weight that reflects how good each one was.

In the wording a student can write in an examination: boosting builds an ensemble sequentially. Each base learner is trained on the whole training set but with the examples reweighted, so that the examples the previous learners got wrong carry more weight. The learners are then combined by a weighted vote, the weight of each being larger when its error was smaller. AdaBoost, short for adaptive boosting, is the standard algorithm, published by Freund and Schapire in 1997.

The idea, against bagging

Hold this comparison and the rest follows.

BaggingBoosting
The learners are trainedin parallel, each blind to the othersin sequence, each on the previous ones' mistakes
Each learner seesa bootstrap sample of the rowsall the rows, reweighted
The vote isequalweighted by each learner's accuracy
It reducesvariancebias, mainly
The base learner should bestrong: a deep treeweak: a stump
Noisy labelsare averaged outare chased, which is its weakness

Ensemble Methods, Bagging and The Random Forest averaged away the variance of models that were already good. Boosting does the opposite: it starts from a model barely better than guessing and accumulates it into a good one. A weak learner need only beat chance.

AdaBoost, as an algorithm

The four lines to reproduce in an examination. Labels are +1 and -1.

  1. Start with every example weighted equally: w[i] = 1/n.
  2. For each round t: train a weak learner h[t] that minimises the weighted error e[t], the total weight of the examples it gets wrong.
  3. Give that learner the weight

alpha[t] = 0.5 * ln((1 - e[t]) / e[t])

  1. Reweight: multiply an example's weight by exp(-alpha[t]) if the learner got it right and by exp(+alpha[t]) if it got it wrong, then divide every weight by their total so they sum to 1 again.

The final prediction is the sign of the weighted sum:

H(x) = sign( sum over t of alpha[t] * h[t](x) )

Why that formula for alpha, which papers ask. Read it at three points.

Weighted error ealphaMeaning
near 0, a nearly perfect learnerlarge and positiveit dominates the vote
exactly 0.5, a coin0it is ignored entirely
above 0.5, worse than a coinnegativeits prediction is inverted and still used

That last row is the one students miss. A learner worse than chance is not discarded: a negative alpha flips it, which is correct, because a consistently wrong witness is as informative as a consistently right one. This is exactly the condition Ensemble Methods, Bagging and The Random Forest found fatal for plain voting, and AdaBoost's weighting is immune to it.

munotes.in370

Boosting and AdaBoost

Two rounds by hand, and the full run

Ten students, hours studied against pass or fail, arranged so that no single threshold on hours can classify them all. That matters: if one stump could, there would be nothing to boost.

# AdaBoost: two rounds worked completely by hand with the weights printed, then
# the full run, and the comparison with a single weak classifier the practical
# asks for. Read against Freund and Schapire 1997.
import math

# Ten students: hours studied, and whether they passed. Deliberately NOT
# separable by any single threshold, so one weak learner cannot get them all.
DATA = [(1, -1), (2, -1), (3, -1), (4, +1), (5, +1),
        (6, +1), (7, -1), (8, -1), (9, +1), (10, +1)]

def stumps():
    """Every decision stump: 'predict s if hours <= t, else -s'."""
    out = []
    for t in [i + 0.5 for i in range(0, 10)]:
        for s in (+1, -1):
            out.append((t, s))
    return out

def predict(stump, x):
    t, s = stump
    return s if x <= t else -s

def best_stump(weights):
    """The stump with the least WEIGHTED error."""
    best = None
    for st in stumps():
        err = sum(w for w, (x, y) in zip(weights, DATA) if predict(st, x) != y)
        if best is None or err < best[0] - 1e-12:
            best = (err, st)
    return best

n = len(DATA)
w = [1.0 / n] * n
model = []

print("ten students, hours studied and pass (+1) or fail (-1):")
print("   " + "  ".join("%d:%+d" % (x, y) for x, y in DATA))
print()
print("a WEAK LEARNER here is a single threshold on hours. no one threshold")
print("classifies all ten, because the passes are not on one side of any line.")
print()
for round_no in (1, 2):
    print("ROUND %d" % round_no)
    print("   weights: " + " ".join("%.4f" % v for v in w))
    err, st = best_stump(w)
    t, s = st
    alpha = 0.5 * math.log((1 - err) / err)
    print("   best stump: predict %+d if hours <= %.1f, else %+d" % (s, t, -s))
    print("   weighted error e = %.4f" % err)
    print("   alpha = 0.5 * ln((1 - %.4f)/%.4f) = %.4f" % (err, err, alpha))
    print("   it gets these WRONG: %s"
          % " ".join("%d" % x for (x, y) in DATA if predict(st, x) != y))
    new = []
    for wi, (x, y) in zip(w, DATA):
        factor = math.exp(-alpha * y * predict(st, x))
        new.append(wi * factor)
    z = sum(new)
    w = [v / z for v in new]
    model.append((alpha, st))
    print("   reweight: multiply by exp(-alpha) if right, exp(+alpha) if wrong,")
    print("             then divide by the total %.4f so they sum to 1." % z)
    print("   new weights: " + " ".join("%.4f" % v for v in w))
    heavy = max(range(n), key=lambda i: w[i])
    print("   the heaviest is now hours = %d, which round %d got wrong."
          % (DATA[heavy][0], round_no))
    print()

def ensemble(model, x):
    total = sum(a * predict(st, x) for a, st in model)
    return (1 if total >= 0 else -1), total

print("THE FULL RUN, and the accuracy after each round:")
w = [1.0 / n] * n
model = []
print("   round | alpha  | weighted error | ensemble accuracy")
for r in range(1, 11):
    err, st = best_stump(w)
    if err <= 0:
        err = 1e-10
    alpha = 0.5 * math.log((1 - err) / err)
    model.append((alpha, st))
    new = [wi * math.exp(-alpha * y * predict(st, x))
           for wi, (x, y) in zip(w, DATA)]
    z = sum(new)
    w = [v / z for v in new]
    acc = sum(1 for x, y in DATA if ensemble(model, x)[0] == y) / n
    print("   %5d | %6.4f | %14.4f | %17.4f" % (r, alpha, err, acc))
print()
best_err, best_single = best_stump([1.0 / n] * n)
single_acc = sum(1 for x, y in DATA if predict(best_single, x) == y) / n
print("THE COMPARISON THE PRACTICAL ASKS FOR:")
print("   the best SINGLE stump           : accuracy %.4f" % single_acc)
print("   the boosted ensemble of %d stumps: accuracy %.4f"
      % (len(model), sum(1 for x, y in DATA if ensemble(model, x)[0] == y) / n))
print()
print("no single threshold can do better than 8 of 10, because the passes are")
print("not on one side of any line. weighted together, with each stump trained")
print("on what the previous ones got wrong, three of them are exact.")
print()
print("and note round 2: the ensemble accuracy DIPPED to 0.7000 before reaching")
print("1.0000 at round 3. boosting is not monotonic round by round; what the")
print("theorem bounds is the training error after ALL the rounds.")
munotes.in371

Boosting and AdaBoost

ten students, hours studied and pass (+1) or fail (-1):
   1:-1  2:-1  3:-1  4:+1  5:+1  6:+1  7:-1  8:-1  9:+1  10:+1

a WEAK LEARNER here is a single threshold on hours. no one threshold
classifies all ten, because the passes are not on one side of any line.

ROUND 1
   weights: 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000
   best stump: predict -1 if hours <= 3.5, else +1
   weighted error e = 0.2000
   alpha = 0.5 * ln((1 - 0.2000)/0.2000) = 0.6931
   it gets these WRONG: 7 8
   reweight: multiply by exp(-alpha) if right, exp(+alpha) if wrong,
             then divide by the total 0.8000 so they sum to 1.
   new weights: 0.0625 0.0625 0.0625 0.0625 0.0625 0.0625 0.2500 0.2500 0.0625 0.0625
   the heaviest is now hours = 7, which round 1 got wrong.

ROUND 2
   weights: 0.0625 0.0625 0.0625 0.0625 0.0625 0.0625 0.2500 0.2500 0.0625 0.0625
   best stump: predict -1 if hours <= 8.5, else +1
   weighted error e = 0.1875
   alpha = 0.5 * ln((1 - 0.1875)/0.1875) = 0.7332
   it gets these WRONG: 4 5 6
   reweight: multiply by exp(-alpha) if right, exp(+alpha) if wrong,
             then divide by the total 0.7806 so they sum to 1.
   new weights: 0.0385 0.0385 0.0385 0.1667 0.1667 0.1667 0.1538 0.1538 0.0385 0.0385
   the heaviest is now hours = 4, which round 2 got wrong.

THE FULL RUN, and the accuracy after each round:
   round | alpha  | weighted error | ensemble accuracy
       1 | 0.6931 |         0.2000 |            0.8000
       2 | 0.7332 |         0.1875 |            0.7000
       3 | 0.7175 |         0.1923 |            1.0000
       4 | 0.7235 |         0.1905 |            1.0000
       5 | 0.7212 |         0.1912 |            1.0000
       6 | 0.7221 |         0.1909 |            1.0000
       7 | 0.7217 |         0.1910 |            1.0000
       8 | 0.7219 |         0.1910 |            1.0000
       9 | 0.7218 |         0.1910 |            1.0000
      10 | 0.7218 |         0.1910 |            1.0000

THE COMPARISON THE PRACTICAL ASKS FOR:
   the best SINGLE stump           : accuracy 0.8000
   the boosted ensemble of 10 stumps: accuracy 1.0000

no single threshold can do better than 8 of 10, because the passes are
not on one side of any line. weighted together, with each stump trained
on what the previous ones got wrong, three of them are exact.

and note round 2: the ensemble accuracy DIPPED to 0.7000 before reaching
1.0000 at round 3. boosting is not monotonic round by round; what the
theorem bounds is the training error after ALL the rounds.
munotes.in372

Boosting and AdaBoost

Reading the two rounds

This is the whole algorithm visible in two tables, and it is what a paper wants written out.

Round 1. All ten weights are 0.1000. The best stump is fail up to 3.5 hours, pass above, which gets the two seven-and-eight-hour failures wrong. Its weighted error is 0.2000, two examples at 0.1 each, so

alpha[1] = 0.5 ln(0.8 / 0.2) = 0.5 ln(4) = 0.6931

Reweighting multiplies the eight correct weights by exp(-0.6931) = 0.5 and the two wrong ones by exp(+0.6931) = 2, giving 0.05 and 0.2, which total 0.8. Dividing by 0.8 gives 0.0625 for the eight and 0.2500 for the two.

Notice what that means. The two examples round 1 got wrong now carry half the total weight between them, 0.25 + 0.25, and the eight it got right carry the other half. That is always true of one AdaBoost round: after reweighting, the examples the last learner got wrong hold exactly half the weight, whatever the error was. It follows from the formula, and it is a clean thing to state in an answer.

munotes.in373

Boosting and AdaBoost

Round 2. Working on those weights, the best stump is now fail up to 8.5 hours, pass above, which gets the two heavy examples right and the three four-to-six-hour passes wrong. Its weighted error is 0.1875, three examples at 0.0625, so alpha[2] = 0.7332. The heaviest weight after round 2 is on four hours, which round 2 got wrong. The algorithm is walking round the data, and each learner attends to what the last one dropped.

The dip, which is left in deliberately

Read the accuracy column of the full run.

RoundEnsemble accuracy
10.8000
20.7000
31.0000
4 to 101.0000

After round 2 the ensemble is worse than after round 1. Two stumps of nearly equal weight, 0.6931 and 0.7332, disagree over much of the range, and a two-member weighted vote is close to a coin toss wherever they do. Round 3 breaks the ties and the ensemble is exact.

Boosting is not monotonic round by round. What Freund and Schapire bound is the training error after all the rounds, not after each one, and a student who expects the number to climb steadily will think the implementation is broken. The practical lesson: judge a boosted model after the rounds are done, and never on an even number of near-equal members.

The comparison the practical asks for

MU's paired practical sets AdaBoost and asks for it against a single weak classifier. The answer is in the run:

Accuracy
The best single stump0.8000
The boosted ensemble of 10 stumps1.0000

And the reason, which is the part worth marks: no threshold on hours can exceed 8 of 10, because the passing students are not on one side of any line. The weak learner's ceiling is a property of its form, not of its training. Boosting does not train the stump better; it adds stumps whose errors lie in different places and lets the weighted vote place a boundary no single stump could express.

Bias, variance, and what boosting is actually doing

In the language of Bias and Variance:

Bagging reduces variance. Boosting reduces bias. A stump has enormous bias, being one threshold, and almost no variance. Adding stumps enlarges the set of functions the model can express, so the bias falls. And with enough rounds a boosted model can overfit, unlike a bagged forest, which only converges.

Boosting can also be read as greedy minimisation of the exponential loss exp(-y * H(x)), adding one term at a time. That reading, due to later authors, explains the reweighting exactly: an example's weight in round t + 1 is proportional to the exponential loss the ensemble currently suffers on it. A paper may ask why the reweighting factor is an exponential, and this is the answer.

munotes.in374

Boosting and AdaBoost

Where boosting fails

The weakness is the mirror of the strength, and an examiner who asks for a limitation wants this.

Boosting chases noise. A mislabelled example is one the learners keep getting wrong, so its weight keeps doubling, and the later rounds spend themselves on a single wrong row. Bagging is untroubled by the same row, since averaging dilutes it. So: noisy labels favour bagging, clean data with a weak learner favours boosting.

Boosting cannot be parallelised. Round t + 1 needs round t's weights, so the rounds are inherently sequential, where a bagged forest's trees can be built at once.

A learner that is too strong ruins it. If the first learner fits the training data exactly, its error is 0, alpha is infinite, and there is nothing left to reweight. This is why boosting uses stumps, and why a boosted ensemble of fully grown trees is a mistake.

Distinctions

BaggingBoosting
Orderparallelsequential
Data per learnerbootstrap sampleall rows, reweighted
Voteequalweighted by alpha
Reducesvariancebias
Base learnerstrong, a deep treeweak, a stump
Noisy labelstoleratedchased
Can overfit with more membersnoyes
A single stumpThe boosted ensemble
Expressesone thresholda weighted sum of thresholds
On this data0.8000, and it cannot do better1.0000
Weighted erroralphaThe learner is
e < 0.5positiveused as it stands
e = 0.50ignored
e > 0.5negativeinverted and used

What it does not mean

Boosting does not resample the data. Every learner sees every row; what changes is the weight. That is the commonest confusion with bagging.

A weak learner is not a bad one. It is one that beats chance, and that is all AdaBoost requires of it.

Accuracy does not rise every round. This run drops from 0.8000 to 0.7000 before reaching 1.0000.

A learner worse than chance is not discarded. Its alpha is negative, which inverts it.

Boosting does not make a stump a better stump. It combines stumps into a model of a different shape.

More rounds are not always safer. Unlike bagging, a boosted model can overfit, and on noisy labels it will.

Quick revision

  • Boosting: sequential ensemble, each learner trained on the reweighted whole set, combined by a weighted vote. AdaBoost is Freund and Schapire, 1997.
  • The four steps: equal weights 1/n; fit the learner of least weighted error e; set alpha = 0.5 ln((1 - e)/e); multiply by exp(-alpha) if right and exp(+alpha) if wrong, then normalise. Predict sign(sum of alpha[t] h[t](x)).
  • alpha is 0 at e = 0.5 and negative above it, which inverts a learner worse than chance.
  • Worked: round 1, error 0.2000, alpha = 0.6931, weights become 0.0625 and 0.2500. Round 2, error 0.1875, alpha = 0.7332, the heaviest weight moves to the row round 2 missed.
  • After any round, the rows the last learner got wrong carry exactly half the total weight.
  • The run goes 0.8000, 0.7000, 1.0000. Not monotonic; the bound is on the error after all the rounds.
  • The practical's comparison: best single stump 0.8000, which is its ceiling on this data; boosted ensemble 1.0000.
  • Boosting reduces bias and wants a weak learner; bagging reduces variance and wants a strong one. Boosting chases mislabelled rows, cannot be parallelised, and can overfit.
munotes.in375

Boosting and AdaBoost

Test yourself

1. State the AdaBoost algorithm. Weight every training example 1/n. In each round, fit the weak learner with the smallest weighted error e, give it the weight alpha = 0.5 * ln((1 - e)/e), then multiply the weight of every example it classified correctly by exp(-alpha) and every one it missed by exp(+alpha), and normalise the weights to sum to one. Predict with the sign of the sum of alpha[t] times h[t](x).

2. Why is alpha defined that way? Give its value at e = 0.5 and above. It gives a nearly perfect learner a large positive weight and a poor one a small weight. At e = 0.5 it is zero, so a learner no better than a coin is ignored. Above 0.5 it is negative, which inverts the learner's prediction and still uses it, since a consistently wrong classifier carries as much information as a consistently right one.

3. Work round 1 on ten equally weighted examples where the best stump misses two. The weighted error is 0.2. alpha = 0.5 ln(0.8/0.2) = 0.5 ln(4) = 0.6931. The eight correct weights are multiplied by exp(-0.6931) = 0.5 to give 0.05 each, the two wrong ones by 2 to give 0.2 each, and the total 0.8 divides out to leave 0.0625 and 0.2500.

4. After a round of AdaBoost, how much of the total weight sits on the examples the last learner got wrong? Exactly half, whatever the error was. It follows from the formula for alpha, and it is why the next learner is forced to attend to those examples.

5. In this chapter's run the ensemble accuracy fell from 0.8000 to 0.7000 before reaching 1.0000. Explain. Boosting is not monotonic round by round. Two stumps of nearly equal weight disagree over much of the input range, and a two-member weighted vote is close to a coin toss wherever they do. The theorem bounds the training error after all the rounds, not after each one.

munotes.in376

Boosting and AdaBoost

6. The best single stump scored 0.8000 and could do no better. Why, and how does the ensemble exceed it? No threshold on hours can classify these ten, because the passing students are not on one side of any line; 8 of 10 is the ceiling of the stump's form, not a failure of its training. The ensemble does not improve the stump. It adds stumps whose errors fall in different places and takes a weighted vote, which expresses a boundary no single threshold can.

7. Compare bagging and boosting on noisy labels, and say which base learner each wants. A mislabelled row is one every learner gets wrong, so boosting doubles its weight round after round and spends the later rounds fitting it, which is why noisy data favours bagging, where averaging dilutes the same row. Boosting wants a weak, high-bias learner such as a stump, because it reduces bias; bagging wants a strong, high-variance learner such as a fully grown tree, because it reduces variance.

Contents This chapter on its own page

munotes.in377

Chapter Sixty-Six

Evaluating a Model

Syllabus topic Module 2, "Implement and evaluate basic machine learning models"

In one line

A single accuracy figure can be high and worthless, so a model is judged by a table of its four kinds of outcome and by scores that separate the two kinds of mistake.

This chapter is licensed by MU's own Course Outcome 3, which asks a student to evaluate machine learning models, not merely to implement them. No module label names a measure, so the measures are set out here in full.

Accuracy, and why it lies

Accuracy is the fraction of predictions that are correct. It is the obvious measure and it is the one that fails.

Take a thousand messages of which 30 are spam. A filter that marks everything as not spam catches nothing at all, and its accuracy is 0.9700. It is the most useless program that could be written for the task and it scores 97 in a hundred.

The cause is class imbalance. When one class is rare, the majority answer scores well by arithmetic alone, and accuracy measures how common the majority is rather than how good the model is. Any accuracy figure must be read against the proportion of the largest class, which is the score a program with no model at all would get. For these messages that baseline is 0.9700, so 0.9700 is not a result; it is the floor.

The confusion matrix

The fix is to stop collapsing the outcomes into one number. Every prediction on a two-class problem falls into one of four cells.

Predicted positivePredicted negative
Actually positivetrue positive (TP)false negative (FN), a miss
Actually negativefalse positive (FP), a false alarmtrue negative (TN)

The two mistakes are not the same mistake, and no single number can hold both. A spam filter's false positive is a wanted letter in the junk folder; its false negative is one more advertisement to delete. A cancer screen's false negative is a missed tumour. Which error to prefer is a decision about cost, taken outside the model, and it is the sentence an examiner is looking for.

The measures

Learn these four formulae. Every one is a ratio of cells in that table.

accuracy = (TP + TN) / (TP + TN + FP + FN) how much is right, overall

precision = TP / (TP + FP) of those FLAGGED, how many should have been

recall = TP / (TP + FN) of those that SHOULD be, how many were flagged

specificity = TN / (TN + FP) of the negatives, how many were left alone

Read the denominators, because they are the whole distinction. Precision divides by what the model said; recall divides by what the truth is. Precision answers "when it flags something, can I believe it"; recall answers "does it find them all".

munotes.in378

Evaluating a Model

And because two numbers are awkward to compare, they are combined as the F1 score, their harmonic mean:

F1 = 2 precision recall / (precision + recall)

The harmonic mean is used and not the ordinary average because it punishes an imbalance. Precision 1.0 with recall 0.0 has an ordinary average of 0.5 and an F1 of 0, which is the honest figure for a model that never flags anything.

The three classifiers, scored

# Evaluating a model, licensed by MU's own Course Outcome 3. Why accuracy lies
# on unbalanced data, the confusion matrix, precision, recall, F1, and k-fold
# cross validation, all computed.
def confusion(truth, pred):
    tp = sum(1 for t, p in zip(truth, pred) if t == 1 and p == 1)
    fn = sum(1 for t, p in zip(truth, pred) if t == 1 and p == 0)
    fp = sum(1 for t, p in zip(truth, pred) if t == 0 and p == 1)
    tn = sum(1 for t, p in zip(truth, pred) if t == 0 and p == 0)
    return tp, fn, fp, tn

def report(name, truth, pred):
    tp, fn, fp, tn = confusion(truth, pred)
    n = len(truth)
    acc = (tp + tn) / n
    prec = tp / (tp + fp) if tp + fp else 0.0
    rec = tp / (tp + fn) if tp + fn else 0.0
    f1 = 2 * prec * rec / (prec + rec) if prec + rec else 0.0
    spec = tn / (tn + fp) if tn + fp else 0.0
    print("   %s" % name)
    print("      confusion matrix          predicted spam   predicted not")
    print("         actually spam      %14d %15d" % (tp, fn))
    print("         actually not       %14d %15d" % (fp, tn))
    print("      accuracy  = (%d + %d)/%d          = %.4f" % (tp, tn, n, acc))
    print("      precision = %d/(%d + %d)            = %.4f" % (tp, tp, fp, prec))
    print("      recall    = %d/(%d + %d)            = %.4f" % (tp, tp, fn, rec))
    print("      specificity = %d/(%d + %d)          = %.4f" % (tn, tn, fp, spec))
    print("      F1 = 2*P*R/(P+R)                 = %.4f" % f1)
    return acc, prec, rec, f1

# 1000 messages, 30 of them spam: an UNBALANCED problem, which is the usual case.
truth = [1] * 30 + [0] * 970
print("1000 messages, %d of them spam. three classifiers, scored:" % sum(truth))
print()
lazy = [0] * 1000
report("A: mark EVERYTHING as not spam. it never catches anything.", truth, lazy)
print()
eager = [1] * 1000
report("B: mark EVERYTHING as spam. it never misses anything.", truth, eager)
print()
real = [1] * 24 + [0] * 6 + [1] * 12 + [0] * 958
report("C: a real filter: catches 24 of 30, and wrongly flags 12 good messages.",
       truth, real)
print()
print("classifier A has an accuracy of 0.9700 and is WORTHLESS. that single")
print("number is why MU's Course Outcome 3 says EVALUATE and not just implement.")
print()
print("PRECISION AND RECALL PULL AGAINST EACH OTHER. the same filter at three")
print("thresholds, from cautious to aggressive:")
print("   threshold | caught of 30 | good mail lost | precision | recall | F1")
for caught, lost in ((10, 1), (24, 12), (29, 90)):
    pred = [1] * caught + [0] * (30 - caught) + [1] * lost + [0] * (970 - lost)
    tp, fn, fp, tn = confusion(truth, pred)
    prec = tp / (tp + fp)
    rec = tp / (tp + fn)
    f1 = 2 * prec * rec / (prec + rec)
    label = "cautious" if caught == 10 else ("balanced" if caught == 24 else "aggressive")
    print("   %-9s | %12d | %14d | %9.4f | %6.4f | %.4f"
          % (label, caught, lost, prec, rec, f1))
print()
print("   cautious: high precision, poor recall. aggressive: the reverse.")
print("   which to prefer is a DECISION about cost, not a property of the model:")
print("   losing a wanted message is worse than seeing a spam one, so a mail")
print("   filter is tuned for precision, and a cancer screen for recall.")
print()
print("K-FOLD CROSS VALIDATION. 20 students, hours studied against pass, with")
print("three labels deliberately wrong. the learner is the best threshold on the")
print("TRAINING rows only; it is then scored on the fold held out.")
print()
# hours, passed. The honest rule is 'pass if hours >= 8'. Rows 5, 11 and 16 are
# WRONG on purpose, so no threshold can score 1.0 and the folds must disagree.
ROWS = [(1, 0), (2, 0), (3, 0), (4, 0), (5, 1), (6, 0), (7, 0), (8, 1),
        (9, 1), (10, 1), (11, 0), (12, 1), (13, 1), (14, 1), (15, 1),
        (16, 0), (17, 1), (18, 1), (19, 1), (20, 1)]

def fit_threshold(train):
    """The threshold with the fewest training mistakes: predict pass if >= t."""
    best = None
    for t in range(1, 22):
        wrong = sum(1 for h, y in train if (1 if h >= t else 0) != y)
        if best is None or wrong < best[0]:
            best = (wrong, t)
    return best[1]

def score(t, rows):
    return sum(1 for h, y in rows if (1 if h >= t else 0) == y) / len(rows)

k = 5
size = len(ROWS) // k
scores = []
print("   fold | tested on hours     | threshold learnt | accuracy on the fold")
for i in range(k):
    test = ROWS[i * size:(i + 1) * size]
    train = ROWS[:i * size] + ROWS[(i + 1) * size:]
    t = fit_threshold(train)
    acc = score(t, test)
    scores.append(acc)
    print("   %4d | %-19s | pass if >= %-5d | %.4f"
          % (i + 1, " ".join(str(h) for h, _ in test), t, acc))
mean = sum(scores) / k
var = sum((s - mean) ** 2 for s in scores) / k
print("   mean accuracy %.4f, spread %.4f" % (mean, var ** 0.5))
print()
print("   every row is tested EXACTLY ONCE, and every row is trained on k-1")
print("   times. the five folds scored %s." % ", ".join("%.2f" % s for s in scores))
print("   a single train/test split is one of those five numbers, chosen by")
print("   accident: it would have reported anything from %.2f to %.2f. the mean"
      % (min(scores), max(scores)))
print("   of five is far more stable, and the SPREAD says how much a single")
print("   number should be trusted.")
print()
print("   for comparison, the threshold fitted on ALL twenty rows is pass if")
t_all = fit_threshold(ROWS)
print("   hours >= %d, and it scores %.4f on those same twenty rows. that number"
      % (t_all, score(t_all, ROWS)))
print("   is training accuracy and means nothing: the model has seen every row.")
munotes.in379

Evaluating a Model

1000 messages, 30 of them spam. three classifiers, scored:

   A: mark EVERYTHING as not spam. it never catches anything.
      confusion matrix          predicted spam   predicted not
         actually spam                   0              30
         actually not                    0             970
      accuracy  = (0 + 970)/1000          = 0.9700
      precision = 0/(0 + 0)            = 0.0000
      recall    = 0/(0 + 30)            = 0.0000
      specificity = 970/(970 + 0)          = 1.0000
      F1 = 2*P*R/(P+R)                 = 0.0000

   B: mark EVERYTHING as spam. it never misses anything.
      confusion matrix          predicted spam   predicted not
         actually spam                  30               0
         actually not                  970               0
      accuracy  = (30 + 0)/1000          = 0.0300
      precision = 30/(30 + 970)            = 0.0300
      recall    = 30/(30 + 0)            = 1.0000
      specificity = 0/(0 + 970)          = 0.0000
      F1 = 2*P*R/(P+R)                 = 0.0583

   C: a real filter: catches 24 of 30, and wrongly flags 12 good messages.
      confusion matrix          predicted spam   predicted not
         actually spam                  24               6
         actually not                   12             958
      accuracy  = (24 + 958)/1000          = 0.9820
      precision = 24/(24 + 12)            = 0.6667
      recall    = 24/(24 + 6)            = 0.8000
      specificity = 958/(958 + 12)          = 0.9876
      F1 = 2*P*R/(P+R)                 = 0.7273

classifier A has an accuracy of 0.9700 and is WORTHLESS. that single
number is why MU's Course Outcome 3 says EVALUATE and not just implement.

PRECISION AND RECALL PULL AGAINST EACH OTHER. the same filter at three
thresholds, from cautious to aggressive:
   threshold | caught of 30 | good mail lost | precision | recall | F1
   cautious  |           10 |              1 |    0.9091 | 0.3333 | 0.4878
   balanced  |           24 |             12 |    0.6667 | 0.8000 | 0.7273
   aggressive |           29 |             90 |    0.2437 | 0.9667 | 0.3893

   cautious: high precision, poor recall. aggressive: the reverse.
   which to prefer is a DECISION about cost, not a property of the model:
   losing a wanted message is worse than seeing a spam one, so a mail
   filter is tuned for precision, and a cancer screen for recall.

K-FOLD CROSS VALIDATION. 20 students, hours studied against pass, with
three labels deliberately wrong. the learner is the best threshold on the
TRAINING rows only; it is then scored on the fold held out.

   fold | tested on hours     | threshold learnt | accuracy on the fold
      1 | 1 2 3 4             | pass if >= 8     | 1.0000
      2 | 5 6 7 8             | pass if >= 5     | 0.5000
      3 | 9 10 11 12          | pass if >= 8     | 0.7500
      4 | 13 14 15 16         | pass if >= 8     | 0.7500
      5 | 17 18 19 20         | pass if >= 8     | 1.0000
   mean accuracy 0.8000, spread 0.1871

   every row is tested EXACTLY ONCE, and every row is trained on k-1
   times. the five folds scored 1.00, 0.50, 0.75, 0.75, 1.00.
   a single train/test split is one of those five numbers, chosen by
   accident: it would have reported anything from 0.50 to 1.00. the mean
   of five is far more stable, and the SPREAD says how much a single
   number should be trusted.

   for comparison, the threshold fitted on ALL twenty rows is pass if
   hours >= 8, and it scores 0.8500 on those same twenty rows. that number
   is training accuracy and means nothing: the model has seen every row.
munotes.in380

Evaluating a Model

Reading the scores

The three classifiers say everything the section needs.

munotes.in381

Evaluating a Model

AccuracyPrecisionRecallF1
A, marks everything not spam0.97000.00000.00000.0000
B, marks everything spam0.03000.03001.00000.0583
C, a real filter0.98200.66670.80000.7273

A has the second-highest accuracy in the table and an F1 of zero. Precision and recall are both 0, because it never produces a true positive, and F1 collapses to 0 while accuracy stays at 0.9700. That is the single most useful thing in this chapter: F1 exposes what accuracy hides.

And B is the opposite trap. It has perfect recall: it never misses a spam message, because it flags everything. A perfect recall on its own is worthless, and so is a perfect precision, which is why the pair is always quoted together or through F1.

C is the only real model. Note that its accuracy, 0.9820, is only 1.2 points above the useless A, while its F1 is 0.7273 against 0.0000. On an unbalanced problem the accuracy scale is compressed into almost nothing, and a difference that matters enormously looks small.

munotes.in382

Evaluating a Model

The trade-off, measured

Precision and recall are not independent quantities that happen to differ. They pull against each other, and the run shows it on one filter at three settings.

SettingCaught of 30Good mail lostPrecisionRecallF1
cautious1010.90910.33330.4878
balanced24120.66670.80000.7273
aggressive29900.24370.96670.3893

Moving the threshold moves both numbers in opposite directions. Flag less and you are right more often about what you flag, and you miss more. Flag more and you catch nearly everything at the cost of ninety wanted letters.

There is no best row. Which to choose depends on which mistake costs more, and that is not something the data can decide:

  • A mail filter is tuned for precision. Losing a wanted letter is far worse than seeing an advertisement.
  • A cancer screen is tuned for recall. A false alarm costs a second test; a miss costs a life.
  • A search engine's first page is tuned for precision; a lawyer's document discovery is tuned for recall.

F1 picked the balanced row here, but F1 weights the two equally, which is an assumption and usually the wrong one. When one error genuinely costs more, say so and use the measure that reflects it.

Cross validation, and why one split is not enough

A single train and test split gives one number, and that number depends on which rows happened to be held out. k-fold cross validation removes the accident: split the data into k equal folds, train on k - 1 of them and test on the one left out, k times, then average.

Every row is tested exactly once and trained on k - 1 times, which is the property to state in an answer.

The run does it properly: the threshold is fitted on the training rows of each fold alone and then scored on the rows held out.

FoldTested onThreshold learntAccuracy
11 2 3 4 hourspass if >= 81.0000
25 6 7 8pass if >= 50.5000
39 10 11 12pass if >= 80.7500
413 14 15 16pass if >= 80.7500
517 18 19 20pass if >= 81.0000

Mean 0.8000, spread 0.1871.

Read fold 2, which is the most instructive line in the chapter. With the four rows from 5 to 8 hours held out, the training data contains no example between 4 and 9 hours, so every threshold in that gap makes exactly the same training mistakes. The thresholds are tied, the tie is broken arbitrarily, pass if >= 5 is chosen, and on the held-out fold it scores 0.5000 where pass if >= 8 would have scored 0.7500.

munotes.in383

Evaluating a Model

Two lessons, both worth marks. A tie on the training data is a real event, and what breaks it is the implementation, not the learning. And the held-out fold is exactly where such a choice shows up, which is the argument for cross validation in a single example.

The spread is the point of the whole method. The five folds scored 1.00, 0.50, 0.75, 0.75 and 1.00. A single split would have reported any one of those, so a paper quoting "accuracy 1.0000" and a paper quoting "accuracy 0.5000" could describe the same model on the same data. The mean of five is stable; the spread of 0.1871 is the honest statement of how little a single figure should be trusted.

And the last line of the run: the threshold fitted on all twenty rows scores 0.8500 on those same twenty rows. That number is training accuracy and means nothing, because the model has seen every row it is being judged on. Overfitting and Underfitting made the same point; here it is one line of output.

Conventional choices: k = 5 or k = 10. Leave-one-out is k = n, the most thorough and the most expensive. Stratified folds keep each class in its original proportion in every fold, which matters on exactly the unbalanced data this chapter began with.

Distinctions

PrecisionRecall
Divides bywhat the model saidwhat the truth is
Answerscan I believe a flagare they all found
Hurt byfalse positivesfalse negatives
Tuned high fora mail filtera cancer screen
AccuracyF1
Classifier A scores0.97000.0000
Counts true negativesyesno
Safe on unbalanced datanoyes
One train and test splitk-fold cross validation
Rows used for testingone subsetevery row, once
Result on this dataanywhere from 0.50 to 1.00mean 0.8000
Reports its own reliabilitynoyes, the spread
Costone fitk fits

What it does not mean

A high accuracy is not a good model. 0.9700 here is what a program with no model scores.

Precision and recall are not two views of the same quantity. They have different denominators and move in opposite directions as the threshold moves.

A perfect recall is not success. Flag everything and recall is 1.0000.

F1 is not the ordinary average. It is the harmonic mean, so one low number drags it down.

munotes.in384

Evaluating a Model

F1 is not neutral. It weights the two errors equally, which is itself a choice, and usually not the right one.

Cross validation does not improve the model. It estimates the model's performance more reliably. Nothing is trained better by being cross validated.

Training accuracy is not a score. The model has seen those rows.

Quick revision

  • Accuracy lies on unbalanced data. 30 spam in 1000: marking everything not spam gives 0.9700 and an F1 of 0.0000. Always read accuracy against the largest class's share.
  • The confusion matrix: TP, FN (a miss), FP (a false alarm), TN. The two mistakes have different costs, and choosing between them is a decision outside the model.
  • precision = TP/(TP+FP), by what the model said. recall = TP/(TP+FN), by what the truth is. specificity = TN/(TN+FP). F1 = 2PR/(P+R), the harmonic mean, which punishes imbalance.
  • Measured trade-off: cautious 0.9091 / 0.3333, balanced 0.6667 / 0.8000, aggressive 0.2437 / 0.9667. Mail filters favour precision, cancer screens recall.
  • k-fold cross validation: k folds, train on k - 1, test on 1, k times, average. Every row tested once, trained on k - 1 times.
  • Measured: folds 1.00, 0.50, 0.75, 0.75, 1.00, mean 0.8000, spread 0.1871. A single split would have reported anything in that range.
  • Fold 2 learnt >= 5 instead of >= 8 because its training rows had a gap and the thresholds tied; the arbitrary tie-break cost it 0.25 on the held-out fold.
  • The threshold fitted on all 20 rows scores 0.8500 on those 20 rows, which is training accuracy and means nothing.
  • k = 5 or 10 conventionally; k = n is leave-one-out; stratified folds preserve class proportions.

Test yourself

1. A spam filter marks every one of 1000 messages as not spam, 30 of which are spam. Give its accuracy and its F1, and say what the figures show. Accuracy is 970/1000 = 0.9700. It never produces a true positive, so precision and recall are both 0 and F1 is 0.0000. A high accuracy on unbalanced data measures how common the majority class is, not how good the model is, so accuracy must always be read against the share of the largest class.

2. Draw the confusion matrix and name its four cells. Rows are the truth, columns the prediction. Actually positive and predicted positive is a true positive; actually positive and predicted negative is a false negative, a miss; actually negative and predicted positive is a false positive, a false alarm; actually negative and predicted negative is a true negative.

3. Define precision and recall, and state the difference in their denominators. Precision is TP/(TP+FP), the fraction of the items the model flagged that should have been flagged. Recall is TP/(TP+FN), the fraction of the items that should have been flagged that were. Precision divides by what the model said; recall divides by what the truth is.

munotes.in385

Evaluating a Model

4. Why is F1 the harmonic mean rather than the ordinary average? Because the harmonic mean punishes an imbalance between the two. A model with precision 1.0 and recall 0.0 has an ordinary average of 0.5, which flatters it, and an F1 of 0, which is the honest figure.

5. A model can be tuned for precision or for recall. Give one application of each and justify. A mail filter is tuned for precision, because a wanted letter in the junk folder costs far more than one advertisement in the inbox. A cancer screen is tuned for recall, because a false alarm costs a second test while a miss can cost a life. The choice is about the cost of the two errors and cannot be made from the data.

6. Describe k-fold cross validation and state what it gives that a single split does not. Divide the data into k equal folds; for each fold in turn, train on the other k-1 and test on it; average the k scores. Every row is tested exactly once and trained on k-1 times. It gives a mean that does not depend on which rows were held out, and a spread that says how much a single figure should be trusted: the folds in this chapter ran from 0.50 to 1.00 around a mean of 0.8000.

7. In this chapter's cross validation, one fold learnt a different threshold and scored 0.5000. Explain. Its four held-out rows were the only training examples between 4 and 9 hours, so with them removed every threshold in that gap made exactly the same training mistakes. The thresholds were tied, the tie was broken arbitrarily in favour of the lowest, and on the held-out rows that choice scored 0.5000 where the better threshold would have scored 0.7500. The training data could not distinguish the two; only the held-out fold could.

Contents This chapter on its own page

munotes.in386

Chapter Sixty-Seven

The Statistical Learning Framework

Syllabus topic Module 2, "Statistical learning framework"

In one line

Learning is choosing one hypothesis out of a declared set so as to minimise the error you can measure, in the hope that it also minimises the error you cannot.

Everything earlier in this module was a particular learner. This chapter is the frame that all of them sit in, and it is what turns machine learning from a collection of tricks into a subject that can be reasoned about.

The five things a learning problem is made of

Name these five and a paper on the framework is answered.

1The data-generating distributionAn unknown, fixed source of pairs (x, y). Every sample is drawn from it independently.
2The training samplen pairs actually drawn. All the learner ever sees.
3The hypothesis space HThe set of functions the learner is allowed to return, declared before any data arrives.
4The loss functionWhat one wrong answer costs. Here, 1 for a wrong label and 0 for a right one.
5The learning ruleHow a member of H is chosen from the sample.

Two of the five are choices made by the person, not the data: the hypothesis space and the loss. A student who can say that has understood the chapter, because both are places where an assumption enters and neither can be checked against the data that follows.

The two risks

The distinction the whole framework turns on.

true risk = the expected loss over the whole distribution cannot be computed

empirical risk = the average loss on the training sample can be computed

The learner can only minimise the second. It is judged on the first. Empirical risk minimisation, or ERM, is the rule that says: return the member of H with the least error on the sample, and hope.

Overfitting and Underfitting was this same gap, seen from the practical end. Here it has a name and a cause.

Three floors, and why the first is not zero

The error of a learned model divides into three parts, and a paper may ask for them.

PartCauseCan it be reduced
Irreducible error, the Bayes errorthe world itself is not a function of xnever, by any method
Approximation errorthe best member of H is still not the truthby enlarging H
Estimation errorthe sample chose the wrong member of Hby more data

The first line is the one that is forgotten. In the measurement below, the recorded label is wrong 15 per cent of the time, so the true rule itself has a true risk of 0.1500. A learner reporting 0.0000 on such data has not done better than the truth; it has memorised the noise.

munotes.in387

The Statistical Learning Framework

The measurement

# The statistical learning framework, measured: empirical risk against true risk
# as the HYPOTHESIS SPACE grows. The bigger the space searched, the better the
# training score and the worse the truth, which is the whole framework in one
# table.
def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(4001)
rnd = lambda: next(gen)                                   # noqa: E731

# The world: hours studied 1..20, and the TRUE rule 'pass if hours >= 8'.
# The label a student actually records is wrong 15 per cent of the time, which
# is the irreducible noise. NOTHING can score better than 0.85 in expectation.
HOURS = list(range(1, 21))
NOISE = 0.15

def truth(h):
    return 1 if h >= 8 else 0

def sample(n):
    out = []
    for _ in range(n):
        h = HOURS[int(rnd() * len(HOURS))]
        y = truth(h)
        if rnd() < NOISE:
            y = 1 - y
        out.append((h, y))
    return out

def risk_empirical(f, data):
    """The error ON THE SAMPLE: what the learner can see."""
    return sum(1 for h, y in data if f(h) != y) / len(data)

def risk_true(f):
    """The error ON THE WORLD: exact, since the world is only 20 points."""
    total = 0.0
    for h in HOURS:
        p_one = NOISE if truth(h) == 0 else 1 - NOISE
        total += p_one if f(h) == 0 else 1 - p_one
    return total / len(HOURS)

# ---- three hypothesis spaces of very different size ------------------------
def space_threshold():
    """'pass if hours >= t'. 21 hypotheses."""
    return [(("threshold %d" % t), (lambda t: lambda h: 1 if h >= t else 0)(t))
            for t in range(1, 22)]

def space_interval():
    """'pass if a <= hours <= b'. 231 hypotheses, and it CONTAINS the thresholds."""
    out = []
    for a in range(1, 22):
        for b in range(a - 1, 21):
            out.append((("interval %d..%d" % (a, b)),
                        (lambda a, b: lambda h: 1 if a <= h <= b else 0)(a, b)))
    return out

def space_memorise(data):
    """Every function on the 20 points: 2**20 of them. Its ERM member can be
    written down directly, with no search: answer each seen point with the
    MAJORITY label recorded there, and anything unseen with 0."""
    tally = {}
    for h, y in data:
        a, b = tally.get(h, (0, 0))
        tally[h] = (a + (1 - y), b + y)
    table = {h: (1 if b > a else 0) for h, (a, b) in tally.items()}
    return [("memorised table", lambda h: table.get(h, 0))]

def erm(space, data):
    """Empirical risk minimisation: the member with the least error ON THE SAMPLE."""
    best = None
    for name, f in space:
        r = risk_empirical(f, data)
        if best is None or r < best[0] - 1e-12:
            best = (r, name, f)
    return best

print("THE SETTING. hours studied 1..20; the true rule is 'pass if hours >= 8';")
print("the recorded label is wrong %.0f per cent of the time." % (NOISE * 100))
print("so the BEST POSSIBLE true error, achieved by the true rule itself, is")
print("%.4f. that part is irreducible and no learner can remove it." % risk_true(truth))
print()
print("the learner sees a SAMPLE and minimises its error on that sample, which")
print("is EMPIRICAL RISK MINIMISATION. what we care about is the error on the")
print("world, the TRUE RISK, which the learner cannot see.")
print()

for n in (8, 20, 200):
    data = sample(n)
    print("SAMPLE OF %d ROWS" % n)
    print("   hypothesis space          | size    | empirical risk | TRUE risk | gap")
    spaces = [("thresholds", space_threshold()),
              ("intervals", space_interval()),
              ("every function", space_memorise(data))]
    for label, space in spaces:
        size = 2 ** 20 if label == "every function" else len(space)
        r_emp, name, f = erm(space, data)
        r_true = risk_true(f)
        print("   %-25s | %7d | %14.4f | %9.4f | %+.4f"
              % (label, size, r_emp, r_true, r_true - r_emp))
    print()

print("READ THE LAST TWO COLUMNS. as the space grows, the empirical risk falls")
print("and the true risk RISES. 'every function' can memorise any sample, so its")
print("empirical risk reaches 0 and it has learned nothing.")
print()
print("and read the same table down the SAMPLE SIZE: with 200 rows the gap")
print("closes, even for the interval space. more data buys back the capacity to")
print("search a larger space. that relation, between sample size, the size of")
print("the hypothesis space, and the gap between the two risks, IS statistical")
print("learning theory.")
munotes.in388

The Statistical Learning Framework

THE SETTING. hours studied 1..20; the true rule is 'pass if hours >= 8';
the recorded label is wrong 15 per cent of the time.
so the BEST POSSIBLE true error, achieved by the true rule itself, is
0.1500. that part is irreducible and no learner can remove it.

the learner sees a SAMPLE and minimises its error on that sample, which
is EMPIRICAL RISK MINIMISATION. what we care about is the error on the
world, the TRUE RISK, which the learner cannot see.

SAMPLE OF 8 ROWS
   hypothesis space          | size    | empirical risk | TRUE risk | gap
   thresholds                |      21 |         0.1250 |    0.1500 | +0.0250
   intervals                 |     231 |         0.1250 |    0.1850 | +0.0600
   every function            | 1048576 |         0.0000 |    0.5000 | +0.5000

SAMPLE OF 20 ROWS
   hypothesis space          | size    | empirical risk | TRUE risk | gap
   thresholds                |      21 |         0.0500 |    0.1500 | +0.1000
   intervals                 |     231 |         0.0500 |    0.1500 | +0.1000
   every function            | 1048576 |         0.0500 |    0.2900 | +0.2400

SAMPLE OF 200 ROWS
   hypothesis space          | size    | empirical risk | TRUE risk | gap
   thresholds                |      21 |         0.1450 |    0.1500 | +0.0050
   intervals                 |     231 |         0.1450 |    0.1500 | +0.0050
   every function            | 1048576 |         0.1450 |    0.1850 | +0.0400

READ THE LAST TWO COLUMNS. as the space grows, the empirical risk falls
and the true risk RISES. 'every function' can memorise any sample, so its
empirical risk reaches 0 and it has learned nothing.

and read the same table down the SAMPLE SIZE: with 200 rows the gap
closes, even for the interval space. more data buys back the capacity to
search a larger space. that relation, between sample size, the size of
the hypothesis space, and the gap between the two risks, IS statistical
learning theory.
munotes.in389

The Statistical Learning Framework

Reading it

Read the table across first, at eight rows.

Hypothesis spaceSizeEmpirical riskTrue riskGap
thresholds210.12500.1500+0.0250
intervals2310.12500.1850+0.0600
every function10485760.00000.5000+0.5000

The largest space scores perfectly on the sample and is a coin on the world. It can memorise any eight rows, so its empirical risk is 0.0000 by construction and it has learned nothing whatever. That single row is the argument for declaring a hypothesis space at all.

And the interval space is the interesting middle. It contains every threshold, so its empirical risk can never be worse, and at eight rows it is the same, 0.1250. Its true risk is worse, 0.1850. Adding hypotheses that were not needed made the answer worse without improving the measurable score at all.

Now read the table down, by sample size.

8 rows20 rows200 rows
thresholds+0.0250+0.1000+0.0050
intervals+0.0600+0.1000+0.0050
every function+0.5000+0.2400+0.0400

The gap closes as the sample grows, and it closes for every space, including the space of a million functions. At 200 rows the threshold and interval learners both reach a true risk of 0.1500, which is the floor, and the interval space's extra capacity costs nothing at all.

So the relation, which is the chapter's one sentence:

The gap between empirical and true risk grows with the size of the hypothesis space and shrinks with the size of the sample. How much data a given space needs is the question statistical learning theory answers.

Capacity, and the word for it

"Size of the hypothesis space" is the crude version. The refined measure is capacity, and the standard one is the VC dimension: the largest number of points that the space can label in every possible way.

SpaceVC dimensionWhy
thresholds on a line1one point can be labelled either way; two points cannot be labelled 1, 0 in that order
intervals on a line2two points, yes; three cannot be labelled 1, 0, 1
every function on n pointsnby definition
munotes.in390

The Statistical Learning Framework

Note what it is not: a count. Both of the first two spaces are finite here, 21 and 231, yet their capacities are 1 and 2. Capacity is about the patterns a space can express, and the generalisation bounds of the subject are written in terms of it.

The shape of the result, which is worth stating even without the algebra: the gap between empirical and true risk is bounded, with high probability, by a quantity that grows with the capacity and falls with the square root of the sample size. That is why the 200-row column is uniformly better and why the million-function space is the last to recover.

Inductive bias, and why it is not optional

The million-function space failed for a reason worth naming. It could fit any labelling of the sample, so the sample gave it no reason to prefer one continuation over another on the points it had not seen.

Inductive bias is the set of assumptions that let a learner prefer one hypothesis over another when both fit the data equally well. Every learner has one:

LearnerIts inductive bias
Linear regressionthe relation is a straight line
A decision tree with pruninga short tree is preferable to a long one
k-nearest neighboursnearby points have similar labels
Naive Bayesthe features are independent given the class

A learner with no inductive bias cannot generalise. This is the honest statement of the no free lunch result: averaged over all possible target functions, every learner scores the same, so there is no best learner, only learners whose bias happens to match the problem. It does not mean all learners are equally good on the problems that actually occur, and a paper that claims it does has overstated it.

Where it meets the earlier chapters

The framework re-describes three things already met, and being able to say so is worth marks.

EarlierIn this language
Underfittingthe approximation error is large: H is too small to contain the truth
Overfittingthe estimation error is large: H is big enough to fit the sample's noise
Bias and variancea small H gives high bias and low variance; a large H the reverse
Regularisationa penalty that makes part of H cheaper, which is capacity control by another route
Cross validationan estimate of the true risk built from the sample alone

And the practical rule that follows: choose the smallest hypothesis space that plausibly contains the truth, then enlarge it only when the measured cross-validation score says the approximation error, not the estimation error, is what is hurting.

munotes.in391

The Statistical Learning Framework

Distinctions

Empirical riskTrue risk
Measured onthe training samplethe whole distribution
Computableyesno, it is estimated
Minimised bythe learnerwhat we actually want
Approximation errorEstimation error
CauseH is too smallthe sample is too small
Curea larger Hmore data
Shows asunderfittingoverfitting
Size of HVC dimension of H
Thresholds here211
Intervals here2312
Measureshow many hypotheseswhich patterns

What it does not mean

Empirical risk is not performance. It is the score on the data the model was chosen with.

A zero empirical risk is not success. On this data, 0.0000 was scored by a model that is a coin on the world.

The irreducible error is not a failure of the learner. No method can go below it, and here it is 0.1500.

A larger hypothesis space is not an improvement. It lowers the approximation error and raises the estimation error, and the interval space shows it paying the second without earning the first.

VC dimension is not the number of hypotheses. A space of 231 functions here has a VC dimension of 2.

No free lunch does not mean all learners are equally good in practice. It means none is best over all possible target functions.

A learner cannot be free of assumptions. Without an inductive bias there is no reason to prefer any continuation of the data.

Quick revision

  • Five parts: the unknown distribution, the sample, the hypothesis space H, the loss, the learning rule. H and the loss are the person's choices.
  • Empirical risk is the error on the sample and is computable; true risk is the error on the distribution and is not. ERM minimises the first.
  • Error splits into irreducible (the Bayes error, here 0.1500), approximation (H too small) and estimation (sample too small).
  • Measured at 8 rows: thresholds 0.1250 / 0.1500; intervals 0.1250 / 0.1850; every function 0.0000 / 0.5000. Perfect on the sample, a coin on the world.
  • Measured by sample size, the gap falls: thresholds +0.0250, +0.1000, +0.0050; every function +0.5000, +0.2400, +0.0400.
  • The gap grows with the capacity of H and shrinks with the sample size.
  • VC dimension is capacity, not count: thresholds 1, intervals 2, all functions on n points n. Bounds grow with capacity and fall with the square root of n.
  • Inductive bias is what lets a learner choose between hypotheses that fit equally; without one it cannot generalise. No free lunch: no learner is best over all possible targets.
  • Underfitting is approximation error, overfitting is estimation error, and cross validation is an estimate of the true risk from the sample alone.
munotes.in392

The Statistical Learning Framework

Test yourself

1. Name the five components of a statistical learning problem and say which are chosen by the person. An unknown data-generating distribution, a training sample drawn independently from it, a hypothesis space declared in advance, a loss function, and a learning rule. The hypothesis space and the loss function are the person's choices, made before the data and not checkable against it.

2. Distinguish empirical risk from true risk, and say what ERM does. Empirical risk is the average loss on the training sample and can be computed. True risk is the expected loss over the whole distribution and cannot. Empirical risk minimisation returns the member of the hypothesis space with the least error on the sample, which is the only thing it can measure.

3. A model reports 0.0000 error on data whose labels are 15 per cent wrong. What has happened? It has memorised the noise. The irreducible error of that problem is 0.1500, achieved by the true rule itself, so an error of 0 on the sample can only mean the model has fitted the wrong labels as well as the right ones and will be far worse on new data.

4. In this chapter's measurement, the interval space had the same empirical risk as the threshold space and a worse true risk. Explain. The interval space contains every threshold, so its empirical risk can never be higher, and on eight rows it was identical at 0.1250. The extra hypotheses gave it more ways to fit the particular sample, so the member ERM selected was tuned to that sample's noise, and its true risk rose from 0.1500 to 0.1850. The extra capacity was paid for and nothing was bought.

5. Give the VC dimension of thresholds and of intervals on a line, and say why it is not a count of hypotheses. Thresholds have VC dimension 1 and intervals 2: one point can be labelled either way by a threshold but two points cannot be labelled positive then negative, and an interval cannot label three points positive, negative, positive. Both spaces are finite here, with 21 and 231 members, so capacity measures which patterns of labels a space can produce, not how many functions it contains.

6. State the relation between hypothesis-space capacity, sample size and the generalisation gap. The gap between empirical and true risk grows with the capacity of the hypothesis space and shrinks as the sample grows, roughly with the square root of the sample size. In the measurement, the gap at 200 rows was +0.0050 for the threshold space and +0.0400 even for the space of a million functions, where at eight rows it had been +0.0250 and +0.5000.

munotes.in393

The Statistical Learning Framework

7. What is inductive bias, and why can a learner not do without one? It is the set of assumptions that let a learner prefer one hypothesis to another when both fit the training data equally well. A space rich enough to fit any labelling gives the sample no way to decide what happens at the unseen points, so without a bias there is no basis for generalising at all. The no free lunch result puts the same thing formally: averaged over all possible target functions every learner scores alike, so a learner is only as good as the match between its bias and the problem.

Contents This chapter on its own page

munotes.in394

Chapter Sixty-Eight

Maximum Likelihood Estimation

Syllabus topic Module 2, "Maximum Likelihood Estimation"

In one line

Choose the parameter value that makes the data you actually observed as probable as possible.

In the wording a student can write in an examination: given a model with unknown parameters and some observed data, the likelihood is the probability of that data as a function of the parameters. The maximum likelihood estimate, or MLE, is the parameter value that maximises it.

Likelihood is not probability

The distinction papers ask for, and the one students state loosely.

ProbabilityLikelihood
Varies overthe data, with the parameter fixedthe parameter, with the data fixed
Sums or integrates to 1yes, over the datano
Is a distribution over the parameternono

For seven heads in ten flips the likelihood is p7 * (1-p)3. Read as a function of p it is not a probability distribution over p: it does not integrate to 1, and saying "the probability that p is 0.7" is a different claim, which needs a prior and belongs to Bayes Rule and Its Use. Maximum likelihood makes no statement about the probability of a parameter.

The recipe

Four steps, and every MLE derivation in the subject is these four.

  1. Write the probability of the observed data under the model, as a function of the parameters. That is the likelihood L.
  2. Take its logarithm, the log likelihood. The maximum is in the same place because the logarithm is increasing.
  3. Differentiate with respect to each parameter and set the derivative to zero.
  4. Solve, and check it is a maximum.

Worked for a coin. With h heads and t tails:

L(p) = ph * (1 - p)t

ln L(p) = h ln(p) + t ln(1 - p)

d/dp = h/p - t/(1 - p) = 0

=> h (1 - p) = t p

=> p = h / (h + t)

So the MLE of a coin's bias is the observed proportion of heads, which is the answer anyone would have guessed. That is the point: maximum likelihood derives the obvious estimate rather than assuming it, and the same four steps then give answers where nothing is obvious.

The computation

# Maximum likelihood estimation, computed: the likelihood of a coin searched by
# hand, why the LOG is used, the closed forms, and the bias the method carries.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(9109)
rnd = lambda: next(gen)                                   # noqa: E731

# ---- 1. the likelihood of a coin, searched ---------------------------------
HEADS, TAILS = 7, 3
n = HEADS + TAILS
print("A COIN flipped %d times: %d heads, %d tails." % (n, HEADS, TAILS))
print("the parameter is p, the probability of heads. the LIKELIHOOD of the data")
print("for a given p is p**%d * (1-p)**%d. it is a function of p, NOT of the" % (HEADS, TAILS))
print("data, and it is not a probability distribution over p.")
print()
print("      p | likelihood        | log likelihood")
for i in range(1, 10):
    p = i / 10
    lik = p ** HEADS * (1 - p) ** TAILS
    print("   %.2f | %.12f | %14.6f" % (p, lik, math.log(lik)))
print()
best = max((i / 1000 for i in range(1, 1000)),
           key=lambda p: p ** HEADS * (1 - p) ** TAILS)
print("   searched on a grid of 1/1000, the maximum is at p = %.3f" % best)
print("   and the calculus says it is exactly heads/n = %d/%d = %.4f."
      % (HEADS, n, HEADS / n))
print("   differentiate the LOG likelihood, %d*ln(p) + %d*ln(1-p), set it to"
      % (HEADS, TAILS))
print("   zero: %d/p = %d/(1-p), so p = %d/%d. THAT is the MLE."
      % (HEADS, TAILS, HEADS, n))
print()

# ---- 2. why the log, measured ----------------------------------------------
print("WHY THE LOG, and it is not only convenience. the likelihood of a long")
print("sequence is a PRODUCT of many numbers below 1:")
for k in (10, 100, 1000, 1200):
    lik = 0.5 ** k
    print("   0.5 ** %-5d = %-24s log = %12.4f" % (k, repr(lik), k * math.log(0.5)))
print("   the fourth line is ZERO in floating point: the likelihood of 1200")
print("   coin flips UNDERFLOWS and the maximisation collapses. the log is a")
print("   sum, stays in range, and has its maximum in the same place because")
print("   the logarithm is increasing.")
print()

# ---- 3. a normal distribution: the closed forms ----------------------------
DATA = [62.0, 71.0, 58.0, 79.0, 66.0, 74.0, 69.0, 61.0]
print("A NORMAL DISTRIBUTION fitted to %d marks: %s"
      % (len(DATA), " ".join("%.0f" % v for v in DATA)))
m = len(DATA)
mu = sum(DATA) / m
var_n = sum((v - mu) ** 2 for v in DATA) / m
var_n1 = sum((v - mu) ** 2 for v in DATA) / (m - 1)
print("   the MLE of the mean is the sample mean          = %.4f" % mu)
print("   the MLE of the variance divides by n            = %.4f" % var_n)
print("   the UNBIASED estimate divides by n - 1          = %.4f" % var_n1)
print("   so the MLE standard deviation is %.4f and the unbiased %.4f."
      % (var_n ** 0.5, var_n1 ** 0.5))
print()

# ---- 4. the MLE variance is BIASED, and here is the measurement ------------
print("THE MLE OF A VARIANCE IS BIASED, and the bias is not a rounding matter.")
print("draw 20000 samples of 5 from a population whose true variance is known,")
print("estimate it both ways, and average the estimates.")
TRUE_MU, TRUE_SD = 70.0, 12.0

def normal():
    """Box-Muller, from the same deterministic stream."""
    u1, u2 = rnd(), rnd()
    if u1 < 1e-12:
        u1 = 1e-12
    return TRUE_MU + TRUE_SD * math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2)

trials, size = 20000, 5
sum_n = sum_n1 = 0.0
for _ in range(trials):
    s = [normal() for _ in range(size)]
    mean = sum(s) / size
    ss = sum((v - mean) ** 2 for v in s)
    sum_n += ss / size
    sum_n1 += ss / (size - 1)
print("   true variance                                   = %.4f" % (TRUE_SD ** 2))
print("   average of the MLE estimate (divide by n)       = %.4f" % (sum_n / trials))
print("   average of the estimate that divides by n - 1   = %.4f" % (sum_n1 / trials))
print("   the MLE is about %.1f per cent too small, and 1/n against 1/(n-1) at"
      % (100 * (1 - (sum_n / trials) / TRUE_SD ** 2)))
print("   n = %d is exactly %.1f per cent. the MLE reuses the sample mean, so"
      % (size, 100 * (1 - (size - 1) / size)))
print("   the deviations it squares are measured from the wrong centre and come")
print("   out too small. MAXIMUM LIKELIHOOD IS NOT THE SAME AS UNBIASED.")
print()

# ---- 5. the zero count -----------------------------------------------------
print("THE OTHER FAILURE: A COUNT OF ZERO. five flips, no heads.")
h, t = 0, 5
print("   MLE: p = %d/%d = %.4f" % (h, h + t, h / (h + t)))
print("   the estimate says heads is IMPOSSIBLE, on five flips. and any later")
print("   sequence containing a head then has likelihood exactly 0, so the")
print("   model cannot be used at all.")
print()
print("   LAPLACE SMOOTHING adds one imagined observation of each outcome:")
print("      p = (%d + 1)/(%d + 2) = %.4f" % (h, h + t, (h + 1) / (h + t + 2)))
print("   which is small but not impossible. more generally, add k:")
for k in (1, 2, 5):
    print("      k = %d:  p = (%d + %d)/(%d + %d) = %.4f"
          % (k, h, k, h + t, 2 * k, (h + k) / (h + t + 2 * k)))
print("   the effect of k fades as the data grows, which is what it should do.")
print("   the same repair is what the naive Bayes chapter needed for an unseen")
print("   word, and it is the point at which pure maximum likelihood is given up.")
munotes.in395

Maximum Likelihood Estimation

A COIN flipped 10 times: 7 heads, 3 tails.
the parameter is p, the probability of heads. the LIKELIHOOD of the data
for a given p is p**7 * (1-p)**3. it is a function of p, NOT of the
data, and it is not a probability distribution over p.

      p | likelihood        | log likelihood
   0.10 | 0.000000072900 |     -16.434177
   0.20 | 0.000006553600 |     -11.935496
   0.30 | 0.000075014100 |      -9.497834
   0.40 | 0.000353894400 |      -7.946512
   0.50 | 0.000976562500 |      -6.931472
   0.60 | 0.001791590400 |      -6.324652
   0.70 | 0.002223566100 |      -6.108643
   0.80 | 0.001677721600 |      -6.390319
   0.90 | 0.000478296900 |      -7.645279

   searched on a grid of 1/1000, the maximum is at p = 0.700
   and the calculus says it is exactly heads/n = 7/10 = 0.7000.
   differentiate the LOG likelihood, 7*ln(p) + 3*ln(1-p), set it to
   zero: 7/p = 3/(1-p), so p = 7/10. THAT is the MLE.

WHY THE LOG, and it is not only convenience. the likelihood of a long
sequence is a PRODUCT of many numbers below 1:
   0.5 ** 10    = 0.0009765625             log =      -6.9315
   0.5 ** 100   = 7.888609052210118e-31    log =     -69.3147
   0.5 ** 1000  = 9.332636185032189e-302   log =    -693.1472
   0.5 ** 1200  = 0.0                      log =    -831.7766
   the fourth line is ZERO in floating point: the likelihood of 1200
   coin flips UNDERFLOWS and the maximisation collapses. the log is a
   sum, stays in range, and has its maximum in the same place because
   the logarithm is increasing.

A NORMAL DISTRIBUTION fitted to 8 marks: 62 71 58 79 66 74 69 61
   the MLE of the mean is the sample mean          = 67.5000
   the MLE of the variance divides by n            = 44.2500
   the UNBIASED estimate divides by n - 1          = 50.5714
   so the MLE standard deviation is 6.6521 and the unbiased 7.1114.

THE MLE OF A VARIANCE IS BIASED, and the bias is not a rounding matter.
draw 20000 samples of 5 from a population whose true variance is known,
estimate it both ways, and average the estimates.
   true variance                                   = 144.0000
   average of the MLE estimate (divide by n)       = 114.9999
   average of the estimate that divides by n - 1   = 143.7499
   the MLE is about 20.1 per cent too small, and 1/n against 1/(n-1) at
   n = 5 is exactly 20.0 per cent. the MLE reuses the sample mean, so
   the deviations it squares are measured from the wrong centre and come
   out too small. MAXIMUM LIKELIHOOD IS NOT THE SAME AS UNBIASED.

THE OTHER FAILURE: A COUNT OF ZERO. five flips, no heads.
   MLE: p = 0/5 = 0.0000
   the estimate says heads is IMPOSSIBLE, on five flips. and any later
   sequence containing a head then has likelihood exactly 0, so the
   model cannot be used at all.

   LAPLACE SMOOTHING adds one imagined observation of each outcome:
      p = (0 + 1)/(5 + 2) = 0.1429
   which is small but not impossible. more generally, add k:
      k = 1:  p = (0 + 1)/(5 + 2) = 0.1429
      k = 2:  p = (0 + 2)/(5 + 4) = 0.2222
      k = 5:  p = (0 + 5)/(5 + 10) = 0.3333
   the effect of k fades as the data grows, which is what it should do.
   the same repair is what the naive Bayes chapter needed for an unseen
   word, and it is the point at which pure maximum likelihood is given up.
munotes.in396

Maximum Likelihood Estimation

Reading it

The grid search agrees with the calculus. The likelihood column rises to 0.002223566100 at p = 0.70 and falls either side, and a search on a grid of one thousandth puts the maximum at exactly 0.700, which is 7/10. The derivation and the arithmetic meet.

munotes.in397

Maximum Likelihood Estimation

The log is not a convenience. Read the four underflow lines:

munotes.in398

Maximum Likelihood Estimation

LikelihoodLog likelihood
0.5 ** 100.0009765625-6.9315
0.5 ** 1007.888609052210118e-31-69.3147
0.5 ** 10009.332636185032189e-302-693.1472
0.5 ** 12000.0-831.7766

The likelihood of 1200 coin flips is zero in floating point. Not small: zero. Every candidate parameter would score 0, the comparison between them is destroyed, and the maximisation returns whatever came first. The log likelihood of the same data is -831.7766, an ordinary number. That is why every real implementation works in logs, and it is a good answer to "why the log likelihood" that goes beyond "sums are easier than products".

The normal distribution's MLEs are worth memorising, since a paper may simply ask for them: the MLE of the mean is the sample mean, 67.5000 here, and the MLE of the variance is the average squared deviation from it, 44.2500, dividing by n.

The first failure: maximum likelihood is biased

The estimate that divides by n is the maximum likelihood one. The estimate that divides by n - 1 is the one every statistics course teaches. They are not the same, and the difference is measured here, not asserted.

Twenty thousand samples of five, drawn from a population whose true variance is 144.0000:

Average estimate
MLE, dividing by n114.9999
dividing by n - 1143.7499

The MLE is 20.1 per cent too small, and 1 - (n-1)/n at n = 5 is exactly 20.0 per cent. The measurement lands on the theory.

The cause, which is the part worth marks. The MLE measures every deviation from the sample mean, and the sample mean is itself pulled towards the sample. So the deviations are taken from a centre that is already too close to the data, and the squares come out too small. Dividing by n - 1 compensates for the one degree of freedom spent on estimating the mean.

munotes.in399

Maximum Likelihood Estimation

So: maximum likelihood is not the same as unbiased. It is the estimate that best explains the data in hand, not the estimate that is right on average over repeated samples. And the bias vanishes as n grows, which is why nobody minds much on large data and everybody minds on small.

The second failure: a count of zero

Five flips, no heads. The MLE is 0/5 = 0.0000, which asserts that heads is impossible on the evidence of five flips. Worse, it is not merely overconfident: any later sequence containing a head has likelihood exactly 0, so the model assigns probability zero to something that just happened and cannot be used at all.

The repair is Laplace smoothing, also called add-one: pretend to have seen one of each outcome before starting.

p = (h + k) / (h + t + 2k) k = 1 is Laplace, add-one

kEstimate
0, plain MLE0.0000
10.1429
20.2222
50.3333

Note that the choice of k matters a great deal on five observations and hardly at all on five thousand, which is exactly the right behaviour: the imagined observations are outvoted by real ones.

And be honest about what has happened: adding imagined counts is no longer maximum likelihood. It is the maximum a posteriori estimate under a prior that says extreme values of p are unlikely, and the constant k is that prior's strength. Naive Bayes needed the same repair for a word never seen in a class, and this is why.

MLE, MAP and Bayesian, in one table

A paper asking how maximum likelihood relates to Bayes wants these three separated.

Maximum likelihoodMaximum a posterioriFully Bayesian
MaximisesP(data given parameter)P(data given parameter) * P(parameter)nothing; it keeps the whole distribution
Uses a priornoyesyes
Returnsone valueone valuea distribution over parameters
On 0 heads in 5p = 0p = 0.1429 with add-onea distribution with little mass near 0.5
Costcheapestcheapexpensive

MLE is MAP with a uniform prior. If every parameter value is equally likely beforehand, the prior is a constant, and maximising the product is the same as maximising the likelihood. That one line is worth stating.

The properties, honestly

What maximum likelihood is good for, and what it is not.

PropertyHolds
Consistent: converges on the true parameter as n growsyes
Asymptotically efficient: no estimator does better for large nyes
Invariant: the MLE of a function of the parameter is that function of the MLEyes
Unbiasedno, as measured above
Well behaved on small samplesno
Well behaved on zero countsno
munotes.in400

Maximum Likelihood Estimation

Distinctions

ProbabilityLikelihood
Fixedthe parameterthe data
Variesthe datathe parameter
Normalisedyesno
MLE of a varianceUnbiased estimate
Divides bynn - 1
On the eight marks44.250050.5714
Averaged over 20000 samples of 5114.9999143.7499
True value144.0000144.0000
Plain MLEWith add-one
0 heads in 50.00000.1429
Can score a head afterwardsno, likelihood 0yes
Is it still maximum likelihoodyesno, it is MAP

What it does not mean

The likelihood is not the probability of the parameter. It is the probability of the data, read as a function of the parameter.

The log is not just for convenience. Without it the likelihood of 1200 flips is 0.0 and the maximisation is destroyed.

Maximum likelihood is not unbiased. Its variance estimate ran 20.1 per cent short of a true 144.

A zero count is not a small probability. It is zero, and it makes the model unusable.

Laplace smoothing is not maximum likelihood. It is MAP under a prior, and saying so is part of a correct answer.

A larger likelihood is not a better model. Adding parameters raises the likelihood always, which is why model comparison needs a penalty for complexity and not a likelihood alone.

Quick revision

  • Likelihood is P(data given parameter) read as a function of the parameter. It is not normalised and is not a distribution over the parameter.
  • The recipe: write L, take ln L, differentiate, set to zero, solve.
  • Coin: L = ph (1-p)t, ln L = h ln p + t ln(1-p), and the MLE is h/(h+t). Measured: 7 heads in 10 peaks at p = 0.700.
  • Why the log: 0.5 1200 is 0.0** in floating point; its log likelihood is -831.7766. Logs also turn products into sums and keep the maximum in the same place.
  • Normal: MLE mean = the sample mean (67.5000); MLE variance = average squared deviation, dividing by n (44.2500), against 50.5714 for n - 1.
  • The MLE variance is biased: over 20000 samples of 5 with a true variance of 144.0000, it averaged 114.9999, 20.1 per cent short, matching 1 - (n-1)/n = 20%. Cause: the deviations are taken from the sample mean, which is pulled towards the sample.
  • Zero counts: 0 heads in 5 gives p = 0, so heads becomes impossible and any head later has likelihood 0. Laplace smoothing gives (h+k)/(h+t+2k), which is 0.1429 at k = 1, and is MAP, not MLE.
  • MLE is MAP with a uniform prior. MAP returns one value with a prior; fully Bayesian keeps the whole distribution.
  • MLE is consistent, asymptotically efficient and invariant, and is not unbiased and not reliable on small samples or zero counts.
munotes.in401

Maximum Likelihood Estimation

Test yourself

1. Distinguish likelihood from probability. Probability varies over the data with the parameter fixed and sums to one over the data. Likelihood is the same expression read as a function of the parameter with the data fixed; it does not sum or integrate to one and is not a distribution over the parameter.

2. Derive the maximum likelihood estimate of a coin's bias from h heads and t tails. The likelihood is ph * (1-p)t. Its logarithm is h ln p + t ln(1-p), whose derivative is h/p - t/(1-p). Setting that to zero gives h(1-p) = tp, so p = h/(h+t), the observed proportion of heads.

3. Give two reasons for maximising the log likelihood rather than the likelihood. Products of many probabilities underflow to zero in floating point, and 0.5 to the power 1200 is exactly 0.0 on this machine, which destroys the comparison between candidate parameters; the log of the same quantity is about -831.78 and computes normally. The log also turns the product into a sum, which differentiates term by term, and because the logarithm is increasing the maximum is in the same place.

4. State the MLEs for a normal distribution and say which one is biased. The MLE of the mean is the sample mean. The MLE of the variance is the average squared deviation from that mean, dividing by n. The variance estimate is biased low; the unbiased version divides by n - 1.

5. Explain why the MLE of a variance is too small, and quantify it at n = 5. The squared deviations are taken from the sample mean, which is itself pulled towards the sample, so they are smaller than deviations from the true mean. The estimate is short by a factor of (n-1)/n, which at n = 5 is 20 per cent. Measured over 20000 samples of five from a population with variance 144, the MLE averaged 115.0 against 143.7 for the n - 1 version.

6. Five coin flips give no heads. Give the MLE, say what is wrong with it, and repair it. The MLE is 0/5 = 0, which asserts heads is impossible on five flips, and any later sequence containing a head then has likelihood exactly zero, so the model cannot be used. Laplace smoothing adds one imagined observation of each outcome, giving (0+1)/(5+2) = 0.1429, which is small without being impossible, and the added counts are outvoted as real data accumulates.

munotes.in402

Maximum Likelihood Estimation

7. How do MLE, MAP and a fully Bayesian treatment differ? MLE maximises the probability of the data given the parameter and uses no prior. MAP maximises the product of that likelihood and a prior over the parameter, returning a single value; MLE is the special case where the prior is uniform. A fully Bayesian treatment returns no single value at all but the whole posterior distribution over the parameter, at a greater computational cost.

Contents This chapter on its own page

munotes.in403

Chapter Sixty-Nine

Learning with Complete Data

Syllabus topic Module 2, "Learning with complete data"

In one line

When the structure is known and every variable is observed in every row, learning a probability model is nothing but counting, one table row at a time.

Complete data means exactly that: each training row gives a value for every variable, with nothing missing and nothing hidden. That is the easy case, and it is easy for a reason worth understanding.

Why it reduces to counting

This is the result the chapter exists for, and a paper may ask for the argument in words.

The likelihood of the whole data set under a Bayesian network is the product, over rows and over nodes, of each node's probability given its parents. Taking the logarithm turns that into a sum:

ln L = sum over rows, sum over nodes of ln P(node's value given its parents' values)

Now notice what each term contains: one node and its parents, and no other parameter. So the sum separates into independent pieces, one for each node and each combination of that node's parents' values. Maximising the whole is therefore maximising each piece on its own, and each piece is the coin problem of Maximum Likelihood Estimation, whose answer is already known:

P(node = true given this row of parents) = (rows with both) / (rows with those parent values)

That is the whole algorithm. No search, no iteration, no gradient: one pass to count, then a division per row. And it holds only because the data is complete. Hidden Variables shows what breaks the moment one value is missing.

How the data was made, and the name for it

The program needs data from a known network, and the way to draw it is worth a sentence because it is a standard method in its own right. Ancestral sampling, also called prior sampling: take the nodes in an order where every parent comes before its children, and draw each node from its own table row, which the parents already drawn have selected. One pass per sample, no rejection, no iteration.

The measurement

# Learning the parameters of a Bayesian network from COMPLETE data: every value
# of every variable observed. The estimate is a count, one table row at a time,
# and the program checks that claim against the network of chapter 40.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(31337)
rnd = lambda: next(gen)                                   # noqa: E731

# The same four-node network as the Bayesian network chapters, with its TRUE
# parameters. The learner is not shown these; it only sees sampled rows.
TRUE = {
    "Burglary":   ([],                         {(): 0.001}),
    "Earthquake": ([],                         {(): 0.002}),
    "Alarm":      (["Burglary", "Earthquake"], {(True, True): 0.95,
                                                (True, False): 0.94,
                                                (False, True): 0.29,
                                                (False, False): 0.001}),
    "Call":       (["Alarm"],                  {(True,): 0.90, (False,): 0.05}),
}
ORDER = ["Burglary", "Earthquake", "Alarm", "Call"]

def draw(net):
    """ANCESTRAL SAMPLING: take the nodes in parent-before-child order and draw
    each from its own row, which the parents already drawn select."""
    row = {}
    for node in ORDER:
        parents, table = net[node]
        p = table[tuple(row[q] for q in parents)]
        row[node] = rnd() < p
    return row

def log_likelihood(net, data):
    total = 0.0
    for row in data:
        for node in ORDER:
            parents, table = net[node]
            p = table[tuple(row[q] for q in parents)]
            total += math.log(p if row[node] else 1 - p)
    return total

print("COMPLETE DATA means every variable is observed in every row. then the")
print("log likelihood SEPARATES: each node's term involves only that node and")
print("its parents, so maximising the whole is maximising each table row on its")
print("own, and each row's answer is a COUNT.")
print()
print("   P(node = true | that row of parents) = (rows with both) / (rows with")
print("   those parent values)")
print()
print("the network needs %d numbers; the full joint over 4 binary variables"
      % sum(2 ** len(TRUE[n][0]) for n in ORDER))
print("would need 2**4 - 1 = 15. that is why the structure is worth having.")
print()

ROWS = [("Burglary", ()), ("Earthquake", ()),
        ("Alarm", (True, True)), ("Alarm", (True, False)),
        ("Alarm", (False, True)), ("Alarm", (False, False)),
        ("Call", (True,)), ("Call", (False,))]

def label(node, key):
    parents, _ = TRUE[node]
    if not parents:
        return "P(%s)" % node
    bits = ", ".join("%s=%s" % (p, "T" if v else "F") for p, v in zip(parents, key))
    return "P(%s | %s)" % (node, bits)

def learn(data):
    """Count. Returns the learned net and the denominator of every row."""
    net, seen = {}, {}
    for node in ORDER:
        parents, table = TRUE[node]
        rows = {}
        for key in table:
            both = sum(1 for r in data
                       if tuple(r[q] for q in parents) == key and r[node])
            denom = sum(1 for r in data if tuple(r[q] for q in parents) == key)
            seen[(node, key)] = denom
            rows[key] = (both / denom) if denom else 0.5      # 0.5: nothing seen
        net[node] = (parents, rows)
    return net, seen

learned = {}
sizes = (2000, 40000, 200000)
data_by_size = {}
for n in sizes:
    data_by_size[n] = [draw(TRUE) for _ in range(n)]
    learned[n] = learn(data_by_size[n])

print("EVERY TABLE ROW, LEARNED BY COUNTING, at three sample sizes.")
print("   row                                 |   true | %s" % " | ".join("%8d" % n for n in sizes))
for node, key in ROWS:
    line = "   %-35s | %6.3f" % (label(node, key), TRUE[node][1][key])
    for n in sizes:
        net, seen = learned[n]
        d = seen[(node, key)]
        line += " | %8s" % ("no data" if d == 0 else "%.4f" % net[node][1][key])
    print(line)
print()
print("   and the DENOMINATOR of each row, which is what the accuracy depends on:")
print("   row                                 | %s" % " | ".join("%8d" % n for n in sizes))
for node, key in ROWS:
    line = "   %-35s" % label(node, key)
    for n in sizes:
        line += " | %8d" % learned[n][1][(node, key)]
    print(line)
print()
print("READ THE ALARM ROWS. P(Alarm | B=F, E=F) has almost every row of the data")
print("behind it and is exact to three places. P(Alarm | B=T, E=T) needs a")
print("burglary AND an earthquake in the same night, whose true probability is")
print("0.001 * 0.002 = 0.000002, so %d rows contain NONE and the parameter is"
      % sizes[-1])
print("simply not estimable. more data does not help evenly: it helps each row")
print("in proportion to how often that row's parent values occur.")
print()

print("THE MLE BEATS THE TRUTH ON THE SAMPLE, which is worth seeing once.")
n = sizes[1]
data = data_by_size[n]
net, _ = learned[n]
ll_true = log_likelihood(TRUE, data)
ll_learned = log_likelihood({k: (v[0], v[1]) for k, v in net.items()}, data)
print("   log likelihood of the %d sampled rows" % n)
print("      under the TRUE parameters    = %.4f" % ll_true)
print("      under the LEARNED parameters = %.4f" % ll_learned)
print("      the learned parameters are higher by %.4f" % (ll_learned - ll_true))
print("   that is not a mistake. maximum likelihood returns the parameters that")
print("   best explain THIS sample, and the truth is not that. the gap is the")
print("   overfitting of the earlier chapter, measured inside a network.")
print()

print("THE ZERO ROW, AND THE REPAIR. at %d rows, P(Alarm | B=T, E=T) saw:" % sizes[0])
d = learned[sizes[0]][1][("Alarm", (True, True))]
print("   %d observations. plain counting gives 0/0, which is undefined; a" % d)
print("   program that returns 0 instead asserts the alarm CANNOT sound during")
print("   a burglary in an earthquake, and any night where it does then has")
print("   likelihood 0 under the whole model.")
print("   LAPLACE: add one imagined observation of each value.")
for both, denom in ((0, 0), (0, 1), (1, 1), (3, 4)):
    print("      %d of %d  ->  plain %-9s  laplace (%d+1)/(%d+2) = %.4f"
          % (both, denom, "undefined" if denom == 0 else "%.4f" % (both / denom),
             both, denom, (both + 1) / (denom + 2)))
print("   a network learned from complete data is therefore counting PLUS a")
print("   smoothing rule, and the rule is not optional on rare parent rows.")
munotes.in404

Learning with Complete Data

COMPLETE DATA means every variable is observed in every row. then the
log likelihood SEPARATES: each node's term involves only that node and
its parents, so maximising the whole is maximising each table row on its
own, and each row's answer is a COUNT.

   P(node = true | that row of parents) = (rows with both) / (rows with
   those parent values)

the network needs 8 numbers; the full joint over 4 binary variables
would need 2**4 - 1 = 15. that is why the structure is worth having.

EVERY TABLE ROW, LEARNED BY COUNTING, at three sample sizes.
   row                                 |   true |     2000 |    40000 |   200000
   P(Burglary)                         |  0.001 |   0.0010 |   0.0012 |   0.0010
   P(Earthquake)                       |  0.002 |   0.0010 |   0.0026 |   0.0019
   P(Alarm | Burglary=T, Earthquake=T) |  0.950 |  no data |  no data |  no data
   P(Alarm | Burglary=T, Earthquake=F) |  0.940 |   1.0000 |   0.9792 |   0.9219
   P(Alarm | Burglary=F, Earthquake=T) |  0.290 |   1.0000 |   0.2788 |   0.2691
   P(Alarm | Burglary=F, Earthquake=F) |  0.001 |   0.0005 |   0.0012 |   0.0008
   P(Call | Alarm=T)                   |  0.900 |   0.8000 |   0.8689 |   0.8916
   P(Call | Alarm=F)                   |  0.050 |   0.0516 |   0.0502 |   0.0502

   and the DENOMINATOR of each row, which is what the accuracy depends on:
   row                                 |     2000 |    40000 |   200000
   P(Burglary)                         |     2000 |    40000 |   200000
   P(Earthquake)                       |     2000 |    40000 |   200000
   P(Alarm | Burglary=T, Earthquake=T) |        0 |        0 |        0
   P(Alarm | Burglary=T, Earthquake=F) |        2 |       48 |      192
   P(Alarm | Burglary=F, Earthquake=T) |        2 |      104 |      379
   P(Alarm | Burglary=F, Earthquake=F) |     1996 |    39848 |   199429
   P(Call | Alarm=T)                   |        5 |      122 |      443
   P(Call | Alarm=F)                   |     1995 |    39878 |   199557

READ THE ALARM ROWS. P(Alarm | B=F, E=F) has almost every row of the data
behind it and is exact to three places. P(Alarm | B=T, E=T) needs a
burglary AND an earthquake in the same night, whose true probability is
0.001 * 0.002 = 0.000002, so 200000 rows contain NONE and the parameter is
simply not estimable. more data does not help evenly: it helps each row
in proportion to how often that row's parent values occur.

THE MLE BEATS THE TRUTH ON THE SAMPLE, which is worth seeing once.
   log likelihood of the 40000 sampled rows
      under the TRUE parameters    = -9507.9267
      under the LEARNED parameters = -9501.9179
      the learned parameters are higher by 6.0088
   that is not a mistake. maximum likelihood returns the parameters that
   best explain THIS sample, and the truth is not that. the gap is the
   overfitting of the earlier chapter, measured inside a network.

THE ZERO ROW, AND THE REPAIR. at 2000 rows, P(Alarm | B=T, E=T) saw:
   0 observations. plain counting gives 0/0, which is undefined; a
   program that returns 0 instead asserts the alarm CANNOT sound during
   a burglary in an earthquake, and any night where it does then has
   likelihood 0 under the whole model.
   LAPLACE: add one imagined observation of each value.
      0 of 0  ->  plain undefined  laplace (0+1)/(0+2) = 0.5000
      0 of 1  ->  plain 0.0000     laplace (0+1)/(1+2) = 0.3333
      1 of 1  ->  plain 1.0000     laplace (1+1)/(1+2) = 0.6667
      3 of 4  ->  plain 0.7500     laplace (3+1)/(4+2) = 0.6667
   a network learned from complete data is therefore counting PLUS a
   smoothing rule, and the rule is not optional on rare parent rows.
munotes.in405

Learning with Complete Data

Reading the two tables

Eight numbers describe this network, against 15 for the full joint distribution over the same four variables. Bayesian Networks argued that; here it is the count of things that have to be learned.

munotes.in406

Learning with Complete Data

The estimates converge, but not at the same speed, and the second table says why. Set the two side by side for the four alarm rows:

munotes.in407

Learning with Complete Data

RowTrueAt 200,000 rowsObservations behind it
Alarm, no burglary, no earthquake0.0010.0008199,429
Alarm, no burglary, earthquake0.2900.2691379
Alarm, burglary, no earthquake0.9400.9219192
Alarm, burglary and earthquake0.950no data0

The last row cannot be estimated from two hundred thousand nights. It needs a burglary and an earthquake on the same night, and the true probability of that is 0.001 * 0.002 = 0.000002, about one night in five hundred thousand. More data does not help a network evenly. It helps each table row in proportion to how often that row's parent values occur, so the rarest rows stay unlearned however large the sample.

Two consequences worth stating in an answer.

A node with many parents is expensive. Its table has 2 to the power of the number of parents rows, and each row needs its own observations, so the data required grows exponentially in the number of parents. That is a practical argument for the sparse graphs Bayesian Networks prized, quite separate from the argument about storage.

Small denominators give wild estimates. At 2,000 rows, two of the alarm rows had two observations each and both returned 1.0000 against true values of 0.940 and 0.290. The estimate 2/2 is the honest maximum likelihood answer and it is useless, which is the next section.

The learned parameters beat the truth

On forty thousand rows:

Log likelihood of the data
Under the true parameters-9507.9267
Under the learned parameters-9501.9179
Difference+6.0088

The learned parameters explain the sample better than the parameters that generated it. That is not an error, and it is not a sign of a good fit either. Maximum likelihood returns whatever best explains this sample, and the sample is not the world: its counts are a little off the true proportions, and the estimate follows them exactly.

munotes.in408

Learning with Complete Data

This is Overfitting and Underfitting seen inside a network, and it gives a clean general statement: the training likelihood of a maximum likelihood fit is always at least the training likelihood of the truth, so a high likelihood on the training data is never evidence that the parameters are right.

The zero row, and the repair

Plain counting on a row with no observations is 0/0, undefined. A program that quietly returns 0 instead makes a much worse claim: that the alarm cannot sound during a burglary in an earthquake. Then any night on which it does has probability zero under the whole model, and the network is unusable, exactly as in Maximum Likelihood Estimation.

Laplace smoothing repairs it, by adding one imagined observation of each value to every row:

ObservationsPlain countWith add-one
0 of 0undefined0.5000
0 of 10.00000.3333
1 of 11.00000.6667
3 of 40.75000.6667

Read the first line: with nothing observed the smoothed estimate is 0.5000, the honest statement that nothing is known. And read the last: with four observations the smoothing still moves the estimate a long way, which is the right behaviour on four observations and would be the wrong behaviour on four thousand, where it barely moves it at all.

So the practical algorithm is counting plus a smoothing rule, and on a network with rare parent combinations the rule is not optional.

What this chapter does not do

Two things are deliberately outside it, and a paper may ask a student to say so.

The structure was given. Which node is a parent of which was fixed in advance, by someone who understood the domain. Learning the structure from data is a much harder problem: the number of possible graphs grows faster than exponentially in the number of nodes, and adding an edge can never lower the training likelihood, so the search needs a penalty for complexity. It is a real subject and it is not this one.

Every value was observed. That is the assumption that made the sum separate. Hidden Variables removes it.

Distinctions

Complete dataIncomplete data
Every variable observedyesno
The log likelihoodseparates into one term per table rowdoes not separate
The estimatea count, in one passneeds iteration
Solved bycountingthe EM algorithm
Learning parametersLearning structure
Giventhe graphnothing but the variables
Search spacenonemore than exponential in the nodes
Training likelihoodis maximised by countingrises with every edge added
Needs a complexity penaltynoyes
A common parent rowA rare parent row
Hereno burglary, no earthquakeburglary and earthquake
Observations in 200,000199,4290
Estimate0.0008 against a true 0.001none
munotes.in409

Learning with Complete Data

What it does not mean

Counting is not a heuristic here. It is the exact maximum likelihood estimate, because the log likelihood separates.

More data does not fix every row. It fixes each row in proportion to how often that row's parent values occur.

A high training likelihood is not evidence of correct parameters. The learned ones beat the truth by 6.0088 on the sample that produced them.

An estimate of 1.0000 from two observations is not a certainty. It is maximum likelihood with a denominator of two.

A count of zero is not a probability of zero. It is the absence of evidence, and treating it as zero destroys the model.

Learning the parameters is not learning the network. The graph was given.

Quick revision

  • Complete data: every variable observed in every row. Then ln L separates into one term per node and per parent configuration, so each table row is estimated on its own.
  • The estimate: P(node = true given a parent row) = (rows with both) / (rows with those parent values). One counting pass, no search.
  • Ancestral sampling draws data from a known network: parents before children, one pass per row.
  • Measured: 8 parameters against 15 for the full joint. Estimates converge, but each row at its own rate, set by its denominator.
  • P(Alarm given burglary and earthquake) had 0 observations in 200,000 rows, since its parent values co-occur with probability 0.000002. Not estimable.
  • A node with k parents has 2k rows, so the data needed grows exponentially in the number of parents**. Another reason for sparse graphs.
  • The learned parameters scored -9501.9179 against the truth's -9507.9267 on the same 40,000 rows: the MLE beats the truth on its own sample, so training likelihood is never evidence of correctness.
  • Laplace smoothing: add one of each value. 0 of 0 becomes 0.5000, 1 of 1 becomes 0.6667, and the effect fades as real counts grow.
  • Out of scope here: structure learning, which searches a super-exponential space and needs a complexity penalty, and missing values, which break the separation.

Test yourself

1. Why does learning a Bayesian network from complete data reduce to counting? The likelihood is a product over rows and nodes of each node's probability given its parents, so the log likelihood is a sum in which every term mentions only one node and its parents. The sum therefore separates into independent pieces, one per node and per combination of parent values, and each piece is the coin problem whose maximum likelihood answer is the observed proportion.

2. Write the estimate for one table row. The number of rows in which the node is true and its parents have the given values, divided by the number of rows in which its parents have those values.

munotes.in410

Learning with Complete Data

3. What is ancestral sampling? Drawing a row from a known network by taking the nodes in an order that puts every parent before its children and sampling each node from the table row its already-drawn parents select. One pass gives one complete sample.

4. In the measurement, one parameter could not be estimated from 200,000 rows. Which, and why? The probability of the alarm given both a burglary and an earthquake. The two parents are independent with probabilities 0.001 and 0.002, so they co-occur about once in five hundred thousand rows, and 200,000 rows contained none. Data helps each table row only in proportion to how often that row's parent values occur.

5. Why is a node with many parents expensive to learn? Its table has two to the power of the number of parents rows, and each row needs its own observations to be estimated, so the amount of data required grows exponentially in the number of parents. This is an argument for sparse graphs independent of the argument about storage.

6. The learned parameters gave a higher log likelihood on the training data than the true parameters. Explain, and give the consequence. Maximum likelihood returns the parameters that best explain the particular sample, and the sample's counts differ slightly from the true proportions, so the estimate follows the sample rather than the truth. It follows that a high training likelihood can never be evidence that the parameters are correct, since the fitted parameters beat the truth on that data by construction.

7. A table row has no observations. Give the plain estimate, what is wrong with it, and the repair. Plain counting gives zero over zero, which is undefined, and a program that returns 0 instead asserts the event is impossible, so any row exhibiting it has likelihood zero and the whole model becomes unusable. Laplace smoothing adds one imagined observation of each value, which turns nothing observed into 0.5, the honest statement that nothing is known, and its influence fades as real observations accumulate.

Contents This chapter on its own page

munotes.in411

Chapter Seventy

Hidden Variables

Syllabus topic Module 2, "Hidden variables"

In one line

A hidden variable is one the model needs and the data does not record, and its absence destroys the counting that made the previous chapter easy.

A hidden variable, also called a latent variable, appears in the model but never in the data. Common cases across this syllabus: which cluster a point belongs to, which coin or which component produced an observation, the state of a system in Hidden Markov Models, the underlying cause behind a set of symptoms.

Why anyone would want one

A hidden variable is not a nuisance forced on the modeller. It is often the whole reason the model is small enough to learn, and a paper may ask why.

Take three lifestyle causes and three symptoms, all binary, where each symptom depends on all three causes.

Without a hidden node, each symptom's table has one row per combination of its three parents:

3 causes, one number each = 3

3 symptoms, 2**3 = 8 rows each = 24

total = 27 numbers

With one hidden node between them, standing for the underlying condition, the causes point at the hidden node and each symptom depends only on it:

3 causes, one number each = 3

the hidden node, 2**3 = 8 rows = 8

3 symptoms, one parent, 2 rows each = 6

total = 17 numbers

Twenty-seven numbers become seventeen, and the saving grows sharply with the number of symptoms: each further symptom costs 8 numbers in the first model and 2 in the second. And the second model says something the first does not, that the symptoms are conditionally independent given the condition, which is a claim about the world and may be false. A hidden variable buys a smaller model at the price of an assumption.

The measurement

# Hidden variables: what breaks when one column of the data is missing. The same
# twelve experiments are solved by counting when the coin is known, and are not
# solvable by counting at all when it is hidden.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(20260930)
rnd = lambda: next(gen)                                   # noqa: E731

P_A, P_B, MIX = 0.80, 0.30, 0.5      # the truth, which the learner never sees
FLIPS, RUNS = 10, 12

records = []                          # (which coin, heads) -- 'which' is HIDDEN
for _ in range(RUNS):
    coin = "A" if rnd() < MIX else "B"
    p = P_A if coin == "A" else P_B
    heads = sum(1 for _ in range(FLIPS) if rnd() < p)
    records.append((coin, heads))

print("TWELVE EXPERIMENTS. each one: pick one of two coins, flip it %d times," % FLIPS)
print("record the number of heads. the COIN USED is the hidden variable.")
print()
print("   what was actually recorded:")
print("      heads out of %d : %s" % (FLIPS, " ".join("%2d" % h for _, h in records)))
print("   and what was NOT recorded, shown here only to prove the point:")
print("      coin used       : %s" % " ".join(" %s" % c for c, _ in records))
print()

# ---- 1. with the hidden column, it is counting ------------------------------
print("IF THE COIN WERE KNOWN the data would be COMPLETE and the answer is a")
print("count, exactly as in the previous chapter:")
for label in ("A", "B"):
    h = sum(x for c, x in records if c == label)
    n = FLIPS * sum(1 for c, _ in records if c == label)
    print("   coin %s: %d heads in %d flips  ->  p = %.4f   (true %.2f)"
          % (label, h, n, h / n, P_A if label == "A" else P_B))
print("   and the mixing weight is just how often each coin was chosen:")
print("      P(coin A) = %d/%d = %.4f   (true %.2f)"
      % (sum(1 for c, _ in records if c == "A"), RUNS,
         sum(1 for c, _ in records if c == "A") / RUNS, MIX))
print()

# ---- 2. without it, there is nothing to count ------------------------------
print("WITHOUT IT, THERE IS NOTHING TO COUNT. to count the heads of coin A you")
print("must know which experiments used coin A, and that is the column you do")
print("not have. the two unknowns are locked together:")
print("   to estimate the parameters you need the coin assignments,")
print("   to infer the coin assignments you need the parameters.")
print()

# ---- 3. the naive repair, and how badly it does ---------------------------
pooled = sum(h for _, h in records) / (FLIPS * RUNS)
print("THE NAIVE REPAIR: ignore the hidden variable and pool every flip.")
print("   %d heads in %d flips  ->  one coin with p = %.4f"
      % (sum(h for _, h in records), FLIPS * RUNS, pooled))
print("   which is neither %.2f nor %.2f. it is their average, and it describes"
      % (P_A, P_B))
print("   NO coin in the experiment. worse, it is a measurably poorer")
print("   explanation of the same data:")

def loglik_one(p, heads):
    return (heads * math.log(p) + (FLIPS - heads) * math.log(1 - p))

def loglik_single(p):
    return sum(loglik_one(p, h) for _, h in records)

def loglik_mixture(pa, pb, w):
    """The likelihood SUMS over the hidden variable, one sum per experiment."""
    total = 0.0
    for _, h in records:
        inner = w * math.exp(loglik_one(pa, h)) + (1 - w) * math.exp(loglik_one(pb, h))
        total += math.log(inner)
    return total

print("      one coin at p = %.4f            log likelihood %.4f"
      % (pooled, loglik_single(pooled)))
print("      the true mixture %.2f / %.2f       log likelihood %.4f"
      % (P_A, P_B, loglik_mixture(P_A, P_B, MIX)))
print("   the mixture explains the data far better, and the single coin cannot")
print("   be rescued by choosing p differently: %.4f is already its best value."
      % pooled)
print()

# ---- 4. why there is no closed form ---------------------------------------
print("WHY NO FORMULA EXISTS. with the coin known, the log likelihood is a sum")
print("of logs, and each parameter appears in its own term, so differentiating")
print("gives one equation per parameter. with the coin hidden, each experiment")
print("contributes")
print("      log( w * P(heads | A) + (1-w) * P(heads | B) )")
print("a LOG OF A SUM. the parameters no longer separate, the derivative of one")
print("involves all of them, and there is no closed-form solution. in a general")
print("network the inner sum runs over every configuration of the hidden")
print("variables, so it is exponential in their number as well.")
print()

# ---- 5. the surface, searched --------------------------------------------
print("SO SEARCH IT. the log likelihood over a grid of (p for A, p for B), with")
print("the mixing weight held at %.1f:" % MIX)
print("   p_B \\ p_A " + "".join("%8.1f" % (i / 10) for i in range(1, 10)))
for j in range(1, 10):
    pb = j / 10
    row = "   %8.1f  " % pb
    for i in range(1, 10):
        row += "%8.1f" % loglik_mixture(i / 10, pb, MIX)
    print(row)
best = None
for i in range(1, 100):
    for j in range(1, 100):
        v = loglik_mixture(i / 100, j / 100, MIX)
        if best is None or v > best[0]:
            best = (v, i / 100, j / 100)
print()
print("   searched on a grid of 1/100, the best is p_A = %.2f, p_B = %.2f at"
      % (best[1], best[2]))
print("   log likelihood %.4f." % best[0])
print()
print("   READ THE SURFACE. it has TWO maxima, mirror images in the diagonal,")
print("   because calling the coins A and B the other way round describes the")
print("   same world: 'LABEL SWITCHING'. and along the diagonal, where the two")
print("   coins are equal, the surface is flat in the direction that would")
print("   separate them. a grid search of this kind costs 9801 evaluations for")
print("   two parameters and is hopeless for a real model, which is why the")
print("   next chapter derives an iteration instead.")
munotes.in412

Hidden Variables

TWELVE EXPERIMENTS. each one: pick one of two coins, flip it 10 times,
record the number of heads. the COIN USED is the hidden variable.

   what was actually recorded:
      heads out of 10 :  9  8  9  9  9  4  8  3  7  6  1  2
   and what was NOT recorded, shown here only to prove the point:
      coin used       :  A  A  A  A  A  B  A  B  A  A  B  B

IF THE COIN WERE KNOWN the data would be COMPLETE and the answer is a
count, exactly as in the previous chapter:
   coin A: 65 heads in 80 flips  ->  p = 0.8125   (true 0.80)
   coin B: 10 heads in 40 flips  ->  p = 0.2500   (true 0.30)
   and the mixing weight is just how often each coin was chosen:
      P(coin A) = 8/12 = 0.6667   (true 0.50)

WITHOUT IT, THERE IS NOTHING TO COUNT. to count the heads of coin A you
must know which experiments used coin A, and that is the column you do
not have. the two unknowns are locked together:
   to estimate the parameters you need the coin assignments,
   to infer the coin assignments you need the parameters.

THE NAIVE REPAIR: ignore the hidden variable and pool every flip.
   75 heads in 120 flips  ->  one coin with p = 0.6250
   which is neither 0.80 nor 0.30. it is their average, and it describes
   NO coin in the experiment. worse, it is a measurably poorer
   explanation of the same data:
      one coin at p = 0.6250            log likelihood -79.3876
      the true mixture 0.80 / 0.30       log likelihood -69.2691
   the mixture explains the data far better, and the single coin cannot
   be rescued by choosing p differently: 0.6250 is already its best value.

WHY NO FORMULA EXISTS. with the coin known, the log likelihood is a sum
of logs, and each parameter appears in its own term, so differentiating
gives one equation per parameter. with the coin hidden, each experiment
contributes
      log( w * P(heads | A) + (1-w) * P(heads | B) )
a LOG OF A SUM. the parameters no longer separate, the derivative of one
involves all of them, and there is no closed-form solution. in a general
network the inner sum runs over every configuration of the hidden
variables, so it is exponential in their number as well.

SO SEARCH IT. the log likelihood over a grid of (p for A, p for B), with
the mixing weight held at 0.5:
   p_B \ p_A      0.1     0.2     0.3     0.4     0.5     0.6     0.7     0.8     0.9
        0.1    -177.4  -137.3  -112.4   -96.4   -85.6   -78.4   -74.1   -72.7   -75.9
        0.2    -137.3  -130.7  -111.3   -95.7   -84.7   -77.0   -71.9   -69.6   -72.1
        0.3    -112.4  -111.3  -106.3   -95.1   -84.8   -77.1   -71.9   -69.3   -70.8
        0.4     -96.4   -95.7   -95.1   -91.7   -84.9   -78.2   -73.1   -70.3   -71.1
        0.5     -85.6   -84.7   -84.8   -84.9   -83.2   -79.4   -75.3   -72.6   -72.8
        0.6     -78.4   -77.0   -77.1   -78.2   -79.4   -79.5   -78.1   -76.2   -76.2
        0.7     -74.1   -71.9   -71.9   -73.1   -75.3   -78.1   -80.9   -81.7   -82.0
        0.8     -72.7   -69.6   -69.3   -70.3   -72.6   -76.2   -81.7   -89.2   -92.5
        0.9     -75.9   -72.1   -70.8   -71.1   -72.8   -76.2   -82.0   -92.5  -111.5

   searched on a grid of 1/100, the best is p_A = 0.28, p_B = 0.82 at
   log likelihood -69.1228.

   READ THE SURFACE. it has TWO maxima, mirror images in the diagonal,
   because calling the coins A and B the other way round describes the
   same world: 'LABEL SWITCHING'. and along the diagonal, where the two
   coins are equal, the surface is flat in the direction that would
   separate them. a grid search of this kind costs 9801 evaluations for
   two parameters and is hopeless for a real model, which is why the
   next chapter derives an iteration instead.
munotes.in413

Hidden Variables

With the column, it is counting

Shown once so the contrast is exact. Given the hidden column, Learning With Complete Data applies unchanged:

munotes.in414

Hidden Variables

CountedEstimateTrue
coin A65 heads in 80 flips0.81250.80
coin B10 heads in 40 flips0.25000.30
mixing weight8 of 12 experiments0.66670.50
munotes.in415

Hidden Variables

Note that even with the labels the estimates are not the true values, because twelve experiments are twelve experiments. That is ordinary sampling error and it is not the subject of this chapter.

Without it, three separate things break

A paper asking what goes wrong wants these three distinguished, not one vague answer.

1. There is nothing to count. To count the heads of coin A you must know which experiments used coin A. The estimate needs the assignments and the assignments need the estimate:

parameters <- need the coin assignments

assignments <- need the parameters

That circularity is the shape of the whole problem, and The EM Algorithm is the observation that a circle can be walked round.

2. The log likelihood no longer separates. With the coin known, each experiment contributes a sum of logs and each parameter sits in its own term, so differentiating gives one independent equation per parameter. With the coin hidden, each experiment contributes

log( w P(heads given A) + (1 - w) P(heads given B) )

a log of a sum. The parameters are tangled inside one logarithm, the derivative with respect to one of them involves all of them, and there is no closed-form solution. That is the technical heart of the chapter.

3. In a general model the sum itself is exponential. Here the inner sum has two terms because one coin is hidden. In a network with k hidden variables the sum runs over every configuration of them, so it has 2**k terms before any maximisation begins.

The naive repair, and how badly it does

The obvious move is to ignore the hidden variable and pool everything. Measured:

Log likelihood of the same 12 experiments
One coin at its best value, p = 0.6250-79.3876
The true mixture, 0.80 and 0.30-69.2691
munotes.in416

Hidden Variables

The pooled estimate is 0.6250, which is neither coin and describes no coin in the experiment. And it is not merely inelegant: it explains the data ten log units worse, which is a factor of about twenty two thousand in probability. Nor can it be rescued by choosing p differently, since 0.6250 is already the best single-coin value; the failure is in the model, not the fit.

This is the general danger of ignoring a latent structure: averaging two populations produces a description of neither, and the result can look perfectly reasonable while being wrong about every individual.

The surface, and the two things it shows

Since no formula exists, the program searches. Read the printed grid.

It has two maxima. The best point on a grid of one hundredth is p_A = 0.28, p_B = 0.82 at -69.1228, and the mirror point 0.82, 0.28 scores identically. Calling the coins the other way round describes the same world, so the likelihood must be symmetric, and every mixture model has as many equivalent optima as there are ways to permute its components. The name is label switching, and it means the parameters of a mixture are only identifiable up to a relabelling.

And the diagonal is a trap. Where p_A = p_B the two coins are the same coin, and because the surface is symmetric about that diagonal, the slope in the direction that would separate them is exactly zero there. So a search started with the two coins equal has no reason to move them apart and never will. That single geometric fact is why the next chapter's algorithm must not be initialised symmetrically, and a paper asking why EM can fail completely is answered by it.

Note also the cost. Nine thousand eight hundred and one evaluations bought two parameters to two decimal places. A model with twenty parameters cannot be searched this way at all, which is the practical reason an iteration is needed and not merely an elegant one.

Distinctions

Complete dataHidden variable
The log likelihood isa sum of logsa log of a sum
Parametersseparateare tangled
Solutionclosed form, a countnone
Cost per extra hidden variablenot applicabledoubles the inner sum
Pooling the dataModelling the mixture
Parametersone, 0.6250two, plus a weight
Describesno coin presentboth
Log likelihood-79.3876-69.2691
Missing at randomHidden by design
Examplea student left a field blankwhich coin was used
Sometimes observedyesnever
Could be filled from other rowssometimesno

What it does not mean

A hidden variable is not missing data. Missing data is sometimes observed and sometimes not; a hidden variable is never observed in any row.

munotes.in417

Hidden Variables

A hidden variable is not a defect of the model. It can cut 27 parameters to 17 here, and the saving grows with the number of observed children.

It is not free, either. It asserts that the children are conditionally independent given it, which may be false.

Pooling is not a conservative approximation. It returns a value describing neither component and loses about ten log units here.

There is no closed-form maximum likelihood estimate. Not a hard one: none, because the parameters sit inside a logarithm of a sum.

The maximum is not unique. Every permutation of the components gives an equal maximum, which is label switching.

A search started with equal components does not converge slowly. It does not converge at all, because the surface has no slope in the separating direction along the diagonal.

Quick revision

  • A hidden or latent variable is in the model and never in the data: a cluster label, a mixture component, an HMM state, an underlying cause.
  • It shrinks the model: three causes and three symptoms need 27 numbers directly and 17 through one hidden node, and each further symptom costs 8 against 2. The price is an assumed conditional independence.
  • Three things break: nothing to count (parameters need assignments, assignments need parameters); the log likelihood becomes a log of a sum, so no closed form exists; and in a general model the inner sum has 2**k terms for k hidden variables.
  • Measured: pooling gives one coin at 0.6250, which is neither of 0.80 and 0.30, at a log likelihood of -79.3876 against the mixture's -69.2691.
  • The searched surface has two maxima, mirror images in the diagonal: label switching, so mixture parameters are identifiable only up to relabelling. Best on a grid of 1/100: 0.28, 0.82 at -69.1228.
  • On the diagonal, where the components are equal, the slope that would separate them is zero, so a symmetric start never moves. Never initialise EM symmetrically.
  • The grid cost 9801 evaluations for two parameters, which is why an iteration is needed rather than a search.

Test yourself

1. Define a hidden variable and give three examples from this syllabus. One that the model contains but the data never records. Which cluster a point belongs to in k-means; which component of a mixture produced an observation; the underlying state of the system in a hidden Markov model.

2. Show with a count why a hidden variable can make a model smaller, and state the price. Three binary causes and three binary symptoms, each symptom depending on all three causes, need 3 numbers for the causes and 8 for each symptom's table, 27 in all. Inserting one hidden node between them gives 3 for the causes, 8 for the hidden node and 2 for each symptom, 17 in all, and each further symptom then costs 2 instead of 8. The price is the assumption that the symptoms are conditionally independent given the hidden node, which may be false.

munotes.in418

Hidden Variables

3. Explain precisely why maximum likelihood has no closed form when a variable is hidden. With complete data each experiment contributes a sum of logarithms in which each parameter appears in its own term, so setting the derivatives to zero gives one independent equation per parameter. With a hidden variable each experiment contributes the logarithm of a sum over that variable's values, so all the parameters sit inside one logarithm, the derivative with respect to any one of them involves all the others, and the equations cannot be solved separately.

4. What is the circularity at the heart of the problem? Estimating the parameters requires knowing which component produced each observation, and inferring which component produced each observation requires the parameters.

5. A data set is a mixture of two coins at 0.80 and 0.30. What happens if the mixture is ignored and all flips pooled? The estimate is the overall proportion of heads, 0.6250 here, which describes neither coin. It is also a measurably worse explanation of the data: log likelihood -79.3876 against -69.2691 for the true mixture, and it cannot be improved by choosing a different single value, because 0.6250 is already the best one.

6. What is label switching, and what does it imply about a mixture's parameters? The likelihood is unchanged by permuting the names of the components, so every optimum has a mirror image with the labels exchanged. The parameters of a mixture are therefore identifiable only up to a relabelling, and two fits that look different may be the same model.

7. Why must an iterative search for mixture parameters not be started with the components equal? Because the likelihood surface is symmetric about the line where the components are equal, its slope in the direction that would separate them is exactly zero on that line. A search started there has no reason to move the components apart and will never separate them, so the failure is total rather than slow.

Contents This chapter on its own page

munotes.in419

Chapter Seventy-One

The EM Algorithm

Syllabus topic Module 2, "EM Algorithm"

In one line

Guess the parameters, use them to work out how probable each hidden value is, count with those probabilities as weights, and repeat until nothing changes.

In the wording a student can write in an examination: the expectation maximisation algorithm, or EM, finds maximum likelihood estimates when some variables are hidden. It alternates an E step, which computes the posterior distribution over the hidden variables given the current parameters, and an M step, which re-estimates the parameters by the ordinary complete-data method using those posteriors as fractional counts.

Why it exists

Hidden Variables left a circle:

the parameters <- need the hidden assignments

the assignments <- need the parameters

EM is the observation that a circle can be walked round. Neither side is known, so start anywhere on one side and go round, and the remarkable fact, proved below by running it, is that every lap improves the fit.

The two steps

Both steps in the form to reproduce in an answer.

E step. For each observation and each value of the hidden variable, compute the posterior probability of that value given the observation and the current parameters. This is Bayes rule:

responsibility of component A for an observation

= w P(observation given A) / ( w P(observation given A) + (1-w) * P(observation given B) )

It is not a guess at the hidden value. It is a distribution over it, and the whole method depends on keeping the distribution rather than choosing from it. The posteriors are called the responsibilities.

M step. Do exactly the counting of Learning With Complete Data, except that each observation contributes to every component, weighted by that component's responsibility:

p for A = (sum of responsibility heads) / (sum of responsibility flips)

w = the average responsibility

Fractional counts. That is the one idea to carry away. An observation is not assigned to a component; it is divided between them.

The run

# Expectation maximisation on the two-coin mixture of the previous chapter: the
# responsibilities of the first E step in full, the whole iteration, the proof
# that the log likelihood never falls, and the two ways it goes wrong.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(20260930)
rnd = lambda: next(gen)                                   # noqa: E731

P_A, P_B, MIX = 0.80, 0.30, 0.5      # the truth, which EM never sees
FLIPS, RUNS = 10, 12
records = []
for _ in range(RUNS):
    coin = "A" if rnd() < MIX else "B"
    p = P_A if coin == "A" else P_B
    heads = sum(1 for _ in range(FLIPS) if rnd() < p)
    records.append((coin, heads))
OBSERVED = [h for _, h in records]     # all EM is given

def p_heads(p, h):
    return p ** h * (1 - p) ** (FLIPS - h)

def loglik(pa, pb, w):
    return sum(math.log(w * p_heads(pa, h) + (1 - w) * p_heads(pb, h))
               for h in OBSERVED)

def e_step(pa, pb, w):
    """RESPONSIBILITIES: for each experiment, the posterior probability that
    coin A produced it. This is Bayes rule, with the current parameters."""
    out = []
    for h in OBSERVED:
        a = w * p_heads(pa, h)
        b = (1 - w) * p_heads(pb, h)
        out.append(a / (a + b))
    return out

def m_step(resp):
    """The counting of the complete-data chapter, with FRACTIONAL counts."""
    heads_a = sum(r * h for r, h in zip(resp, OBSERVED))
    flips_a = sum(r * FLIPS for r in resp)
    heads_b = sum((1 - r) * h for r, h in zip(resp, OBSERVED))
    flips_b = sum((1 - r) * FLIPS for r in resp)
    return heads_a / flips_a, heads_b / flips_b, sum(resp) / len(resp)

print("EM is given ONLY the head counts: %s" % " ".join("%d" % h for h in OBSERVED))
print("the coin used in each experiment is hidden. EM never sees it.")
print()
print("THE IDEA. if the coins were known the answer would be a count; if the")
print("parameters were known the coins could be inferred by Bayes rule. so:")
print("   E step: with the current parameters, compute for each experiment the")
print("           PROBABILITY that each coin produced it. that is not a guess at")
print("           the hidden value; it is a distribution over it.")
print("   M step: do the counting of the complete-data case, but weight each")
print("           experiment by those probabilities. FRACTIONAL COUNTS.")
print("repeat. the log likelihood cannot fall, which is proved below by running.")
print()

pa, pb, w = 0.60, 0.50, 0.5
print("START at p_A = %.2f, p_B = %.2f, w = %.2f, chosen deliberately UNEQUAL."
      % (pa, pb, w))
print()
print("THE FIRST E STEP IN FULL. responsibility of coin A for each experiment:")
resp = e_step(pa, pb, w)
print("   heads | P(heads | A)  | P(heads | B)  | responsibility of A")
for h, r in zip(OBSERVED, resp):
    print("   %5d | %13.10f | %13.10f | %18.4f"
          % (h, p_heads(pa, h), p_heads(pb, h), r))
print()
middling = min(resp, key=lambda r: abs(r - 0.5))
print("   nine heads is far more likely under the coin currently believed to be")
print("   the heavier one, so it is assigned to A with high probability; two")
print("   heads goes the other way. NOTHING IS ROUNDED: the experiment at %.4f"
      % middling)
print("   counts %.2f towards coin A and %.2f towards coin B, both at once."
      % (middling, 1 - middling))
print()
print("THE FIRST M STEP. the fractional counts:")
heads_a = sum(r * h for r, h in zip(resp, OBSERVED))
flips_a = sum(r * FLIPS for r in resp)
print("   coin A: %.4f heads out of %.4f flips  ->  p_A = %.4f"
      % (heads_a, flips_a, heads_a / flips_a))
heads_b = sum((1 - r) * h for r, h in zip(resp, OBSERVED))
flips_b = sum((1 - r) * FLIPS for r in resp)
print("   coin B: %.4f heads out of %.4f flips  ->  p_B = %.4f"
      % (heads_b, flips_b, heads_b / flips_b))
print("   w = the average responsibility = %.4f" % (sum(resp) / len(resp)))
print()

print("THE WHOLE ITERATION.")
print("   iter |    p_A |    p_B |      w | log likelihood | change")
print("   %4d | %6.4f | %6.4f | %6.4f | %14.6f |" % (0, pa, pb, w, loglik(pa, pb, w)))
prev = loglik(pa, pb, w)
for it in range(1, 21):
    pa, pb, w = m_step(e_step(pa, pb, w))
    ll = loglik(pa, pb, w)
    print("   %4d | %6.4f | %6.4f | %6.4f | %14.6f | %+.6f"
          % (it, pa, pb, w, ll, ll - prev))
    prev_at_19, prev = prev, ll
print()
print("   the CHANGE column is POSITIVE at every round until it reaches zero.")
print("   that is the theorem: each round of EM increases the log likelihood or")
print("   leaves it unchanged, so the iteration converges. it says nothing about")
print("   converging to the BEST maximum, only to a stationary point.")
print("   the last row's %+.6f is floating-point rounding at a fixed point that"
      % (ll - prev_at_19))
print("   has already been reached; the two values differ by %.2e, which is the"
      % abs(ll - prev_at_19))
print("   last few bits of a double and not a decrease.")
print()
print("   the grid search of the previous chapter found %.4f as the best value"
      % -69.1228)
print("   on a grid of 1/100, holding the mixing weight at 0.5. EM reached %.4f"
      % loglik(pa, pb, w))
print("   in %d rounds without any search, and it fits the weight too, which is"
      % 20)
print("   where most of the difference between the two numbers comes from.")
print("   true parameters were %.2f and %.2f with w = %.2f; EM recovered %.4f"
      % (P_A, P_B, MIX, pa))
print("   and %.4f with w = %.4f from twelve experiments." % (pb, w))
print()

print("FAILURE ONE: A SYMMETRIC START. set both coins to the same value.")
pa, pb, w = 0.50, 0.50, 0.5
print("   iter |    p_A |    p_B |      w | log likelihood")
for it in range(0, 6):
    print("   %4d | %6.4f | %6.4f | %6.4f | %14.6f" % (it, pa, pb, w, loglik(pa, pb, w)))
    pa, pb, w = m_step(e_step(pa, pb, w))
print("   it never moves. with the coins equal every responsibility is exactly")
print("   0.5, so both fractional counts are the same and the M step returns the")
print("   pooled estimate for both coins, for ever. EM IS STUCK AT A SADDLE.")
print()

print("FAILURE TWO: THE LABELS COME OUT THE OTHER WAY. start with B the heavier.")
pa, pb, w = 0.50, 0.60, 0.5
for _ in range(60):
    pa, pb, w = m_step(e_step(pa, pb, w))
print("   converged to p_A = %.4f, p_B = %.4f, w = %.4f" % (pa, pb, w))
print("   log likelihood %.6f, which is the SAME as before." % loglik(pa, pb, w))
print("   the two coins have simply exchanged names. nothing is wrong with the")
print("   fit; the names of mixture components are not recoverable from data.")
print()

print("WHAT DIFFERENT STARTS CONVERGE TO, run out to 200 rounds each:")
print("   start p_A, p_B | final p_A | final p_B | final w | log likelihood")
for start in ((0.60, 0.50), (0.50, 0.60), (0.99, 0.01), (0.01, 0.99),
              (0.70, 0.65), (0.50, 0.50)):
    pa, pb, w = start[0], start[1], 0.5
    for _ in range(200):
        pa, pb, w = m_step(e_step(pa, pb, w))
    print("   %6.2f, %6.2f  | %9.4f | %9.4f | %7.4f | %14.6f"
          % (start[0], start[1], pa, pb, w, loglik(pa, pb, w)))
print("   every unequal start reaches the same log likelihood, at one of the two")
print("   relabellings. the equal start reaches a worse value and stays there.")
print("   in practice EM is run from several random starts and the best kept.")
munotes.in420

The EM Algorithm

EM is given ONLY the head counts: 9 8 9 9 9 4 8 3 7 6 1 2
the coin used in each experiment is hidden. EM never sees it.

THE IDEA. if the coins were known the answer would be a count; if the
parameters were known the coins could be inferred by Bayes rule. so:
   E step: with the current parameters, compute for each experiment the
           PROBABILITY that each coin produced it. that is not a guess at
           the hidden value; it is a distribution over it.
   M step: do the counting of the complete-data case, but weight each
           experiment by those probabilities. FRACTIONAL COUNTS.
repeat. the log likelihood cannot fall, which is proved below by running.

START at p_A = 0.60, p_B = 0.50, w = 0.50, chosen deliberately UNEQUAL.

THE FIRST E STEP IN FULL. responsibility of coin A for each experiment:
   heads | P(heads | A)  | P(heads | B)  | responsibility of A
       9 |  0.0040310784 |  0.0009765625 |             0.8050
       8 |  0.0026873856 |  0.0009765625 |             0.7335
       9 |  0.0040310784 |  0.0009765625 |             0.8050
       9 |  0.0040310784 |  0.0009765625 |             0.8050
       9 |  0.0040310784 |  0.0009765625 |             0.8050
       4 |  0.0005308416 |  0.0009765625 |             0.3522
       8 |  0.0026873856 |  0.0009765625 |             0.7335
       3 |  0.0003538944 |  0.0009765625 |             0.2660
       7 |  0.0017915904 |  0.0009765625 |             0.6472
       6 |  0.0011943936 |  0.0009765625 |             0.5502
       1 |  0.0001572864 |  0.0009765625 |             0.1387
       2 |  0.0002359296 |  0.0009765625 |             0.1946

   nine heads is far more likely under the coin currently believed to be
   the heavier one, so it is assigned to A with high probability; two
   heads goes the other way. NOTHING IS ROUNDED: the experiment at 0.5502
   counts 0.55 towards coin A and 0.45 towards coin B, both at once.

THE FIRST M STEP. the fractional counts:
   coin A: 51.2810 heads out of 68.3571 flips  ->  p_A = 0.7502
   coin B: 23.7190 heads out of 51.6429 flips  ->  p_B = 0.4593
   w = the average responsibility = 0.5696

THE WHOLE ITERATION.
   iter |    p_A |    p_B |      w | log likelihood | change
      0 | 0.6000 | 0.5000 | 0.5000 |     -79.362332 |
      1 | 0.7502 | 0.4593 | 0.5696 |     -72.405673 | +6.956659
      2 | 0.8212 | 0.3260 | 0.6038 |     -68.901852 | +3.503821
      3 | 0.8215 | 0.2836 | 0.6347 |     -68.617504 | +0.284349
      4 | 0.8166 | 0.2687 | 0.6503 |     -68.567150 | +0.050353
      5 | 0.8144 | 0.2630 | 0.6565 |     -68.559498 | +0.007652
      6 | 0.8136 | 0.2610 | 0.6587 |     -68.558535 | +0.000963
      7 | 0.8133 | 0.2603 | 0.6594 |     -68.558422 | +0.000113
      8 | 0.8132 | 0.2601 | 0.6597 |     -68.558409 | +0.000013
      9 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000001
     10 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     11 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     12 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     13 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     14 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     15 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     16 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     17 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     18 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     19 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | +0.000000
     20 | 0.8132 | 0.2600 | 0.6598 |     -68.558408 | -0.000000

   the CHANGE column is POSITIVE at every round until it reaches zero.
   that is the theorem: each round of EM increases the log likelihood or
   leaves it unchanged, so the iteration converges. it says nothing about
   converging to the BEST maximum, only to a stationary point.
   the last row's -0.000000 is floating-point rounding at a fixed point that
   has already been reached; the two values differ by 1.42e-14, which is the
   last few bits of a double and not a decrease.

   the grid search of the previous chapter found -69.1228 as the best value
   on a grid of 1/100, holding the mixing weight at 0.5. EM reached -68.5584
   in 20 rounds without any search, and it fits the weight too, which is
   where most of the difference between the two numbers comes from.
   true parameters were 0.80 and 0.30 with w = 0.50; EM recovered 0.8132
   and 0.2600 with w = 0.6598 from twelve experiments.

FAILURE ONE: A SYMMETRIC START. set both coins to the same value.
   iter |    p_A |    p_B |      w | log likelihood
      0 | 0.5000 | 0.5000 | 0.5000 |     -83.177662
      1 | 0.6250 | 0.6250 | 0.5000 |     -79.387589
      2 | 0.6250 | 0.6250 | 0.5000 |     -79.387589
      3 | 0.6250 | 0.6250 | 0.5000 |     -79.387589
      4 | 0.6250 | 0.6250 | 0.5000 |     -79.387589
      5 | 0.6250 | 0.6250 | 0.5000 |     -79.387589
   it never moves. with the coins equal every responsibility is exactly
   0.5, so both fractional counts are the same and the M step returns the
   pooled estimate for both coins, for ever. EM IS STUCK AT A SADDLE.

FAILURE TWO: THE LABELS COME OUT THE OTHER WAY. start with B the heavier.
   converged to p_A = 0.2600, p_B = 0.8132, w = 0.3402
   log likelihood -68.558408, which is the SAME as before.
   the two coins have simply exchanged names. nothing is wrong with the
   fit; the names of mixture components are not recoverable from data.

WHAT DIFFERENT STARTS CONVERGE TO, run out to 200 rounds each:
   start p_A, p_B | final p_A | final p_B | final w | log likelihood
     0.60,   0.50  |    0.8132 |    0.2600 |  0.6598 |     -68.558408
     0.50,   0.60  |    0.2600 |    0.8132 |  0.3402 |     -68.558408
     0.99,   0.01  |    0.8132 |    0.2600 |  0.6598 |     -68.558408
     0.01,   0.99  |    0.2600 |    0.8132 |  0.3402 |     -68.558408
     0.70,   0.65  |    0.8132 |    0.2600 |  0.6598 |     -68.558408
     0.50,   0.50  |    0.6250 |    0.6250 |  0.5000 |     -79.387589
   every unequal start reaches the same log likelihood, at one of the two
   relabellings. the equal start reaches a worse value and stays there.
   in practice EM is run from several random starts and the best kept.
munotes.in421

The EM Algorithm

The first E step, read

Twelve experiments, with the parameters at the deliberately poor start p_A = 0.60, p_B = 0.50.

munotes.in422

The EM Algorithm

HeadsResponsibility of A
90.8050
80.7335
70.6472
60.5502
40.3522
30.2660
20.1946
10.1387
munotes.in423

The EM Algorithm

The ordering is the point: the more heads, the more the heavier coin is held responsible, and the numbers in between are genuinely in between. The six-head experiment sits at 0.5502 and contributes 0.55 of itself to coin A and 0.45 to coin B, at the same time. Nothing is rounded to a label, and rounding it would be a different and worse algorithm.

munotes.in424

The EM Algorithm

The first M step, read

Fractional countEstimate
coin A51.2810 heads out of 68.3571 flipsp_A = 0.7502
coin B23.7190 heads out of 51.6429 flipsp_B = 0.4593
weightaverage responsibilityw = 0.5696
munotes.in425

The EM Algorithm

68.3571 flips. No such number of flips was performed. The fractional counts are what the complete-data counting becomes when membership is a probability, and they are the reason the M step is as easy as counting: the M step of EM is the previous chapter's formula with weights.

And notice that one round has already moved p_A from 0.60 to 0.7502 and p_B from 0.50 to 0.4593. The coins are separating on their own, from a start that barely distinguished them.

The monotonicity, which is the theorem

Read the change column:

RoundLog likelihoodChange
0-79.362332
1-72.405673+6.956659
2-68.901852+3.503821
3-68.617504+0.284349
5-68.559498+0.007652
9-68.558408+0.000001

Every change is positive. That is the theorem, and it is the reason EM is used: each round increases the log likelihood or leaves it unchanged, so the sequence of likelihoods is increasing and bounded, and therefore converges.

The argument in one sentence, for a paper that asks why: the E step builds a lower bound on the log likelihood that touches it at the current parameters, and the M step maximises that bound, so the new likelihood is at least the bound's value, which is at least the old likelihood. The inequality behind it is Jensen's.

The theorem promises no more than that. It says the likelihood does not fall. It does not say EM reaches the largest maximum, nor that it converges quickly, nor that the answer is unique.

And the convergence has a characteristic shape: +6.96, then +3.50, then +0.28, then +0.05. Almost all the progress is in the first two or three rounds and the rest is polish. In practice EM is stopped when the change falls below a threshold, not after a fixed number of rounds.

The last row prints -0.000000, a difference of 1.42e-14. That is floating-point rounding at a fixed point already reached, the last few bits of a double, and not a decrease. It is left in the output because an implementation that tests change > 0 to decide whether to continue will behave oddly at convergence, and a student who has never seen it will misread it as a bug in the theorem.

What it recovered

TrueEM, from 12 experiments
p_A0.800.8132
p_B0.300.2600
w0.500.6598

Close on the coins, poor on the weight, from twelve experiments in which coin A happened to be chosen eight times. EM is maximum likelihood, so it inherits everything from Maximum Likelihood Estimation: it is not unbiased, it is unreliable on small samples, and it will fit the sample in preference to the truth.

munotes.in426

The EM Algorithm

Failure one: the symmetric start

Set both coins to the same value and EM never moves.

Roundp_Ap_BLog likelihood
00.50000.5000-83.177662
10.62500.6250-79.387589
2 to 50.62500.6250-79.387589

The mechanism is exact and worth stating: with the two components identical, every responsibility is exactly 0.5, so both fractional counts are the same, so the M step returns the same pooled estimate for both. The state reproduces itself for ever. Hidden Variables predicted this from the shape of the surface: on the diagonal there is no slope in the direction that would separate the components, and EM is sitting on a saddle.

Note that the likelihood did rise once, from -83.18 to -79.39, so the theorem is not violated. It converged, to the single-coin answer 0.6250, which is the pooled estimate the previous chapter measured as ten log units worse than the truth.

Failure two: the labels come out the other way

Started with B as the heavier coin, EM converges to p_A = 0.2600, p_B = 0.8132, w = 0.3402, at a log likelihood of -68.558408, identical to the first run. The coins have exchanged names.

Nothing is wrong with the fit. This is the label switching of the previous chapter: the names of mixture components are not recoverable from data, and any program that compares two EM runs parameter by parameter will report a difference that does not exist.

What different starts reach

StartFinal p_AFinal p_BLog likelihood
0.60, 0.500.81320.2600-68.558408
0.50, 0.600.26000.8132-68.558408
0.99, 0.010.81320.2600-68.558408
0.70, 0.650.81320.2600-68.558408
0.50, 0.500.62500.6250-79.387589

Every unequal start reaches the same likelihood, at one of the two relabellings. The equal start reaches a worse value and stays there. Hence the standard practice, which a paper may ask for: run EM from several random starting points and keep the fit with the highest likelihood.

Where EM appears

The same two steps, under other names, and being able to place them is worth marks.

ApplicationThe hidden variableThe name there
Mixture of Gaussianswhich component produced a pointsoft clustering
Clustering and k-meanswhich cluster a point belongs tohard EM: the responsibility is forced to 0 or 1
Hidden Markov Modelsthe state at each time stepBaum-Welch, using forward-backward as its E step
Filling in missing valuesthe missing entriesimputation by EM
munotes.in427

The EM Algorithm

k-means is EM with the E step rounded. That one sentence connects two chapters of this module and is the cleanest way to remember either.

Distinctions

E stepM step
Computesthe posterior over the hidden variablethe parameters
UsesBayes ruleweighted counting
Holds fixedthe parametersthe responsibilities
EMGradient ascent on the likelihood
Step sizenone to choosemust be chosen
Guarantees the likelihood risesyes, every roundonly for a small enough step
Parameters stay valid probabilitiesyes, automaticallymust be constrained
Converges to the global maximumnono
Soft assignment, EMHard assignment, k-means
A point belongs toevery component, with a weightexactly one
Counts arefractionalwhole
A point at 0.5502splits 0.55 and 0.45goes entirely to one

What it does not mean

The E step does not guess the hidden value. It computes a distribution over it, and keeping the distribution is the method.

The M step is not a new estimator. It is the complete-data count with fractional weights.

EM does not find the global maximum. It converges to a stationary point, which may be a worse maximum or even a saddle.

A converged EM run is not a unique answer. Its mirror image with the labels exchanged fits identically.

A symmetric start does not converge slowly. It cannot move at all.

A tiny negative change is not a violation of the theorem. At the fixed point here it is 1.42e-14, which is floating-point rounding.

EM is not an alternative to maximum likelihood. It is a way of computing it, and it inherits all of maximum likelihood's weaknesses.

Quick revision

  • EM finds maximum likelihood estimates with hidden variables, by alternating two steps until the likelihood stops changing.
  • E step: by Bayes rule, the posterior probability of each hidden value given the observation and the current parameters. These are the responsibilities, a distribution, not a choice.
  • M step: the complete-data count, with each observation weighted by its responsibilities. Fractional counts: measured here as 51.2810 heads out of 68.3571 flips.
  • The log likelihood never falls. Measured: +6.956659, +3.503821, +0.284349, +0.050353, +0.007652. The E step builds a lower bound touching the likelihood; the M step maximises it; Jensen's inequality is behind it.
  • Almost all the gain is in the first two or three rounds, so stop on the size of the change, not a fixed count.
  • Recovered 0.8132 and 0.2600 against a true 0.80 and 0.30, with w = 0.6598 against 0.50, from twelve experiments.
  • A symmetric start is stuck: equal components give every responsibility exactly 0.5, so the M step returns the pooled value 0.6250 for both, for ever. A saddle.
  • Label switching: the mirror fit scores identically, -68.558408 either way. Components are not identifiable by name.
  • Practice: several random restarts, keep the highest likelihood.
  • EM is behind Gaussian mixtures, Baum-Welch for HMMs, and imputation, and k-means is EM with the responsibilities forced to 0 or 1.
munotes.in428

The EM Algorithm

Test yourself

1. State the two steps of EM. The E step computes, for each observation, the posterior distribution over the hidden variable given the observation and the current parameters, by Bayes rule. The M step re-estimates the parameters by the ordinary complete-data method, counting each observation towards every value of the hidden variable in proportion to that posterior.

2. What is a responsibility, and why must it not be rounded? The posterior probability that a particular component produced a particular observation. Rounding it to the most likely component throws away the information that the observation is ambiguous, which is precisely what lets the components separate gradually; keeping the distribution is what makes the method work, and the rounded version is a different algorithm, k-means.

3. What is meant by a fractional count? The M step's denominators and numerators are sums of weights rather than whole observations, so a coin can be credited with 51.2810 heads out of 68.3571 flips even though no such number of flips took place. Each observation contributes part of itself to every component.

4. State the convergence property of EM and the property it does not have. Each round leaves the log likelihood the same or increases it, so the sequence is increasing and bounded and therefore converges. It does not follow that the limit is the global maximum: EM converges to a stationary point, which may be a poorer local maximum or a saddle.

5. Sketch why the likelihood cannot fall. The E step constructs a function of the parameters that lies below the log likelihood everywhere and touches it at the current parameters, by Jensen's inequality. The M step moves to the maximum of that lower bound, so the bound's value does not fall, and the log likelihood at the new parameters is at least the bound's value there.

6. EM is started with both components identical. What happens, and why? It never separates them. With identical components every responsibility is exactly one half, so both weighted counts are identical and the M step returns the same pooled estimate for both components, reproducing the state for ever. The likelihood surface is symmetric about that line and has no slope in the separating direction, so the point is a saddle.

7. Two EM runs on the same data return different parameters and the same log likelihood. Explain. They have found the same fit with the components' names exchanged. The likelihood is invariant under permuting the components, so each optimum has a mirror image, and mixture parameters are identifiable only up to relabelling. Comparing runs parameter by parameter will report a difference that is not there; comparing likelihoods will not.

Contents This chapter on its own page

munotes.in429

Chapter Seventy-Two

Hidden Markov Models

Syllabus topic Module 2, "Hidden Markov Models"

In one line

A hidden Markov model is a chain of hidden states, each depending only on the one before it, with one visible observation emitted from each state.

Everything so far in this module has treated the training rows as independent. The Statistical Learning Framework said so explicitly. A hidden Markov model is the first model in the syllabus for data that arrives in order, where each row depends on the one before it.

The example used throughout

The hidden state is whether a student revised that evening. The observation is whether they answered the next morning's one-question quiz correctly. The state is never recorded; the quiz mark always is.

Two properties make it a good example and they are both realistic. Study habits are sticky, so tomorrow resembles today, which is what the transition matrix will say. And a quiz is noisy evidence: a student who revised can still get it wrong, and a student who did not can still guess right.

The three parts

A paper asking "define a hidden Markov model" wants these three and the two assumptions below.

Written
1The initial distributionthe probability of each state on the first step
2The transition matrixP(next state given current state)
3The emission matrixP(observation given state)

And the count of numbers, which is the argument for the model:

N states, M observations: (N - 1) + N(N - 1) + N(M - 1)

Note what is not there: any number that depends on the length of the sequence, and any number indexed by a history. A model that let each day depend on all previous days would need a table indexed by every possible past, which is why the assumptions below are not a simplification of convenience but the thing that makes the model finite.

The two assumptions

Both must be stated, and the second is the one students forget.

1. The Markov assumption. The next state depends only on the current state, not on any earlier one. This is what "Markov" means, and it is what the word first-order refers to.

2. Output independence. The observation on a step depends only on that step's state, not on earlier states or earlier observations.

The model, sampled and checked

# A hidden Markov model, built and checked: the three parts, the Markov property
# verified by counting, and the cost of answering the evaluation question by
# brute force. The hidden state is whether a student revised that evening; the
# observation is whether the next morning's one-question quiz was answered.
from itertools import product
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(555035)
rnd = lambda: next(gen)                                   # noqa: E731

STATES = ["revised", "did not"]
OBS = ["correct", "wrong"]
# 1. the initial distribution
INIT = [0.5, 0.5]
# 2. the transition matrix: habits are STICKY, so 0.9 to stay
TRANS = [[0.9, 0.1],
         [0.1, 0.9]]
# 3. the emission matrix: P(observation | state)
EMIT = [[0.9, 0.1],      # revised  -> correct 0.9
        [0.2, 0.8]]      # did not  -> correct 0.2

print("THE THREE PARTS OF A HIDDEN MARKOV MODEL")
print("   states (HIDDEN)      : %s" % ", ".join(STATES))
print("   observations (SEEN)  : %s" % ", ".join(OBS))
print()
print("   1. the initial distribution over states")
for i, s in enumerate(STATES):
    print("         P(day 1 = %-8s) = %.2f" % (s, INIT[i]))
print("   2. the transition matrix, P(tomorrow | today)")
print("         today \\ tomorrow    revised    did not")
for i, s in enumerate(STATES):
    print("         %-18s %s" % (s, "  ".join("%9.2f" % v for v in TRANS[i])))
print("   3. the emission matrix, P(observation | state)")
print("         state \\ observed    correct      wrong")
for i, s in enumerate(STATES):
    print("         %-18s %s" % (s, "  ".join("%9.2f" % v for v in EMIT[i])))
print()
print("   the numbers needed: %d for the initial state, %d for the transitions,"
      % (len(STATES) - 1, len(STATES) * (len(STATES) - 1)))
print("   %d for the emissions. a model over %d states and %d observations needs"
      % (len(STATES) * (len(OBS) - 1), len(STATES), len(OBS)))
print("   N-1 + N(N-1) + N(M-1) numbers, and NOT one per possible history.")
print()

print("THE TWO ASSUMPTIONS, which are what the word 'Markov' is doing here.")
print("   1. the MARKOV assumption: tomorrow's state depends only on today's,")
print("      not on any earlier day.")
print("   2. the OUTPUT INDEPENDENCE assumption: what is observed on a day")
print("      depends only on that day's state.")
print()

def step(state):
    return 0 if rnd() < TRANS[state][0] else 1

def emit(state):
    return 0 if rnd() < EMIT[state][0] else 1

print("A SAMPLED FORTNIGHT. the first row is the truth and is NOT available to")
print("any algorithm; the second row is the whole of the data.")
s = 0 if rnd() < INIT[0] else 1
states, obs = [], []
for day in range(14):
    if day:
        s = step(s)
    states.append(s)
    obs.append(emit(s))
print("   day        : %s" % " ".join("%2d" % (d + 1) for d in range(14)))
print("   state      : %s" % " ".join(" %s" % ("R" if v == 0 else "N") for v in states))
print("   observed   : %s" % " ".join(" %s" % ("C" if v == 0 else "W") for v in obs))
print("   R = revised, N = did not, C = correct, W = wrong")
print()

print("THE MARKOV ASSUMPTION, CHECKED BY COUNTING. draw 400000 days and ask")
print("whether YESTERDAY adds anything once TODAY is known.")
long_states = []
s = 0 if rnd() < INIT[0] else 1
for _ in range(400000):
    long_states.append(s)
    s = step(s)

def frac(cond):
    hits = [long_states[i + 1] for i in range(1, len(long_states) - 1) if cond(i)]
    return (sum(1 for v in hits if v == 0) / len(hits), len(hits))

p, n = frac(lambda i: long_states[i] == 0)
print("   P(tomorrow revised | today revised)                      = %.4f  (%d cases)" % (p, n))
p, n = frac(lambda i: long_states[i] == 0 and long_states[i - 1] == 0)
print("   P(tomorrow revised | today revised, yesterday revised)   = %.4f  (%d cases)" % (p, n))
p, n = frac(lambda i: long_states[i] == 0 and long_states[i - 1] == 1)
print("   P(tomorrow revised | today revised, yesterday did not)   = %.4f  (%d cases)" % (p, n))
print("   all three are the model's 0.90. knowing yesterday changes NOTHING once")
print("   today is known, which is the assumption stated as a measurement.")
print()

print("THE STATIONARY DISTRIBUTION, by repeated multiplication.")
d = [1.0, 0.0]
MILESTONES = (1, 2, 5, 10, 50, 200)
for day in range(1, max(MILESTONES) + 1):
    d = [sum(d[i] * TRANS[i][j] for i in range(2)) for j in range(2)]
    if day in MILESTONES:
        print("   after %3d day%s from a certain start: %.6f revised, %.6f did not"
              % (day, " " if day == 1 else "s", d[0], d[1]))
print("   it settles at 0.5 / 0.5, which for this matrix is the long-run share")
print("   of revising days whatever the first day was.")
print()

print("THE THREE QUESTIONS AN HMM IS ASKED")
print("   1. EVALUATION: how probable is this observation sequence? (forward)")
print("   2. DECODING:   which state sequence most likely produced it? (Viterbi)")
print("   3. LEARNING:   what are the three matrices, given only observations?")
print("                  (Baum-Welch, which is EM with forward-backward inside)")
print()

SEQ = [0, 0, 0, 1]        # correct, correct, correct, wrong
print("EVALUATION BY BRUTE FORCE, on %s:" % ", ".join(OBS[o] for o in SEQ))
print("   every possible state path is enumerated and its probability added.")

def path_prob(path, seq):
    p = INIT[path[0]] * EMIT[path[0]][seq[0]]
    for t in range(1, len(seq)):
        p *= TRANS[path[t - 1]][path[t]] * EMIT[path[t]][seq[t]]
    return p

total, best = 0.0, None
print("   path  | probability")
for path in product((0, 1), repeat=len(SEQ)):
    p = path_prob(path, SEQ)
    total += p
    if best is None or p > best[0]:
        best = (p, path)
    print("   %-5s | %.8f" % ("".join("R" if v == 0 else "N" for v in path), p))
print("   %-5s | %.8f  <- the total, P(observations)" % ("SUM", total))
print()
print("   the most likely single path is %s at %.8f, which is only %.1f per cent"
      % ("".join("R" if v == 0 else "N" for v in best[1]), best[0],
         100 * best[0] / total))
print("   of the total. THE MOST LIKELY PATH IS NOT THE ANSWER TO 'how probable")
print("   is this sequence'. the two questions have different answers and need")
print("   different algorithms.")
print()
print("AND THE COST. enumerating paths is N**T for N states and T days:")
for t in (4, 10, 20, 40, 100):
    print("   T = %3d : %d paths" % (t, 2 ** t))
print("   at %d days a modern machine would not finish. the next chapter does" % 100)
print("   the same sum in T * N**2 arithmetic operations, which at T = 100 is")
print("   %d, by never enumerating a path at all." % (100 * 4))
munotes.in430

Hidden Markov Models

THE THREE PARTS OF A HIDDEN MARKOV MODEL
   states (HIDDEN)      : revised, did not
   observations (SEEN)  : correct, wrong

   1. the initial distribution over states
         P(day 1 = revised ) = 0.50
         P(day 1 = did not ) = 0.50
   2. the transition matrix, P(tomorrow | today)
         today \ tomorrow    revised    did not
         revised                 0.90       0.10
         did not                 0.10       0.90
   3. the emission matrix, P(observation | state)
         state \ observed    correct      wrong
         revised                 0.90       0.10
         did not                 0.20       0.80

   the numbers needed: 1 for the initial state, 2 for the transitions,
   2 for the emissions. a model over 2 states and 2 observations needs
   N-1 + N(N-1) + N(M-1) numbers, and NOT one per possible history.

THE TWO ASSUMPTIONS, which are what the word 'Markov' is doing here.
   1. the MARKOV assumption: tomorrow's state depends only on today's,
      not on any earlier day.
   2. the OUTPUT INDEPENDENCE assumption: what is observed on a day
      depends only on that day's state.

A SAMPLED FORTNIGHT. the first row is the truth and is NOT available to
any algorithm; the second row is the whole of the data.
   day        :  1  2  3  4  5  6  7  8  9 10 11 12 13 14
   state      :  R  R  R  N  N  N  N  N  N  R  N  R  R  R
   observed   :  C  C  C  W  W  W  W  W  C  W  W  C  C  C
   R = revised, N = did not, C = correct, W = wrong

THE MARKOV ASSUMPTION, CHECKED BY COUNTING. draw 400000 days and ask
whether YESTERDAY adds anything once TODAY is known.
   P(tomorrow revised | today revised)                      = 0.8999  (200461 cases)
   P(tomorrow revised | today revised, yesterday revised)   = 0.8997  (180389 cases)
   P(tomorrow revised | today revised, yesterday did not)   = 0.9018  (20072 cases)
   all three are the model's 0.90. knowing yesterday changes NOTHING once
   today is known, which is the assumption stated as a measurement.

THE STATIONARY DISTRIBUTION, by repeated multiplication.
   after   1 day  from a certain start: 0.900000 revised, 0.100000 did not
   after   2 days from a certain start: 0.820000 revised, 0.180000 did not
   after   5 days from a certain start: 0.663840 revised, 0.336160 did not
   after  10 days from a certain start: 0.553687 revised, 0.446313 did not
   after  50 days from a certain start: 0.500007 revised, 0.499993 did not
   after 200 days from a certain start: 0.500000 revised, 0.500000 did not
   it settles at 0.5 / 0.5, which for this matrix is the long-run share
   of revising days whatever the first day was.

THE THREE QUESTIONS AN HMM IS ASKED
   1. EVALUATION: how probable is this observation sequence? (forward)
   2. DECODING:   which state sequence most likely produced it? (Viterbi)
   3. LEARNING:   what are the three matrices, given only observations?
                  (Baum-Welch, which is EM with forward-backward inside)

EVALUATION BY BRUTE FORCE, on correct, correct, correct, wrong:
   every possible state path is enumerated and its probability added.
   path  | probability
   RRRR  | 0.02657205
   RRRN  | 0.02361960
   RRNR  | 0.00007290
   RRNN  | 0.00524880
   RNRR  | 0.00007290
   RNRN  | 0.00006480
   RNNR  | 0.00001620
   RNNN  | 0.00116640
   NRRR  | 0.00065610
   NRRN  | 0.00058320
   NRNR  | 0.00000180
   NRNN  | 0.00012960
   NNRR  | 0.00014580
   NNRN  | 0.00012960
   NNNR  | 0.00003240
   NNNN  | 0.00233280
   SUM   | 0.06084495  <- the total, P(observations)

   the most likely single path is RRRR at 0.02657205, which is only 43.7 per cent
   of the total. THE MOST LIKELY PATH IS NOT THE ANSWER TO 'how probable
   is this sequence'. the two questions have different answers and need
   different algorithms.

AND THE COST. enumerating paths is N**T for N states and T days:
   T =   4 : 16 paths
   T =  10 : 1024 paths
   T =  20 : 1048576 paths
   T =  40 : 1099511627776 paths
   T = 100 : 1267650600228229401496703205376 paths
   at 100 days a modern machine would not finish. the next chapter does
   the same sum in T * N**2 arithmetic operations, which at T = 100 is
   400, by never enumerating a path at all.
munotes.in431

Hidden Markov Models

The sampled fortnight

Read the two rows against each other.

munotes.in432

Hidden Markov Models

state : R R R N N N N N N R N R R R

observed : C C C W W W W W C W W C C C

munotes.in433

Hidden Markov Models

Days 9 and 10 are the whole difficulty of the subject in two columns. On day 9 the student did not revise and answered correctly, which the emission matrix allows one time in five. On day 10 the student did revise and answered wrongly, which it allows one time in ten. The observation is evidence, not the state. Any algorithm reading only the second row will be wrong about those two days, and no better algorithm exists, because the information is not in the data.

munotes.in434

Hidden Markov Models

Note also the runs. The states come in blocks, because a sticky transition matrix produces blocks, and that is exactly the structure an algorithm can exploit: a single odd observation surrounded by a run is more likely to be emission noise than a one-day change of habit.

The Markov assumption, counted

The assumption is usually stated and then believed. Here it is measured, over 400,000 days:

EstimateCases
next revised, given today revised0.8999200,461
next revised, given today revised and yesterday revised0.8997180,389
next revised, given today revised and yesterday did not0.901820,072

All three are the model's 0.90. Conditioning on yesterday changes nothing once today is known, which is the Markov property as an arithmetic fact rather than an assertion. It holds here because the data was generated by such a model; on real data it is an assumption about the world and can be checked in exactly this way, by seeing whether the extra conditioning moves the number.

The stationary distribution

Start certain that day one was a revising day, and push the distribution forward:

AfterRevisedDid not
1 day0.9000000.100000
2 days0.8200000.180000
5 days0.6638400.336160
10 days0.5536870.446313
50 days0.5000070.499993
200 days0.5000000.500000

The certainty decays, and after fifty days the first day is forgotten. The limit is the stationary distribution: the long-run share of revising days, whatever the chain started from. How fast it decays is set by the transition matrix. This one is sticky, so the memory of day one survives about ten days; a matrix nearer 0.5 forgets it in two.

The three questions

Every use of an HMM is one of these three, and naming them with their algorithms is the cleanest answer to "what can an HMM do".

QuestionAlgorithmChapter
Evaluationhow probable is this observation sequenceforwardThe Forward Algorithm and Viterbi
Decodingwhich state sequence most likely produced itViterbiThe Forward Algorithm and Viterbi
Learningwhat are the three matrices, from observations aloneBaum-WelchThe EM Algorithm

Baum-Welch is EM. The hidden variable is the state at each step, the E step computes the posterior over states by forward and backward passes, and the M step re-estimates the three matrices with fractional counts. So everything The EM Algorithm said applies unchanged: the likelihood never falls, the answer depends on the start, and several restarts are kept.

Evaluation by brute force, and the number that matters

On the four-day sequence correct, correct, correct, wrong, all sixteen paths are enumerated and their probabilities added, giving P(observations) = 0.06084495.

Now the number to remember. The most likely single path is RRRR at 0.02657205, which is 43.7 per cent of the total.

munotes.in435

Hidden Markov Models

So "how probable is this sequence" and "which path was it" are different questions with different answers. The probability of the sequence is a sum over paths; the best path is one term of that sum, here holding well under half of it. A student who reports the best path's probability as the sequence's probability is out by a factor of more than two on a four-day sequence, and by far more on a long one.

The cost, and why the next chapter exists

DaysPaths
416
101024
201,048,576
401,099,511,627,776
1001,267,650,600,228,229,401,496,703,205,376

Enumeration costs NT. It is exact and it is unusable: at a hundred days no machine will finish. The Forward Algorithm and Viterbi computes the same sum in T * N2 operations, which at a hundred days is 400, by never enumerating a path at all.

Where HMMs are used

Worth naming, because a paper may ask for applications.

FieldHidden stateObservation
Speech recognitionthe phoneme being spokena slice of the sound signal
Part-of-speech taggingthe word's grammatical classthe word
Gene findingcoding or non-coding regionthe base at that position
Handwriting recognitionthe letter being writtena stroke segment

Speech was the application that made the model famous, and Rabiner's 1989 tutorial is the standard reference. Modern speech systems use neural networks, and an honest answer says so: the HMM is the classical treatment and the reason the problem was tractable at all for two decades.

Its place among the models of this book

An HMM is a Bayesian network unrolled in time: one node per state, one per observation, the same two matrices repeated at every step. That is why it needs no new theory: Inference in a Bayesian Network already covers what its questions are, and the next chapter's algorithms are that inference specialised to a chain, where the structure makes it cheap.

Distinctions

A Markov chainA hidden Markov model
The state isobservedhidden
Partsinitial, transitioninitial, transition, emission
Questionwhat will the state bewhat was the state
The Markov assumptionOutput independence
Restrictsthe state sequencethe observations
Saysthe next state depends only on the current onean observation depends only on its own state
EvaluationDecoding
Askshow probable is the sequencewhich path produced it
Combines paths bysummingmaximising
Answer here0.06084495RRRR, at 0.02657205
AlgorithmforwardViterbi

What it does not mean

The observation is not the state. Day 9 was a non-revising day answered correctly; day 10 a revising day answered wrongly.

munotes.in436

Hidden Markov Models

The Markov assumption is not about the observations. That is output independence, a separate assumption.

The number of parameters does not grow with the length of the sequence. That is the point of the assumptions.

The stationary distribution is not the initial distribution. It is the limit the chain forgets its way into, here after about fifty days.

The best path's probability is not the sequence's probability. It is 43.7 per cent of it here.

Brute force is not merely slow. At 100 days it is 2**100 paths, which is not slow but impossible.

An HMM is not a new kind of model. It is a Bayesian network repeated in time.

Quick revision

  • Three parts: the initial distribution, the transition matrix P(next given current), the emission matrix P(observation given state). Numbers needed: (N-1) + N(N-1) + N(M-1), independent of sequence length.
  • Two assumptions: the Markov assumption, on the states, and output independence, on the observations.
  • Measured over 400,000 days: 0.8999, 0.8997, 0.9018. Yesterday adds nothing once today is known.
  • The sampled fortnight contains a non-revising day answered correctly and a revising day answered wrongly: the observation is evidence, not the state.
  • The stationary distribution is reached by repeated multiplication: 0.900000, 0.820000, 0.663840, 0.553687, 0.500007, 0.500000. The start is forgotten.
  • Three questions: evaluation (forward), decoding (Viterbi), learning (Baum-Welch, which is EM with forward and backward passes as its E step).
  • P(observations) = 0.06084495 by brute force; the best path RRRR is 0.02657205, only 43.7 per cent of it. Summing and maximising are different questions.
  • Cost of enumeration is NT: 16 paths at 4 days, over 1030 at 100. The forward algorithm does the same sum in T * N2, which is 400** at 100 days.
  • Applications: speech recognition (Rabiner, 1989), part-of-speech tagging, gene finding, handwriting. An HMM is a Bayesian network unrolled in time.

Test yourself

1. Define a hidden Markov model and state how many numbers it needs. A chain of hidden states with one observation emitted at each step, specified by an initial distribution over states, a transition matrix giving the probability of the next state given the current one, and an emission matrix giving the probability of each observation given the state. With N states and M observations it needs (N-1) + N(N-1) + N(M-1) numbers, whatever the length of the sequence.

2. State the two independence assumptions and say what each restricts. The Markov assumption restricts the states: the next state depends only on the current state and not on any earlier one. Output independence restricts the observations: what is observed at a step depends only on that step's state, not on earlier states or observations.

munotes.in437

Hidden Markov Models

3. How would you check the Markov assumption on real data? Estimate the probability of the next state conditioned on the current state alone, then estimate it again conditioned on the current state and the one before, and compare. If the extra conditioning moves the number, the assumption fails. On the measurement in this chapter the three estimates were 0.8999, 0.8997 and 0.9018, all the model's 0.90.

4. Distinguish a Markov chain from a hidden Markov model. In a Markov chain the state itself is observed, and the model is the initial distribution and the transition matrix. In a hidden Markov model the state is never observed and a third component, the emission matrix, relates each state to what is seen.

5. Name the three questions asked of an HMM with the algorithm for each. Evaluation, how probable a given observation sequence is, answered by the forward algorithm. Decoding, which state sequence most likely produced it, answered by Viterbi. Learning, what the three matrices are given observations alone, answered by Baum-Welch, which is EM with forward and backward passes as its E step.

6. Why is the probability of the most likely path not the probability of the observation sequence? The probability of the sequence is the sum of the probabilities of every path that could have produced it; the best path contributes one term of that sum. On the four-day sequence here the sum is 0.06084495 and the best path is 0.02657205, which is 43.7 per cent of it, so reporting the one for the other is wrong by more than a factor of two.

7. Why can the evaluation question not be answered by enumeration in practice? Enumeration costs NT paths for N states and T steps: 16 at four days, about a million at twenty, and over a thousand million million million million million at a hundred. The forward algorithm computes the identical sum in T * N2 operations, 400 at a hundred days, by combining paths as it goes instead of listing them.

Contents This chapter on its own page

munotes.in438

Chapter Seventy-Three

The Forward Algorithm and Viterbi

Syllabus topic Module 2, "Hidden Markov Models"

In one line

Both algorithms fill the same table one step at a time; the forward algorithm adds where paths meet, and Viterbi takes the larger and remembers where it came from.

Hidden Markov Models left two questions unanswered and one number as a warning: enumerating paths costs NT, which is 2100 at a hundred days. This chapter answers both questions in T * N**2.

The one idea behind both

State it in an examination in exactly this form, because everything else follows.

Two paths that are in the same state at the same step have the same future. So they need not be kept apart: they can be combined the moment they meet, and carried forward as a single number.

How they are combined is the only difference between the two algorithms.

Combines meeting paths byAnswers
Forwardadding themhow probable is this observation sequence
Viterbitaking the maximum, and noting whichwhich single path is most likely

The forward algorithm

Write alpha[t][s] for the probability of the observations up to and including step t and being in state s at step t. Two lines define it:

alpha[1][s] = P(state s) * P(observation 1 given s)

alpha[t][s] = ( sum over r of alpha[t-1][r] P(s given r) ) P(observation t given s)

And the answer to the evaluation question is the last row, summed:

P(observations) = sum over s of alpha[T][s]

Viterbi

The same recursion with one word changed, plus a note of where each maximum came from.

delta[1][s] = P(state s) * P(observation 1 given s)

delta[t][s] = ( max over r of delta[t-1][r] P(s given r) ) P(observation t given s)

back[t][s] = the r that achieved that maximum

Then backtrack: take the largest entry of the last row and follow the back pointers to step 1. The pointers are not an optimisation. Without them the table gives the probability of the best path and not the path itself, and a student who omits them has answered half the question.

Both, filled in and checked

# The forward algorithm and Viterbi on the model of the previous chapter: the two
# tables filled in by hand, checked against brute-force enumeration, and the case
# where the most likely SEQUENCE is not the sequence of most likely STATES.
from itertools import product
import math

STATES = ["revised", "did not"]
OBS = ["correct", "wrong"]
INIT = [0.5, 0.5]
TRANS = [[0.9, 0.1],
         [0.1, 0.9]]
EMIT = [[0.9, 0.1],
        [0.2, 0.8]]
N = len(STATES)
SEQ = [0, 0, 0, 1]          # correct, correct, correct, wrong
tag = lambda i: "R" if i == 0 else "N"                    # noqa: E731

def brute(seq):
    """The definition: every path, summed. Correct, and unusable beyond toys."""
    total, best = 0.0, None
    for path in product(range(N), repeat=len(seq)):
        p = INIT[path[0]] * EMIT[path[0]][seq[0]]
        for t in range(1, len(seq)):
            p *= TRANS[path[t - 1]][path[t]] * EMIT[path[t]][seq[t]]
        total += p
        if best is None or p > best[0]:
            best = (p, path)
    return total, best

print("THE OBSERVATIONS: %s" % ", ".join(OBS[o] for o in SEQ))
print()
print("THE FORWARD ALGORITHM. alpha[t][s] is the probability of the observations")
print("up to and including day t AND being in state s on day t. it is built one")
print("day at a time, and no path is ever written down.")
print()
print("   alpha[1][s] = P(state s) * P(observation 1 | s)")
print("   alpha[t][s] = ( sum over r of alpha[t-1][r] * P(s | r) ) * P(obs t | s)")
print()
alpha = [[INIT[s] * EMIT[s][SEQ[0]] for s in range(N)]]
print("   day | observed |   alpha[revised] |   alpha[did not] |         total")
print("   %3d | %-8s | %16.10f | %16.10f | %13.10f"
      % (1, OBS[SEQ[0]], alpha[0][0], alpha[0][1], sum(alpha[0])))
for t in range(1, len(SEQ)):
    row = []
    for s in range(N):
        row.append(sum(alpha[t - 1][r] * TRANS[r][s] for r in range(N)) * EMIT[s][SEQ[t]])
    alpha.append(row)
    print("   %3d | %-8s | %16.10f | %16.10f | %13.10f"
          % (t + 1, OBS[SEQ[t]], row[0], row[1], sum(row)))
p_obs = sum(alpha[-1])
print()
print("   P(observations) = the last row summed = %.8f" % p_obs)
total, best = brute(SEQ)
print("   brute force over all %d paths          = %.8f" % (N ** len(SEQ), total))
print("   the two agree to %d decimal places, which is the claim: the forward"
      % 8)
print("   algorithm computes the SAME sum, by adding paths together as soon as")
print("   they reach the same state instead of keeping them apart.")
print()
print("   WHY IT IS CHEAPER. two paths that are in the same state on day t have")
print("   the same future, so their probabilities can be added on day t and")
print("   carried forward as one number. that is the only idea in the algorithm.")
print("   cost, in the two ways of counting the same answer:")
print("      days T |    T * N**2, forward |               N**T, enumerated")
for t in (4, 20, 100, 400):
    print("      %6d | %20d | %30d" % (t, t * N * N, N ** t))
print("   at T = 4 they are the same, which is why a four-day example can be")
print("   done both ways; by T = 100 one of them has stopped being a number a")
print("   machine can hold.")
print()

print("FILTERING: the probability of each state GIVEN THE OBSERVATIONS SO FAR,")
print("which is each alpha row divided by its own total.")
print("   day | observed | P(revised | obs so far) | P(did not | obs so far)")
for t in range(len(SEQ)):
    tot = sum(alpha[t])
    print("   %3d | %-8s | %21.4f | %22.4f"
          % (t + 1, OBS[SEQ[t]], alpha[t][0] / tot, alpha[t][1] / tot))
print()

print("THE BACKWARD PASS. beta[t][s] is the probability of the observations")
print("AFTER day t, given that day t was in state s. it is the same recursion")
print("run from the end.")
beta = [[1.0] * N for _ in SEQ]
for t in range(len(SEQ) - 2, -1, -1):
    for s in range(N):
        beta[t][s] = sum(TRANS[s][r] * EMIT[r][SEQ[t + 1]] * beta[t + 1][r]
                         for r in range(N))
print("   day |    beta[revised] |    beta[did not]")
for t in range(len(SEQ)):
    print("   %3d | %16.10f | %16.10f" % (t + 1, beta[t][0], beta[t][1]))
print()
print("SMOOTHING: P(state on day t | ALL the observations) = alpha * beta / P(obs).")
print("   this is forward-backward, and it is the E step of Baum-Welch.")
print("   day | observed | P(revised | everything) | most likely state that day")
smoothed = []
for t in range(len(SEQ)):
    g = [alpha[t][s] * beta[t][s] / p_obs for s in range(N)]
    smoothed.append(g)
    print("   %3d | %-8s | %22.4f | %s"
          % (t + 1, OBS[SEQ[t]], g[0], STATES[0 if g[0] >= g[1] else 1]))
print()

print("VITERBI. the same table, with MAXIMUM in place of the sum, and a note of")
print("where each maximum came from so the path can be recovered.")
print()
print("   delta[1][s] = P(state s) * P(observation 1 | s)")
print("   delta[t][s] = ( max over r of delta[t-1][r] * P(s | r) ) * P(obs t | s)")
print()
delta = [[INIT[s] * EMIT[s][SEQ[0]] for s in range(N)]]
back = [[None] * N]
print("   day | observed |   delta[revised] |   delta[did not] | came from")
print("   %3d | %-8s | %16.10f | %16.10f | -"
      % (1, OBS[SEQ[0]], delta[0][0], delta[0][1]))
for t in range(1, len(SEQ)):
    row, ptr = [], []
    for s in range(N):
        cands = [(delta[t - 1][r] * TRANS[r][s], r) for r in range(N)]
        bestv, bestr = max(cands, key=lambda c: c[0])
        row.append(bestv * EMIT[s][SEQ[t]])
        ptr.append(bestr)
    delta.append(row)
    back.append(ptr)
    print("   %3d | %-8s | %16.10f | %16.10f | %s"
          % (t + 1, OBS[SEQ[t]], row[0], row[1],
             "revised from %s, did not from %s" % (tag(ptr[0]), tag(ptr[1]))))
last = 0 if delta[-1][0] >= delta[-1][1] else 1
path = [last]
for t in range(len(SEQ) - 1, 0, -1):
    last = back[t][last]
    path.insert(0, last)
print()
print("   the largest entry in the last row is %.10f, and following the pointers"
      % max(delta[-1]))
print("   back gives the path %s." % "".join(tag(s) for s in path))
print("   brute force says the best path is %s at %.10f."
      % ("".join(tag(s) for s in best[1]), best[0]))
print()

print("AND HERE IS THE POINT OF THE CHAPTER.")
pointwise = [0 if g[0] >= g[1] else 1 for g in smoothed]
print("   the most likely SEQUENCE, from Viterbi          : %s"
      % "".join(tag(s) for s in path))
print("   the sequence of most likely STATES, from smoothing: %s"
      % "".join(tag(s) for s in pointwise))
print("   day 4's smoothed probability of 'revised' is %.4f, BELOW a half, so"
      % smoothed[3][0])
print("   taken on its own day 4 is more likely a non-revising day. but the best")
print("   whole path keeps it as a revising day, because switching for one day")
print("   and switching back costs two transitions at 0.10 each, and the path is")
print("   scored as a whole.")
print()
print("   THE TWO ANSWERS ARE ANSWERS TO DIFFERENT QUESTIONS. the smoothed row")
print("   is right about day 4 in isolation; Viterbi is right about the sequence.")
print("   and note what could go wrong with the pointwise answer in a model with")
print("   FORBIDDEN transitions: it can return a path of probability ZERO, since")
print("   nothing makes its days consistent with one another.")
print()

print("UNDERFLOW, WHICH EVERY IMPLEMENTATION MUST HANDLE.")
print("   alpha is the probability of a longer and longer sequence, so it")
print("   shrinks by roughly a constant factor every day. run the recursion on a")
print("   long stretch of correct answers and watch what a double does:")
DAYS = 5000
a = [INIT[s] * EMIT[s][0] for s in range(N)]
zero_b, frozen = None, None
prev = None
for t in range(1, DAYS):
    a = [sum(a[r] * TRANS[r][s] for r in range(N)) * EMIT[s][0] for s in range(N)]
    day = t + 1
    if day in (10, 100, 1000, 3000, 3400, 3600, 4000, 5000):
        print("   day %4d : alpha = %s   filtering P(revised) = %.4f"
              % (day, ", ".join("%.4e" % v for v in a),
                 a[0] / (a[0] + a[1]) if a[0] + a[1] else float("nan")))
    if zero_b is None and a[1] == 0.0:
        zero_b = day
    if frozen is None and prev is not None and a == prev:
        frozen = day
    prev = list(a)
print()
print("   READ IT. on day %d the second entry becomes exactly 0.0, and from" % zero_b)
print("   there the filtering ratio is exactly 1.0000: the algorithm has become")
print("   CERTAIN, silently, because of arithmetic and not evidence.")
print("   on day %d the first entry stops changing altogether. it freezes at" % frozen)
print("   %.4e, a subnormal so small that multiplying it by 0.81 rounds back"
      % a[0])
print("   to itself, so the recursion runs for ever without moving. it never")
print("   even reaches 0, which a program testing for 0 would at least notice.")
print()
print("   THE TWO STANDARD REPAIRS")
print("      1. NORMALISE every row as it is computed and keep the scale factor.")
print("         the normalised rows ARE the filtering distribution, and")
print("         P(observations) is the product of the factors, so nothing is lost.")
print("      2. work in LOGS. Viterbi can always do this, because maximising")
print("         needs no addition and the logarithm turns the products into sums.")
print("         a forward pass in logs needs log(exp(x) + exp(y)), which is done")
print("         by factoring out the larger term.")
print()
a = [INIT[s] * EMIT[s][0] for s in range(N)]
log_p = math.log(sum(a))
a = [v / sum(a) for v in a]
for t in range(1, DAYS):
    a = [sum(a[r] * TRANS[r][s] for r in range(N)) * EMIT[s][0] for s in range(N)]
    c = sum(a)
    log_p += math.log(c)
    a = [v / c for v in a]
print("   the NORMALISED forward pass over the same %d days:" % DAYS)
print("      log P(observations) = %.4f" % log_p)
print("      filtering row       = %.6f revised, %.6f did not" % (a[0], a[1]))
la = [math.log(INIT[s] * EMIT[s][0]) for s in range(N)]
for t in range(1, DAYS):
    la = [max(la[r] + math.log(TRANS[r][s]) for r in range(N))
          + math.log(EMIT[s][0]) for s in range(N)]
print("   and Viterbi in logs over the same %d days:" % DAYS)
print("      the best path scores %.4f, an ordinary number." % max(la))
print("   both are exact where the plain recursion had stopped working entirely.")
munotes.in439

The Forward Algorithm and Viterbi

THE OBSERVATIONS: correct, correct, correct, wrong

THE FORWARD ALGORITHM. alpha[t][s] is the probability of the observations
up to and including day t AND being in state s on day t. it is built one
day at a time, and no path is ever written down.

   alpha[1][s] = P(state s) * P(observation 1 | s)
   alpha[t][s] = ( sum over r of alpha[t-1][r] * P(s | r) ) * P(obs t | s)

   day | observed |   alpha[revised] |   alpha[did not] |         total
     1 | correct  |     0.4500000000 |     0.1000000000 |  0.5500000000
     2 | correct  |     0.3735000000 |     0.0270000000 |  0.4005000000
     3 | correct  |     0.3049650000 |     0.0123300000 |  0.3172950000
     4 | wrong    |     0.0275701500 |     0.0332748000 |  0.0608449500

   P(observations) = the last row summed = 0.06084495
   brute force over all 16 paths          = 0.06084495
   the two agree to 8 decimal places, which is the claim: the forward
   algorithm computes the SAME sum, by adding paths together as soon as
   they reach the same state instead of keeping them apart.

   WHY IT IS CHEAPER. two paths that are in the same state on day t have
   the same future, so their probabilities can be added on day t and
   carried forward as one number. that is the only idea in the algorithm.
   cost, in the two ways of counting the same answer:
      days T |    T * N**2, forward |               N**T, enumerated
           4 |                   16 |                             16
          20 |                   80 |                        1048576
         100 |                  400 | 1267650600228229401496703205376
         400 |                 1600 | 2582249878086908589655919172003011874329705792829223512830659356540647622016841194629645353280137831435903171972747493376
   at T = 4 they are the same, which is why a four-day example can be
   done both ways; by T = 100 one of them has stopped being a number a
   machine can hold.

FILTERING: the probability of each state GIVEN THE OBSERVATIONS SO FAR,
which is each alpha row divided by its own total.
   day | observed | P(revised | obs so far) | P(did not | obs so far)
     1 | correct  |                0.8182 |                 0.1818
     2 | correct  |                0.9326 |                 0.0674
     3 | correct  |                0.9611 |                 0.0389
     4 | wrong    |                0.4531 |                 0.5469

THE BACKWARD PASS. beta[t][s] is the probability of the observations
AFTER day t, given that day t was in state s. it is the same recursion
run from the end.
   day |    beta[revised] |    beta[did not]
     1 |     0.1262970000 |     0.0401130000
     2 |     0.1523000000 |     0.1467000000
     3 |     0.1700000000 |     0.7300000000
     4 |     1.0000000000 |     1.0000000000

SMOOTHING: P(state on day t | ALL the observations) = alpha * beta / P(obs).
   this is forward-backward, and it is the E step of Baum-Welch.
   day | observed | P(revised | everything) | most likely state that day
     1 | correct  |                 0.9341 | revised
     2 | correct  |                 0.9349 | revised
     3 | correct  |                 0.8521 | revised
     4 | wrong    |                 0.4531 | did not

VITERBI. the same table, with MAXIMUM in place of the sum, and a note of
where each maximum came from so the path can be recovered.

   delta[1][s] = P(state s) * P(observation 1 | s)
   delta[t][s] = ( max over r of delta[t-1][r] * P(s | r) ) * P(obs t | s)

   day | observed |   delta[revised] |   delta[did not] | came from
     1 | correct  |     0.4500000000 |     0.1000000000 | -
     2 | correct  |     0.3645000000 |     0.0180000000 | revised from R, did not from N
     3 | correct  |     0.2952450000 |     0.0072900000 | revised from R, did not from R
     4 | wrong    |     0.0265720500 |     0.0236196000 | revised from R, did not from R

   the largest entry in the last row is 0.0265720500, and following the pointers
   back gives the path RRRR.
   brute force says the best path is RRRR at 0.0265720500.

AND HERE IS THE POINT OF THE CHAPTER.
   the most likely SEQUENCE, from Viterbi          : RRRR
   the sequence of most likely STATES, from smoothing: RRRN
   day 4's smoothed probability of 'revised' is 0.4531, BELOW a half, so
   taken on its own day 4 is more likely a non-revising day. but the best
   whole path keeps it as a revising day, because switching for one day
   and switching back costs two transitions at 0.10 each, and the path is
   scored as a whole.

   THE TWO ANSWERS ARE ANSWERS TO DIFFERENT QUESTIONS. the smoothed row
   is right about day 4 in isolation; Viterbi is right about the sequence.
   and note what could go wrong with the pointwise answer in a model with
   FORBIDDEN transitions: it can return a path of probability ZERO, since
   nothing makes its days consistent with one another.

UNDERFLOW, WHICH EVERY IMPLEMENTATION MUST HANDLE.
   alpha is the probability of a longer and longer sequence, so it
   shrinks by roughly a constant factor every day. run the recursion on a
   long stretch of correct answers and watch what a double does:
   day   10 : alpha = 7.1589e-02, 2.2625e-03   filtering P(revised) = 0.9694
   day  100 : alpha = 5.6952e-10, 1.7999e-11   filtering P(revised) = 0.9694
   day 1000 : alpha = 5.7828e-91, 1.8275e-92   filtering P(revised) = 0.9694
   day 3000 : alpha = 5.9823e-271, 1.8906e-272   filtering P(revised) = 0.9694
   day 3400 : alpha = 6.0230e-307, 1.9035e-308   filtering P(revised) = 0.9694
   day 3600 : alpha = 2.4703e-323, 0.0000e+00   filtering P(revised) = 1.0000
   day 4000 : alpha = 2.4703e-323, 0.0000e+00   filtering P(revised) = 1.0000
   day 5000 : alpha = 2.4703e-323, 0.0000e+00   filtering P(revised) = 1.0000

   READ IT. on day 3578 the second entry becomes exactly 0.0, and from
   there the filtering ratio is exactly 1.0000: the algorithm has become
   CERTAIN, silently, because of arithmetic and not evidence.
   on day 3583 the first entry stops changing altogether. it freezes at
   2.4703e-323, a subnormal so small that multiplying it by 0.81 rounds back
   to itself, so the recursion runs for ever without moving. it never
   even reaches 0, which a program testing for 0 would at least notice.

   THE TWO STANDARD REPAIRS
      1. NORMALISE every row as it is computed and keep the scale factor.
         the normalised rows ARE the filtering distribution, and
         P(observations) is the product of the factors, so nothing is lost.
      2. work in LOGS. Viterbi can always do this, because maximising
         needs no addition and the logarithm turns the products into sums.
         a forward pass in logs needs log(exp(x) + exp(y)), which is done
         by factoring out the larger term.

   the NORMALISED forward pass over the same 5000 days:
      log P(observations) = -1036.6120
      filtering row       = 0.969365 revised, 0.030635 did not
   and Viterbi in logs over the same 5000 days:
      the best path scores -1054.1929, an ordinary number.
   both are exact where the plain recursion had stopped working entirely.
munotes.in440

The Forward Algorithm and Viterbi

The forward table, read

DayObservedalpha revisedalpha did notTotal
1correct0.45000000000.10000000000.5500000000
2correct0.37350000000.02700000000.4005000000
3correct0.30496500000.01233000000.3172950000
4wrong0.02757015000.03327480000.0608449500
munotes.in441

The Forward Algorithm and Viterbi

The last total, 0.06084495, is exactly the figure brute force obtained from all sixteen paths in Hidden Markov Models. The forward algorithm is not an approximation. It is the same sum, rearranged so that paths are added as soon as they meet.

munotes.in442

The Forward Algorithm and Viterbi

Note the fourth row. Up to day 3 the revising entry dominates. The single wrong answer on day 4 reverses them, 0.0276 against 0.0333, because a wrong answer is four times more likely from a non-revising day than a revising one.

munotes.in443

The Forward Algorithm and Viterbi

The cost

DaysT * N**2, forwardN**T, enumerated
41616
20801,048,576
100400over 10**30
4001600unwritable
munotes.in444

The Forward Algorithm and Viterbi

At four days they agree, which is why a four-day example can honestly be done both ways and checked. By twenty days the forward algorithm is thirteen thousand times cheaper, and by a hundred the comparison has stopped being meaningful.

munotes.in445

The Forward Algorithm and Viterbi

Filtering, smoothing, and the backward pass

Three questions about the states, easily confused, and a paper may ask for exactly this distinction.

UsesAsks
Filteringthe observations so farwhat is the state now
Smoothingall the observationswhat was the state at an earlier step
Predictionthe observations so farwhat will the state be later

Filtering is each alpha row divided by its own total:

DayObservedP(revised, given what is seen so far)
1correct0.8182
2correct0.9326
3correct0.9611
4wrong0.4531

Confidence builds over three correct answers and one wrong answer undoes most of it, which is the behaviour wanted from a filter.

The backward pass computes beta[t][s], the probability of the observations after step t given that step t was in state s. It is the same recursion run from the end, with beta[T][s] = 1.

Smoothing multiplies the two and normalises:

P(state at t given ALL observations) = alpha[t][s] * beta[t][s] / P(observations)

DayFilteringSmoothing
10.81820.9341
20.93260.9349
30.96110.8521
40.45310.4531

Read day 1 and day 3. Smoothing changes the past. Day 1 rises from 0.8182 to 0.9341, because days 2 and 3 were also correct and that is retrospective evidence for a revising habit. Day 3 falls from 0.9611 to 0.8521, because day 4 was wrong and a sticky model reads that partly backwards. Day 4 is unchanged, since for the last step there is no future to add.

Together the two passes are forward-backward, and The EM Algorithm named it already: forward-backward is the E step of Baum-Welch, because the responsibilities EM needs are exactly these smoothed probabilities.

The Viterbi table, read

DayObserveddelta reviseddelta did notCame from
1correct0.45000000000.1000000000-
2correct0.36450000000.0180000000revised from R, did not from N
3correct0.29524500000.0072900000revised from R, did not from R
4wrong0.02657205000.0236196000revised from R, did not from R
munotes.in446

The Forward Algorithm and Viterbi

The largest last-row entry is 0.0265720500, and the pointers lead back to RRRR, which is what brute force found. Compare the tables: the forward row 4 had 0.0275701500 for revised and Viterbi has 0.0265720500. Viterbi's entries are smaller, because a maximum is at most a sum, and the gap is the probability of the paths that were discarded.

And here is the point of the chapter

Two answers, both correct, to two different questions:

The most likely sequence, from ViterbiRRRR
The sequence of most likely states, from smoothingRRRN

Day 4's smoothed probability of a revising day is 0.4531, below a half, so taken on its own day 4 was more likely a non-revising day. Yet the best whole path keeps it as a revising day, because switching away for one day and back again costs two transitions at 0.10 each, and Viterbi scores the path as a whole.

So: the sequence of individually most likely states need not be the most likely sequence. A student who computes the smoothed probabilities and reads off the largest at each step has not run Viterbi and may get a different answer.

And the failure can be worse than different. In a model with forbidden transitions, of probability zero, the pointwise answer can name a sequence that is impossible, because nothing in the procedure requires consecutive days to be consistent with one another. Viterbi cannot do this, since it only ever extends real paths.

Which to use is decided by the question. Tagging each word of a sentence with its most probable part of speech is a pointwise question. Transcribing a spoken word, where the letters must form a legal word, is a Viterbi question.

Underflow, which is worse than it looks

Maximum Likelihood Estimation met underflow in a likelihood. Here it is measured in the recursion, over a long run of correct answers:

DayalphaFiltering P(revised)
107.1589e-02, 2.2625e-030.9694
10005.7828e-91, 1.8275e-920.9694
34006.0230e-307, 1.9035e-3080.9694
36002.4703e-323, 0.0000e+001.0000
50002.4703e-323, 0.0000e+001.0000

Three separate things go wrong, and none of them raises an error.

1. The model becomes certain by arithmetic. From day 3578 the second entry is exactly 0.0, so filtering reports 1.0000: absolute certainty about a hidden state, produced by rounding and not by evidence.

2. The recursion freezes. On day 3583 the first entry stops changing. It sits at 2.5e-323, a subnormal so small that multiplying it by 0.81 rounds back to itself, and the loop can then run for ever without moving.

munotes.in447

The Forward Algorithm and Viterbi

3. It never reaches zero. A program that watched for 0.0 would at least notice; this one never triggers.

The two standard repairs, and a paper may ask for them:

Normalise each row as it is computed and keep the scale factors. The normalised rows are the filtering distribution, and log P(observations) is the sum of the logs of the factors, so nothing is lost. Measured over the same 5000 days: log P(observations) = -1036.6120 and a filtering row of 0.969365, which is the value the honest recursion had on day 10.

Work in logs. Viterbi can always do this, because maximising needs no addition and the logarithm turns the products into sums; over 5000 days the best path scores -1054.1929, an ordinary number. A forward pass in logs needs log(exp(x) + exp(y)), which is computed by factoring out the larger term rather than by exponentiating.

Distinctions

ForwardViterbi
Meeting paths areaddedmaximised
Needs backpointersnoyes
AnswersP(observations)the best path
Here0.06084495000.0265720500, RRRR
Can work purely in logsneeds careyes, trivially
FilteringSmoothing
Usesobservations so farall observations
Passesforward onlyforward and backward
Day 1 here0.81820.9341
Day 3 here0.96110.8521
Pointwise most likely statesMost likely sequence
FromsmoothingViterbi
HereRRRNRRRR
Can be impossibleyesno
Right fortagging each itema sequence that must be coherent

What it does not mean

The forward algorithm is not an approximation. It gives the identical 0.06084495.

Viterbi's last row does not give P(observations). It gives the best path's probability, which is smaller.

Viterbi is not finished without backtracking. The table alone gives a probability, not a path.

Filtering is not smoothing. Filtering uses the past only, and here the two differ on days 1 and 3.

The most likely states are not the most likely sequence. RRRN against RRRR on four days.

Underflow does not announce itself. The recursion silently reports certainty, then freezes at a subnormal, and never reaches zero.

Normalising is not a loss of information. The scale factors carry P(observations), exactly.

Quick revision

  • One idea: paths in the same state at the same step share their future, so they are combined where they meet. Forward adds; Viterbi maximises and remembers.
  • alpha[1][s] = P(s) P(obs 1 given s); alpha[t][s] = (sum over r of alpha[t-1][r] P(s given r)) * P(obs t given s). Then P(observations) is the last row summed: 0.06084495, equal to brute force.
  • Cost T * N2: 80 at 20 days against 1,048,576 paths; 400** at 100 days.
  • Filtering divides each alpha row by its total: 0.8182, 0.9326, 0.9611, 0.4531. Backward gives beta; smoothing is alpha * beta / P(obs): 0.9341, 0.9349, 0.8521, 0.4531.
  • Smoothing changes the past: day 1 rises to 0.9341, day 3 falls to 0.8521, and the last day never changes. Together they are forward-backward, the E step of Baum-Welch.
  • Viterbi: delta with max in place of sum, plus back pointers, then backtrack. Best path RRRR at 0.0265720500, smaller than the forward entry because a max is at most a sum.
  • Viterbi gives RRRR; the pointwise most likely states give RRRN. Day 4 alone favours a non-revising day at 0.4531, but switching away and back costs two transitions at 0.10. With forbidden transitions the pointwise answer can even be impossible.
  • Underflow: from day 3578 filtering silently reports 1.0000; on day 3583 alpha freezes at 2.5e-323 and never reaches 0. Repairs: normalise each row and keep the factors (log P = -1036.6120, filtering 0.969365), or work in logs (best path -1054.1929).
munotes.in448

The Forward Algorithm and Viterbi

Test yourself

1. State the single observation that makes both algorithms possible. Two paths that are in the same state at the same step have exactly the same future, so they can be combined at that step and carried forward as one number instead of being kept apart.

2. Write the forward recursion and say how P(observations) is obtained. alpha[1][s] is the initial probability of state s times the probability of the first observation given s. For later steps, alpha[t][s] is the sum over previous states r of alpha[t-1][r] times the transition probability from r to s, all multiplied by the probability of the observation at t given s. The probability of the observation sequence is the sum of the final row.

3. How does Viterbi differ from the forward algorithm, and what must be stored? It replaces the sum over previous states with a maximum, and it stores, for each state and step, which previous state achieved that maximum. Those backpointers are then followed from the largest entry of the last row to recover the path; without them the table gives only the best path's probability.

4. Distinguish filtering from smoothing, with the values from this chapter. Filtering uses only the observations up to the step in question and needs the forward pass alone: 0.8182, 0.9326, 0.9611, 0.4531 here. Smoothing uses all the observations and needs the backward pass too: 0.9341, 0.9349, 0.8521, 0.4531. Later evidence raised day 1 and lowered day 3, and the last step is identical because it has no future.

5. Why is Viterbi's entry for the last step smaller than the forward algorithm's? Because a maximum over paths is at most a sum over the same paths. The difference is the total probability of all the paths Viterbi discarded in favour of the best one.

munotes.in449

The Forward Algorithm and Viterbi

6. Give an example where the sequence of most likely states differs from the most likely sequence, and explain. On the observations correct, correct, correct, wrong, smoothing gives a probability of 0.4531 for a revising day on day 4, so the pointwise answer is RRRN, while Viterbi returns RRRR. Switching state for a single day and switching back costs two transitions of probability 0.10 each, so although day 4 alone favours the other state, no whole path through it is as probable as staying. In a model with forbidden transitions the pointwise answer can even name an impossible sequence, since nothing requires its steps to be consistent.

7. What happens to a plain forward recursion on a long sequence, and what are the two repairs? Alpha shrinks by roughly a constant factor per step. In this measurement the smaller entry became exactly zero on day 3578, so filtering reported absolute certainty produced by rounding rather than evidence, and on day 3583 the larger entry froze at about 2.5e-323, a subnormal that multiplication by 0.81 returns unchanged, so the recursion could run for ever without moving and never reached zero. The repairs are to normalise each row as it is computed, keeping the scale factors whose logarithms sum to log P(observations), or to work in logarithms throughout, which Viterbi can do directly and the forward pass can do using a stable form of log of a sum of exponentials.

Contents This chapter on its own page

munotes.in450

Chapter Seventy-Four

Clustering and k-Means

Syllabus topic Module 2, "Concept of clustering"

In one line

Choose k centres, give every point to its nearest one, move each centre to the mean of its own points, and repeat until nothing moves.

This is the first unsupervised algorithm in the book. Supervised and Unsupervised Learning drew the distinction; here it matters concretely: there are no labels anywhere in the input, and the true groups appear in this chapter only to score the result afterwards.

The algorithm

Three lines, and a paper asking for k-means wants exactly these.

  1. Choose k initial centres, called centroids.
  2. Assign: give every point to the nearest centroid.
  3. Recentre: move every centroid to the mean of the points assigned to it.

Repeat 2 and 3 until the assignment stops changing.

And what it is minimising, which must be named:

within-cluster sum of squares = sum over points of (distance from the point to its own centroid)**2

Also called the inertia. Everything the algorithm does, and every way it fails, follows from the fact that this is the quantity being reduced.

The measurement

# k-means, built and measured: the iteration, the sum of squares falling every
# round, the dependence on the start, why the sum of squares cannot choose k,
# and a shape it gets wrong. No labels are used anywhere except to score it.
import math
from itertools import combinations

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(8123)
rnd = lambda: next(gen)                                   # noqa: E731

# 24 students, each a point: (hours of study a week, attendance per cent).
# There are three real groups, and k-means is never told so or told which.
CENTRES = [(4.0, 55.0), (12.0, 72.0), (22.0, 90.0)]
points, truth = [], []
for g, (cx, cy) in enumerate(CENTRES):
    for _ in range(8):
        points.append((cx + (rnd() - 0.5) * 5.0, cy + (rnd() - 0.5) * 20.0))
        truth.append(g)

def d2(a, b):
    return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2

def assign(pts, cents):
    out = []
    for p in pts:
        out.append(min(range(len(cents)), key=lambda i: d2(p, cents[i])))
    return out

def recentre(pts, labels, k, old):
    cents = []
    for i in range(k):
        members = [p for p, l in zip(pts, labels) if l == i]
        if not members:
            cents.append(old[i])            # an EMPTY cluster keeps its centre
        else:
            cents.append((sum(m[0] for m in members) / len(members),
                          sum(m[1] for m in members) / len(members)))
    return cents

def sse(pts, labels, cents):
    """Within-cluster sum of squares: what k-means actually minimises."""
    return sum(d2(p, cents[l]) for p, l in zip(pts, labels))

def kmeans(pts, k, start, rounds=40):
    cents = list(start)
    labels = assign(pts, cents)
    history = [sse(pts, labels, cents)]
    for _ in range(rounds):
        cents = recentre(pts, labels, k, cents)
        new = assign(pts, cents)
        history.append(sse(pts, new, cents))
        if new == labels:
            break
        labels = new
    return labels, cents, history

print("24 STUDENTS, each a point (hours of study a week, attendance per cent).")
print("   %s" % "  ".join("(%.0f,%.0f)" % p for p in points[:8]))
print("   %s" % "  ".join("(%.0f,%.0f)" % p for p in points[8:16]))
print("   %s" % "  ".join("(%.0f,%.0f)" % p for p in points[16:]))
print("   there are three real groups. k-means is told NEITHER how many nor which.")
print()

print("THE ALGORITHM. pick k centres; then repeat two steps until nothing moves:")
print("   ASSIGN:  give every point to its nearest centre.")
print("   RECENTRE: move every centre to the mean of its own points.")
print()
start = [points[0], points[1], points[2]]
print("START with the first three students as centres: %s"
      % "  ".join("(%.1f,%.1f)" % c for c in start))
print()
labels, cents, hist = kmeans(points, 3, start)
print("   round | cluster sizes | sum of squares | change")
lab, ce = assign(points, start), list(start)
print("   %5d | %13s | %14.4f |" % (0, str([lab.count(i) for i in range(3)]),
                                    sse(points, lab, ce)))
prev = sse(points, lab, ce)
for r in range(1, 12):
    ce = recentre(points, lab, 3, ce)
    new = assign(points, ce)
    s = sse(points, new, ce)
    print("   %5d | %13s | %14.4f | %+.4f"
          % (r, str([new.count(i) for i in range(3)]), s, s - prev))
    if new == lab and abs(s - prev) < 1e-12:
        print("   nothing moved. converged.")
        break
    lab, prev = new, s
print()
print("   the final centres: %s" % "  ".join("(%.2f, %.2f)" % c for c in ce))
print("   the true centres  : %s" % "  ".join("(%.2f, %.2f)" % c for c in CENTRES))
print()
print("   THE SUM OF SQUARES NEVER RISES, and that is a proof of convergence:")
print("   the assign step cannot increase it, since every point moves to a")
print("   nearer centre or stays; the recentre step cannot increase it, since")
print("   the mean is the point that minimises the sum of squared distances to a")
print("   set. there are finitely many assignments, so it must stop.")
print()

def purity(labels):
    """Only for SCORING. k-means never sees the true groups."""
    total = 0
    for i in set(labels):
        members = [t for t, l in zip(truth, labels) if l == i]
        if members:
            total += max(members.count(g) for g in set(members))
    return total / len(labels)

print("SCORED AGAINST THE TRUE GROUPS (which the algorithm never saw):")
print("   %d of %d points are in a cluster whose majority is their own group:"
      % (round(purity(lab) * len(lab)), len(lab)))
print("   purity %.4f" % purity(lab))
print()

print("THE ANSWER DEPENDS ON THE START. the same data, five different sets of")
print("three starting centres:")
print("   starting centres taken from students | sum of squares | purity")
for pick in ((0, 1, 2), (0, 8, 16), (7, 15, 23), (0, 16, 17), (0, 16, 19)):
    st = [points[i] for i in pick]
    lb, cc, h = kmeans(points, 3, st)
    print("   %-36s | %14.4f | %.4f  sizes %s"
          % (str(tuple(p + 1 for p in pick)), sse(points, lb, cc), purity(lb),
             [lb.count(i) for i in range(3)]))
print("   they do NOT all reach the same answer. so try EVERY possible starting")
print("   triple of students and count where they end up:")
tally = {}
for c in combinations(range(len(points)), 3):
    lb, cc, h = kmeans(points, 3, [points[i] for i in c])
    key = round(sse(points, lb, cc), 4)
    tally[key] = tally.get(key, 0) + 1
worse = sum(n for v, n in tally.items() if v > min(tally))
print("      sum of squares | starts that reach it | purity there")
for v in sorted(tally):
    for c in combinations(range(len(points)), 3):
        lb, cc, h = kmeans(points, 3, [points[i] for i in c])
        if round(sse(points, lb, cc), 4) == v:
            break
    print("      %14.4f | %20d | %.4f" % (v, tally[v], purity(lb)))
print("   %d starting triples in %d, %.0f per cent of them, end somewhere worse"
      % (worse, sum(tally.values()), 100 * worse / sum(tally.values())))
print("   than the best. k-means minimises the sum of squares by descending, and")
print("   a descent stops at the bottom of whatever valley it began in. the")
print("   remedies are to run it several times and keep the lowest sum of")
print("   squares, or to choose the starting centres more carefully.")
print()

print("K-MEANS++ , which is the careful choice: the first centre is a point, and")
print("each later centre is the point FURTHEST from the centres chosen so far.")
plus = [points[0]]
while len(plus) < 3:
    far = max(points, key=lambda p: min(d2(p, c) for c in plus))
    plus.append(far)
lb, cc, h = kmeans(points, 3, plus)
print("   centres chosen: %s" % "  ".join("(%.1f,%.1f)" % c for c in plus))
print("   sum of squares %.4f, purity %.4f" % (sse(points, lb, cc), purity(lb)))
print("   (the published k-means++ picks each later centre at RANDOM with")
print("   probability proportional to the squared distance; taking the furthest")
print("   point is the deterministic version, and it is enough to see the idea.)")
print()

print("WHY THE SUM OF SQUARES CANNOT CHOOSE k.")
print("   k | best sum of squares over 6 starts | drop from k-1")
prev_s = None
for k in range(1, 9):
    best = None
    for off in range(6):
        st = [points[(off * 4 + i * 8) % len(points)] for i in range(k)]
        lb, cc, h = kmeans(points, k, st)
        s = sse(points, lb, cc)
        if best is None or s < best:
            best = s
    print("   %1d | %33.4f | %s"
          % (k, best, "-" if prev_s is None else "%.4f" % (prev_s - best)))
    prev_s = best
print("   it falls at every step and reaches 0 when k = the number of points.")
print("   SO THE QUANTITY k-MEANS MINIMISES CANNOT BE USED TO CHOOSE k. the drop")
print("   column is where the information is: the fall is large up to k = 3 and")
print("   small after it, and that bend is the ELBOW METHOD. it is a judgement,")
print("   not a calculation, and the next chapter gives a measure that is not.")
print()

print("A SHAPE IT GETS WRONG. two long thin bands, side by side:")
bands, band_truth = [], []
for i in range(20):
    t = i / 19.0
    bands.append((2.0 + 40.0 * t, 20.0 + 2.0 * t))
    band_truth.append(0)
    bands.append((2.0 + 40.0 * t, 23.0 + 2.0 * t))
    band_truth.append(1)
lb, cc, h = kmeans(bands, 2, [bands[0], bands[1]])
right = sum(1 for a, b in zip(lb, band_truth) if a == b)
right = max(right, len(lb) - right)
print("   the two bands are %d points each, 3 units apart and 40 units long." % 20)
print("   k-means with k = 2 puts %d of %d points in the right band."
      % (right, len(lb)))
print("   centres: %s" % "  ".join("(%.1f, %.1f)" % c for c in cc))
print("   it cuts the bands ACROSS instead of separating them, because it")
print("   assigns by distance to a centre, which makes every cluster a round")
print("   blob. k-means assumes clusters that are SPHERICAL, of SIMILAR SIZE and")
print("   of SIMILAR SPREAD, and it fails on anything else however much data it")
print("   is given.")
munotes.in451

Clustering and k-Means

24 STUDENTS, each a point (hours of study a week, attendance per cent).
   (3,46)  (5,52)  (2,51)  (5,56)  (6,50)  (4,54)  (5,55)  (5,57)
   (13,78)  (13,81)  (11,70)  (13,77)  (13,64)  (11,73)  (14,73)  (12,64)
   (21,82)  (24,82)  (22,86)  (20,95)  (21,91)  (20,96)  (24,98)  (24,85)
   there are three real groups. k-means is told NEITHER how many nor which.

THE ALGORITHM. pick k centres; then repeat two steps until nothing moves:
   ASSIGN:  give every point to its nearest centre.
   RECENTRE: move every centre to the mean of its own points.

START with the first three students as centres: (3.4,46.3)  (5.0,52.0)  (1.9,50.5)

   round | cluster sizes | sum of squares | change
       0 |    [1, 22, 1] |     17959.2746 |
       1 |    [1, 16, 7] |      3325.8711 | -14633.4035
       2 |    [1, 14, 9] |      1864.6401 | -1461.2310
       3 |    [3, 13, 8] |      1640.6691 | -223.9710
       4 |    [5, 13, 6] |      1463.3749 | -177.2942
       5 |    [7, 12, 5] |      1365.6213 | -97.7537
       6 |    [8, 11, 5] |      1034.3900 | -331.2312
       7 |     [8, 9, 7] |       840.9354 | -193.4546
       8 |     [8, 8, 8] |       735.2446 | -105.6908
       9 |     [8, 8, 8] |       708.6394 | -26.6053
      10 |     [8, 8, 8] |       708.6394 | +0.0000
   nothing moved. converged.

   the final centres: (4.26, 52.63)  (21.96, 89.46)  (12.49, 72.48)
   the true centres  : (4.00, 55.00)  (12.00, 72.00)  (22.00, 90.00)

   THE SUM OF SQUARES NEVER RISES, and that is a proof of convergence:
   the assign step cannot increase it, since every point moves to a
   nearer centre or stays; the recentre step cannot increase it, since
   the mean is the point that minimises the sum of squared distances to a
   set. there are finitely many assignments, so it must stop.

SCORED AGAINST THE TRUE GROUPS (which the algorithm never saw):
   24 of 24 points are in a cluster whose majority is their own group:
   purity 1.0000

THE ANSWER DEPENDS ON THE START. the same data, five different sets of
three starting centres:
   starting centres taken from students | sum of squares | purity
   (1, 2, 3)                            |       708.6394 | 1.0000  sizes [8, 8, 8]
   (1, 9, 17)                           |       708.6394 | 1.0000  sizes [8, 8, 8]
   (8, 16, 24)                          |       708.6394 | 1.0000  sizes [8, 8, 8]
   (1, 17, 18)                          |       805.9969 | 0.9167  sizes [10, 6, 8]
   (1, 17, 20)                          |       973.7239 | 0.7500  sizes [10, 10, 4]
   they do NOT all reach the same answer. so try EVERY possible starting
   triple of students and count where they end up:
      sum of squares | starts that reach it | purity there
            708.6394 |                 1186 | 1.0000
            805.9969 |                  355 | 0.9167
            973.7239 |                  483 | 0.7500
   838 starting triples in 2024, 41 per cent of them, end somewhere worse
   than the best. k-means minimises the sum of squares by descending, and
   a descent stops at the bottom of whatever valley it began in. the
   remedies are to run it several times and keep the lowest sum of
   squares, or to choose the starting centres more carefully.

K-MEANS++ , which is the careful choice: the first centre is a point, and
each later centre is the point FURTHEST from the centres chosen so far.
   centres chosen: (3.4,46.3)  (23.6,98.5)  (11.1,73.3)
   sum of squares 708.6394, purity 1.0000
   (the published k-means++ picks each later centre at RANDOM with
   probability proportional to the squared distance; taking the furthest
   point is the deterministic version, and it is enough to see the idea.)

WHY THE SUM OF SQUARES CANNOT CHOOSE k.
   k | best sum of squares over 6 starts | drop from k-1
   1 |                         7400.7166 | -
   2 |                         1764.5806 | 5636.1360
   3 |                          708.6394 | 1055.9412
   4 |                          439.6363 | 269.0031
   5 |                          251.4924 | 188.1439
   6 |                          181.0671 | 70.4253
   7 |                          156.1405 | 24.9265
   8 |                          142.0802 | 14.0604
   it falls at every step and reaches 0 when k = the number of points.
   SO THE QUANTITY k-MEANS MINIMISES CANNOT BE USED TO CHOOSE k. the drop
   column is where the information is: the fall is large up to k = 3 and
   small after it, and that bend is the ELBOW METHOD. it is a judgement,
   not a calculation, and the next chapter gives a measure that is not.

A SHAPE IT GETS WRONG. two long thin bands, side by side:
   the two bands are 20 points each, 3 units apart and 40 units long.
   k-means with k = 2 puts 20 of 40 points in the right band.
   centres: (11.5, 22.0)  (32.5, 23.0)
   it cuts the bands ACROSS instead of separating them, because it
   assigns by distance to a centre, which makes every cluster a round
   blob. k-means assumes clusters that are SPHERICAL, of SIMILAR SIZE and
   of SIMILAR SPREAD, and it fails on anything else however much data it
   is given.
munotes.in452

Clustering and k-Means

The run, read

Twenty-four students as points, three real groups, from a deliberately poor start: three centres taken from students who are all in the same group.

munotes.in453

Clustering and k-Means

RoundCluster sizesSum of squares
01, 22, 117959.2746
11, 16, 73325.8711
33, 13, 81640.6691
68, 11, 51034.3900
88, 8, 8735.2446
98, 8, 8708.6394
108, 8, 8708.6394, nothing moved
munotes.in454

Clustering and k-Means

From a start that put 22 of 24 points in one cluster, the centres walk out to (4.26, 52.63), (12.49, 72.48) and (21.96, 89.46), against true group centres of (4, 55), (12, 72) and (22, 90). All 24 points end in a cluster whose majority is their own group: purity 1.0000.

munotes.in455

Clustering and k-Means

Note that the sizes settle at 8, 8, 8 on round 8 but the sum of squares keeps falling to round 9. The assignment can stop changing after the centroids have moved, so the stopping test must be on the assignment, and one more recentring is free.

Why it always converges

The proof is two sentences and papers ask for it.

The assign step cannot increase the sum of squares, because each point either moves to a nearer centroid or stays where it is. The recentre step cannot increase it either, because the mean of a set of points is exactly the point that minimises the sum of squared distances to that set.

So the sum of squares never rises, and since there are only finitely many ways to assign n points to k clusters, the algorithm must stop. But "it converges" is a much weaker statement than students read into it, which is the next section.

munotes.in456

Clustering and k-Means

The census of local optima

Every one of the 2024 possible starting triples was run, and they land on exactly three values:

Sum of squaresStarts reaching itPurity thereSizes
708.639411861.00008, 8, 8
805.99693550.916710, 6, 8
973.72394830.750010, 10, 4

838 starts in 2024, 41 per cent, end somewhere worse than the best, and the worst of them gets a quarter of the students into the wrong group. This is not a rare pathology; it is two starts in five on well-separated data with three obvious groups.

The cause is exactly the cause in Gradient Descent: the algorithm descends, and a descent stops at the bottom of whatever valley it began in. Two remedies, both standard:

Restart. Run k-means several times from different starts and keep the fit with the lowest sum of squares. Note what makes this legitimate: the sum of squares is computable without labels, so choosing between runs by it is not cheating.

Choose the start well. k-means++ spreads the initial centres out: the first is a data point, and each later one is chosen with probability proportional to its squared distance from the centres already chosen. The deterministic version, taking the furthest point each time, is measured here and reaches 708.6394 with purity 1.0000 in one run.

Why the sum of squares cannot choose k

The obvious idea is to try every k and take the best sum of squares. It does not work, and the reason is arithmetic.

kBest sum of squaresDrop from k-1
17400.7166
21764.58065636.1360
3708.63941055.9412
4439.6363269.0031
5251.4924188.1439
6181.067170.4253
8142.080214.0604

It falls at every step, and at k = n every point is its own centre and the sum of squares is exactly 0. So the quantity k-means minimises always prefers more clusters, and using it to select k selects n.

The information is in the drop column. The fall is 5636 then 1056, then 269, 188, 70, 14: large up to k = 3 and small after it. Plotting the sum of squares against k gives a curve with a bend at 3, and choosing k at the bend is the elbow method.

Be honest about what it is: a judgement made by eye, not a calculation. On data with less separation the bend is not there to find. Hierarchical Clustering and Judging a Clustering gives a measure that does not have this defect.

What k-means assumes, and a shape it gets wrong

Two long thin bands, twenty points each, three units apart and forty units long. k-means with k = 2 puts 20 of 40 points in the right band, which is exactly chance, and its centres are (11.5, 22.0) and (32.5, 23.0): it has cut the bands across rather than separating them.

munotes.in457

Clustering and k-Means

The reason is in the objective. Assignment is by distance to a centre, so every cluster is the set of points nearest one point, which is a round blob. Two bands cannot be described that way, and cutting them crosswise genuinely gives the smaller sum of squares. k-means is not failing to optimise; it is optimising the wrong thing for this shape.

So the assumptions, which a paper may ask for directly. k-means expects clusters that are:

sphericalnot elongated, curved, or nested
of similar sizea big cluster will be split to feed a small one
of similar spreada tight cluster and a diffuse one will be mismatched
separated by distancenot by density or by shape

And no amount of data repairs any of them.

The practical points

Five things that decide whether a k-means run is worth anything.

Scaling matters. The algorithm is built on distance, so a feature measured in thousands dominates one measured in tens, exactly as k-Nearest Neighbours measured. Features are normally standardised first. In the data here, hours run from about 2 to 24 and attendance from 46 to 98, so attendance carries most of the distance, and the grouping found is largely a grouping by attendance.

Outliers pull centroids. The centroid is a mean, and one distant point moves it. k-medoids uses an actual data point as the centre and a median-like criterion, and is far more robust.

Empty clusters happen. A centroid can end up nearest to nothing. An implementation must do something: keep it where it is, as this one does, or restart it at the point furthest from its centre.

k must be given. It is an input, not a result.

The cost is low. One round is O(n k d) for n points in d dimensions, and the number of rounds is small: nine here from a bad start. That cheapness is the main reason k-means is the most used clustering algorithm despite everything above.

k-means is EM with the E step rounded

The EM Algorithm promised this connection and it is worth making precisely.

EM on a mixturek-means
E stepthe posterior probability of each component for each pointthe nearest centre, a probability of 1
M stepweighted mean with fractional countsplain mean of the assigned points
A borderline pointsplits between clustersgoes entirely to one
Cluster shapecan be elongated, via a covariancespherical only
munotes.in458

Clustering and k-Means

k-means is hard-assignment EM. And that identity explains its two main defects at once: rounding the responsibilities is what makes it sensitive to the start, and having no covariance is what makes its clusters round.

Distinctions

SupervisedUnsupervised, here
Inputpoints and labelspoints only
k-means uses labelsnot applicablenever, only the scoring does
Correct answerdefineda matter of judgement
The assign stepThe recentre step
Changesthe labelsthe centroids
Cannot increase the sum of squares becauseeach point moves to a nearer centrethe mean minimises squared distance
Restartingk-means++
Costk times the workone run
Herebest of several reaches 708.6394reaches 708.6394 at once

What it does not mean

Convergence is not correctness. 41 per cent of starts converge to a worse answer here.

The sum of squares cannot choose k. It falls with every extra cluster and reaches zero at k = n.

The elbow is not a calculation. It is read off a curve by eye, and on some data there is no bend.

k-means does not find clusters of any shape. On two bands it scores exactly chance.

Nor is that a bug. The crosswise cut really does have the smaller sum of squares; the objective is what is wrong for the shape.

Purity is not available in practice. It needs the true groups, which unsupervised learning does not have.

Scaling is not a detail. The distance is dominated by whichever feature has the larger range.

Quick revision

  • k-means: choose k centroids; assign each point to the nearest; recentre each on the mean of its points; repeat until the assignment stops changing.
  • It minimises the within-cluster sum of squares, also called the inertia.
  • Convergence: assign cannot raise the objective, because points move to nearer centres; recentre cannot, because the mean minimises squared distance; there are finitely many assignments.
  • Measured: from a bad start, 17959.2746 down to 708.6394 in nine rounds; centres (4.26, 52.63), (12.49, 72.48), (21.96, 89.46) against a true (4, 55), (12, 72), (22, 90); purity 1.0000.
  • All 2024 starting triples reach one of three answers: 708.6394 (1186 starts, purity 1.0000), 805.9969 (355, 0.9167), 973.7239 (483, purity 0.7500). 838 starts, 41 per cent, end worse.
  • Remedies: several restarts, keep the lowest sum of squares (legitimate, since it needs no labels), or k-means++, which spreads the initial centres and reaches 708.6394 in one run.
  • The sum of squares falls with every extra cluster and is 0 at k = n, so it cannot choose k. Use the drop: 5636, 1056, 269, 188, 70, 14, whose bend at k = 3 is the elbow method, a judgement by eye.
  • On two bands 3 apart and 40 long it scores 20 of 40, exactly chance, cutting them across. k-means assumes clusters that are spherical, of similar size and spread, separated by distance.
  • Practical: standardise the features; the centroid is a mean so outliers pull it (k-medoids is robust); empty clusters must be handled; k is an input; one round costs O(n k d).
  • k-means is EM with the responsibilities rounded to 0 and 1, which explains both the sensitivity to the start and the round clusters.
munotes.in459

Clustering and k-Means

Test yourself

1. State the k-means algorithm and the quantity it minimises. Choose k centroids; assign every point to its nearest centroid; move every centroid to the mean of the points assigned to it; repeat until the assignment stops changing. It minimises the within-cluster sum of squares, the total squared distance from each point to its own centroid.

2. Prove that k-means terminates. The assign step cannot increase the sum of squares, since every point either moves to a nearer centroid or stays. The recentre step cannot increase it either, since the mean of a set of points is the point minimising the sum of squared distances to that set. The objective therefore never rises, and as there are only finitely many assignments of points to clusters the process must stop.

3. Why does convergence not mean the answer is right? Because the algorithm only descends, so it stops at the bottom of the valley it started in. Over all 2024 possible starting triples on this data, 838 of them, 41 per cent, converged to a worse sum of squares than the best, and the worst put a quarter of the students in the wrong group.

4. Give two ways of dealing with the dependence on the start. Run the algorithm several times from different starts and keep the result with the lowest sum of squares, which is legitimate because that quantity needs no labels. Or choose the starting centres so that they are spread out, as k-means++ does by picking each later centre with probability proportional to its squared distance from those already chosen; the deterministic furthest-point version reached the best answer here in a single run.

5. Why can the within-cluster sum of squares not be used to choose k, and what is used instead? It falls with every extra cluster and is exactly zero when k equals the number of points, so minimising it selects the largest possible k. The drops between successive values are used instead: here 5636, 1056, 269, 188, 70, 14, whose bend at three is the elbow method. That is a judgement made by eye rather than a calculation.

munotes.in460

Clustering and k-Means

6. k-means was given two long thin bands and scored 20 of 40. Explain, and say whether it is a bug. It cut the bands across their length instead of separating them, with centres side by side along the bands. It is not a bug: assignment is by distance to a single centre, so every cluster is effectively a round blob, and for bands 3 units apart and 40 long the crosswise cut genuinely has the smaller sum of squares. The objective is the wrong one for that shape, and more data cannot fix it.

7. In what sense is k-means a special case of EM? The E step of EM computes the posterior probability of each component for each point; k-means rounds that to the single nearest centre, giving it probability one. The M step of EM takes a weighted mean with fractional counts; k-means takes the plain mean of the points assigned. So k-means is hard-assignment EM, and the rounding explains its sensitivity to initialisation while the absence of a covariance explains why its clusters must be round.

Contents This chapter on its own page

munotes.in461

Chapter Seventy-Five

Hierarchical Clustering, and Judging a Clustering

Syllabus topic Module 2, "Concept of clustering"

In one line

Start with every point as its own cluster and repeatedly merge the two closest, keeping the whole sequence of merges as a tree.

Clustering and k-means needed k in advance and gave a different answer depending on where it started. This chapter's method needs neither, and then has a difficulty of its own.

Two directions

Agglomerative, bottom-upDivisive, top-down
Starts withn clusters of one pointone cluster of n points
Each stepmerges the two closestsplits one cluster
CostO(n**3) naivelyworse: the first split alone has 2**(n-1) options
Usedalmost alwaysrarely, with a heuristic split

Everything below is agglomerative, which is what "hierarchical clustering" means in practice.

The algorithm, and the one decision in it

Three lines:

  1. Every point is its own cluster.
  2. Find the two closest clusters and merge them, recording the distance.
  3. Repeat until one cluster remains.

The record of merges, each with its distance, is the dendrogram: a tree whose height at each join is the distance at which the merge happened. Cutting it horizontally at any height gives a clustering, so one run gives every k at once, which is a real advantage over k-means.

And the one decision: step 2 needs the distance between two clusters, not two points.

LinkageThe distance between two clusters isTends to give
Singlethe closest pair, one from eachlong, straggly clusters
Completethe furthest paircompact, roughly equal clusters
Averagethe mean over all pairsa compromise
Wardthe increase in total within-cluster sum of squarescompact clusters, like k-means

Ward's method is worth knowing by name: it merges the pair whose merger raises the sum of squares least, which makes it the hierarchical relative of k-means and the commonest choice in practice after complete linkage.

The measurement

# Agglomerative clustering on the same 24 students, with the three linkages and
# their merge distances printed, the case where single linkage beats k-means and
# the case where it fails, and the silhouette coefficient, which unlike the sum
# of squares can be used to choose the number of clusters.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(8123)
rnd = lambda: next(gen)                                   # noqa: E731

CENTRES = [(4.0, 55.0), (12.0, 72.0), (22.0, 90.0)]
points, truth = [], []
for g, (cx, cy) in enumerate(CENTRES):
    for _ in range(8):
        points.append((cx + (rnd() - 0.5) * 5.0, cy + (rnd() - 0.5) * 20.0))
        truth.append(g)

def dist(a, b):
    return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

def linkage(c1, c2, pts, how):
    ds = [dist(pts[i], pts[j]) for i in c1 for j in c2]
    if how == "single":
        return min(ds)
    if how == "complete":
        return max(ds)
    return sum(ds) / len(ds)                      # average

def agglomerate(pts, how, log=False):
    """Every point its own cluster; merge the closest pair; repeat."""
    clusters = [[i] for i in range(len(pts))]
    merges = []
    while len(clusters) > 1:
        best = None
        for i in range(len(clusters)):
            for j in range(i + 1, len(clusters)):
                d = linkage(clusters[i], clusters[j], pts, how)
                if best is None or d < best[0]:
                    best = (d, i, j)
        d, i, j = best
        merges.append((d, len(clusters[i]), len(clusters[j]), len(clusters) - 1))
        clusters[i] = clusters[i] + clusters[j]
        del clusters[j]
        if log:
            print("   %8.4f | %4d + %-4d | %d clusters left"
                  % (d, merges[-1][1], merges[-1][2], merges[-1][3]))
    return merges

def cut(pts, how, k):
    """The same process, stopped when k clusters remain."""
    clusters = [[i] for i in range(len(pts))]
    while len(clusters) > k:
        best = None
        for i in range(len(clusters)):
            for j in range(i + 1, len(clusters)):
                d = linkage(clusters[i], clusters[j], pts, how)
                if best is None or d < best[0]:
                    best = (d, i, j)
        _, i, j = best
        clusters[i] = clusters[i] + clusters[j]
        del clusters[j]
    labels = [0] * len(pts)
    for ci, c in enumerate(clusters):
        for i in c:
            labels[i] = ci
    return labels

def purity(labels, tr):
    total = 0
    for i in set(labels):
        members = [t for t, l in zip(tr, labels) if l == i]
        total += max(members.count(g) for g in set(members))
    return total / len(labels)

print("AGGLOMERATIVE CLUSTERING. start with every point its own cluster; merge")
print("the two closest clusters; repeat until one is left. no k is needed, and")
print("no starting centres, so NOTHING depends on a random choice: the same data")
print("always gives the same tree.")
print()
print("THE ONLY CHOICE IS HOW TO MEASURE THE DISTANCE BETWEEN TWO CLUSTERS:")
print("   SINGLE linkage   : the CLOSEST pair of points, one from each")
print("   COMPLETE linkage : the FURTHEST pair")
print("   AVERAGE linkage  : the mean over all pairs")
print()
print("THE MERGE SEQUENCE under complete linkage. this list IS the dendrogram:")
print("   distance | sizes joined | after the merge")
agglomerate(points, "complete", log=True)
print()
print("   read the distance column downwards. it rises, and the LAST few merges")
print("   are far more expensive than the ones before them. a big jump means two")
print("   things that were not close have been forced together, so CUTTING THE")
print("   TREE JUST BELOW THE BIGGEST JUMP is the hierarchical version of the")
print("   elbow method.")
print()

print("THE THREE LINKAGES, cut to three clusters, scored against the true groups:")
print("   linkage  | cluster sizes | purity")
for how in ("single", "complete", "average"):
    lb = cut(points, how, 3)
    print("   %-8s | %13s | %.4f"
          % (how, str(sorted([lb.count(i) for i in set(lb)], reverse=True)),
             purity(lb, truth)))
print("   they are not the same answer. the linkage is a modelling decision and")
print("   it changes the result.")
print()

print("WHERE SINGLE LINKAGE WINS: the two bands that defeated k-means.")
bands, band_truth = [], []
for i in range(20):
    t = i / 19.0
    bands.append((2.0 + 40.0 * t, 20.0 + 2.0 * t))
    band_truth.append(0)
    bands.append((2.0 + 40.0 * t, 23.0 + 2.0 * t))
    band_truth.append(1)
for how in ("single", "complete", "average"):
    lb = cut(bands, how, 2)
    right = sum(1 for a, b in zip(lb, band_truth) if a == b)
    right = max(right, len(lb) - right)
    print("   %-8s linkage: %d of %d points in the right band" % (how, right, len(lb)))
print("   k-means managed 20 of 40, which is chance. SINGLE LINKAGE GETS ALL 40,")
print("   because it only ever asks whether two clusters have a CLOSE PAIR, so a")
print("   long thin band is joined up along its length. it needs no notion of a")
print("   centre and therefore no assumption that clusters are round.")
print()

print("WHERE SINGLE LINKAGE FAILS: CHAINING. two compact groups of nine points")
print("spaced 2 apart, 24 units away from one another, and a thin line of 19")
print("points 1 apart laid between them.")
GA = [(x, y) for x in (0.0, 2.0, 4.0) for y in (0.0, 2.0, 4.0)]
GB = [(x + 24.0, y) for x, y in GA]
BRIDGE = [(5.0 + 1.0 * i, 2.0) for i in range(19)]
chain = GA + GB + BRIDGE
for how in ("single", "complete", "average"):
    lb = cut(chain, how, 2)
    a, b = set(lb[:9]), set(lb[9:18])
    ok = len(a) == 1 and len(b) == 1 and a != b
    print("   %-8s linkage: cluster sizes %-10s  the two real groups are %s"
          % (how, str(sorted([lb.count(i) for i in set(lb)], reverse=True)),
             "SEPARATED" if ok else "IN ONE CLUSTER"))
print("   single linkage walks along the bridge one unit at a time and joins")
print("   everything into a single cluster of 36, leaving one stray point as the")
print("   second. THIS IS THE CHAINING EFFECT: a thin path of points, which may")
print("   be nothing but noise, merges two real groups, because single linkage")
print("   only ever asks whether SOME pair is close. complete linkage asks about")
print("   the FURTHEST pair and is immune, which is why it is the usual default.")
print()

def silhouette(pts, labels):
    """For each point: a = mean distance inside its cluster, b = the smallest
    mean distance to another cluster, s = (b - a) / max(a, b). A point alone in
    its cluster scores 0 by convention."""
    out = []
    for i, p in enumerate(pts):
        own = [j for j, l in enumerate(labels) if l == labels[i] and j != i]
        if not own:
            out.append(0.0)
            continue
        a = sum(dist(p, pts[j]) for j in own) / len(own)
        b = None
        for c in set(labels):
            if c == labels[i]:
                continue
            others = [j for j, l in enumerate(labels) if l == c]
            m = sum(dist(p, pts[j]) for j in others) / len(others)
            if b is None or m < b:
                b = m
        out.append((b - a) / max(a, b))
    return sum(out) / len(out), out

print("JUDGING A CLUSTERING WITHOUT LABELS: THE SILHOUETTE COEFFICIENT.")
print("   for each point, a = its mean distance to the other points of its own")
print("   cluster, b = the smallest mean distance to any other cluster, and")
print("      s = (b - a) / max(a, b)")
print("   s is near +1 when the point is much closer to its own cluster than to")
print("   any other, near 0 on a boundary, and NEGATIVE when the point is closer")
print("   to another cluster than to its own, meaning it is in the wrong one.")
print("   the score of a clustering is the mean of s over every point.")
print()
print("FIRST, DATA WITH GROUPS THAT REALLY ARE SEPARATE: the same three centres,")
print("drawn with a quarter of the spread.")
gen2 = lcg(8123)
r2 = lambda: next(gen2)                                   # noqa: E731
tight = []
for cx, cy in CENTRES:
    for _ in range(8):
        tight.append((cx + (r2() - 0.5) * 5.0, cy + (r2() - 0.5) * 5.0))
print("   k | mean silhouette, complete linkage")
for k in range(2, 9):
    m, each = silhouette(tight, cut(tight, "complete", k))
    print("   %1d | %33.4f%s" % (k, m, "   <- the maximum" if k == 3 else ""))
print("   A CLEAR MAXIMUM AT k = 3, which is how many groups the data has. and")
print("   notice what the sum of squares could never do: the silhouette FALLS")
print("   when k is too large, because splitting a real cluster puts its halves")
print("   close together and the term b collapses. so it can choose k.")
print()
print("NOW THE DATA WE HAVE ACTUALLY BEEN USING, whose groups overlap:")
print("   k | complete linkage | best k-means | worst point, complete linkage")

def kmeans_fp(pts, k, rounds=60):
    """k-means from the furthest-point start of the previous chapter."""
    ce = [pts[0]]
    while len(ce) < k:
        ce.append(max(pts, key=lambda p: min((p[0] - c[0]) ** 2 + (p[1] - c[1]) ** 2
                                             for c in ce)))
    lab = [min(range(k), key=lambda i: dist(p, ce[i])) for p in pts]
    for _ in range(rounds):
        nc = []
        for i in range(k):
            m = [p for p, l in zip(pts, lab) if l == i]
            nc.append((sum(x for x, _ in m) / len(m), sum(y for _, y in m) / len(m))
                      if m else ce[i])
        ce = nc
        new = [min(range(k), key=lambda i: dist(p, ce[i])) for p in pts]
        if new == lab:
            break
        lab = new
    return lab

for k in range(2, 9):
    m, each = silhouette(points, cut(points, "complete", k))
    mk, _ = silhouette(points, kmeans_fp(points, k))
    print("   %1d | %16.4f | %12.4f | %+.4f" % (k, m, mk, min(each)))
print()
print("   READ THIS HONESTLY. the silhouette still has a maximum, which is the")
print("   property that matters. but the two columns do not agree about WHERE:")
print("   complete linkage is highest at k = 5, and k-means is highest at k = 3")
print("   by a margin of well under a hundredth, which is no margin at all.")
print("   the data has three groups by construction, and a measure of GEOMETRY")
print("   cannot see that, because with this much spread the groups genuinely do")
print("   overlap. AN INTERNAL MEASURE SCORES THE SHAPE OF A CLUSTERING, NOT ITS")
print("   TRUTH. it is good for rejecting an absurd k and poor at picking between")
print("   neighbouring ones.")
print()
lb = cut(points, "complete", 3)
m, each = silhouette(points, lb)
neg = [i + 1 for i, v in enumerate(each) if v < 0]
print("   at k = 3 on that data the mean silhouette is %.4f, and students %s"
      % (m, " and ".join(str(n) for n in neg)))
print("   score BELOW ZERO, meaning they sit nearer another cluster than their")
print("   own. the per-point scores are worth reading, not only the mean:")
print("   %s" % " ".join("%+.2f" % v for v in each))
print()
print("   ROUGH READING OF THE MEAN, a convention and not a law:")
print("      above 0.70   a strong structure")
print("      0.50 to 0.70 a reasonable one")
print("      0.25 to 0.50 weak; the structure may not be real")
print("      below 0.25   no useful structure was found")
print()
print("AND THE COST. agglomerative clustering compares every pair of clusters at")
print("every step: O(n**3) as written here, O(n**2 log n) with a heap, against")
print("O(n * k * d) PER ROUND for k-means.")
for n in (24, 1000, 100000):
    print("   n = %6d : n**2 = %d pairs in the distance matrix" % (n, n * n))
print("   the n**2 matrix is the real limit. hierarchical clustering is for")
print("   thousands of points; k-means is for millions.")
munotes.in462

Hierarchical Clustering, and Judging a Clustering

AGGLOMERATIVE CLUSTERING. start with every point its own cluster; merge
the two closest clusters; repeat until one is left. no k is needed, and
no starting centres, so NOTHING depends on a random choice: the same data
always gives the same tree.

THE ONLY CHOICE IS HOW TO MEASURE THE DISTANCE BETWEEN TWO CLUSTERS:
   SINGLE linkage   : the CLOSEST pair of points, one from each
   COMPLETE linkage : the FURTHEST pair
   AVERAGE linkage  : the mean over all pairs

THE MERGE SEQUENCE under complete linkage. this list IS the dendrogram:
   distance | sizes joined | after the merge
     0.9107 |    1 + 1    | 23 clusters left
     0.9832 |    1 + 1    | 22 clusters left
     1.0176 |    1 + 1    | 21 clusters left
     1.4700 |    1 + 1    | 20 clusters left
     1.9838 |    1 + 1    | 19 clusters left
     2.0818 |    2 + 1    | 18 clusters left
     2.3671 |    1 + 1    | 17 clusters left
     2.5256 |    1 + 1    | 16 clusters left
     2.8634 |    1 + 1    | 15 clusters left
     3.1529 |    3 + 1    | 14 clusters left
     3.6511 |    2 + 1    | 13 clusters left
     4.0796 |    2 + 2    | 12 clusters left
     4.4547 |    2 + 1    | 11 clusters left
     4.6174 |    1 + 2    | 10 clusters left
     5.5156 |    2 + 1    | 9 clusters left
     5.9512 |    1 + 3    | 8 clusters left
     8.1394 |    3 + 1    | 7 clusters left
     9.8479 |    3 + 2    | 6 clusters left
    10.9379 |    4 + 4    | 5 clusters left
    13.6570 |    3 + 4    | 4 clusters left
    24.0932 |    7 + 4    | 3 clusters left
    28.8921 |    8 + 5    | 2 clusters left
    55.9519 |   13 + 11   | 1 clusters left

   read the distance column downwards. it rises, and the LAST few merges
   are far more expensive than the ones before them. a big jump means two
   things that were not close have been forced together, so CUTTING THE
   TREE JUST BELOW THE BIGGEST JUMP is the hierarchical version of the
   elbow method.

THE THREE LINKAGES, cut to three clusters, scored against the true groups:
   linkage  | cluster sizes | purity
   single   |     [8, 8, 8] | 1.0000
   complete |    [11, 8, 5] | 0.8750
   average  |     [8, 8, 8] | 1.0000
   they are not the same answer. the linkage is a modelling decision and
   it changes the result.

WHERE SINGLE LINKAGE WINS: the two bands that defeated k-means.
   single   linkage: 40 of 40 points in the right band
   complete linkage: 20 of 40 points in the right band
   average  linkage: 20 of 40 points in the right band
   k-means managed 20 of 40, which is chance. SINGLE LINKAGE GETS ALL 40,
   because it only ever asks whether two clusters have a CLOSE PAIR, so a
   long thin band is joined up along its length. it needs no notion of a
   centre and therefore no assumption that clusters are round.

WHERE SINGLE LINKAGE FAILS: CHAINING. two compact groups of nine points
spaced 2 apart, 24 units away from one another, and a thin line of 19
points 1 apart laid between them.
   single   linkage: cluster sizes [36, 1]     the two real groups are IN ONE CLUSTER
   complete linkage: cluster sizes [19, 18]    the two real groups are SEPARATED
   average  linkage: cluster sizes [20, 17]    the two real groups are SEPARATED
   single linkage walks along the bridge one unit at a time and joins
   everything into a single cluster of 36, leaving one stray point as the
   second. THIS IS THE CHAINING EFFECT: a thin path of points, which may
   be nothing but noise, merges two real groups, because single linkage
   only ever asks whether SOME pair is close. complete linkage asks about
   the FURTHEST pair and is immune, which is why it is the usual default.

JUDGING A CLUSTERING WITHOUT LABELS: THE SILHOUETTE COEFFICIENT.
   for each point, a = its mean distance to the other points of its own
   cluster, b = the smallest mean distance to any other cluster, and
      s = (b - a) / max(a, b)
   s is near +1 when the point is much closer to its own cluster than to
   any other, near 0 on a boundary, and NEGATIVE when the point is closer
   to another cluster than to its own, meaning it is in the wrong one.
   the score of a clustering is the mean of s over every point.

FIRST, DATA WITH GROUPS THAT REALLY ARE SEPARATE: the same three centres,
drawn with a quarter of the spread.
   k | mean silhouette, complete linkage
   2 |                            0.6772
   3 |                            0.8714   <- the maximum
   4 |                            0.7252
   5 |                            0.6110
   6 |                            0.6219
   7 |                            0.4856
   8 |                            0.5147
   A CLEAR MAXIMUM AT k = 3, which is how many groups the data has. and
   notice what the sum of squares could never do: the silhouette FALLS
   when k is too large, because splitting a real cluster puts its halves
   close together and the term b collapses. so it can choose k.

NOW THE DATA WE HAVE ACTUALLY BEEN USING, whose groups overlap:
   k | complete linkage | best k-means | worst point, complete linkage
   2 |           0.5726 |       0.6088 | -0.1436
   3 |           0.5287 |       0.6091 | -0.3824
   4 |           0.5300 |       0.5969 | -0.0790
   5 |           0.5792 |       0.6005 | -0.1828
   6 |           0.4916 |       0.5418 | -0.1828
   7 |           0.5585 |       0.5487 | -0.0563
   8 |           0.4871 |       0.4823 | -0.0563

   READ THIS HONESTLY. the silhouette still has a maximum, which is the
   property that matters. but the two columns do not agree about WHERE:
   complete linkage is highest at k = 5, and k-means is highest at k = 3
   by a margin of well under a hundredth, which is no margin at all.
   the data has three groups by construction, and a measure of GEOMETRY
   cannot see that, because with this much spread the groups genuinely do
   overlap. AN INTERNAL MEASURE SCORES THE SHAPE OF A CLUSTERING, NOT ITS
   TRUTH. it is good for rejecting an absurd k and poor at picking between
   neighbouring ones.

   at k = 3 on that data the mean silhouette is 0.5287, and students 9 and 12
   score BELOW ZERO, meaning they sit nearer another cluster than their
   own. the per-point scores are worth reading, not only the mean:
   +0.69 +0.79 +0.77 +0.71 +0.76 +0.78 +0.76 +0.62 -0.28 +0.12 +0.72 -0.38 +0.54 +0.61 +0.55 +0.50 +0.45 +0.47 +0.59 +0.60 +0.62 +0.58 +0.55 +0.57

   ROUGH READING OF THE MEAN, a convention and not a law:
      above 0.70   a strong structure
      0.50 to 0.70 a reasonable one
      0.25 to 0.50 weak; the structure may not be real
      below 0.25   no useful structure was found

AND THE COST. agglomerative clustering compares every pair of clusters at
every step: O(n**3) as written here, O(n**2 log n) with a heap, against
O(n * k * d) PER ROUND for k-means.
   n =     24 : n**2 = 576 pairs in the distance matrix
   n =   1000 : n**2 = 1000000 pairs in the distance matrix
   n = 100000 : n**2 = 10000000000 pairs in the distance matrix
   the n**2 matrix is the real limit. hierarchical clustering is for
   thousands of points; k-means is for millions.
munotes.in463

Hierarchical Clustering, and Judging a Clustering

The dendrogram as a list

The merge sequence printed under complete linkage is the dendrogram. Read the distance column downwards: it rises, and it must, because complete linkage's distances can only grow as clusters grow.

munotes.in464

Hierarchical Clustering, and Judging a Clustering

The useful feature is a big jump. A large merge distance means two things that were not close have been forced together, so cutting the tree just below the biggest jump is the hierarchical version of the elbow method, and it is read off the same way, by eye.

munotes.in465

Hierarchical Clustering, and Judging a Clustering

Note what the tree gives that k-means cannot: the structure inside a cluster. The order and heights of the merges say which students are near neighbours and which joined their group late, and that is often more useful than the labels.

munotes.in466

Hierarchical Clustering, and Judging a Clustering

The three linkages disagree

LinkageCluster sizes at k = 3Purity
single8, 8, 81.0000
complete11, 8, 50.8750
average8, 8, 81.0000
munotes.in467

Hierarchical Clustering, and Judging a Clustering

On this data single and average recover the three groups exactly and complete does not, putting eleven students in one cluster and five in another. That is worth noticing precisely because complete linkage is the usual default: the linkage is a modelling choice, and the default is not always right.

munotes.in468

Hierarchical Clustering, and Judging a Clustering

Where single linkage wins

The two long thin bands that reduced k-means to 20 of 40, which is exactly chance:

munotes.in469

Hierarchical Clustering, and Judging a Clustering

Points in the right band
k-means20 of 40
single linkage40 of 40
complete linkage20 of 40
average linkage20 of 40

Single linkage gets every point right. The reason is exactly its definition: it asks only whether two clusters contain a close pair, so a long band is joined up along its own length, one neighbour at a time. It has no notion of a centre, and therefore no assumption that clusters are round, which is the assumption that defeated k-means. Complete and average linkage, which do care about the far end of a cluster, fail here as k-means does.

Where single linkage fails

Two compact groups of nine, twenty-four units apart, with nineteen points laid in a thin line between them:

LinkageCluster sizesThe two real groups
single36, 1in one cluster
complete19, 18separated
average20, 17separated

Single linkage walks along the bridge one unit at a time and joins everything into a single cluster of 36, leaving one stray point as the second cluster. This is the chaining effect, and it is the exact price of the property that won the previous section: caring only about the closest pair means a thin path of points, which may be nothing but noise, is enough to merge two real groups.

So the honest summary: single linkage finds clusters of any shape and is destroyed by a thin bridge; complete linkage is immune to bridges and insists that clusters are compact. Neither is better. They fail on different data, and knowing which failure the data invites is the skill.

Judging a clustering without labels

Every score used so far in this book needed the right answer. Clustering has none, so a different kind of measure is needed.

Internal validationExternal validation
Uses labelsnoyes
Measuresthe geometry of the clusteringagreement with the truth
Examplessilhouette, Davies-Bouldin, the sum of squarespurity, the Rand index
Available in practiceyesonly when labels exist, which is not the clustering case

Purity is a research instrument, not a working one. It has been quoted throughout these two chapters only because the groups were built by hand; on real data there is nothing to compare with.

The silhouette coefficient

For each point:

a = its mean distance to the other points of its OWN cluster

b = the smallest mean distance to any OTHER cluster

s = (b - a) / max(a, b)

s nearMeans
+1far closer to its own cluster than to any other
0on a boundary between two clusters
negativecloser to another cluster than to its own: in the wrong one
munotes.in470

Hierarchical Clustering, and Judging a Clustering

The score of a clustering is the mean of s over every point.

On well separated data it works cleanly. The same three centres drawn with a quarter of the spread:

kMean silhouette
20.6772
30.8714
40.7252
50.6110
80.5147

A clear maximum at the right k. And note what the within-cluster sum of squares could never do: the silhouette falls when k is too large, because splitting a real cluster puts its two halves close together and the term b collapses. The silhouette can choose k; the sum of squares cannot.

And now the honest part

On the data these two chapters have actually been using, whose groups overlap:

kComplete linkageBest k-means
20.57260.6088
30.52870.6091
40.53000.5969
50.57920.6005
70.55850.5487

The silhouette still has a maximum, which is the property that matters. But the two columns do not agree about where it is. Complete linkage peaks at k = 5. k-means peaks at k = 3, by 0.0003 over k = 2, which is no margin at all.

The data has three groups by construction, and the measure cannot see it, because at this spread the groups genuinely do overlap. An internal measure scores the shape of a clustering, not its truth. It is good for rejecting an absurd k and poor at choosing between neighbouring ones, and a paper that presents a silhouette maximum as proof of the number of clusters has claimed more than the measure supports.

And read the per-point scores, not only the mean. At k = 3 on that data the mean is 0.5287 and two students score below zero, meaning they sit nearer another cluster than their own. The mean hides them; the list does not.

A rough convention for the mean, which is a convention and not a law:

Mean silhouetteReading
above 0.70a strong structure
0.50 to 0.70a reasonable one
0.25 to 0.50weak; the structure may not be real
below 0.25no useful structure found

The cost, which decides when it can be used

PointsPairs in the distance matrix
24576
1,0001,000,000
100,00010,000,000,000

Time is O(n3) as written here and O(n2 log n) with a heap, against O(n k d) per round for k-means. But the real limit is memory: the n2 distance matrix. Hierarchical clustering is for thousands of points; k-means is for millions.**

Which to use

SituationMethod
Millions of pointsk-means
k unknown and the structure worth inspectinghierarchical, read the tree
Elongated or curved clusterssingle linkage
Noise likely to bridge groupscomplete or Ward
Compact clusters wanted, with a treeWard
A repeatable answer requiredhierarchical: it is deterministic
munotes.in471

Hierarchical Clustering, and Judging a Clustering

Distinctions

k-meansHierarchical
Needs k in advanceyesno, the cut chooses it later
Depends on a random startyes, 41 per cent of starts were worseno, deterministic
Gives every k at oncenoyes
CostO(n k d) per roundO(n**2) memory
Cluster shaperound onlydepends on the linkage
Single linkageComplete linkage
Cluster distanceclosest pairfurthest pair
On the two bands40 of 4020 of 40
On the bridge36 and 119 and 18
Cluster shapeanycompact
Sum of squaresSilhouette
As k growsfalls for everrises then falls
Can choose knoyes, with care
Needs labelsnono
Per-point versionnoyes, and it is worth reading

What it does not mean

Hierarchical clustering is not free of choices. The linkage is a modelling decision and the three disagree, here by 0.875 against 1.000 in purity.

Complete linkage is not the safe default. It scored 0.8750 where single and average scored 1.0000, and it failed the bands.

Single linkage is not better. It got all 40 band points and was destroyed by a bridge of noise.

A dendrogram does not choose k. The cut height is read off by eye, like the elbow.

A silhouette maximum is not the number of clusters. Here it fell at 5 under one method and 3 under another on data with three groups.

The mean silhouette is not the whole story. Two students scored negative at k = 3 and the mean hid them.

Purity is not usable in practice. It needs the true groups, which clustering by definition lacks.

Hierarchical clustering does not scale. The n**2 distance matrix is the limit.

Quick revision

  • Agglomerative: every point its own cluster; merge the two closest; repeat. Divisive works downwards and is rarely used.
  • The merge sequence with its distances is the dendrogram; cutting it at a height gives a clustering, so one run gives every k. Cut below the biggest jump.
  • Linkages: single (closest pair), complete (furthest pair), average (mean of pairs), Ward (least increase in the sum of squares, the hierarchical relative of k-means).
  • Measured at k = 3: single and average 1.0000 purity, complete 0.8750 with sizes 11, 8, 5. The linkage changes the answer.
  • On two long bands: k-means 20 of 40, complete and average 20 of 40, single linkage 40 of 40, because it never uses a centre.
  • On two groups joined by a thin bridge: single linkage gives 36 and 1, merging both real groups; complete gives 19 and 18. That is the chaining effect.
  • Internal validation needs no labels (silhouette); external validation does (purity, Rand index) and is unavailable in practice.
  • Silhouette: a = mean distance within its own cluster, b = smallest mean distance to another, s = (b - a) / max(a, b). Negative means the point is in the wrong cluster.
  • On well separated data the silhouette peaks cleanly at the right k: 0.6772, 0.8714, 0.7252, 0.6110. It falls for large k, which is why it can choose k where the sum of squares cannot.
  • On overlapping data it peaked at 5 for complete linkage and at 3 by 0.0003 for k-means, on data with three real groups. An internal measure scores geometry, not truth. Read the per-point scores: two were negative at k = 3.
  • Cost: O(n3) time, O(n2) memory, which is the real limit. Thousands of points, not millions.
munotes.in472

Hierarchical Clustering, and Judging a Clustering

Test yourself

1. Describe agglomerative clustering and say what a dendrogram is. Begin with every point as its own cluster, repeatedly merge the two closest clusters, and record the distance at each merge until one cluster remains. The dendrogram is that record drawn as a tree whose join heights are the merge distances; cutting it horizontally at any height yields a clustering, so a single run provides every number of clusters.

2. Define the three main linkages and say what shape each favours. Single linkage takes the distance between two clusters to be that of their closest pair, and favours long straggly clusters. Complete linkage takes the furthest pair, and favours compact clusters of similar size. Average linkage takes the mean over all pairs and is a compromise.

3. Single linkage got all 40 points of two thin bands right where k-means scored 20 of 40. Explain. Single linkage asks only whether two clusters contain a close pair, so it joins a band up along its own length one neighbour at a time. It never refers to a cluster centre, so it makes no assumption that clusters are round, which is precisely the assumption that made k-means cut the bands crosswise.

4. What is the chaining effect, and which linkage suffers from it? Single linkage. A thin path of points between two real groups is enough to merge them, because each step of the path is a close pair; in the measurement a bridge of nineteen points joined two groups of nine into a single cluster of 36, leaving one stray point as the second cluster. Complete linkage, which considers the furthest pair, is immune.

munotes.in473

Hierarchical Clustering, and Judging a Clustering

5. Distinguish internal from external cluster validation and say which is available in practice. Internal validation uses only the data and the clustering, and measures its geometry: the silhouette coefficient, for example. External validation compares the clustering with known true labels, as purity does. Only internal validation is available in practice, since a clustering problem is one where the labels are not known.

6. Define the silhouette coefficient and say why it can choose k when the sum of squares cannot. For each point, a is its mean distance to the other members of its own cluster, b is the smallest mean distance to any other cluster, and s is (b - a) divided by the larger of the two; the score is the mean over all points. The sum of squares falls with every extra cluster and is zero when each point is its own cluster, so it always prefers a larger k. The silhouette falls once k is too large, because splitting a genuine cluster leaves its halves close together and reduces b, so it has an interior maximum.

7. In this chapter the silhouette peaked at k = 5 for one method and k = 3 for another on data with three real groups. What follows? That an internal measure scores the shape of a clustering and not its correctness. Where the groups genuinely overlap, several numbers of clusters describe the geometry about equally well, and the margin between them, 0.0003 in one case, carries no information. A silhouette maximum can rule out an absurd k but should not be presented as proof of how many clusters the data has, and the per-point scores, two of which were negative here, say more than the mean.

Contents This chapter on its own page

munotes.in474

Chapter Seventy-Six

Support, Confidence and Lift

Syllabus topic Module 2, "Association rule mining"

In one line

An association rule says that baskets containing one set of items tend to contain another, and it takes three numbers to say whether that is worth anything.

Association rule mining, or market basket analysis, is unsupervised: there is no label and no target. The data is a list of transactions, each a set of items, and the output is a set of rules.

The vocabulary

TermMeaning
Transactionone basket: a set of items bought together
Itemone thing that can be in a basket
Itemsetany set of items
k-itemsetan itemset of exactly k items
Ruleif A then B, written A -> B, where A and B are disjoint itemsets
AntecedentA, the left side
ConsequentB, the right side

A and B must be disjoint. A rule with an item on both sides is trivially true and means nothing.

The three measures

Learn all three with their formulae. A paper asking about association rules is almost certainly asking about these.

support(A -> B) = support(A and B together)

the fraction of all baskets the rule is about

confidence(A -> B) = support(A and B) / support(A)

of the baskets containing A, the fraction that also contain B

lift(A -> B) = confidence(A -> B) / support(B)

how much more often B appears with A than it appears at all

And the reading of lift, which is what the measure is for:

LiftMeaning
= 1A tells you nothing about B: they are independent
> 1they occur together more often than independence would give
< 1they avoid each other

The measurement

# Support, confidence and lift on a basket of real-looking transactions, with the
# trap that makes the three measures necessary: a rule with 100 per cent
# confidence that says nothing at all.
from itertools import combinations

# 20 baskets from a college stationery counter. Deliberately built so that TEA is
# bought in nearly every basket, which is what breaks confidence.
BASKETS = [
    ("notebook", "pen", "tea"),
    ("notebook", "pen", "tea", "highlighter"),
    ("notebook", "pen", "tea"),
    ("notebook", "pen", "highlighter", "tea"),
    ("notebook", "pen", "tea"),
    ("notebook", "tea"),
    ("pen", "tea"),
    ("pen", "tea", "samosa"),
    ("tea", "samosa"),
    ("tea", "samosa"),
    ("tea", "samosa", "photocopy"),
    ("tea", "photocopy"),
    ("photocopy", "stapler", "tea"),
    ("photocopy", "stapler"),
    ("photocopy", "stapler", "tea"),
    ("notebook", "pen", "highlighter"),
    ("notebook", "highlighter", "tea"),
    ("tea",),
    ("tea", "samosa"),
    ("notebook", "pen", "tea", "samosa"),
]
ITEMS = sorted({i for b in BASKETS for i in b})
n = len(BASKETS)

def support(itemset):
    """The FRACTION of all baskets containing every item of the set."""
    s = set(itemset)
    return sum(1 for b in BASKETS if s <= set(b)) / n

def count(itemset):
    s = set(itemset)
    return sum(1 for b in BASKETS if s <= set(b))

print("%d BASKETS from a college stationery counter." % n)
for i, b in enumerate(BASKETS):
    print("   %2d: %s" % (i + 1, ", ".join(sorted(b))))
print()
print("SUPPORT of a single item: how often it appears at all.")
print("   item        | baskets | support")
for it in ITEMS:
    print("   %-11s | %7d | %.4f" % (it, count([it]), support([it])))
print()
print("   NOTE TEA: %d of %d baskets, support %.4f. keep that number in view;"
      % (count(["tea"]), n, support(["tea"])))
print("   everything that goes wrong below goes wrong because of it.")
print()

print("A RULE is written  if A then B, with A and B disjoint sets of items.")
print("THE THREE MEASURES:")
print("   support(A -> B)    = support(A and B together)")
print("                        how much of the data the rule is about")
print("   confidence(A -> B) = support(A and B) / support(A)")
print("                        of the baskets with A, the fraction that have B")
print("   lift(A -> B)       = confidence(A -> B) / support(B)")
print("                        how much MORE often B appears with A than at all")
print()
print("   lift = 1 means A tells you NOTHING about B.")
print("   lift > 1 means they occur together more often than chance.")
print("   lift < 1 means they AVOID each other.")
print()

def rule(a, b):
    sup = support(list(a) + list(b))
    conf = sup / support(a)
    lift = conf / support(b)
    return sup, conf, lift

RULES = [
    (("notebook",), ("pen",)),
    (("pen",), ("notebook",)),
    (("notebook", "pen"), ("highlighter",)),
    (("photocopy",), ("stapler",)),
    (("stapler",), ("photocopy",)),
    (("samosa",), ("tea",)),
    (("stapler",), ("tea",)),
    (("notebook",), ("samosa",)),
    (("samosa",), ("notebook",)),
    (("highlighter",), ("photocopy",)),
]
print("TEN RULES, MEASURED:")
print("   rule                                | support | confidence |   lift")
for a, b in RULES:
    sup, conf, lift = rule(a, b)
    print("   %-35s | %7.4f | %10.4f | %6.4f"
          % ("if " + "+".join(a) + " then " + "+".join(b), sup, conf, lift))
print()

sup, conf, lift = rule(("samosa",), ("tea",))
print("THE TRAP, AND IT IS THE POINT OF THE CHAPTER.")
print("   read 'if samosa then tea': support %.4f, confidence %.4f, lift %.4f."
      % (sup, conf, lift))
print("   EVERY ONE of the %d samosa baskets also had tea. a confidence of 1.0000"
      % count(["samosa"]))
print("   on six baskets reads like a law of the canteen.")
print("   it is nothing. tea is in %d of %d baskets anyway, so a rule predicting"
      % (count(["tea"]), n))
print("   tea from ANYTHING is right about %.0f per cent of the time by arithmetic"
      % (support(["tea"]) * 100))
print("   alone. the lift of %.4f is the honest figure: samosa buyers take tea" % lift)
print("   %.0f per cent more often than the counter's customers in general, which"
      % ((lift - 1) * 100))
print("   is almost exactly as often.")
print()
print("   A HIGH CONFIDENCE MEANS ONLY THAT THE CONSEQUENT IS COMMON, unless the")
print("   lift says otherwise. that is why the third measure exists.")
print()
sup, conf, lift = rule(("stapler",), ("tea",))
print("   and the same item can go the other way. 'if stapler then tea':")
print("   confidence %.4f, which is still a majority, and lift %.4f. stapler"
      % (conf, lift))
print("   buyers take tea about %.0f per cent LESS often than everyone else. the"
      % ((1 - lift) * 100))
print("   confidence hides a negative association completely.")
print()

print("CONFIDENCE IS ASYMMETRIC; LIFT IS SYMMETRIC. the same two items both ways:")
for a, b in ((("photocopy",), ("stapler",)), (("stapler",), ("photocopy",))):
    sup, conf, lift = rule(a, b)
    print("   if %-10s then %-10s : support %.4f, confidence %.4f, lift %.4f"
          % (a[0], b[0], sup, conf, lift))
print("   the confidences are %.4f and %.4f; the lifts are both %.4f."
      % (rule(("photocopy",), ("stapler",))[1], rule(("stapler",), ("photocopy",))[1],
         rule(("stapler",), ("photocopy",))[2]))
print("   every stapler basket had a photocopy, but only %d of the %d photocopy"
      % (count(["stapler", "photocopy"]), count(["photocopy"])))
print("   baskets had a stapler. and the lifts MUST agree, because")
print("      lift(A -> B) = support(A and B) / (support(A) * support(B))")
print("   which does not care which way round it is written.")
print("   SO LIFT MEASURES AN ASSOCIATION AND CONFIDENCE MEASURES A PREDICTION.")
print("   they answer different questions, and a paper may ask for exactly this.")
print()

print("NEGATIVE ASSOCIATION, which the measures can also find:")
for a, b in ((("notebook",), ("samosa",)), (("stapler",), ("tea",))):
    sup, conf, lift = rule(a, b)
    print("   if %-11s then %-10s : support %.4f, lift %.4f  (%d basket%s)"
          % (a[0], b[0], sup, lift,
             count([a[0], b[0]]), "" if count([a[0], b[0]]) == 1 else "s"))
print("   a lift below 1 means the pair occurs together LESS often than")
print("   independence would give. notebooks and samosas avoid each other")
print("   strongly: stationery and food are different errands.")
print()
print("   BUT LOOK AT THE BASKET COUNT. the notebook and samosa rule rests on")
print("   %d basket. a lift computed from %d observation is not a finding, and"
      % (count(["notebook", "samosa"]), count(["notebook", "samosa"])))
print("   the extreme case is worse still:")
sup, conf, lift = rule(("highlighter",), ("photocopy",))
print("      if highlighter then photocopy : support %.4f, confidence %.4f,"
      % (sup, conf))
print("      lift %.4f, on %d baskets." % (lift, count(["highlighter", "photocopy"])))
print("   a lift of exactly 0 does not mean the two CANNOT occur together. it")
print("   means they did not, in %d baskets, and with supports of %.2f and %.2f"
      % (n, support(["highlighter"]), support(["photocopy"])))
print("   independence would have predicted only %.1f such baskets anyway."
      % (n * support(["highlighter"]) * support(["photocopy"])))
print("   ABSENCE OF EVIDENCE IS NOT EVIDENCE OF AVOIDANCE.")
print()

print("WHY SUPPORT IS NEEDED AT ALL. every rule below has PERFECT confidence:")
perfect = []
for size in (1, 2):
    for a in combinations(ITEMS, size):
        for b in ITEMS:
            if b in a:
                continue
            if support(a) > 0 and abs(support(list(a) + [b]) / support(a) - 1.0) < 1e-12:
                perfect.append((a, (b,)))
for a, b in perfect:
    sup, conf, lift = rule(a, b)
    c = count(list(a) + list(b))
    print("   %-34s support %.4f (%d basket%s), lift %.4f%s"
          % ("if " + "+".join(a) + " then " + "+".join(b), sup, c,
             "" if c == 1 else "s", lift, "   <- one basket" if c == 1 else ""))
thin = [(a, b) for a, b in perfect if count(list(a) + list(b)) <= 2]
print("   %d of those %d rules rest on two baskets or fewer. confidence 1.0000"
      % (len(thin), len(perfect)))
print("   on one basket is not a pattern; it is a coincidence that has not yet")
print("   been contradicted. SUPPORT IS THE GUARD AGAINST THIS, and it is why")
print("   the next chapter's algorithm searches by support FIRST and computes")
print("   confidence only afterwards, on what survives.")
print()

print("A LAST WARNING. none of the three measures is evidence of CAUSE. the")
print("notebook and pen rule has a lift of %.4f, and nothing in the arithmetic"
      % rule(("notebook",), ("pen",))[2])
print("says whether buying a notebook causes the pen, the pen causes the")
print("notebook, or a term beginning causes both. the measures describe")
print("co-occurrence; the explanation has to come from outside them.")
munotes.in475

Support, Confidence and Lift

20 BASKETS from a college stationery counter.
    1: notebook, pen, tea
    2: highlighter, notebook, pen, tea
    3: notebook, pen, tea
    4: highlighter, notebook, pen, tea
    5: notebook, pen, tea
    6: notebook, tea
    7: pen, tea
    8: pen, samosa, tea
    9: samosa, tea
   10: samosa, tea
   11: photocopy, samosa, tea
   12: photocopy, tea
   13: photocopy, stapler, tea
   14: photocopy, stapler
   15: photocopy, stapler, tea
   16: highlighter, notebook, pen
   17: highlighter, notebook, tea
   18: tea
   19: samosa, tea
   20: notebook, pen, samosa, tea

SUPPORT of a single item: how often it appears at all.
   item        | baskets | support
   highlighter |       4 | 0.2000
   notebook    |       9 | 0.4500
   pen         |       9 | 0.4500
   photocopy   |       5 | 0.2500
   samosa      |       6 | 0.3000
   stapler     |       3 | 0.1500
   tea         |      18 | 0.9000

   NOTE TEA: 18 of 20 baskets, support 0.9000. keep that number in view;
   everything that goes wrong below goes wrong because of it.

A RULE is written  if A then B, with A and B disjoint sets of items.
THE THREE MEASURES:
   support(A -> B)    = support(A and B together)
                        how much of the data the rule is about
   confidence(A -> B) = support(A and B) / support(A)
                        of the baskets with A, the fraction that have B
   lift(A -> B)       = confidence(A -> B) / support(B)
                        how much MORE often B appears with A than at all

   lift = 1 means A tells you NOTHING about B.
   lift > 1 means they occur together more often than chance.
   lift < 1 means they AVOID each other.

TEN RULES, MEASURED:
   rule                                | support | confidence |   lift
   if notebook then pen                |  0.3500 |     0.7778 | 1.7284
   if pen then notebook                |  0.3500 |     0.7778 | 1.7284
   if notebook+pen then highlighter    |  0.1500 |     0.4286 | 2.1429
   if photocopy then stapler           |  0.1500 |     0.6000 | 4.0000
   if stapler then photocopy           |  0.1500 |     1.0000 | 4.0000
   if samosa then tea                  |  0.3000 |     1.0000 | 1.1111
   if stapler then tea                 |  0.1000 |     0.6667 | 0.7407
   if notebook then samosa             |  0.0500 |     0.1111 | 0.3704
   if samosa then notebook             |  0.0500 |     0.1667 | 0.3704
   if highlighter then photocopy       |  0.0000 |     0.0000 | 0.0000

THE TRAP, AND IT IS THE POINT OF THE CHAPTER.
   read 'if samosa then tea': support 0.3000, confidence 1.0000, lift 1.1111.
   EVERY ONE of the 6 samosa baskets also had tea. a confidence of 1.0000
   on six baskets reads like a law of the canteen.
   it is nothing. tea is in 18 of 20 baskets anyway, so a rule predicting
   tea from ANYTHING is right about 90 per cent of the time by arithmetic
   alone. the lift of 1.1111 is the honest figure: samosa buyers take tea
   11 per cent more often than the counter's customers in general, which
   is almost exactly as often.

   A HIGH CONFIDENCE MEANS ONLY THAT THE CONSEQUENT IS COMMON, unless the
   lift says otherwise. that is why the third measure exists.

   and the same item can go the other way. 'if stapler then tea':
   confidence 0.6667, which is still a majority, and lift 0.7407. stapler
   buyers take tea about 26 per cent LESS often than everyone else. the
   confidence hides a negative association completely.

CONFIDENCE IS ASYMMETRIC; LIFT IS SYMMETRIC. the same two items both ways:
   if photocopy  then stapler    : support 0.1500, confidence 0.6000, lift 4.0000
   if stapler    then photocopy  : support 0.1500, confidence 1.0000, lift 4.0000
   the confidences are 0.6000 and 1.0000; the lifts are both 4.0000.
   every stapler basket had a photocopy, but only 3 of the 5 photocopy
   baskets had a stapler. and the lifts MUST agree, because
      lift(A -> B) = support(A and B) / (support(A) * support(B))
   which does not care which way round it is written.
   SO LIFT MEASURES AN ASSOCIATION AND CONFIDENCE MEASURES A PREDICTION.
   they answer different questions, and a paper may ask for exactly this.

NEGATIVE ASSOCIATION, which the measures can also find:
   if notebook    then samosa     : support 0.0500, lift 0.3704  (1 basket)
   if stapler     then tea        : support 0.1000, lift 0.7407  (2 baskets)
   a lift below 1 means the pair occurs together LESS often than
   independence would give. notebooks and samosas avoid each other
   strongly: stationery and food are different errands.

   BUT LOOK AT THE BASKET COUNT. the notebook and samosa rule rests on
   1 basket. a lift computed from 1 observation is not a finding, and
   the extreme case is worse still:
      if highlighter then photocopy : support 0.0000, confidence 0.0000,
      lift 0.0000, on 0 baskets.
   a lift of exactly 0 does not mean the two CANNOT occur together. it
   means they did not, in 20 baskets, and with supports of 0.20 and 0.25
   independence would have predicted only 1.0 such baskets anyway.
   ABSENCE OF EVIDENCE IS NOT EVIDENCE OF AVOIDANCE.

WHY SUPPORT IS NEEDED AT ALL. every rule below has PERFECT confidence:
   if highlighter then notebook       support 0.2000 (4 baskets), lift 2.2222
   if samosa then tea                 support 0.3000 (6 baskets), lift 1.1111
   if stapler then photocopy          support 0.1500 (3 baskets), lift 4.0000
   if highlighter+pen then notebook   support 0.1500 (3 baskets), lift 2.2222
   if highlighter+tea then notebook   support 0.1500 (3 baskets), lift 2.2222
   if notebook+samosa then pen        support 0.0500 (1 basket), lift 2.2222   <- one basket
   if notebook+samosa then tea        support 0.0500 (1 basket), lift 1.1111   <- one basket
   if pen+samosa then tea             support 0.1000 (2 baskets), lift 1.1111
   if photocopy+samosa then tea       support 0.0500 (1 basket), lift 1.1111   <- one basket
   if stapler+tea then photocopy      support 0.1000 (2 baskets), lift 4.0000
   5 of those 10 rules rest on two baskets or fewer. confidence 1.0000
   on one basket is not a pattern; it is a coincidence that has not yet
   been contradicted. SUPPORT IS THE GUARD AGAINST THIS, and it is why
   the next chapter's algorithm searches by support FIRST and computes
   confidence only afterwards, on what survives.

A LAST WARNING. none of the three measures is evidence of CAUSE. the
notebook and pen rule has a lift of 1.7284, and nothing in the arithmetic
says whether buying a notebook causes the pen, the pen causes the
notebook, or a term beginning causes both. the measures describe
co-occurrence; the explanation has to come from outside them.
munotes.in476

Support, Confidence and Lift

The trap

The chapter is this one rule. if samosa then tea:

munotes.in477

Support, Confidence and Lift

support0.3000, six baskets
confidence1.0000
lift1.1111
munotes.in478

Support, Confidence and Lift

Every one of the six samosa baskets also contained tea. A confidence of 1.0000 on six baskets reads like a law of the canteen, and it is nothing at all. Tea is in 18 of 20 baskets anyway, so a rule predicting tea from anything is right about 90 per cent of the time by arithmetic alone. The lift of 1.1111 is the honest figure: samosa buyers take tea 11 per cent more often than the counter's customers in general, which is to say about as often.

munotes.in479

Support, Confidence and Lift

A high confidence means only that the consequent is common, unless the lift says otherwise. That is why the third measure exists, and it is the single most examinable point in the topic.

munotes.in480

Support, Confidence and Lift

And the same item can run the other way without the confidence showing it. if stapler then tea has a confidence of 0.6667, still a majority, and a lift of 0.7407: stapler buyers take tea about 26 per cent less often than everyone else. The confidence hides a negative association completely.

Confidence is asymmetric, lift is symmetric

The same two items both ways:

RuleSupportConfidenceLift
if photocopy then stapler0.15000.60004.0000
if stapler then photocopy0.15001.00004.0000

Every stapler basket had a photocopy, but only 3 of the 5 photocopy baskets had a stapler. The confidences differ; the lifts are identical, and they must be, because lift can be written

lift(A -> B) = support(A and B) / ( support(A) * support(B) )

which does not care which way round the rule is written.

So: lift measures an association, confidence measures a prediction. They answer different questions. If the question is "what should I put next to the photocopier", the direction matters and confidence is the measure. If it is "are these two things related at all", direction is meaningless and lift is the measure.

Negative association, and a warning about counting

A lift below 1 is a real finding, and often more useful than a positive one:

RuleSupportLiftBaskets
if notebook then samosa0.05000.37041
if stapler then tea0.10000.74072

Notebooks and samosas avoid each other strongly: stationery and food are different errands.

But look at the basket count. The first rule rests on one basket. A lift computed from one observation is not a finding, and the extreme case is worse: if highlighter then photocopy has a support of 0.0000, a confidence of 0.0000 and a lift of exactly 0, on zero baskets.

A lift of 0 does not mean the two cannot occur together. It means they did not, in twenty baskets, and with supports of 0.20 and 0.25 independence would have predicted only 1.0 such basket anyway. Absence of evidence is not evidence of avoidance, and a lift of 0 on a pair that was never likely to co-occur is a statement about the sample size.

Why support is needed at all

Ten rules in this data have a confidence of exactly 1.0000, and five of them rest on two baskets or fewer, three on a single basket.

Confidence 1.0000 on one basket is not a pattern; it is a coincidence that has not yet been contradicted. Support is the guard against it, and it is why The Apriori Algorithm searches by support first and computes confidence only afterwards, on what survives.

munotes.in481

Support, Confidence and Lift

So the three measures divide the work cleanly, and this is the way to remember them:

MeasureThe question it answersWhat it guards against
Supportis the rule about enough of the dataa coincidence on two baskets
Confidencewhen A happens, how often does Ban unreliable prediction
Liftdoes A tell me anything about B at alla common consequent

Three further measures, named

Worth knowing by name, since a question may mention them.

DefinitionReads
Leveragesupport(A and B) - support(A) * support(B)the same idea as lift, as a difference rather than a ratio, so it also accounts for how big the rule is
Conviction(1 - support(B)) / (1 - confidence(A -> B))how much more often the rule would be broken if A and B were independent
Minimum thresholdsminsup and minconfthe two numbers a mining run is given, and the answer depends entirely on them

The choice of minsup is not a technicality. Too high and every rule found is obvious; too low and the number of rules explodes past the point where anyone can read them.

What the measures cannot do

None of the three is evidence of cause. The notebook and pen rule has a lift of 1.7284, and nothing in the arithmetic says whether buying the notebook causes the pen, the pen causes the notebook, or the start of a term causes both.

Two further limits worth stating, because they are the usual criticisms:

The rare item problem. A high minsup throws away every rule about an item that is seldom bought, and those are often the profitable ones. Lowering minsup to catch them produces an unreadable number of rules about common items.

Too many rules. With m items there are 3m - 2(m+1) + 1 possible rules, so a real catalogue produces more rules than any person can inspect, and the output must itself be ranked and filtered.

Distinctions

SupportConfidenceLift
Depends on the directionnoyesno
Range0 to 10 to 10 upwards
Value under independencethe product of the twosupport(B)1
Guards againsta tiny samplea weak predictiona common consequent
if samosa then tea0.30001.00001.1111
A useful ruleThe trap here
Confidencehigh1.0000
Liftclearly above 11.1111
Exampleif stapler then photocopy, lift 4.0000if samosa then tea
ClassificationAssociation rules
Targetone named labelany item can be the consequent
Supervisedyesno
Outputone modelmany rules
Judged byaccuracy, F1support, confidence, lift, and a person
munotes.in482

Support, Confidence and Lift

What it does not mean

A confidence of 1.0000 is not a discovery. Here it belongs to a rule with a lift of 1.1111.

Lift is not a direction. It is identical both ways, so it cannot say which item to place where.

A lift of 0 is not proof that two items repel. With these supports, independence predicted one such basket in twenty.

A rule with high support is not therefore interesting. Common items give high support and low lift.

No measure here shows cause. Co-occurrence is all that is measured.

The rules are not a model. They are a list of observations that a person must still read and judge.

Quick revision

  • Data: transactions of items. A rule A -> B has disjoint antecedent and consequent.
  • support(A -> B) = support(A and B). confidence = support(A and B) / support(A). lift = confidence / support(B), equivalently support(A and B) / (support(A) * support(B)).
  • Lift = 1 means independence; above 1, association; below 1, avoidance.
  • The trap: if samosa then tea, confidence 1.0000, lift 1.1111, because tea is in 18 of 20 baskets. A high confidence means only that the consequent is common.
  • if stapler then tea: confidence 0.6667, lift 0.7407. A majority confidence concealing a 26 per cent negative association.
  • Confidence is asymmetric, lift is symmetric: photocopy -> stapler 0.6000 and stapler -> photocopy 1.0000, both lift 4.0000. Lift measures association; confidence measures a prediction.
  • Ten rules here have confidence 1.0000 and five rest on two baskets or fewer. Support is the guard, which is why Apriori searches by support first.
  • A lift of 0 on 0 baskets is not avoidance: independence predicted only 1.0 such basket.
  • Named also: leverage (a difference instead of a ratio), conviction, and the thresholds minsup and minconf, on which the whole output depends.
  • Limits: no causation; the rare item problem (a high minsup hides the profitable items); and too many rules, 3m - 2(m+1) + 1 possible for m items.

Test yourself

1. Define support, confidence and lift. Support of a rule is the fraction of all transactions containing every item of both sides. Confidence is the support of both sides divided by the support of the antecedent, that is, the proportion of baskets containing the antecedent that also contain the consequent. Lift is the confidence divided by the support of the consequent, equivalently the support of both sides divided by the product of the two separate supports.

munotes.in483

Support, Confidence and Lift

2. A rule has a confidence of 1.0000 and a lift of 1.1111. What has been found? Almost nothing. The consequent is present in about 90 per cent of all baskets, so predicting it from any antecedent succeeds nearly always by arithmetic. The lift shows the antecedent raises its frequency by only about a tenth, so the rule is barely different from independence.

3. Why is confidence asymmetric and lift not? Confidence divides by the support of the antecedent, which changes when the rule is reversed: here photocopy to stapler gives 0.6000 and stapler to photocopy gives 1.0000. Lift can be written as the support of both items divided by the product of their separate supports, an expression that is unchanged by swapping them, so both directions give 4.0000.

4. What does a lift below 1 mean, and what must be checked before believing it? That the items occur together less often than independence would predict, so they avoid one another. The number of transactions behind the rule must be checked: the notebook and samosa rule has a lift of 0.3704 from a single basket, and the highlighter and photocopy pair has a lift of exactly 0 from none, where independence would have predicted only one such basket in twenty. Absence of evidence is not evidence of avoidance.

5. Why is support needed if confidence and lift are available? Because confidence and lift can both be computed from a handful of transactions and mean nothing there. Ten rules in this data have a confidence of exactly 1.0000 and five of them rest on two baskets or fewer, three on one. Support measures whether the rule concerns enough of the data to be worth examining, which is why mining filters by support before anything else.

6. State the rare item problem. A minimum support high enough to keep the number of rules manageable discards every rule concerning items that are bought seldom, and those are frequently the most profitable. Lowering the threshold to include them produces so many rules about common items that the output cannot be read.

7. Do these measures establish cause? Justify. No. They measure co-occurrence only. A lift of 1.7284 between notebooks and pens is consistent with the notebook purchase prompting the pen, the pen purchase prompting the notebook, or a third circumstance such as the start of a term prompting both, and the arithmetic cannot distinguish them. An explanation must come from knowledge outside the transaction data.

Contents This chapter on its own page

munotes.in484

Chapter Seventy-Seven

The Apriori Algorithm

Syllabus topic Module 2, "Association rule mining (Apriori concept)"

In one line

Find the frequent itemsets one size at a time, using the fact that a set cannot be frequent unless every one of its subsets is.

Support, Confidence and Lift gave the measures and said that support must be checked first. This chapter is the algorithm that does it, published by Agrawal and Srikant in 1994 and still the standard treatment of the problem.

The problem

With m items there are 2m - 1 non-empty itemsets. Seven items give 127, which can be counted directly. A shop with ten thousand items gives 210000, which cannot be written down, let alone counted.

And the database is usually too large to hold in memory, so the number of passes over the data matters as much as the number of itemsets.

The one property that makes it possible

Downward closure, also called the Apriori property or anti-monotonicity:

if an itemset is frequent, EVERY subset of it is frequent

equivalently: if ANY subset is infrequent, the set cannot be frequent

The proof is one line, and papers ask for it: every basket containing the whole set contains each of its subsets, so a subset's count is at least the set's count, and its support is at least the set's support.

The second form is the useful one, because it lets a candidate be rejected without being counted. That is the entire saving.

The algorithm

Two steps per level, repeated until nothing survives.

  1. Level 1: count every single item; keep those with support at least minsup. Call the survivors L1.
  2. For k = 2, 3, ...
  • Join: form candidates of size k by joining pairs of L(k-1) sets that agree on their first k - 2 items.
  • Prune: discard any candidate that has an infrequent subset of size k - 1. No counting here.
  • Count the survivors in one pass over the database and keep those with support at least minsup. These are Lk.
  1. Stop when Lk is empty. The frequent itemsets are the union of all the Lk.
  2. Generate rules from each frequent itemset of two or more items, and keep those whose confidence reaches minconf.

Note the structure: support is used to search, confidence only afterwards. The search is by support because support has downward closure and confidence does not.

The run

# Apriori, run in full on the same 20 baskets: every candidate set, every count,
# the pruning step doing its work, the rules generated afterwards, and the cost
# against counting every possible itemset.
from itertools import combinations

BASKETS = [
    ("notebook", "pen", "tea"),
    ("notebook", "pen", "tea", "highlighter"),
    ("notebook", "pen", "tea"),
    ("notebook", "pen", "highlighter", "tea"),
    ("notebook", "pen", "tea"),
    ("notebook", "tea"),
    ("pen", "tea"),
    ("pen", "tea", "samosa"),
    ("tea", "samosa"),
    ("tea", "samosa"),
    ("tea", "samosa", "photocopy"),
    ("tea", "photocopy"),
    ("photocopy", "stapler", "tea"),
    ("photocopy", "stapler"),
    ("photocopy", "stapler", "tea"),
    ("notebook", "pen", "highlighter"),
    ("notebook", "highlighter", "tea"),
    ("tea",),
    ("tea", "samosa"),
    ("notebook", "pen", "tea", "samosa"),
]
SETS = [set(b) for b in BASKETS]
ITEMS = sorted({i for b in BASKETS for i in b})
n = len(BASKETS)
MINSUP = 0.15          # 3 baskets in 20
MINCONF = 0.70

counted = 0            # how many itemsets were counted against the database
passes = 0             # how many times the database was read

def count(itemset):
    global counted
    counted += 1
    s = set(itemset)
    return sum(1 for b in SETS if s <= b)

def support(itemset):
    return count(itemset) / n

print("THE PROBLEM. %d items means %d non-empty itemsets to consider:"
      % (len(ITEMS), 2 ** len(ITEMS) - 1))
print("   %s" % ", ".join(ITEMS))
print("   counting all %d against %d baskets is possible here and is not possible"
      % (2 ** len(ITEMS) - 1, n))
print("   at all in a shop with 10000 items, where the number is 2**10000.")
print()
print("THE ONE PROPERTY THAT SAVES IT: DOWNWARD CLOSURE, also called the apriori")
print("property or anti-monotonicity.")
print("   IF AN ITEMSET IS FREQUENT, EVERY SUBSET OF IT IS FREQUENT.")
print("   equivalently: if any subset is INFREQUENT, the set cannot be frequent.")
print("   the reason is one line: every basket containing the whole set contains")
print("   each of its subsets, so a subset's count is at least the set's count.")
print()
print("   checked on this data, for every frequent pair and triple:")
ok = bad = 0
for size in (2, 3):
    for c in combinations(ITEMS, size):
        s = set(c)
        cnt = sum(1 for b in SETS if s <= b)
        if cnt / n >= MINSUP:
            for k in range(1, size):
                for sub in combinations(c, k):
                    ss = set(sub)
                    subcnt = sum(1 for b in SETS if ss <= b)
                    if subcnt >= cnt:
                        ok += 1
                    else:
                        bad += 1
print("      %d subset comparisons, %d of them consistent, %d violations."
      % (ok + bad, ok, bad))
print()
print("MINIMUM SUPPORT %.2f, which is %d baskets of %d. MINIMUM CONFIDENCE %.2f."
      % (MINSUP, round(MINSUP * n), n, MINCONF))
print()

def apriori():
    global passes
    frequent = {}
    # ---- level 1: every single item -----------------------------------------
    passes += 1
    level = []
    print("LEVEL 1. count every item.")
    print("   itemset               | baskets | support | kept")
    for it in ITEMS:
        c = count([it])
        keep = c / n >= MINSUP
        print("   %-21s | %7d | %7.4f | %s" % (it, c, c / n, "yes" if keep else "NO"))
        if keep:
            level.append((it,))
            frequent[(it,)] = c
    print("   L1 has %d itemsets." % len(level))
    print()
    k = 2
    while level:
        # ---- JOIN: two frequent (k-1)-sets sharing their first k-2 items ----
        cands = []
        for i in range(len(level)):
            for j in range(i + 1, len(level)):
                a, b = level[i], level[j]
                if a[:k - 2] == b[:k - 2]:
                    cands.append(tuple(sorted(set(a) | set(b))))
        cands = sorted(set(c for c in cands if len(c) == k))
        print("LEVEL %d. JOIN gives %d candidate%s."
              % (k, len(cands), "" if len(cands) == 1 else "s"))
        # ---- PRUNE: drop any candidate with an infrequent (k-1)-subset ------
        kept, pruned = [], []
        for c in cands:
            subs = [tuple(s) for s in combinations(c, k - 1)]
            if all(s in frequent for s in subs):
                kept.append(c)
            else:
                missing = [s for s in subs if s not in frequent]
                pruned.append((c, missing[0]))
        if pruned:
            print("   PRUNE removes %d of them WITHOUT COUNTING ANYTHING:" % len(pruned))
            for c, miss in pruned:
                print("      %-30s because %s is not frequent"
                      % ("+".join(c), "+".join(miss)))
        else:
            print("   PRUNE removes none.")
        if not kept:
            print("   nothing left to count. the algorithm stops.")
            print()
            break
        passes += 1
        print("   COUNT the %d survivor%s:" % (len(kept), "" if len(kept) == 1 else "s"))
        print("   itemset                    | baskets | support | kept")
        level = []
        for c in kept:
            cnt = count(c)
            keep = cnt / n >= MINSUP
            print("   %-26s | %7d | %7.4f | %s"
                  % ("+".join(c), cnt, cnt / n, "yes" if keep else "NO"))
            if keep:
                level.append(c)
                frequent[c] = cnt
        print("   L%d has %d itemset%s." % (k, len(level), "" if len(level) == 1 else "s"))
        print()
        k += 1
    return frequent

frequent = apriori()
print("THE FREQUENT ITEMSETS, all of them:")
for size in sorted({len(k) for k in frequent}):
    rows = sorted(k for k in frequent if len(k) == size)
    print("   size %d: %s" % (size, ";  ".join("+".join(r) for r in rows)))
print()
print("THE COST, MEASURED.")
print("   itemsets counted against the database : %d" % counted)
print("   every possible non-empty itemset      : %d" % (2 ** len(ITEMS) - 1))
print("   passes over the database              : %d" % passes)
print("   apriori counted %.0f per cent of the itemsets a brute force would."
      % (100.0 * counted / (2 ** len(ITEMS) - 1)))
print("   the saving here is modest because %d items is a toy. the saving is the"
      % len(ITEMS))
print("   difference between possible and impossible on a real catalogue, and it")
print("   comes entirely from the prune step, which rejects candidates WITHOUT")
print("   LOOKING AT THE DATA AT ALL.")
print()

print("GENERATING THE RULES. for each frequent itemset of 2 or more items, every")
print("way of splitting it into a non-empty antecedent and a non-empty")
print("consequent is a candidate rule; keep those above the confidence threshold.")
print("   rule                                    | support | conf   |   lift")
rules = []
for iset, cnt in frequent.items():
    if len(iset) < 2:
        continue
    for r in range(1, len(iset)):
        for a in combinations(iset, r):
            b = tuple(x for x in iset if x not in a)
            conf = cnt / frequent[tuple(sorted(a))]
            lift = conf / (frequent[tuple(sorted(b))] / n
                           if tuple(sorted(b)) in frequent
                           else sum(1 for bk in SETS if set(b) <= bk) / n)
            rules.append((conf, lift, a, b, cnt / n))
for conf, lift, a, b, sup in sorted(rules, reverse=True):
    if conf >= MINCONF:
        print("   %-39s | %7.4f | %6.4f | %6.4f"
              % ("if " + "+".join(a) + " then " + "+".join(b), sup, conf, lift))
print()
print("   %d of the %d candidate rules pass the confidence threshold."
      % (sum(1 for c, _, _, _, _ in rules if c >= MINCONF), len(rules)))
print("   NOTE THE LIFT COLUMN. several rules above %.2f confidence have a lift"
      % MINCONF)
print("   near 1, and they are the tea rules again: high confidence because tea")
print("   is everywhere. apriori CANNOT filter these out, because it never looks")
print("   at lift. the filtering is the analyst's job and it is not optional.")
print()

print("THE THRESHOLD DECIDES EVERYTHING. the same data at four minimum supports:")
print("   minsup | baskets | frequent itemsets | largest itemset | rules above %.2f"
      % MINCONF)
for ms in (0.05, 0.10, 0.15, 0.25, 0.50):
    freq = {}
    for size in range(1, len(ITEMS) + 1):
        for c in combinations(ITEMS, size):
            s = set(c)
            cnt = sum(1 for b in SETS if s <= b)
            if cnt / n >= ms:
                freq[c] = cnt
    biggest = max((len(k) for k in freq), default=0)
    nrules = 0
    for iset, cnt in freq.items():
        if len(iset) < 2:
            continue
        for r in range(1, len(iset)):
            for a in combinations(iset, r):
                if cnt / freq[tuple(sorted(a))] >= MINCONF:
                    nrules += 1
    print("   %6.2f | %7d | %17d | %15d | %d"
          % (ms, round(ms * n), len(freq), biggest, nrules))
print("   at %.2f a 'finding' can rest on a single basket; at %.2f only tea"
      % (0.05, 0.50))
print("   itself survives and there are no rules at all.")
print("   THERE IS NO CORRECT VALUE. the threshold is a decision about how much")
print("   of the data a finding must cover before it is worth reading, and it is")
print("   made by the person, not by the algorithm.")
munotes.in485

The Apriori Algorithm

THE PROBLEM. 7 items means 127 non-empty itemsets to consider:
   highlighter, notebook, pen, photocopy, samosa, stapler, tea
   counting all 127 against 20 baskets is possible here and is not possible
   at all in a shop with 10000 items, where the number is 2**10000.

THE ONE PROPERTY THAT SAVES IT: DOWNWARD CLOSURE, also called the apriori
property or anti-monotonicity.
   IF AN ITEMSET IS FREQUENT, EVERY SUBSET OF IT IS FREQUENT.
   equivalently: if any subset is INFREQUENT, the set cannot be frequent.
   the reason is one line: every basket containing the whole set contains
   each of its subsets, so a subset's count is at least the set's count.

   checked on this data, for every frequent pair and triple:
      36 subset comparisons, 36 of them consistent, 0 violations.

MINIMUM SUPPORT 0.15, which is 3 baskets of 20. MINIMUM CONFIDENCE 0.70.

LEVEL 1. count every item.
   itemset               | baskets | support | kept
   highlighter           |       4 |  0.2000 | yes
   notebook              |       9 |  0.4500 | yes
   pen                   |       9 |  0.4500 | yes
   photocopy             |       5 |  0.2500 | yes
   samosa                |       6 |  0.3000 | yes
   stapler               |       3 |  0.1500 | yes
   tea                   |      18 |  0.9000 | yes
   L1 has 7 itemsets.

LEVEL 2. JOIN gives 21 candidates.
   PRUNE removes none.
   COUNT the 21 survivors:
   itemset                    | baskets | support | kept
   highlighter+notebook       |       4 |  0.2000 | yes
   highlighter+pen            |       3 |  0.1500 | yes
   highlighter+photocopy      |       0 |  0.0000 | NO
   highlighter+samosa         |       0 |  0.0000 | NO
   highlighter+stapler        |       0 |  0.0000 | NO
   highlighter+tea            |       3 |  0.1500 | yes
   notebook+pen               |       7 |  0.3500 | yes
   notebook+photocopy         |       0 |  0.0000 | NO
   notebook+samosa            |       1 |  0.0500 | NO
   notebook+stapler           |       0 |  0.0000 | NO
   notebook+tea               |       8 |  0.4000 | yes
   pen+photocopy              |       0 |  0.0000 | NO
   pen+samosa                 |       2 |  0.1000 | NO
   pen+stapler                |       0 |  0.0000 | NO
   pen+tea                    |       8 |  0.4000 | yes
   photocopy+samosa           |       1 |  0.0500 | NO
   photocopy+stapler          |       3 |  0.1500 | yes
   photocopy+tea              |       4 |  0.2000 | yes
   samosa+stapler             |       0 |  0.0000 | NO
   samosa+tea                 |       6 |  0.3000 | yes
   stapler+tea                |       2 |  0.1000 | NO
   L2 has 9 itemsets.

LEVEL 3. JOIN gives 5 candidates.
   PRUNE removes 1 of them WITHOUT COUNTING ANYTHING:
      photocopy+stapler+tea          because stapler+tea is not frequent
   COUNT the 4 survivors:
   itemset                    | baskets | support | kept
   highlighter+notebook+pen   |       3 |  0.1500 | yes
   highlighter+notebook+tea   |       3 |  0.1500 | yes
   highlighter+pen+tea        |       2 |  0.1000 | NO
   notebook+pen+tea           |       6 |  0.3000 | yes
   L3 has 3 itemsets.

LEVEL 4. JOIN gives 1 candidate.
   PRUNE removes 1 of them WITHOUT COUNTING ANYTHING:
      highlighter+notebook+pen+tea   because highlighter+pen+tea is not frequent
   nothing left to count. the algorithm stops.

THE FREQUENT ITEMSETS, all of them:
   size 1: highlighter;  notebook;  pen;  photocopy;  samosa;  stapler;  tea
   size 2: highlighter+notebook;  highlighter+pen;  highlighter+tea;  notebook+pen;  notebook+tea;  pen+tea;  photocopy+stapler;  photocopy+tea;  samosa+tea
   size 3: highlighter+notebook+pen;  highlighter+notebook+tea;  notebook+pen+tea

THE COST, MEASURED.
   itemsets counted against the database : 32
   every possible non-empty itemset      : 127
   passes over the database              : 3
   apriori counted 25 per cent of the itemsets a brute force would.
   the saving here is modest because 7 items is a toy. the saving is the
   difference between possible and impossible on a real catalogue, and it
   comes entirely from the prune step, which rejects candidates WITHOUT
   LOOKING AT THE DATA AT ALL.

GENERATING THE RULES. for each frequent itemset of 2 or more items, every
way of splitting it into a non-empty antecedent and a non-empty
consequent is a candidate rule; keep those above the confidence threshold.
   rule                                    | support | conf   |   lift
   if stapler then photocopy               |  0.1500 | 1.0000 | 4.0000
   if highlighter+tea then notebook        |  0.1500 | 1.0000 | 2.2222
   if highlighter+pen then notebook        |  0.1500 | 1.0000 | 2.2222
   if highlighter then notebook            |  0.2000 | 1.0000 | 2.2222
   if samosa then tea                      |  0.3000 | 1.0000 | 1.1111
   if pen then tea                         |  0.4000 | 0.8889 | 0.9877
   if notebook then tea                    |  0.4000 | 0.8889 | 0.9877
   if notebook+pen then tea                |  0.3000 | 0.8571 | 0.9524
   if photocopy then tea                   |  0.2000 | 0.8000 | 0.8889
   if pen then notebook                    |  0.3500 | 0.7778 | 1.7284
   if notebook then pen                    |  0.3500 | 0.7778 | 1.7284
   if highlighter then notebook+pen        |  0.1500 | 0.7500 | 2.1429
   if highlighter then notebook+tea        |  0.1500 | 0.7500 | 1.8750
   if pen+tea then notebook                |  0.3000 | 0.7500 | 1.6667
   if notebook+tea then pen                |  0.3000 | 0.7500 | 1.6667
   if highlighter+notebook then pen        |  0.1500 | 0.7500 | 1.6667
   if highlighter then pen                 |  0.1500 | 0.7500 | 1.6667
   if highlighter+notebook then tea        |  0.1500 | 0.7500 | 0.8333
   if highlighter then tea                 |  0.1500 | 0.7500 | 0.8333

   19 of the 36 candidate rules pass the confidence threshold.
   NOTE THE LIFT COLUMN. several rules above 0.70 confidence have a lift
   near 1, and they are the tea rules again: high confidence because tea
   is everywhere. apriori CANNOT filter these out, because it never looks
   at lift. the filtering is the analyst's job and it is not optional.

THE THRESHOLD DECIDES EVERYTHING. the same data at four minimum supports:
   minsup | baskets | frequent itemsets | largest itemset | rules above 0.70
     0.05 |       1 |                31 |               4 | 28
     0.10 |       2 |                25 |               4 | 22
     0.15 |       3 |                19 |               3 | 19
     0.25 |       5 |                10 |               3 | 8
     0.50 |      10 |                 1 |               1 | 0
   at 0.05 a 'finding' can rest on a single basket; at 0.50 only tea
   itself survives and there are no rules at all.
   THERE IS NO CORRECT VALUE. the threshold is a decision about how much
   of the data a finding must cover before it is worth reading, and it is
   made by the person, not by the algorithm.
munotes.in486

The Apriori Algorithm

Reading the levels

minsup = 0.15, which is 3 baskets of 20, and minconf = 0.70.

munotes.in487

The Apriori Algorithm

LevelCandidates after joinRemoved by pruneCountedFrequent
17 items77
2210219
35143
41100, so it stops
munotes.in488

The Apriori Algorithm

Level 2 can never prune anything, and it is worth knowing why. A candidate pair's only subsets of size 1 are its two items, and both came from L1, so both are frequent by construction. Pruning begins to earn its keep at level 3.

munotes.in489

The Apriori Algorithm

And at level 3 it earns it visibly: photocopy+stapler+tea is rejected because stapler+tea is not frequent, and it is rejected without touching the data. At level 4 the single candidate highlighter+notebook+pen+tea goes the same way, because highlighter+pen+tea had only two baskets, and with nothing left to count the algorithm terminates.

munotes.in490

The Apriori Algorithm

The stopping condition is Lk empty, not k reaching some limit. The largest frequent itemset here has three items, and the algorithm discovers that rather than being told it.

The cost

Itemsets counted against the database32
Every possible non-empty itemset127
Passes over the database3

Apriori counted 25 per cent of what brute force would. Be honest about the size of that: seven items is a toy, and a quarter is not a dramatic saving. The point is not the ratio here but that the saving comes from a step that rejects candidates without looking at the data at all, and on a real catalogue that is the difference between possible and impossible.

And note the three passes. Apriori needs one pass per level, so the number of database reads is the size of the largest frequent itemset plus one. That is its main practical cost and the thing its successors attack: FP-growth builds a compressed tree of the transactions and needs only two passes, and is the algorithm actually used on large data.

Generating the rules

Each frequent itemset of size k can be split into an antecedent and a consequent in 2k - 2 ways, and every split is a candidate rule. Nineteen of the thirty-six candidates** pass a confidence of 0.70.

The best of them:

RuleSupportConfidenceLift
if stapler then photocopy0.15001.00004.0000
if highlighter then notebook0.20001.00002.2222
if samosa then tea0.30001.00001.1111
if pen then tea0.40000.88890.9877
if photocopy then tea0.20000.80000.8889
if notebook then pen0.35000.77781.7284

Read the lift column. if pen then tea has a confidence of 0.8889 and a lift of 0.9877, which is below 1: pen buyers take tea slightly less often than the counter's customers in general. if photocopy then tea is worse, at 0.8889 lift. Both passed the confidence threshold comfortably.

munotes.in491

The Apriori Algorithm

Apriori cannot filter these out, because it never looks at lift. It filters by support and then by confidence, and both of those measures are satisfied by a common consequent. The filtering by lift is the analyst's job, done afterwards, and it is not optional.

The threshold decides everything

minsupBasketsFrequent itemsetsLargest itemsetRules above 0.70
0.05131428
0.10225422
0.15319319
0.2551038
0.5010110

At 0.05 a finding can rest on a single basket. At 0.50 only tea itself survives and there are no rules at all.

There is no correct value. The threshold is a decision about how much of the data a finding must cover before it is worth reading, and it is made by the person. Two consequences worth stating: the output size is extremely sensitive to it, and any published set of rules is meaningless without the thresholds that produced it.

The weaknesses, and what replaced it

A paper asking for Apriori's limitations wants these.

WeaknessWhy
One pass per levelexpensive when the data does not fit in memory
Candidate generationthe number of candidates can still be enormous at level 2, where L1 of m frequent items gives m(m-1)/2 pairs
The rare item problema minsup low enough to catch uncommon items floods the output
No account of liftthe rules it returns include ones with a lift below 1
Binary onlyan item is present or absent; quantities and prices are ignored

FP-growth is the standard successor: it builds an FP-tree, a compressed representation of all the transactions, in two passes, and then mines it recursively with no candidate generation at all. It is faster and it is harder to explain, which is why Apriori is what is taught: the Apriori property is the idea, and FP-growth is an implementation of the same insight.

Distinctions

SupportConfidence
Has downward closureyesno
Used forthe searchfiltering afterwards
Order in the algorithmfirstsecond
JoinPrune
Producescandidates of size ka shorter list of the same
Reads the databasenono
Level 221 candidatesremoves 0, necessarily
Level 35 candidatesremoves 1
AprioriFP-growth
Passes over the dataone per level, 3 here2
Candidate generationyesnone
Data structurelists of candidatesan FP-tree
Easier to explainyesno
munotes.in492

The Apriori Algorithm

What it does not mean

Apriori does not find rules. It finds frequent itemsets; the rules are generated afterwards.

The prune step does not count anything. That is the whole point of it.

Pruning at level 2 is not a saving. It can never remove a candidate there.

Apriori does not stop at a fixed size. It stops when a level is empty, which is how it discovers that the largest frequent itemset has three items.

A rule Apriori returns is not necessarily interesting. Several here have a lift below 1.

The rule set is not a property of the data alone. It is a property of the data and the two thresholds.

Apriori is not the algorithm used at scale. FP-growth is.

Quick revision

  • m items give 2m - 1 itemsets: 127 for 7, and 210000 for a real shop.
  • Downward closure: if an itemset is frequent every subset is, so if any subset is infrequent the set cannot be. Proof: a basket containing the set contains every subset, so the subset's count is at least as large.
  • The algorithm: count single items to get L1; then join, prune, count, per level; stop when a level is empty; then generate rules.
  • Support searches, confidence filters afterwards, because support has downward closure and confidence does not.
  • Measured at minsup = 0.15 and minconf = 0.70: levels of 7, 21, 5, 1 candidates, pruning 0, then 1, then 1; frequent itemsets 7, 9, 3; it stops at level 4.
  • Level 2 can never prune, since a pair's single-item subsets are both in L1. Level 3 rejects photocopy+stapler+tea because stapler+tea is not frequent, without reading the data.
  • Cost: 32 itemsets counted against 127 possible, and 3 passes, one per level.
  • 19 of 36 candidate rules pass the confidence threshold, and several have a lift below 1: if pen then tea is 0.8889 confidence and 0.9877 lift. Apriori never looks at lift, so filtering by it is the analyst's job.
  • Thresholds decide everything: minsup of 0.05 gives 31 itemsets and 28 rules; 0.50 gives 1 itemset and no rules. There is no correct value, and a rule set is meaningless without its thresholds.
  • Weaknesses: one pass per level, candidate explosion at level 2, the rare item problem, no account of lift, binary items only. FP-growth replaces it: an FP-tree in two passes with no candidate generation.

Test yourself

1. State the Apriori property and prove it. If an itemset is frequent then every subset of it is frequent; equivalently, if any subset is infrequent then the set cannot be frequent. Every transaction containing the whole itemset necessarily contains each of its subsets, so a subset's count is at least the count of the set and its support is at least the set's support.

munotes.in493

The Apriori Algorithm

2. Describe the algorithm. Count each single item and keep those reaching the minimum support, giving L1. Then for each k from 2: join pairs of frequent (k-1)-itemsets that agree on their first k-2 items to form candidates; prune any candidate having an infrequent subset of size k-1, without counting; count the survivors in one pass over the data and keep those reaching minimum support. Stop when a level yields nothing, then generate rules from the frequent itemsets and keep those reaching the minimum confidence.

3. Why is the search done by support rather than by confidence? Because support has the downward closure property and confidence does not. A set's support cannot exceed that of any of its subsets, which allows candidates to be discarded without counting; nothing comparable holds for confidence, so it can only be applied to itemsets already found.

4. Why can the prune step never remove anything at level 2? A candidate pair's only subsets of size one are its two items, and both were taken from L1, so both are frequent by construction. Pruning first becomes useful at level 3.

5. Give an example of the prune step working, from this chapter. At level 3 the candidate photocopy, stapler and tea was discarded because the pair stapler and tea had only two baskets and so was not frequent. It was rejected without being counted at all. At level 4 the only candidate was discarded for the same reason.

6. Apriori returned a rule with a confidence of 0.8889 and a lift of 0.9877. What does that show about the algorithm? That Apriori filters by support and then by confidence and never examines lift, so it will return rules whose consequent is simply common. Here pen buyers take tea slightly less often than customers in general, yet the rule passes both thresholds. Filtering by lift must be done by the analyst afterwards.

7. How does FP-growth improve on Apriori? It makes two passes over the data instead of one per level, building an FP-tree that holds the transactions in compressed form, and then mines the frequent itemsets recursively from that tree with no candidate generation at all. It rests on the same downward closure insight but avoids both the repeated scans and the candidate lists.

Contents This chapter on its own page

munotes.in494

Chapter Seventy-Eight

The Reinforcement Learning Framework

Syllabus topic Module 2, "Reinforcement learning framework"

In one line

An agent acts, the world answers with a number, and the agent must work out for itself which of its past actions earned it.

This is the third setting in the syllabus, after supervised and unsupervised learning, and it is different from both in a way worth being precise about.

The vocabulary

Every one of these will be used in the next three chapters.

TermMeaning
Agentthe thing that chooses
Environmenteverything else
Statewhat the agent observes at a step
Actionwhat it may do
Rewarda single number the environment returns
Policya rule giving an action for each state, written as a mapping
Returnthe total reward from a step onwards, usually discounted
Valuethe expected return from a state under a policy
Episodeone run from a start state to a terminal state

Keep reward and value apart. A reward is what arrives at one step; a value is the whole future expected from a state. A state with reward 0 can have a high value, because of what follows it.

Three ways it differs from supervised learning

A paper asking "how does reinforcement learning differ" wants these three, not one.

1. The feedback is evaluative, not instructive. Supervised learning is told the correct label. A reinforcement learner is told how good its action was and never what it should have done.

2. The reward is delayed. The move that lost the game may be the tenth before the end, and the agent must work out which of its past actions to credit or blame. This is the credit assignment problem, and it is the central difficulty.

3. The agent generates its own data. What the agent sees depends on what it did, so a poor policy collects a poor data set and may never observe the states where it would have learned better. Nothing in supervised learning has this property, and it is the reason for the whole exploration question below.

The measurement

# The reinforcement learning setting, measured: what a reward is, why a discount
# changes the answer rather than only the arithmetic, and why an agent that
# always takes the best known action can be permanently wrong.
def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(4242)
rnd = lambda: next(gen)                                   # noqa: E731

print("THE SETTING. an AGENT acts in an ENVIRONMENT. at each step it observes a")
print("STATE, chooses an ACTION, receives a REWARD and lands in a new state. it")
print("is told NOTHING about which action was right; only the reward arrives.")
print()
print("   policy   : a rule giving the action to take in each state")
print("   return   : the total reward from a step onwards, usually DISCOUNTED")
print("   value    : the expected return from a state under a policy")
print("   episode  : one run from a start state to a terminal state")
print()
print("WHAT MAKES IT DIFFERENT FROM SUPERVISED LEARNING")
print("   the feedback is a REWARD, not a correct answer: the agent is told how")
print("      good its action was, never what it should have done.")
print("   the reward is DELAYED: the move that lost the game may be the tenth")
print("      before the end. this is the CREDIT ASSIGNMENT problem.")
print("   the data is not given: the agent's own actions decide what it sees,")
print("      so a bad policy collects a bad data set.")
print()

print("A CORRIDOR, to show what the discount actually does.")
print("   five rooms in a line. from the start the agent may go LEFT and collect")
print("   5 after one step, or go RIGHT and collect 20 after four steps.")
print("   which is better is NOT a fact about the corridor. it depends on the")
print("   discount factor, and the discount factor is part of the problem.")
print()
print("      gamma | left: 5 after 1 step | right: 20 after 4 steps | choose")
for g in (0.5, 0.7, 0.8, 0.9, 0.95, 1.0):
    left = g ** 1 * 5
    right = g ** 4 * 20
    print("      %5.2f | %20.4f | %23.4f | %s"
          % (g, left, right, "LEFT" if left > right else "RIGHT"))
print()
print("   the switch happens where gamma**1 * 5 = gamma**4 * 20, that is where")
print("   gamma**3 = 0.25, at gamma = %.4f. BELOW it the agent is short sighted"
      % (0.25 ** (1.0 / 3)))
print("   and takes the near reward; above it, patient.")
print()
print("   AND WHY DISCOUNT AT ALL, since it changes the answer?")
print("      1. a reward now is worth more than the same reward later, which is")
print("         true of money, of marks and of most things.")
print("      2. without it, a task that never ends has an INFINITE return and")
print("         every policy is equally good. with gamma below 1 the sum")
print("         converges: a reward of 1 for ever is worth 1/(1-gamma) =")
print("         %.1f at gamma = 0.9, not infinity." % (1 / (1 - 0.9)))
print("      3. it expresses uncertainty about the future continuing at all.")
print()

print("EXPLORATION AGAINST EXPLOITATION, which is the other thing that makes")
print("reinforcement learning hard. three actions with unknown payoffs:")
ARMS = [("A", 0.30), ("B", 0.55), ("C", 0.50)]
print("   action | true probability of a reward of 1")
for name, p in ARMS:
    print("   %6s | %.2f" % (name, p))
print("   the agent is NOT told these. it must find the best by trying.")
print()

def pull(i):
    return 1.0 if rnd() < ARMS[i][1] else 0.0

def run(epsilon, steps, seed):
    """Try each action ONCE, then act. Ties are broken by the lowest index, so
    the first pulls matter: that is the whole point of the measurement."""
    global gen, rnd
    gen = lcg(seed)
    rnd = lambda: next(gen)                               # noqa: E731
    total = [0.0] * len(ARMS)
    tries = [0] * len(ARMS)
    reward = 0.0
    for i in range(len(ARMS)):
        r = pull(i)
        total[i] += r
        tries[i] += 1
        reward += r
    for _ in range(steps - len(ARMS)):
        means = [total[i] / tries[i] for i in range(len(ARMS))]
        if rnd() < epsilon:
            i = min(int(rnd() * len(ARMS)), len(ARMS) - 1)
        else:
            i = max(range(len(ARMS)), key=lambda j: means[j])
        r = pull(i)
        total[i] += r
        tries[i] += 1
        reward += r
    means = [total[i] / tries[i] for i in range(len(ARMS))]
    believes = ARMS[max(range(len(ARMS)), key=lambda j: means[j])][0]
    return reward, tries, believes

print("   PURE EXPLOITATION, epsilon = 0: try each action once, then always take")
print("   the one with the best average so far. ten runs of 500 steps:")
print("      run | reward | times each action was taken | believes best")
wrong = 0
for s in range(10):
    reward, tries, believes = run(0.0, 500, 1000 + s * 7919)
    if believes != "B":
        wrong += 1
    print("      %3d | %6.0f | %-27s | %s" % (s + 1, reward, str(tries), believes))
print("   %d of 10 runs ended believing the wrong action was best, and in every" % wrong)
print("   one of those the agent had stopped trying the others ENTIRELY. a greedy")
print("   agent whose first pull of the best action happens to pay nothing will")
print("   never pull it again, because pulling it is not the best action")
print("   according to what it knows. the mistake is permanent.")
print()
print("   EPSILON-GREEDY, epsilon = 0.10: take a random action one time in ten.")
print("      run | reward | times each action was taken | believes best")
wrong2 = 0
for s in range(10):
    reward, tries, believes = run(0.10, 500, 1000 + s * 7919)
    if believes != "B":
        wrong2 += 1
    print("      %3d | %6.0f | %-27s | %s" % (s + 1, reward, str(tries), believes))
print("   %d of 10 runs ended on the wrong action, and every action is still" % wrong2)
print("   being sampled, so a wrong belief can still be corrected.")
print()
print("   AND THE COST OF EXPLORING, over 2000 steps:")
print("      epsilon | mean reward over 10 runs | runs believing the best action")
for eps in (0.0, 0.01, 0.05, 0.10, 0.30, 1.0):
    tot, right = 0.0, 0
    for s in range(10):
        reward, tries, believes = run(eps, 2000, 1000 + s * 7919)
        tot += reward
        if believes == "B":
            right += 1
    print("      %7.2f | %24.1f | %d of 10" % (eps, tot / 10, right))
print()
print("   READ THE TWO COLUMNS TOGETHER, because neither alone is the answer.")
print("   epsilon = 0 is the cheapest policy and the least reliable. epsilon = 1")
print("   never stops exploring: it identifies the best action most often and")
print("   collects the AVERAGE payoff of the three, because it never uses what")
print("   it has learnt. the useful values are in between, and the whole subject")
print("   of reinforcement learning is spent between them.")
print()
print("   IN PRACTICE epsilon is DECAYED: explore heavily at first and less as")
print("   the estimates settle, which buys the identification without paying for")
print("   it for ever.")
munotes.in495

The Reinforcement Learning Framework

THE SETTING. an AGENT acts in an ENVIRONMENT. at each step it observes a
STATE, chooses an ACTION, receives a REWARD and lands in a new state. it
is told NOTHING about which action was right; only the reward arrives.

   policy   : a rule giving the action to take in each state
   return   : the total reward from a step onwards, usually DISCOUNTED
   value    : the expected return from a state under a policy
   episode  : one run from a start state to a terminal state

WHAT MAKES IT DIFFERENT FROM SUPERVISED LEARNING
   the feedback is a REWARD, not a correct answer: the agent is told how
      good its action was, never what it should have done.
   the reward is DELAYED: the move that lost the game may be the tenth
      before the end. this is the CREDIT ASSIGNMENT problem.
   the data is not given: the agent's own actions decide what it sees,
      so a bad policy collects a bad data set.

A CORRIDOR, to show what the discount actually does.
   five rooms in a line. from the start the agent may go LEFT and collect
   5 after one step, or go RIGHT and collect 20 after four steps.
   which is better is NOT a fact about the corridor. it depends on the
   discount factor, and the discount factor is part of the problem.

      gamma | left: 5 after 1 step | right: 20 after 4 steps | choose
       0.50 |               2.5000 |                  1.2500 | LEFT
       0.70 |               3.5000 |                  4.8020 | RIGHT
       0.80 |               4.0000 |                  8.1920 | RIGHT
       0.90 |               4.5000 |                 13.1220 | RIGHT
       0.95 |               4.7500 |                 16.2901 | RIGHT
       1.00 |               5.0000 |                 20.0000 | RIGHT

   the switch happens where gamma**1 * 5 = gamma**4 * 20, that is where
   gamma**3 = 0.25, at gamma = 0.6300. BELOW it the agent is short sighted
   and takes the near reward; above it, patient.

   AND WHY DISCOUNT AT ALL, since it changes the answer?
      1. a reward now is worth more than the same reward later, which is
         true of money, of marks and of most things.
      2. without it, a task that never ends has an INFINITE return and
         every policy is equally good. with gamma below 1 the sum
         converges: a reward of 1 for ever is worth 1/(1-gamma) =
         10.0 at gamma = 0.9, not infinity.
      3. it expresses uncertainty about the future continuing at all.

EXPLORATION AGAINST EXPLOITATION, which is the other thing that makes
reinforcement learning hard. three actions with unknown payoffs:
   action | true probability of a reward of 1
        A | 0.30
        B | 0.55
        C | 0.50
   the agent is NOT told these. it must find the best by trying.

   PURE EXPLOITATION, epsilon = 0: try each action once, then always take
   the one with the best average so far. ten runs of 500 steps:
      run | reward | times each action was taken | believes best
        1 |    152 | [498, 1, 1]                 | A
        2 |    275 | [1, 498, 1]                 | B
        3 |    281 | [1, 498, 1]                 | B
        4 |    249 | [1, 1, 498]                 | C
        5 |    282 | [1, 496, 3]                 | B
        6 |    296 | [1, 498, 1]                 | B
        7 |    150 | [498, 1, 1]                 | A
        8 |    139 | [498, 1, 1]                 | A
        9 |    270 | [3, 495, 2]                 | B
       10 |    268 | [5, 493, 2]                 | B
   4 of 10 runs ended believing the wrong action was best, and in every
   one of those the agent had stopped trying the others ENTIRELY. a greedy
   agent whose first pull of the best action happens to pay nothing will
   never pull it again, because pulling it is not the best action
   according to what it knows. the mistake is permanent.

   EPSILON-GREEDY, epsilon = 0.10: take a random action one time in ten.
      run | reward | times each action was taken | believes best
        1 |    269 | [25, 456, 19]               | B
        2 |    271 | [17, 461, 22]               | B
        3 |    266 | [18, 466, 16]               | B
        4 |    259 | [13, 29, 458]               | C
        5 |    260 | [22, 104, 374]              | B
        6 |    292 | [22, 459, 19]               | B
        7 |    261 | [17, 465, 18]               | B
        8 |    235 | [44, 26, 430]               | C
        9 |    262 | [18, 458, 24]               | B
       10 |    279 | [19, 461, 20]               | B
   2 of 10 runs ended on the wrong action, and every action is still
   being sampled, so a wrong belief can still be corrected.

   AND THE COST OF EXPLORING, over 2000 steps:
      epsilon | mean reward over 10 runs | runs believing the best action
         0.00 |                    949.7 | 6 of 10
         0.01 |                   1044.1 | 8 of 10
         0.05 |                   1075.9 | 8 of 10
         0.10 |                   1075.4 | 10 of 10
         0.30 |                   1034.5 | 9 of 10
         1.00 |                    911.5 | 10 of 10

   READ THE TWO COLUMNS TOGETHER, because neither alone is the answer.
   epsilon = 0 is the cheapest policy and the least reliable. epsilon = 1
   never stops exploring: it identifies the best action most often and
   collects the AVERAGE payoff of the three, because it never uses what
   it has learnt. the useful values are in between, and the whole subject
   of reinforcement learning is spent between them.

   IN PRACTICE epsilon is DECAYED: explore heavily at first and less as
   the estimates settle, which buys the identification without paying for
   it for ever.
munotes.in496

The Reinforcement Learning Framework

The discount factor changes the answer

Five rooms in a line. From the start, going left collects 5 after one step; going right collects 20 after four steps. Which is better?

munotes.in497

The Reinforcement Learning Framework

gammaLeft, 5 after 1 stepRight, 20 after 4 stepsChoose
0.502.50001.2500LEFT
0.703.50004.8020RIGHT
0.904.500013.1220RIGHT
1.005.000020.0000RIGHT
munotes.in498

The Reinforcement Learning Framework

The question has no answer until gamma is fixed. The switch is where gamma1 5 = gamma4 20, that is gamma3 = 0.25, at gamma = 0.6300**. Below it the agent is short-sighted and takes the near reward; above it, patient.

munotes.in499

The Reinforcement Learning Framework

So the discount factor is part of the problem, not a setting of the solver. A paper that treats gamma as a tuning knob like a learning rate has misunderstood it: changing gamma changes which policy is optimal.

And why discount at all, given that it changes the answer. Three reasons, all worth giving:

1A reward now is worth more than the same reward later, which is true of money, of marks, and of most things.
2Without it, a task that never ends has an infinite return and every policy is equally good. With gamma below 1 the sum converges: a reward of 1 for ever is worth 1/(1 - gamma), which is 10.0 at gamma = 0.9, not infinity.
3It expresses uncertainty about whether the future will arrive at all.

Episodic tasks, which end, can use gamma = 1 safely. Continuing tasks, which do not, cannot.

Exploration against exploitation

The second difficulty, and the one that has no clean solution. Three actions, with unknown payoff probabilities of 0.30, 0.55 and 0.50. The agent must find the best by trying.

munotes.in500

The Reinforcement Learning Framework

Pure exploitation, epsilon = 0: try each action once, then always take the one with the best average.

RunRewardTimes each action takenBelieves best
1152498, 1, 1A, the worst
22751, 498, 1B
42491, 1, 498C

The agent commits to whichever action happened to pay on its single first trial, and in run 1 that was the worst of the three, pulled 498 times out of 500. Four of ten runs ended believing the wrong action was best, and in every one of them the other actions had stopped being tried at all.

The trap stated plainly: an agent whose first trial of the best action pays nothing will never try it again, because trying it is not the best action according to what it knows. The mistake is self-sealing and permanent.

Epsilon-greedy is the standard repair: with probability epsilon, take a random action; otherwise take the best known one. At epsilon = 0.10, two of ten runs ended on the wrong action, and every action was still being sampled, so a wrong belief could still be corrected.

The cost of exploring, measured

epsilonMean reward over 2000 stepsRuns believing the best action
0.00949.76 of 10
0.011044.18 of 10
0.051075.98 of 10
0.101075.410 of 10
0.301034.59 of 10
1.00911.510 of 10

Read both columns together, because neither alone is the answer.

epsilon = 0 collects the least and is the least reliable. epsilon = 1 identifies the best action every time and collects the least but one, because it never uses what it has learned: it earns the average payoff of the three actions for ever. The best total is around 0.05 to 0.10, which explores enough to be sure and then spends most of its steps on the answer.

In practice epsilon is decayed: explore heavily at first and less as the estimates settle, which buys the identification without paying for it for ever. Optimistic initial values are the other standard trick: start every action's estimate too high, so that any action not yet tried looks attractive and gets tried once by a purely greedy agent.

Designing the reward

The reward is not given by nature; somebody writes it, and a badly written one is the commonest cause of a strange policy.

DangerWhat happens
Reward hackingthe agent finds a way to earn the number without doing the intended task
Rewarding the method rather than the goalthe agent does the method and not the goal; reward the outcome
Sparse rewardsnothing but a win at the end gives almost no signal to learn from
Shapingintermediate rewards help, and can change the optimal policy if added carelessly
munotes.in501

The Reinforcement Learning Framework

The reward hypothesis is the assumption the whole field rests on: that every goal can be expressed as the maximisation of the expected value of a single scalar reward. It is an assumption, and Ethical Issues in AI Systems returns to what happens when a real objective does not fit in one number.

Where it is used

FieldThe reward
Board and video gameswinning
Robot controlstaying upright, reaching a target
Recommendationa click, a purchase, time spent
Scheduling and routingthroughput, delay avoided
Tuning a large language modela human preference between two answers

The third row is worth pausing over: a system rewarded for time spent will learn to hold attention, which is not the same as being useful, and that is reward hacking in production rather than in a laboratory.

Distinctions

SupervisedReinforcement
Feedbackthe correct answera number
Whenimmediatelydelayed
Datagiventhe agent's own actions decide it
Difficultygeneralisationcredit assignment, exploration
RewardValue
Coversone stepthe whole future
Given bythe environmentestimated by the agent
A state with reward 0is worth nothing nowmay be worth a great deal
epsilon = 0epsilon = 1
Exploresneveralways
Reward here949.7911.5
Found the best6 of 1010 of 10
Fails bycommitting to a mistakenever using what it knows

What it does not mean

Reinforcement learning is not supervised learning with delayed labels. There is no label at any point; only a number saying how good the action was.

The discount factor is not a tuning parameter. It changes which policy is optimal, here at gamma 0.6300.

Gamma below 1 is not always required. Episodic tasks can use 1; continuing tasks cannot, or the return is infinite.

A greedy agent does not converge on the best action. Here it committed to the worst action in one run of ten and never revisited it.

More exploration is not better. epsilon = 1 identified the best action every time and earned less than epsilon = 0.05.

A high reward is not evidence of the intended behaviour. That is reward hacking.

Quick revision

  • Agent, environment, state, action, reward, policy, return, value, episode. A reward is one step; a value is the expected return from a state.
  • Three differences from supervised learning: feedback is evaluative, not instructive; the reward is delayed, giving the credit assignment problem; the agent's actions generate its own data.
  • The discount changes the answer. 5 after one step against 20 after four: LEFT below gamma = 0.6300, RIGHT above, since the switch is at gamma**3 = 0.25.
  • Why discount: a reward now is worth more; a continuing task would otherwise have infinite return, whereas 1/(1-gamma) is 10.0 at gamma = 0.9; and the future may not arrive. Episodic tasks may use gamma = 1, continuing ones may not.
  • Greedy fails permanently. Three actions at 0.30, 0.55, 0.50: a purely greedy agent commits to whichever paid on its single first trial, took the worst action 498 times in one run, and ended wrong in 4 of 10.
  • Epsilon-greedy at 0.10: wrong in 2 of 10, and still sampling everything.
  • Cost of exploring over 2000 steps: 0.00 gives 949.7 and 6 of 10; 0.05 gives 1075.9; 0.10 gives 1075.4 and 10 of 10; 1.00 gives 911.5 and 10 of 10. The best totals are in between.
  • Practice: decay epsilon, or use optimistic initial values.
  • Reward design: beware reward hacking, rewarding the method instead of the goal, and sparse rewards; shaping helps and can change the optimal policy. The reward hypothesis is that any goal can be written as one scalar to maximise.
munotes.in502

The Reinforcement Learning Framework

Test yourself

1. Give three ways reinforcement learning differs from supervised learning. The feedback is a reward saying how good the action was rather than the correct answer; the reward is delayed, so the agent must decide which earlier action to credit, which is the credit assignment problem; and the agent's own choices determine what data it sees, so a poor policy can collect data that never reveals a better one.

2. Distinguish a reward from a value. A reward is the single number the environment returns at one step. A value is the expected total discounted reward from a state onwards under a policy, so a state paying nothing immediately can still have a high value because of what follows it.

3. Show that the discount factor can change which policy is optimal. Take 5 available after one step against 20 after four. The first is worth gamma 5 and the second gamma4 20, which are equal when gamma3 = 0.25, at gamma about 0.6300. Below that value the nearer reward is preferred and above it the larger one, so the optimal policy depends on gamma and gamma is part of the problem statement.

4. Give three reasons for discounting. A reward received now is worth more than the same reward later. Without discounting a task that never terminates has infinite return and every policy is equally good, whereas with gamma below one the sum converges, a unit reward for ever being worth 1/(1-gamma), or 10 at gamma 0.9. And discounting expresses uncertainty about whether the future will arrive at all.

munotes.in503

The Reinforcement Learning Framework

5. Why can a purely greedy agent be permanently wrong? Because its estimate of an action can only improve if it takes that action, and it will not take an action its current estimate says is inferior. If the best action happens to pay nothing on its first trial, its estimate stays low for ever and it is never tried again. In the measurement, four runs in ten ended believing a worse action was best, one of them having taken the worst of three actions 498 times out of 500.

6. What does the measurement show about the value of exploring? That both extremes are poor. With no exploration the agent earned 949.7 over 2000 steps and found the best action in only six runs of ten. With continuous exploration it found the best action every time and earned 911.5, because it never used what it knew. Values around 0.05 to 0.10 earned about 1075 and identified the best action reliably.

7. What is reward hacking, and how does the reward hypothesis relate to it? Reward hacking is the agent finding a way to earn the reward without performing the intended task, such as a recommender rewarded for time spent learning to hold attention rather than to be useful. The reward hypothesis, that every goal can be expressed as maximising a single scalar reward, is what makes the problem tractable, and reward hacking is what happens when the scalar chosen is not in fact the goal.

Contents This chapter on its own page

munotes.in504

Chapter Seventy-Nine

Markov Decision Processes

Syllabus topic Module 2, "Markov Decision Processes"

In one line

A Markov decision process is the formal statement of a reinforcement learning problem: states, actions, a transition model, a reward and a discount.

The Reinforcement Learning Framework described the setting in words. This chapter writes it down, and being able to write it down is what makes the next chapter's equations possible.

The five parts

A paper asking "define an MDP" wants exactly these, with the Markov property stated.

Sthe set of states
Athe set of actions
Pthe transition model, P(s' given s, a)the probability of landing in s'
Rthe rewardattached to a state, or to a transition
gammathe discount factorbetween 0 and 1

Note what is not in the list: any mention of time, of history, or of how the agent got to a state.

The measurement

# A Markov decision process written out in full: the five parts, the transition
# model checked, and three fixed policies EVALUATED so that the difference
# between judging a policy and finding one is visible.
COLS, ROWS = 4, 3
WALL = (1, 1)
TERMINAL = {(3, 2): 1.0, (3, 1): -1.0}
START = (0, 0)
LIVING = -0.04          # the reward for being in any non-terminal square
GAMMA = 1.0
ACTIONS = ["N", "S", "E", "W"]
MOVE = {"N": (0, 1), "S": (0, -1), "E": (1, 0), "W": (-1, 0)}
# A slip sends the agent at right angles to the way it meant to go.
SIDEWAYS = {"N": ("W", "E"), "S": ("E", "W"), "E": ("N", "S"), "W": ("S", "N")}
P_INTENDED, P_SLIP = 0.8, 0.1

STATES = [(c, r) for r in range(ROWS) for c in range(COLS) if (c, r) != WALL]

def legal(s):
    c, r = s
    return 0 <= c < COLS and 0 <= r < ROWS and (c, r) != WALL

def move(s, a):
    """Walking into a wall or off the edge leaves the agent where it was."""
    d = MOVE[a]
    t = (s[0] + d[0], s[1] + d[1])
    return t if legal(t) else s

def transitions(s, a):
    """P(s' | s, a) as a list of (probability, next state)."""
    left, right = SIDEWAYS[a]
    out = {}
    for p, act in ((P_INTENDED, a), (P_SLIP, left), (P_SLIP, right)):
        t = move(s, act)
        out[t] = out.get(t, 0.0) + p
    return [(p, t) for t, p in sorted(out.items())]

def reward(s):
    return TERMINAL[s] if s in TERMINAL else LIVING

def draw(grid, fmt="%6s"):
    for r in range(ROWS - 1, -1, -1):
        line = "   "
        for c in range(COLS):
            line += fmt % ("#" if (c, r) == WALL else grid.get((c, r), "."))
        print(line.rstrip())

print("A MARKOV DECISION PROCESS HAS FIVE PARTS.")
print("   S      the set of states")
print("   A      the set of actions")
print("   P      the transition model, P(s' | s, a)")
print("   R      the reward")
print("   gamma  the discount factor")
print()
print("THE GRID. the robot starts at the bottom left and is trying to reach the")
print("+1 square. # is a pillar it cannot enter.")
labels = {t: "%+.0f" % v for t, v in TERMINAL.items()}
labels[START] = "start"
draw(labels)
print()
print("   S: %d squares, two of them terminal." % len(STATES))
print("   A: %s. gamma = %.2f. reward %.2f in every non-terminal square,"
      % (", ".join(ACTIONS), GAMMA, LIVING))
print("      %+.0f and %+.0f in the two terminal ones."
      % (TERMINAL[(3, 2)], TERMINAL[(3, 1)]))
print()
print("   P: THE FLOOR IS SLIPPERY. an action goes the intended way with")
print("      probability %.1f and at right angles with probability %.1f each."
      % (P_INTENDED, P_SLIP))
print("      walking into the pillar or off the edge leaves the robot where it was.")
print()
print("   one state and action written out in full, from %s going N:" % str((0, 0)))
for p, t in transitions((0, 0), "N"):
    why = "intended" if t == (0, 1) else ("blocked, stays put" if t == (0, 0) else "slipped")
    print("      P(%s | %s, N) = %.1f   (%s)" % (str(t), str((0, 0)), p, why))
print("   and from %s going N, where the pillar is above:" % str((1, 0)))
for p, t in transitions((1, 0), "N"):
    why = "blocked by the pillar, stays put" if t == (1, 0) else "slipped"
    print("      P(%s | %s, N) = %.1f   (%s)" % (str(t), str((1, 0)), p, why))
print()
bad = 0
for s in STATES:
    if s in TERMINAL:
        continue
    for a in ACTIONS:
        tot = sum(p for p, _ in transitions(s, a))
        if abs(tot - 1.0) > 1e-12:
            bad += 1
print("   CHECKED: for all %d non-terminal states and %d actions the transition"
      % (len(STATES) - len(TERMINAL), len(ACTIONS)))
print("   probabilities sum to 1. violations: %d." % bad)
print()

print("THE MARKOV PROPERTY, which is what the M stands for.")
print("   P(s' | s, a) depends on the CURRENT state and action only. how the")
print("   robot reached (2,1) does not change what happens next from (2,1).")
print("   THAT IS AN ASSUMPTION ABOUT THE PROBLEM, and it is what lets a policy")
print("   be a function of the state alone rather than of the whole history.")
print()
print("A POLICY maps each state to an action. for an MDP with a fixed discount")
print("an optimal policy can always be taken to be")
print("   DETERMINISTIC: no need to randomise, since one action is at least as")
print("      good as any mixture of actions.")
print("   STATIONARY: the same in a state whenever it is visited, since the")
print("      future from a state does not depend on the time of arrival.")
print("   so the search is over %d**%d = %d policies, which is finite and far"
      % (len(ACTIONS), len(STATES) - len(TERMINAL),
         len(ACTIONS) ** (len(STATES) - len(TERMINAL))))
print("   too many to try one at a time.")
print()

def evaluate(policy, tol=1e-10):
    """POLICY EVALUATION: the value of every state UNDER A GIVEN POLICY.
    V(s) = R(s) + gamma * sum over s' of P(s' | s, policy(s)) * V(s')"""
    V = {s: 0.0 for s in STATES}
    for s in TERMINAL:
        V[s] = TERMINAL[s]
    sweeps = 0
    while True:
        sweeps += 1
        delta = 0.0
        for s in STATES:
            if s in TERMINAL:
                continue
            total = sum(p * V[t] for p, t in transitions(s, policy[s]))
            new = reward(s) + GAMMA * total
            delta = max(delta, abs(new - V[s]))
            V[s] = new
        if delta < tol:
            return V, sweeps

def show_policy(policy):
    g = dict(policy)
    for t, v in TERMINAL.items():
        g[t] = "%+.0f" % v
    draw(g)

print("EVALUATING A FIXED POLICY. this is the PREDICTION problem: not 'what")
print("should the robot do' but 'how good is this particular rule'.")
print()
POLICIES = {
    "always north": {s: "N" for s in STATES if s not in TERMINAL},
    "always east": {s: "E" for s in STATES if s not in TERMINAL},
    "along the bottom and up the right hand side": {
        (0, 0): "E", (1, 0): "E", (2, 0): "E", (3, 0): "N",
        (0, 1): "N", (2, 1): "N",
        (0, 2): "E", (1, 2): "E", (2, 2): "E"},
    "up the left hand side and along the top": {
        (0, 0): "N", (1, 0): "E", (2, 0): "N", (3, 0): "W",
        (0, 1): "N", (2, 1): "N",
        (0, 2): "E", (1, 2): "E", (2, 2): "E"},
}
for name, pol in POLICIES.items():
    V, sweeps = evaluate(pol)
    print("   %s" % name.upper())
    show_policy(pol)
    print("   its values:")
    draw({s: "%+.3f" % V[s] for s in STATES}, fmt="%9s")
    print("   value of the start square: %+.4f, after %d sweeps."
          % (V[START], sweeps))
    print()

print("READ THE FOUR START VALUES TOGETHER:")
for name, pol in POLICIES.items():
    V, _ = evaluate(pol)
    print("   %+.4f   %s" % (V[START], name))
print()
v_north = evaluate(POLICIES["always north"])[0][START]
v_right = evaluate(POLICIES["along the bottom and up the right hand side"])[0][START]
v_top = evaluate(POLICIES["up the left hand side and along the top"])[0][START]
print("   'always north' is worth %+.4f: the robot presses into the top wall and"
      % v_north)
print("   reaches the goal only by slipping sideways along the top row.")
print("   'always east' is worth %+.4f, because from the bottom right corner it"
      % evaluate(POLICIES["always east"])[0][START])
print("   presses east into the edge and slips into the -1 square.")
print()
print("   AND THE TWO ROUTES THAT LOOK SENSIBLE ON THE MAP ARE %+.4f APART."
      % (v_top - v_right))
print("   going right along the bottom and up the right hand side is the SHORTER")
print("   route, and it is worth %+.4f, because the only way up the right hand" % v_right)
print("   column passes through the -1 square. going up the left and along the")
print("   top is longer, costs more steps at %.2f each, and is worth %+.4f."
      % (LIVING, v_top))
print("   THE SHORT ROUTE ON THE MAP IS THE BAD POLICY, and no amount of looking")
print("   at the grid says so. only the evaluation does.")
print()
print("NOTICE WHAT EVALUATION DOES NOT DO. it scores a policy that was handed to")
print("it; it never proposes one. finding the best policy is the CONTROL problem")
print("and it needs the next chapter's equations.")
munotes.in505

Markov Decision Processes

A MARKOV DECISION PROCESS HAS FIVE PARTS.
   S      the set of states
   A      the set of actions
   P      the transition model, P(s' | s, a)
   R      the reward
   gamma  the discount factor

THE GRID. the robot starts at the bottom left and is trying to reach the
+1 square. # is a pillar it cannot enter.
        .     .     .    +1
        .     #     .    -1
    start     .     .     .

   S: 11 squares, two of them terminal.
   A: N, S, E, W. gamma = 1.00. reward -0.04 in every non-terminal square,
      +1 and -1 in the two terminal ones.

   P: THE FLOOR IS SLIPPERY. an action goes the intended way with
      probability 0.8 and at right angles with probability 0.1 each.
      walking into the pillar or off the edge leaves the robot where it was.

   one state and action written out in full, from (0, 0) going N:
      P((0, 0) | (0, 0), N) = 0.1   (blocked, stays put)
      P((0, 1) | (0, 0), N) = 0.8   (intended)
      P((1, 0) | (0, 0), N) = 0.1   (slipped)
   and from (1, 0) going N, where the pillar is above:
      P((0, 0) | (1, 0), N) = 0.1   (slipped)
      P((1, 0) | (1, 0), N) = 0.8   (blocked by the pillar, stays put)
      P((2, 0) | (1, 0), N) = 0.1   (slipped)

   CHECKED: for all 9 non-terminal states and 4 actions the transition
   probabilities sum to 1. violations: 0.

THE MARKOV PROPERTY, which is what the M stands for.
   P(s' | s, a) depends on the CURRENT state and action only. how the
   robot reached (2,1) does not change what happens next from (2,1).
   THAT IS AN ASSUMPTION ABOUT THE PROBLEM, and it is what lets a policy
   be a function of the state alone rather than of the whole history.

A POLICY maps each state to an action. for an MDP with a fixed discount
an optimal policy can always be taken to be
   DETERMINISTIC: no need to randomise, since one action is at least as
      good as any mixture of actions.
   STATIONARY: the same in a state whenever it is visited, since the
      future from a state does not depend on the time of arrival.
   so the search is over 4**9 = 262144 policies, which is finite and far
   too many to try one at a time.

EVALUATING A FIXED POLICY. this is the PREDICTION problem: not 'what
should the robot do' but 'how good is this particular rule'.

   ALWAYS NORTH
        N     N     N    +1
        N     #     N    -1
        N     N     N     N
   its values:
      -1.400   -1.000   -0.200   +1.000
      -1.450        #   -0.333   -1.000
      -1.466   -1.196   -0.525   -0.992
   value of the start square: -1.4662, after 910 sweeps.

   ALWAYS EAST
        E     E     E    +1
        E     #     E    -1
        E     E     E     E
   its values:
      +0.500   +0.694   +0.744   +1.000
      -0.648        #   -0.905   -1.000
      -1.396   -1.439   -1.389   -1.400
   value of the start square: -1.3959, after 204 sweeps.

   ALONG THE BOTTOM AND UP THE RIGHT HAND SIDE
        E     E     E    +1
        N     #     N    -1
        E     E     E     N
   its values:
      +0.812   +0.868   +0.918   +1.000
      +0.762        #   +0.660   -1.000
      -0.794   -0.938   -0.888   -1.032
   value of the start square: -0.7940, after 26 sweeps.

   UP THE LEFT HAND SIDE AND ALONG THE TOP
        E     E     E    +1
        N     #     N    -1
        N     E     N     W
   its values:
      +0.812   +0.868   +0.918   +1.000
      +0.762        #   +0.660   -1.000
      +0.691   +0.527   +0.577   +0.357
   value of the start square: +0.6910, after 27 sweeps.

READ THE FOUR START VALUES TOGETHER:
   -1.4662   always north
   -1.3959   always east
   -0.7940   along the bottom and up the right hand side
   +0.6910   up the left hand side and along the top

   'always north' is worth -1.4662: the robot presses into the top wall and
   reaches the goal only by slipping sideways along the top row.
   'always east' is worth -1.3959, because from the bottom right corner it
   presses east into the edge and slips into the -1 square.

   AND THE TWO ROUTES THAT LOOK SENSIBLE ON THE MAP ARE +1.4850 APART.
   going right along the bottom and up the right hand side is the SHORTER
   route, and it is worth -0.7940, because the only way up the right hand
   column passes through the -1 square. going up the left and along the
   top is longer, costs more steps at -0.04 each, and is worth +0.6910.
   THE SHORT ROUTE ON THE MAP IS THE BAD POLICY, and no amount of looking
   at the grid says so. only the evaluation does.

NOTICE WHAT EVALUATION DOES NOT DO. it scores a policy that was handed to
it; it never proposes one. finding the best policy is the CONTROL problem
and it needs the next chapter's equations.
munotes.in506

Markov Decision Processes

Reading the model

A four by three grid with a pillar, a +1 square and a -1 square, and a slippery floor: an action goes the intended way with probability 0.8 and at right angles with probability 0.1 each. Walking into the pillar or off the edge leaves the robot where it was.

munotes.in507

Markov Decision Processes

Two transitions written out in full, and they are worth reading closely:

munotes.in508

Markov Decision Processes

from (0,0) going N: P((0,1)) = 0.8 intended, P((1,0)) = 0.1 slipped, P((0,0)) = 0.1 blocked

from (1,0) going N: P((1,0)) = 0.8 blocked by the pillar, P((0,0)) = 0.1, P((2,0)) = 0.1

munotes.in509

Markov Decision Processes

The second one is the case students forget: the most likely outcome of the intended action is to stay exactly where you are, because the pillar is in the way. A transition model must account for blocked moves, and if it does not, the probabilities stop summing to 1. The program checks that: for all 9 non-terminal states and 4 actions, 0 violations.

The Markov property

P(s' given s, a) depends on the current state and action only. How the robot reached a square does not change what happens next from it.

That is an assumption about the problem, not a property of the mathematics. It is what allows a policy to be a function of the state alone rather than of the entire history, and it is the same assumption Hidden Markov Models made about a chain of states.

When it fails, the usual repair is to enlarge the state until it holds: if what matters is the last two squares, make the state the pair of squares. That works and it multiplies the number of states.

What a policy is, and how many there are

A policy maps each state to an action. For an MDP with a fixed discount, an optimal policy can always be taken to be:

Why
deterministicone action is at least as good as any mixture of actions, so nothing is gained by randomising
stationarythe future from a state does not depend on when the state was reached, so the best action there is always the same

Both facts matter for the search. They reduce the problem to choosing one action per state, so the number of policies here is 49 = 262144. Finite, and far too many to try one at a time**, which is exactly why the next chapter exists.

Policy evaluation

The prediction problem: not "what should the robot do" but "how good is this particular rule". One equation, applied repeatedly until it stops changing:

V(s) = R(s) + gamma sum over s' of P(s' given s, policy(s)) V(s')

Read it as a sentence: the value of a state is its own reward plus the discounted average value of where the policy takes you. The terminal states keep their own values and are never updated.

munotes.in510

Markov Decision Processes

The four policies

PolicyValue of the start squareSweeps
always north-1.4662910
always east-1.3959204
along the bottom and up the right hand side-0.794026
up the left hand side and along the top+0.691027

Always north presses into the top wall and reaches the goal only by slipping sideways along the top row, which takes a great many steps at -0.04 each, and it needs 910 sweeps to settle, because the values propagate slowly through a policy that mostly stands still.

Always east is worse than it looks: from the bottom right corner it presses east into the edge and slips into the -1 square.

And now the measurement that matters. The two routes that look sensible on the map are 1.4850 apart.

Right along the bottom, then up the right hand column-0.7940
Up the left hand column, then along the top+0.6910

The shorter route is the bad one, because the only way up the right hand column passes through the -1 square. The longer route costs more steps at -0.04 each and is worth nearly one and a half more.

Nothing about the picture says so. A person looking at the grid sees a short path and a long path. Only the evaluation distinguishes them, and that is the argument for having the machinery at all.

Prediction and control

The distinction to state in an answer.

PredictionControl
Questionhow good is this policywhat is the best policy
Inputa policynone
Methodpolicy evaluationvalue iteration, policy iteration, Q-learning
Chapterthis onethe next two

Policy evaluation never proposes a policy. It scores one handed to it. Turning it into a search is the whole content of The Bellman Equations, Value Iteration and Policy Iteration.

What the model is, and when you have it

An MDP as written here assumes P and R are known. That is a strong assumption and it divides the subject.

Model-basedModel-free
P and Rknown, or learnednever needed
Methodvalue iteration, policy iterationQ-learning, SARSA
Needsa description of the worldonly experience of it
This chapter and the nextyesQ-Learning

For the grid, the slip probabilities were given. For a real robot on a real floor they are not, and either they are estimated by counting, which is Learning With Complete Data again, or the model is done away with entirely.

Distinctions

RewardValue
Ofa state, immediatelya state, under a policy
Here-0.04 everywhere-1.4662 to +0.6910 at the start square
Depends on the policynoyes
munotes.in511

Markov Decision Processes

A search problemAn MDP
Actionsdeterministicstochastic
Answera sequence of actionsa policy, an action for every state
Whythe plan cannot go wrongthe robot may end up anywhere, so it needs an answer everywhere
StationaryDeterministic
Meansthe same action in a state whenever visitedno randomising between actions
Becausethe future does not depend on the time of arrivalone action is at least as good as any mixture

What it does not mean

An MDP is not a search problem. Its answer is a policy, not a route, because the actions can go wrong.

The Markov property is not automatic. It is an assumption, repaired by enlarging the state.

A transition model is not complete without blocked moves. From one square here the most likely outcome of going north is staying put.

The shorter route is not the better policy. It is worth -0.7940 against +0.6910.

Policy evaluation does not find a policy. It scores one.

Knowing the MDP is not the usual case. Model-free methods exist because P is usually unknown.

Quick revision

  • An MDP is S, A, P(s' given s, a), R, gamma. No time and no history appear in it.
  • The Markov property: the next state depends on the current state and action only. It is an assumption, repaired by enlarging the state.
  • A transition model must handle blocked moves: from (1,0) going north, P(stay) = 0.8. Checked here: 9 states, 4 actions, 0 violations.
  • An optimal policy can be taken to be deterministic and stationary, so the search is over 4**9 = 262144 policies: finite, and far too many to enumerate.
  • Policy evaluation: V(s) = R(s) + gamma sum of P(s' given s, policy(s)) V(s'), applied until it stops changing.
  • Measured start values: always north -1.4662 (910 sweeps), always east -1.3959, bottom and right -0.7940, left and top +0.6910.
  • The shorter route is worth 1.4850 less, because the only way up the right hand column passes the -1 square. The map does not show this; the evaluation does.
  • Prediction is scoring a policy; control is finding one. Evaluation does only the first.
  • Model-based methods need P and R; model-free methods, such as Q-learning, do not.

Test yourself

1. Define a Markov decision process. A set of states, a set of actions, a transition model giving the probability of each next state from a state and action, a reward, and a discount factor. Nothing in the definition refers to time or to the history of how a state was reached.

2. State the Markov property and say what it buys. The probability of the next state depends only on the current state and the action taken, not on any earlier state. It allows a policy to be a function of the state alone rather than of the whole history, which is what makes the problem finite.

munotes.in512

Markov Decision Processes

3. Why must a transition model account for blocked moves? Because an action that would take the agent into an obstacle or off the edge must lead somewhere, and leaving it out makes the probabilities fail to sum to one. In this grid, going north from the square below the pillar leaves the robot where it is with probability 0.8, so the most likely outcome of the intended action is no movement at all.

4. Why is the answer to an MDP a policy rather than a sequence of actions? Because the actions are stochastic. A planned sequence assumes each action has its intended effect; here an action goes sideways one time in five, so the agent can find itself in a square its plan never anticipated and needs an answer for every state.

5. Write the policy evaluation equation and say what it computes. V(s) equals the reward of s plus gamma times the sum over next states of the probability of reaching them under the policy's action, each multiplied by its own value. Applied repeatedly until the values stop changing, it gives the expected discounted return from every state under that fixed policy. It is the prediction problem.

6. In the measurement, the shorter route scored -0.7940 and the longer one +0.6910. Explain. The only way up the right hand column passes through the -1 square, so the short route's final step risks the penalty and frequently incurs it. The long route up the left hand side and along the top pays an extra -0.04 for each additional step but never passes beside the penalty, and it is worth 1.4850 more. The grid drawing gives no hint of this; only evaluating the two policies does.

7. Distinguish prediction from control, and model-based from model-free. Prediction asks how good a given policy is and is answered by policy evaluation; control asks which policy is best and needs value iteration, policy iteration or a learning method. Model-based methods assume the transition model and reward are known, or learn them; model-free methods such as Q-learning never form a model and work from experience alone.

Contents This chapter on its own page

munotes.in513

Chapter Eighty

The Bellman Equations, Value Iteration and Policy Iteration

Syllabus topic Module 2, "Markov Decision Processes"

In one line

The value of a state under the best policy is the value of the best action from it, and that single sentence, applied over and over, solves the problem.

The Bellman optimality equation

Write it, because a paper on this topic will ask for it.

V(s) = max over a of sum over s' of P(s' given s, a) [ R + gamma V(s') ]

And the policy follows from the values:

policy*(s) = the action a that achieves that maximum

Read the equation as a sentence: the best you can do from here is, over the actions available, the best average of what you get now and what you can do from where you land.

It is not a formula to evaluate. It is a system of equations, one per state, each mentioning its neighbours, with a max inside. The max is what makes it non-linear, and that is precisely why the ordinary methods for simultaneous equations do not apply and an iteration is needed instead.

Compare it with the evaluation equation of Markov Decision Processes, which had policy(s) where this has max over a. That one word is the whole difference between prediction and control.

The measurement

# The Bellman optimality equation solved two ways on the grid of the previous
# chapter: value iteration and policy iteration, their costs compared, and the
# optimal policy shown changing when the cost of a step changes.
COLS, ROWS = 4, 3
WALL = (1, 1)
TERMINAL = {(3, 2): 1.0, (3, 1): -1.0}
START = (0, 0)
ACTIONS = ["N", "S", "E", "W"]
MOVE = {"N": (0, 1), "S": (0, -1), "E": (1, 0), "W": (-1, 0)}
SIDEWAYS = {"N": ("W", "E"), "S": ("E", "W"), "E": ("N", "S"), "W": ("S", "N")}
P_INTENDED, P_SLIP = 0.8, 0.1
STATES = [(c, r) for r in range(ROWS) for c in range(COLS) if (c, r) != WALL]
INNER = [s for s in STATES if s not in TERMINAL]

def legal(s):
    c, r = s
    return 0 <= c < COLS and 0 <= r < ROWS and (c, r) != WALL

def move(s, a):
    d = MOVE[a]
    t = (s[0] + d[0], s[1] + d[1])
    return t if legal(t) else s

def transitions(s, a):
    left, right = SIDEWAYS[a]
    out = {}
    for p, act in ((P_INTENDED, a), (P_SLIP, left), (P_SLIP, right)):
        t = move(s, act)
        out[t] = out.get(t, 0.0) + p
    return [(p, t) for t, p in sorted(out.items())]

def draw(grid, fmt="%8s"):
    for r in range(ROWS - 1, -1, -1):
        print(("   " + "".join(fmt % ("#" if (c, r) == WALL else grid.get((c, r), "."))
                               for c in range(COLS))).rstrip())

def q_value(s, a, V, living, gamma):
    return sum(p * (living + gamma * V[t]) for p, t in transitions(s, a))

print("THE BELLMAN OPTIMALITY EQUATION. the value of a state under the best")
print("policy is the value of the best action from it:")
print()
print("   V*(s) = max over a of  sum over s' of P(s' | s, a) * [ R + gamma * V*(s') ]")
print()
print("   it is not a formula to evaluate but a SYSTEM OF EQUATIONS: one per")
print("   state, each mentioning its neighbours, and with a max inside. the max")
print("   is what makes it non-linear and what stops it being solved by the")
print("   ordinary methods for simultaneous equations.")
print()
print("   and the policy falls out of it afterwards:")
print("      policy*(s) = the action a that achieves that maximum")
print()

def value_iteration(living, gamma, tol=1e-9, log=False):
    """Apply the Bellman equation as an ASSIGNMENT, over and over."""
    V = {s: 0.0 for s in STATES}
    for t, v in TERMINAL.items():
        V[t] = v
    sweeps = 0
    while True:
        sweeps += 1
        delta = 0.0
        new = dict(V)
        for s in INNER:
            best = max(q_value(s, a, V, living, gamma) for a in ACTIONS)
            delta = max(delta, abs(best - V[s]))
            new[s] = best
        V = new
        if log and (sweeps <= 6 or sweeps % 5 == 0 or delta < tol):
            print("   sweep %3d | start square %+.6f | largest change %.8f"
                  % (sweeps, V[START], delta))
        if delta < tol:
            return V, sweeps

def greedy(V, living, gamma):
    return {s: max(ACTIONS, key=lambda a: q_value(s, a, V, living, gamma))
            for s in INNER}

LIVING, GAMMA = -0.04, 1.0
print("VALUE ITERATION, at a step cost of %.2f and gamma %.2f." % (LIVING, GAMMA))
print("   start every state at 0, apply the equation to every state, repeat.")
V, sweeps = value_iteration(LIVING, GAMMA, log=True)
print()
print("   the values it converges to:")
draw({s: "%+.4f" % V[s] for s in STATES}, fmt="%10s")
print("   and the policy that is greedy with respect to them:")
pol = greedy(V, LIVING, GAMMA)
g = dict(pol)
for t, v in TERMINAL.items():
    g[t] = "%+.0f" % v
draw(g)
print()
print("   the start square is worth %+.4f under the best policy, against %+.4f"
      % (V[START], 0.6910))
print("   for the best of the four policies guessed in the previous chapter.")
print()
print("   NOTICE THE SQUARE BELOW THE -1, at (3,0): the policy there is %s."
      % pol[(3, 0)])
print("   going north from it would be the short way to the goal and would enter")
print("   the -1 square. the robot is told to go WEST, AWAY from the goal, and")
print("   that is the correct answer. a slippery floor makes the safe long route")
print("   worth more than the dangerous short one.")
print()
print("   AND THE CONVERGENCE. the largest change per sweep falls steadily and")
print("   the POLICY settles long before the VALUES do:")
Vp = {s: 0.0 for s in STATES}
for t, v in TERMINAL.items():
    Vp[t] = v
last = None
print("   sweep | largest change | policy the same as the final one")
for k in range(1, 31):
    new = dict(Vp)
    delta = 0.0
    for s in INNER:
        b = max(q_value(s, a, Vp, LIVING, GAMMA) for a in ACTIONS)
        delta = max(delta, abs(b - Vp[s]))
        new[s] = b
    Vp = new
    same = greedy(Vp, LIVING, GAMMA) == pol
    if k <= 12 or k % 5 == 0:
        print("   %5d | %14.8f | %s" % (k, delta, "yes" if same else "no"))
    if same and last is None:
        last = k
print("   the policy first matches the final one at sweep %d, and the values" % last)
print("   need %d sweeps to settle. IN PRACTICE THE POLICY IS WHAT IS WANTED, so" % sweeps)
print("   value iteration is usually stopped long before the values converge.")
print()

def policy_iteration(living, gamma, log=False):
    """Evaluate the current policy EXACTLY, then improve it. Repeat."""
    pol = {s: "N" for s in INNER}
    rounds = 0
    total_sweeps = 0
    while True:
        rounds += 1
        # --- evaluation -------------------------------------------------
        V = {s: 0.0 for s in STATES}
        for t, v in TERMINAL.items():
            V[t] = v
        while True:
            total_sweeps += 1
            delta = 0.0
            new = dict(V)
            for s in INNER:
                x = q_value(s, pol[s], V, living, gamma)
                delta = max(delta, abs(x - V[s]))
                new[s] = x
            V = new
            if delta < 1e-9:
                break
        # --- improvement ------------------------------------------------
        better = greedy(V, living, gamma)
        changed = sum(1 for s in INNER if better[s] != pol[s])
        if log:
            print("   round %d | start square %+.6f | actions changed: %d"
                  % (rounds, V[START], changed))
        if changed == 0:
            return pol, V, rounds, total_sweeps
        pol = better

print("POLICY ITERATION, the other way. instead of sweeping the values towards")
print("the answer, alternate two exact steps:")
print("   EVALUATE   the current policy completely, giving its true values.")
print("   IMPROVE    replace every action by the one that is best against those")
print("              values. if nothing changes, the policy is optimal and the")
print("              algorithm stops, with a PROOF rather than a tolerance.")
print()
pol2, V2, rounds, ev_sweeps = policy_iteration(LIVING, GAMMA, log=True)
print()
print("   it finished in %d rounds of improvement." % rounds)
print("   the policy it reached:")
g = dict(pol2)
for t, v in TERMINAL.items():
    g[t] = "%+.0f" % v
draw(g)
print("   identical to value iteration's policy: %s."
      % ("yes" if pol2 == pol else "NO"))
print("   largest difference between the two sets of values: %.10f"
      % max(abs(V2[s] - V[s]) for s in STATES))
print()
print("   THE COST, COMPARED:")
print("      value iteration  : %d sweeps of all %d states" % (sweeps, len(INNER)))
print("      policy iteration : %d improvement rounds, %d evaluation sweeps in all"
      % (rounds, ev_sweeps))
print("   policy iteration needs FEW rounds and each round is expensive; value")
print("   iteration needs MANY sweeps and each is cheap. on a small problem the")
print("   evaluation can be solved exactly as simultaneous equations, which makes")
print("   policy iteration very fast; on a large one it cannot, and the")
print("   evaluation is itself done by sweeping, which is what this program does.")
print()
print("   AND POLICY ITERATION STOPS WITH A PROOF. 'no action changed' means the")
print("   policy is greedy with respect to its own values, which is exactly the")
print("   Bellman optimality condition. value iteration stops when a number gets")
print("   small, which is a tolerance and not a proof.")
print()

print("THE STEP COST DECIDES THE POLICY, and this is the measurement worth")
print("remembering. the same grid, the same slip, four different step costs:")
for living in (-0.01, -0.04, -0.20, -2.00):
    Vx, _ = value_iteration(living, GAMMA)
    px = greedy(Vx, living, GAMMA)
    g = dict(px)
    for t, v in TERMINAL.items():
        g[t] = "%+.0f" % v
    print()
    print("   step cost %.2f    start square worth %+.4f" % (living, Vx[START]))
    draw(g)
    print("      at (3,0), below the -1 square, the policy is %s" % px[(3, 0)])
    print("      at (2,1), beside the -1 square, the policy is %s" % px[(2, 1)])
print()
print("   READ THE FOUR GRIDS AGAINST EACH OTHER.")
print("   at -0.01 a step is nearly free, so the robot takes the longest safest")
print("   route and keeps well away from the -1 square.")
print("   at -2.00 every step is agony. the robot heads for the nearest exit")
print("   whichever exit it is, and from the squares beside the -1 it walks")
print("   deliberately INTO the penalty, because -1 now is better than several")
print("   more steps at -2 each.")
print()
print("   THE REWARD FUNCTION IS NOT A DETAIL OF THE IMPLEMENTATION. it is the")
print("   statement of what the robot is for, and changing one number in it")
print("   changes the behaviour completely. that is the whole of the reward")
print("   design warning of the framework chapter, measured.")
munotes.in514

The Bellman Equations, Value Iteration and Policy Iteration

THE BELLMAN OPTIMALITY EQUATION. the value of a state under the best
policy is the value of the best action from it:

   V*(s) = max over a of  sum over s' of P(s' | s, a) * [ R + gamma * V*(s') ]

   it is not a formula to evaluate but a SYSTEM OF EQUATIONS: one per
   state, each mentioning its neighbours, and with a max inside. the max
   is what makes it non-linear and what stops it being solved by the
   ordinary methods for simultaneous equations.

   and the policy falls out of it afterwards:
      policy*(s) = the action a that achieves that maximum

VALUE ITERATION, at a step cost of -0.04 and gamma 1.00.
   start every state at 0, apply the equation to every state, repeat.
   sweep   1 | start square -0.040000 | largest change 0.76000000
   sweep   2 | start square -0.080000 | largest change 0.60000000
   sweep   3 | start square -0.120000 | largest change 0.47200000
   sweep   4 | start square -0.160000 | largest change 0.36960000
   sweep   5 | start square +0.162496 | largest change 0.32249600
   sweep   6 | start square +0.384896 | largest change 0.22240000
   sweep  10 | start square +0.675440 | largest change 0.04350145
   sweep  15 | start square +0.704281 | largest change 0.00723468
   sweep  20 | start square +0.705282 | largest change 0.00034648
   sweep  25 | start square +0.705308 | largest change 0.00000931
   sweep  30 | start square +0.705308 | largest change 0.00000021
   sweep  35 | start square +0.705308 | largest change 0.00000000
   sweep  37 | start square +0.705308 | largest change 0.00000000

   the values it converges to:
      +0.8116   +0.8678   +0.9178   +1.0000
      +0.7616         #   +0.6603   -1.0000
      +0.7053   +0.6553   +0.6114   +0.3879
   and the policy that is greedy with respect to them:
          E       E       E      +1
          N       #       N      -1
          N       W       W       W

   the start square is worth +0.7053 under the best policy, against +0.6910
   for the best of the four policies guessed in the previous chapter.

   NOTICE THE SQUARE BELOW THE -1, at (3,0): the policy there is W.
   going north from it would be the short way to the goal and would enter
   the -1 square. the robot is told to go WEST, AWAY from the goal, and
   that is the correct answer. a slippery floor makes the safe long route
   worth more than the dangerous short one.

   AND THE CONVERGENCE. the largest change per sweep falls steadily and
   the POLICY settles long before the VALUES do:
   sweep | largest change | policy the same as the final one
       1 |     0.76000000 | no
       2 |     0.60000000 | no
       3 |     0.47200000 | no
       4 |     0.36960000 | no
       5 |     0.32249600 | no
       6 |     0.22240000 | no
       7 |     0.14542848 | no
       8 |     0.07915034 | no
       9 |     0.05098588 | no
      10 |     0.04350145 | no
      11 |     0.02816814 | no
      12 |     0.01685783 | yes
      15 |     0.00723468 | yes
      20 |     0.00034648 | yes
      25 |     0.00000931 | yes
      30 |     0.00000021 | yes
   the policy first matches the final one at sweep 12, and the values
   need 37 sweeps to settle. IN PRACTICE THE POLICY IS WHAT IS WANTED, so
   value iteration is usually stopped long before the values converge.

POLICY ITERATION, the other way. instead of sweeping the values towards
the answer, alternate two exact steps:
   EVALUATE   the current policy completely, giving its true values.
   IMPROVE    replace every action by the one that is best against those
              values. if nothing changes, the policy is optimal and the
              algorithm stops, with a PROOF rather than a tolerance.

   round 1 | start square -1.466201 | actions changed: 6
   round 2 | start square +0.508237 | actions changed: 1
   round 3 | start square +0.691004 | actions changed: 1
   round 4 | start square +0.705308 | actions changed: 1
   round 5 | start square +0.705308 | actions changed: 0

   it finished in 5 rounds of improvement.
   the policy it reached:
          E       E       E      +1
          N       #       N      -1
          N       W       W       W
   identical to value iteration's policy: yes.
   largest difference between the two sets of values: 0.0000000004

   THE COST, COMPARED:
      value iteration  : 37 sweeps of all 9 states
      policy iteration : 5 improvement rounds, 994 evaluation sweeps in all
   policy iteration needs FEW rounds and each round is expensive; value
   iteration needs MANY sweeps and each is cheap. on a small problem the
   evaluation can be solved exactly as simultaneous equations, which makes
   policy iteration very fast; on a large one it cannot, and the
   evaluation is itself done by sweeping, which is what this program does.

   AND POLICY ITERATION STOPS WITH A PROOF. 'no action changed' means the
   policy is greedy with respect to its own values, which is exactly the
   Bellman optimality condition. value iteration stops when a number gets
   small, which is a tolerance and not a proof.

THE STEP COST DECIDES THE POLICY, and this is the measurement worth
remembering. the same grid, the same slip, four different step costs:

   step cost -0.01    start square worth +0.9232
          E       E       E      +1
          N       #       W      -1
          N       W       W       S
      at (3,0), below the -1 square, the policy is S
      at (2,1), beside the -1 square, the policy is W

   step cost -0.04    start square worth +0.7053
          E       E       E      +1
          N       #       N      -1
          N       W       W       W
      at (3,0), below the -1 square, the policy is W
      at (2,1), beside the -1 square, the policy is N

   step cost -0.20    start square worth -0.3273
          E       E       E      +1
          N       #       N      -1
          N       E       N       W
      at (3,0), below the -1 square, the policy is W
      at (2,1), beside the -1 square, the policy is N

   step cost -2.00    start square worth -10.8153
          E       E       E      +1
          N       #       E      -1
          E       E       E       N
      at (3,0), below the -1 square, the policy is N
      at (2,1), beside the -1 square, the policy is E

   READ THE FOUR GRIDS AGAINST EACH OTHER.
   at -0.01 a step is nearly free, so the robot takes the longest safest
   route and keeps well away from the -1 square.
   at -2.00 every step is agony. the robot heads for the nearest exit
   whichever exit it is, and from the squares beside the -1 it walks
   deliberately INTO the penalty, because -1 now is better than several
   more steps at -2 each.

   THE REWARD FUNCTION IS NOT A DETAIL OF THE IMPLEMENTATION. it is the
   statement of what the robot is for, and changing one number in it
   changes the behaviour completely. that is the whole of the reward
   design warning of the framework chapter, measured.
munotes.in515

The Bellman Equations, Value Iteration and Policy Iteration

Value iteration

The idea is to treat the equation as an assignment: start every value at 0 and apply it to every state, over and over.

munotes.in516

The Bellman Equations, Value Iteration and Policy Iteration

SweepStart squareLargest change
1-0.0400000.76000000
5+0.1624960.32249600
10+0.6754400.04350145
20+0.7052820.00034648
37+0.7053080.00000000
munotes.in517

The Bellman Equations, Value Iteration and Policy Iteration

The converged values, and the policy greedy with respect to them:

munotes.in518

The Bellman Equations, Value Iteration and Policy Iteration

+0.8116 +0.8678 +0.9178 +1.0000 E E E +1

+0.7616 # +0.6603 -1.0000 N # N -1

+0.7053 +0.6553 +0.6114 +0.3879 N W W W

munotes.in519

The Bellman Equations, Value Iteration and Policy Iteration

The start square is worth +0.7053, against +0.6910 for the best of the four hand-written policies in the previous chapter. The best guess was close, and it was still a guess.

The square below the penalty

Look at (3,0), directly below the -1. The policy there is W: go west, away from the goal.

Going north from that square is the short way to the goal and it enters the -1. The floor is slippery, so even aiming elsewhere is risky, and the correct answer is to move away from the goal entirely. A slippery floor makes the safe long route worth more than the dangerous short one, and no amount of looking at the grid produces that answer.

The policy settles long before the values

SweepLargest changePolicy equals the final one
80.07915034no
110.02816814no
120.01685783yes
200.00034648yes
370.00000000yes

The policy first matches the final one at sweep 12; the values need 37 sweeps to settle.

The reason is simple and worth stating: the policy depends only on which action is largest, not on how much larger it is, so it stops changing as soon as the ordering is right. In practice the policy is what is wanted, so value iteration is usually stopped long before the values converge, and the stopping rule is often "the greedy policy has not changed for several sweeps".

Policy iteration

The other route. Instead of sweeping values towards the answer, alternate two exact steps:

munotes.in520

The Bellman Equations, Value Iteration and Policy Iteration

Evaluatecompute the current policy's true values, by the equation of the previous chapter
Improvereplace every action by the one best against those values

Stop when no action changes.

RoundStart squareActions changed
1-1.4662016
2+0.5082371
3+0.6910041
4+0.7053081
5+0.7053080

Five rounds, and the policy it reaches is identical to value iteration's, with the values agreeing to 0.0000000004.

And it stops with a proof, not a tolerance. "No action changed" means the policy is greedy with respect to its own values, which is the Bellman optimality condition. Value iteration stops when a number becomes small, which is a threshold someone chose.

The costs, honestly

Value iteration37 sweeps of 9 states
Policy iteration5 improvement rounds, and 994 evaluation sweeps in all

In this implementation policy iteration does far more arithmetic, because each evaluation is itself run to convergence by sweeping.

The honest account, which is what an examiner wants:

Policy iteration needs few rounds and each round is expensive. On a small problem the evaluation can be solved exactly, as a set of linear simultaneous equations, since with the policy fixed there is no max and the system is linear. Then policy iteration is very fast, and it is guaranteed to terminate because there are finitely many policies and each round strictly improves.

Value iteration needs many sweeps and each is cheap. On a large problem the exact solve is impossible, so the evaluation is itself done by sweeping, and the advantage disappears.

Modified policy iteration is the usual compromise: run the evaluation for a fixed small number of sweeps instead of to convergence. It is between the two and is what most implementations do.

The step cost decides the policy

This is the measurement to remember from the chapter. The same grid, the same slippery floor, four different step costs:

Step costStart squareAt (3,0)At (2,1)
-0.01+0.9232SW
-0.04+0.7053WN
-0.20-0.3273WN
-2.00-10.8153NE

At -0.01 a step is nearly free, so the robot takes the longest, safest route. Look at (3,0): the policy is S, which is straight into the bottom edge. The robot is deliberately bumping into a wall. Read the transition model to see why: going south from there it stays put four times in five and slips west one time in ten, with no chance of entering the -1, whereas going west slips north into the penalty one time in ten. At one hundredth of a point per step, shuffling sideways by accident is worth more than a one in ten risk.

At -2.00 every step is agony, and the policy at the squares beside the -1 is to walk into it: (2,1) goes E and (3,0) goes N, both straight into the penalty. A penalty of -1 now is better than a few more steps at -2 each, and the start square is worth -10.8153, so the robot is simply trying to end.

munotes.in521

The Bellman Equations, Value Iteration and Policy Iteration

The reward function is not an implementation detail. It is the statement of what the robot is for. Changing one number in it changed the behaviour from cautious to suicidal without a line of the algorithm being touched. That is the reward design warning of The Reinforcement Learning Framework, measured.

Distinctions

Policy evaluationValue iteration
The equation haspolicy(s)max over a
Linearyesno
Answerspredictioncontrol
Value iterationPolicy iteration
Iterates onthe valuesthe policy
Rounds here37 sweeps5 rounds
Work here37 sweeps994 evaluation sweeps
Stops ona tolerancea proof: no action changed
Each roundcheapexpensive, unless solved exactly
The valuesThe policy
Depend onhow much largerwhich is larger
Settled at sweep3712
Wanted in practicerarelyusually

What it does not mean

The Bellman equation is not a formula to substitute into. It is a non-linear system, one equation per state.

Value iteration is not a heuristic. It converges to the unique optimal values, and the max is the only reason an iteration is needed.

The optimal policy does not head for the goal from every square. From below the penalty it goes west, away from it.

Policy iteration is not always cheaper. Here it did 994 evaluation sweeps against 37.

Converged values are not required. The policy was final 25 sweeps earlier.

The step cost is not a small detail. Four values of it gave four different policies, one of them suicidal.

Quick revision

  • Bellman optimality: V(s) = max over a of sum of P(s' given s, a) [R + gamma V(s')], and policy*(s) is the action attaining the max. The max makes it non-linear.
  • Value iteration: apply the equation as an assignment to every state, repeatedly. Converged here in 37 sweeps to a start value of +0.7053, against +0.6910 for the best guessed policy.
  • At (3,0), below the penalty, the optimal action is W, away from the goal. A slippery floor makes the safe long route worth more.
  • The policy was final at sweep 12, the values at sweep 37, because the policy depends only on which action is largest. Stop early in practice.
  • Policy iteration: evaluate exactly, improve greedily, stop when no action changes. 5 rounds, the same policy, values agreeing to 4e-10. It stops with a proof, not a tolerance, and terminates because policies are finite and each round strictly improves.
  • Costs here: value iteration 37 sweeps; policy iteration 5 rounds but 994 evaluation sweeps. With the policy fixed the evaluation is linear and can be solved exactly, which is when policy iteration wins. Modified policy iteration runs the evaluation for a few sweeps only.
  • Step cost decides the policy: -0.01 gives +0.9232 and a robot that bumps into a wall rather than risk the penalty; -2.00 gives -10.8153 and a robot that walks into the penalty. The reward function states what the agent is for.
munotes.in522

The Bellman Equations, Value Iteration and Policy Iteration

Test yourself

1. Write the Bellman optimality equation and say why it cannot be solved directly. The value of a state under the best policy is the maximum over actions of the sum over next states of the transition probability times the reward plus gamma times the next state's optimal value. It is a system of equations, one per state, each referring to its neighbours, and the maximum makes the system non-linear, so the standard methods for simultaneous linear equations do not apply.

2. Describe value iteration. Initialise every value, apply the Bellman optimality equation to every state as an assignment, and repeat until the largest change in a sweep falls below a tolerance. The optimal policy is then the action attaining the maximum in each state.

3. Describe policy iteration and say how it knows it has finished. Begin from any policy. Evaluate it exactly, giving its true values, then improve it by replacing each action with the one best against those values. Repeat. When no action changes, the policy is greedy with respect to its own values, which is the Bellman optimality condition, so it is optimal; the algorithm stops with a proof rather than with a tolerance, and it must terminate because there are finitely many policies and each round strictly improves the current one.

4. Why did the policy stop changing 25 sweeps before the values did? The policy depends only on which action has the largest value, not on how much larger it is. Once the ordering of the actions in every state is correct the policy is final, while the values continue to creep towards their limits.

5. The optimal policy in the square below the penalty is to move away from the goal. Explain. The only route north from that square enters the penalty, and the floor is slippery, so even an action aimed elsewhere can drift into it. Moving west reduces the chance of entering the penalty enough to outweigh the extra steps at 0.04 each, so the safe long route is worth more than the dangerous short one.

munotes.in523

The Bellman Equations, Value Iteration and Policy Iteration

6. Compare the costs of the two algorithms honestly. Policy iteration needed 5 improvement rounds and value iteration 37 sweeps, but each of policy iteration's rounds required a complete evaluation, 994 sweeps in total here. When the evaluation can be solved exactly as linear simultaneous equations, which is possible because the policy is fixed and the maximum disappears, policy iteration is fast; on a large problem it cannot be, and the advantage goes. Modified policy iteration, evaluating for a few sweeps only, is the usual compromise.

7. What did changing the step cost show? That the reward function decides the behaviour. At a cost of 0.01 a step the robot took the longest safest route and even bumped deliberately into a wall, since standing still risked nothing while moving west risked the penalty one time in ten. At a cost of 2 a step it walked deliberately into the penalty from the squares beside it, because a single penalty of one was cheaper than a few more steps. The algorithm was identical in all four cases.

Contents This chapter on its own page

munotes.in524

Chapter Eighty-One

Q-Learning

Syllabus topic Module 2, "Q-Learning"

In one line

Learn the value of each action by moving your estimate a little way towards what actually happened, and you never need a model of the world at all.

The Bellman Equations, Value Iteration and Policy Iteration solved the grid by summing over every possible next state, weighted by P(s' given s, a). That sum needs the model. This chapter removes it.

The Q function

Q(s, a) is the value of taking action a in state s and behaving well afterwards. It differs from V(s) by carrying the action, and that difference is the whole point:

V(s) = max over a of Q(s, a) the value of a state

policy(s) = the a that attains it and the policy falls straight out

With V alone, choosing an action needs P(s' given s, a) to see where each action leads. With Q, the policy is read off directly, with no model.

The update

Write it exactly; a paper on Q-learning will ask for it.

Q(s,a) <- Q(s,a) + alpha [ r + gamma max over a' of Q(s',a') - Q(s,a) ]

The bracket is the temporal difference error: what this one step suggests the value is, minus what was believed. alpha, the learning rate, decides how much of the correction to apply.

And notice where the model would have been. The Bellman equation summed over every next state weighted by its probability. This update uses the one next state that actually happened. The average is accumulated over many visits instead of being computed, and that is the whole trick: sampling replaces the sum.

The measurement

# Q-learning on the same grid, with NO transition model given to the agent: it
# learns only from experience. The answer is checked against value iteration,
# which is allowed to see the model, and then SARSA is put beside it.
COLS, ROWS = 4, 3
WALL = (1, 1)
TERMINAL = {(3, 2): 1.0, (3, 1): -1.0}
START = (0, 0)
LIVING, GAMMA = -0.04, 1.0
ACTIONS = ["N", "S", "E", "W"]
MOVE = {"N": (0, 1), "S": (0, -1), "E": (1, 0), "W": (-1, 0)}
SIDEWAYS = {"N": ("W", "E"), "S": ("E", "W"), "E": ("N", "S"), "W": ("S", "N")}
P_INTENDED, P_SLIP = 0.8, 0.1
STATES = [(c, r) for r in range(ROWS) for c in range(COLS) if (c, r) != WALL]
INNER = [s for s in STATES if s not in TERMINAL]

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

def legal(s):
    c, r = s
    return 0 <= c < COLS and 0 <= r < ROWS and (c, r) != WALL

def move(s, a):
    d = MOVE[a]
    t = (s[0] + d[0], s[1] + d[1])
    return t if legal(t) else s

def transitions(s, a):
    left, right = SIDEWAYS[a]
    out = {}
    for p, act in ((P_INTENDED, a), (P_SLIP, left), (P_SLIP, right)):
        t = move(s, act)
        out[t] = out.get(t, 0.0) + p
    return [(p, t) for t, p in sorted(out.items())]

def draw(grid, fmt="%8s"):
    for r in range(ROWS - 1, -1, -1):
        print(("   " + "".join(fmt % ("#" if (c, r) == WALL else grid.get((c, r), "."))
                               for c in range(COLS))).rstrip())

# ---- the answer the agent must reach, computed WITH the model ---------------
def value_iteration():
    V = {s: 0.0 for s in STATES}
    for t, v in TERMINAL.items():
        V[t] = v
    while True:
        delta, new = 0.0, dict(V)
        for s in INNER:
            best = max(sum(p * (LIVING + GAMMA * V[t]) for p, t in transitions(s, a))
                       for a in ACTIONS)
            delta = max(delta, abs(best - V[s]))
            new[s] = best
        V = new
        if delta < 1e-12:
            return V

V_STAR = value_iteration()
POLICY_STAR = {s: max(ACTIONS,
                      key=lambda a: sum(p * (LIVING + GAMMA * V_STAR[t])
                                        for p, t in transitions(s, a)))
               for s in INNER}

print("THE AGENT IS GIVEN NOTHING. it does not know the slip probabilities, the")
print("step cost, where the pillar is, or where the exits are. it knows the four")
print("actions and it can see which square it is in. everything else it must")
print("learn from what happens.")
print()
print("   Q(s, a) is the value of TAKING action a in state s and behaving well")
print("   afterwards. the update, after every single step:")
print()
print("      Q(s,a) <- Q(s,a) + alpha * [ r + gamma * max over a' of Q(s',a')")
print("                                   - Q(s,a) ]")
print()
print("   the bracket is the TEMPORAL DIFFERENCE ERROR: what the step actually")
print("   suggests the value is, minus what was believed. alpha decides how much")
print("   of that correction to apply.")
print()
print("   NOTE WHERE THE MODEL WOULD HAVE BEEN. the Bellman equation summed over")
print("   every next state weighted by P(s'|s,a). this update uses the ONE next")
print("   state that actually happened. the average is accumulated over many")
print("   visits instead of being computed, which is why no model is needed.")
print()

def step(gen, s, a):
    """The environment. The agent may call it; it may not look inside."""
    r = next(gen)
    left, right = SIDEWAYS[a]
    act = a if r < P_INTENDED else (left if r < P_INTENDED + P_SLIP else right)
    t = move(s, act)
    return t, (TERMINAL[t] if t in TERMINAL else LIVING)

def learn(episodes, alpha, epsilon, seed, sarsa=False, random_behaviour=False):
    gen = lcg(seed)
    Q = {(s, a): 0.0 for s in INNER for a in ACTIONS}
    for ep in range(episodes):
        s = INNER[min(int(next(gen) * len(INNER)), len(INNER) - 1)]

        def choose(state):
            if random_behaviour or next(gen) < epsilon:
                return ACTIONS[min(int(next(gen) * 4), 3)]
            return max(ACTIONS, key=lambda a: Q[(state, a)])

        a = choose(s)
        for _ in range(200):
            t, r = step(gen, s, a)
            if t in TERMINAL:
                Q[(s, a)] += alpha * (r - Q[(s, a)])
                break
            a2 = choose(t)
            nxt = Q[(t, a2)] if sarsa else max(Q[(t, b)] for b in ACTIONS)
            Q[(s, a)] += alpha * (r + GAMMA * nxt - Q[(s, a)])
            s, a = t, a2
    return Q

def evaluate(policy):
    """THE AUTHOR'S measuring instrument, not the agent's: what is a learnt
    policy actually worth, computed with the model the agent never saw."""
    V = {s: 0.0 for s in STATES}
    for t, v in TERMINAL.items():
        V[t] = v
    while True:
        delta, new = 0.0, dict(V)
        for s in INNER:
            x = sum(p * (LIVING + GAMMA * V[t]) for p, t in transitions(s, policy[s]))
            delta = max(delta, abs(x - V[s]))
            new[s] = x
        V = new
        if delta < 1e-12:
            return V

def report(Q):
    V = {s: max(Q[(s, a)] for a in ACTIONS) for s in INNER}
    pol = {s: max(ACTIONS, key=lambda a: Q[(s, a)]) for s in INNER}
    err = max(abs(V[s] - V_STAR[s]) for s in INNER)
    agree = sum(1 for s in INNER if pol[s] == POLICY_STAR[s])
    return V, pol, err, agree, evaluate(pol)[START]

print("LEARNING. alpha = 0.10, epsilon = 0.20, episodes from random squares.")
print("   the last column is what matters: not whether the learnt policy MATCHES")
print("   the optimal one, but what it is WORTH. the optimal policy is worth")
print("   %+.4f from the start square." % V_STAR[START])
print()
print("   episodes | largest value error | actions matching | policy is worth")
Q = None
for k in (10, 100, 1000, 10000, 100000):
    Q = learn(k, 0.10, 0.20, 99991)
    V, pol, err, agree, worth = report(Q)
    print("   %8d | %19.4f | %5d of %d       | %+.4f"
          % (k, err, agree, len(INNER), worth))
print()
V, pol, err, agree, worth = report(Q)
print("   after 100000 episodes, the values Q-learning believes:")
draw({s: "%+.4f" % V[s] for s in INNER}, fmt="%10s")
print("   what value iteration computed WITH the model:")
draw({s: "%+.4f" % V_STAR[s] for s in INNER}, fmt="%10s")
print("   the policy it acts on, then the optimal one:")
g1, g2 = dict(pol), dict(POLICY_STAR)
for t, v in TERMINAL.items():
    g1[t] = g2[t] = "%+.0f" % v
draw(g1)
print("   ---")
draw(g2)
print("   %d of %d actions agree, and the learnt policy is worth %+.4f against"
      % (agree, len(INNER), worth))
print("   %+.4f for the optimal one: a loss of %.4f."
      % (V_STAR[START], V_STAR[START] - worth))
print()
print("   THE VALUES ARE STILL WRONG BY %.4f AND THE POLICY IS RIGHT. with a" % err)
print("   CONSTANT alpha the updates never stop moving: every visit pulls the")
print("   estimate part of the way towards a single sampled outcome, so it keeps")
print("   bouncing around the true value for ever. the bounce is roughly")
print("   proportional to alpha.")
print()
print("   ALPHA AGAINST THE ERROR, at 20000 episodes each:")
print("   alpha | largest value error | actions matching | policy is worth")
for al in (0.50, 0.20, 0.10, 0.05, 0.02):
    Qa = learn(20000, al, 0.20, 99991)
    V2, pol2, err2, agree2, worth2 = report(Qa)
    print("   %5.2f | %19.4f | %5d of %d       | %+.4f"
          % (al, err2, agree2, len(INNER), worth2))
print("   a large alpha learns quickly and settles badly; a small one settles")
print("   well and learns slowly. TO CONVERGE EXACTLY, alpha must SHRINK over")
print("   time: the standard condition is that the alphas sum to infinity, so")
print("   every estimate can still be moved anywhere, while their squares sum to")
print("   something finite, so the bouncing dies away.")
print()

print("OFF-POLICY, which is the property that matters. run it again with the")
print("agent choosing UNIFORMLY AT RANDOM at every step, never once using what")
print("it has learnt:")
Qr = learn(100000, 0.05, 1.0, 99991, random_behaviour=True)
Vr, polr, errr, agreer, worthr = report(Qr)
draw({s: polr[s] for s in INNER})
print("   largest value error %.4f, %d of %d actions matching, and the policy it"
      % (errr, agreer, len(INNER)))
print("   learnt is worth %+.4f against the optimal %+.4f."
      % (worthr, V_STAR[START]))
print("   AN AGENT THAT NEVER ONCE ACTED ON WHAT IT KNEW LEARNT THE OPTIMAL")
print("   POLICY. that is what OFF-POLICY means: the policy learnt")
print("   about is not the policy used to act, because the update takes the")
print("   MAXIMUM over the next state's actions rather than the action the agent")
print("   will actually take. it is also why the method can learn from logged")
print("   data, from a human demonstrator, or from an old policy's records.")
print()

print("SARSA, the on-policy relative. one symbol changes in the update:")
print("      Q-learning : ... + gamma * MAX over a' of Q(s',a')")
print("      SARSA      : ... + gamma * Q(s', a'), where a' is the action the")
print("                   agent will ACTUALLY take next")
print("   so SARSA learns the value of the policy it is following, exploration")
print("   and all. the name is the five things its update uses: s, a, r, s', a'.")
print()
print("   both on this grid, alpha 0.10, epsilon 0.20, 100000 episodes:")
print("   method     | largest value error | actions matching | policy is worth")
for name, Qx in (("Q-learning", Q), ("SARSA", learn(100000, 0.10, 0.20, 99991,
                                                    sarsa=True))):
    Vx, polx, errx, agreex, worthx = report(Qx)
    print("   %-10s | %19.4f | %5d of %d       | %+.4f"
          % (name, errx, agreex, len(INNER), worthx))
print("   on a forgiving grid they end in much the same place. the difference")
print("   needs an environment where exploring is DANGEROUS.")
print()

print("SO HERE IS ONE: A CLIFF. a %d by %d corridor, start at the bottom left,"
      % (6, 3))
print("goal at the bottom right, and every square between them along the bottom")
print("is a fall costing -100 that ends the episode. every other step costs -1.")
print("THIS FLOOR IS NOT SLIPPERY: the danger is entirely the agent's own")
print("exploration.")

CW, CH = 6, 3
CLIFF = [(c, 0) for c in range(1, CW - 1)]
CSTART, CGOAL = (0, 0), (CW - 1, 0)
CINNER = [(c, r) for r in range(CH) for c in range(CW) if (c, r) not in CLIFF
          and (c, r) != CGOAL]

def cliff_step(s, a):
    d = MOVE[a]
    t = (s[0] + d[0], s[1] + d[1])
    if not (0 <= t[0] < CW and 0 <= t[1] < CH):
        t = s
    if t in CLIFF:
        return CSTART, -100.0, True
    if t == CGOAL:
        return t, -1.0, True
    return t, -1.0, False

def cliff_run(episodes, alpha, epsilon, seed, sarsa):
    gen = lcg(seed)
    Q = {(s, a): 0.0 for s in CINNER for a in ACTIONS}
    rewards = []
    for ep in range(episodes):
        s = CSTART
        pick = (lambda st: ACTIONS[min(int(next(gen) * 4), 3)]
                if next(gen) < epsilon
                else max(ACTIONS, key=lambda a: Q[(st, a)]))
        a = pick(s)
        total = 0.0
        for _ in range(300):
            t, r, done = cliff_step(s, a)
            total += r
            if done:
                Q[(s, a)] += alpha * (r - Q[(s, a)])
                break
            a2 = pick(t)
            nxt = Q[(t, a2)] if sarsa else max(Q[(t, b)] for b in ACTIONS)
            Q[(s, a)] += alpha * (r + GAMMA * nxt - Q[(s, a)])
            s, a = t, a2
        rewards.append(total)
    return Q, rewards

print("   method     | mean reward per episode over the last 500 | route taken")
for name, flag in (("Q-learning", False), ("SARSA", True)):
    Q, rewards = cliff_run(3000, 0.10, 0.10, 20260930, flag)
    greedy_pol = {s: max(ACTIONS, key=lambda a: Q[(s, a)]) for s in CINNER}
    s, route = CSTART, [CSTART]
    for _ in range(20):
        t, r, done = cliff_step(s, greedy_pol[s])
        route.append(t)
        s = t
        if done:
            break
    rows = sorted({p[1] for p in route})
    print("   %-10s | %41.2f | rows used: %s"
          % (name, sum(rewards[-500:]) / 500, ", ".join(str(r) for r in rows)))
print()
print("   Q-LEARNING learns the OPTIMAL route, which runs along row 1, directly")
print("   above the cliff. SARSA learns a route further from the edge.")
print("   neither is mistaken. Q-learning's update takes the maximum, so it")
print("   learns the value of the best route ASSUMING NO EXPLORATION; while it")
print("   is still exploring, one random step in ten sends it over the edge and")
print("   it collects a worse reward. SARSA's update uses the action it will")
print("   really take, so the cost of its own exploration is built into the")
print("   values, and it prefers a route where a random step is survivable.")
print()
print("   SO: Q-LEARNING LEARNS THE OPTIMAL POLICY AND SARSA LEARNS THE BEST")
print("   POLICY FOR AN AGENT THAT EXPLORES. if the exploration is switched off")
print("   at the end, Q-learning's answer is better. if the agent must keep")
print("   exploring in the real world, and falling off the cliff is a real")
print("   robot falling off a real table, SARSA's is.")
munotes.in525

Q-Learning

THE AGENT IS GIVEN NOTHING. it does not know the slip probabilities, the
step cost, where the pillar is, or where the exits are. it knows the four
actions and it can see which square it is in. everything else it must
learn from what happens.

   Q(s, a) is the value of TAKING action a in state s and behaving well
   afterwards. the update, after every single step:

      Q(s,a) <- Q(s,a) + alpha * [ r + gamma * max over a' of Q(s',a')
                                   - Q(s,a) ]

   the bracket is the TEMPORAL DIFFERENCE ERROR: what the step actually
   suggests the value is, minus what was believed. alpha decides how much
   of that correction to apply.

   NOTE WHERE THE MODEL WOULD HAVE BEEN. the Bellman equation summed over
   every next state weighted by P(s'|s,a). this update uses the ONE next
   state that actually happened. the average is accumulated over many
   visits instead of being computed, which is why no model is needed.

LEARNING. alpha = 0.10, epsilon = 0.20, episodes from random squares.
   the last column is what matters: not whether the learnt policy MATCHES
   the optimal one, but what it is WORTH. the optimal policy is worth
   +0.7053 from the start square.

   episodes | largest value error | actions matching | policy is worth
         10 |              0.8099 |     5 of 9       | -1.0641
        100 |              0.6555 |     5 of 9       | +0.2855
       1000 |              0.2007 |     7 of 9       | +0.6817
      10000 |              0.0775 |     7 of 9       | +0.2625
     100000 |              0.1067 |     9 of 9       | +0.7053

   after 100000 episodes, the values Q-learning believes:
      +0.8784   +0.9209   +0.9824         .
      +0.8199         #   +0.5965         .
      +0.7537   +0.6960   +0.6505   +0.2812
   what value iteration computed WITH the model:
      +0.8116   +0.8678   +0.9178         .
      +0.7616         #   +0.6603         .
      +0.7053   +0.6553   +0.6114   +0.3879
   the policy it acts on, then the optimal one:
          E       E       E      +1
          N       #       N      -1
          N       W       W       W
   ---
          E       E       E      +1
          N       #       N      -1
          N       W       W       W
   9 of 9 actions agree, and the learnt policy is worth +0.7053 against
   +0.7053 for the optimal one: a loss of 0.0000.

   THE VALUES ARE STILL WRONG BY 0.1067 AND THE POLICY IS RIGHT. with a
   CONSTANT alpha the updates never stop moving: every visit pulls the
   estimate part of the way towards a single sampled outcome, so it keeps
   bouncing around the true value for ever. the bounce is roughly
   proportional to alpha.

   ALPHA AGAINST THE ERROR, at 20000 episodes each:
   alpha | largest value error | actions matching | policy is worth
    0.50 |              0.2855 |     8 of 9       | +0.7053
    0.20 |              0.1552 |     8 of 9       | +0.6926
    0.10 |              0.0798 |     8 of 9       | +0.6926
    0.05 |              0.0923 |     7 of 9       | +0.6926
    0.02 |              0.0736 |     8 of 9       | +0.6926
   a large alpha learns quickly and settles badly; a small one settles
   well and learns slowly. TO CONVERGE EXACTLY, alpha must SHRINK over
   time: the standard condition is that the alphas sum to infinity, so
   every estimate can still be moved anywhere, while their squares sum to
   something finite, so the bouncing dies away.

OFF-POLICY, which is the property that matters. run it again with the
agent choosing UNIFORMLY AT RANDOM at every step, never once using what
it has learnt:
          E       E       E       .
          N       #       N       .
          N       W       W       W
   largest value error 0.0730, 9 of 9 actions matching, and the policy it
   learnt is worth +0.7053 against the optimal +0.7053.
   AN AGENT THAT NEVER ONCE ACTED ON WHAT IT KNEW LEARNT THE OPTIMAL
   POLICY. that is what OFF-POLICY means: the policy learnt
   about is not the policy used to act, because the update takes the
   MAXIMUM over the next state's actions rather than the action the agent
   will actually take. it is also why the method can learn from logged
   data, from a human demonstrator, or from an old policy's records.

SARSA, the on-policy relative. one symbol changes in the update:
      Q-learning : ... + gamma * MAX over a' of Q(s',a')
      SARSA      : ... + gamma * Q(s', a'), where a' is the action the
                   agent will ACTUALLY take next
   so SARSA learns the value of the policy it is following, exploration
   and all. the name is the five things its update uses: s, a, r, s', a'.

   both on this grid, alpha 0.10, epsilon 0.20, 100000 episodes:
   method     | largest value error | actions matching | policy is worth
   Q-learning |              0.1067 |     9 of 9       | +0.7053
   SARSA      |              0.2045 |     9 of 9       | +0.7053
   on a forgiving grid they end in much the same place. the difference
   needs an environment where exploring is DANGEROUS.

SO HERE IS ONE: A CLIFF. a 6 by 3 corridor, start at the bottom left,
goal at the bottom right, and every square between them along the bottom
is a fall costing -100 that ends the episode. every other step costs -1.
THIS FLOOR IS NOT SLIPPERY: the danger is entirely the agent's own
exploration.
   method     | mean reward per episode over the last 500 | route taken
   Q-learning |                                    -19.39 | rows used: 0, 1
   SARSA      |                                    -13.81 | rows used: 0, 1, 2

   Q-LEARNING learns the OPTIMAL route, which runs along row 1, directly
   above the cliff. SARSA learns a route further from the edge.
   neither is mistaken. Q-learning's update takes the maximum, so it
   learns the value of the best route ASSUMING NO EXPLORATION; while it
   is still exploring, one random step in ten sends it over the edge and
   it collects a worse reward. SARSA's update uses the action it will
   really take, so the cost of its own exploration is built into the
   values, and it prefers a route where a random step is survivable.

   SO: Q-LEARNING LEARNS THE OPTIMAL POLICY AND SARSA LEARNS THE BEST
   POLICY FOR AN AGENT THAT EXPLORES. if the exploration is switched off
   at the end, Q-learning's answer is better. if the agent must keep
   exploring in the real world, and falling off the cliff is a real
   robot falling off a real table, SARSA's is.
munotes.in526

Q-Learning

Learning from nothing

The agent is given no slip probabilities, no step cost, no knowledge of where the pillar or the exits are. It knows the four actions and can see which square it is in.

munotes.in527

Q-Learning

EpisodesLargest value errorActions matchingThe policy is worth
100.80995 of 9-1.0641
1000.65555 of 9+0.2855
10000.20077 of 9+0.6817
100000.07757 of 9+0.2625
1000000.10679 of 9+0.7053
munotes.in528

Q-Learning

Read the last column, not the middle one. What matters is not whether the learnt policy matches the optimal one but what it is worth, and the two are not the same thing.

munotes.in529

Q-Learning

Look at the 1000-episode and 10000-episode rows: both match in 7 of 9 states, and one is worth +0.6817 and the other +0.2625. Which two states disagree matters enormously, and a count of matching actions hides it entirely. At 100,000 episodes the policy is identical to the optimal one and worth +0.7053, a loss of 0.0000 against an algorithm that was allowed to see the model.

munotes.in530

Q-Learning

The values are still wrong by 0.1067 while the policy is exactly right. Same point as the previous chapter: the policy needs only the order of the action values.

munotes.in531

Q-Learning

Why the values never quite settle

With a constant alpha the updates never stop moving. Every visit pulls the estimate part of the way towards a single sampled outcome, so it bounces around the true value for ever, and the bounce is roughly proportional to alpha.

munotes.in532

Q-Learning

alphaLargest value error at 30,000 episodesThe policy is worth
0.500.2736+0.7053
0.200.1076+0.6926
0.100.1062+0.6681
0.050.0396+0.6926
0.020.0779+0.6926

A large alpha learns quickly and settles badly; a small one settles well and learns slowly. At 0.02 the error is larger than at 0.05 simply because 30,000 episodes were not enough for it.

To converge exactly, alpha must shrink. The standard condition, worth quoting: the learning rates must sum to infinity, so that any estimate can still be moved anywhere however late, while the sum of their squares is finite, so that the bouncing dies away. 1/n satisfies both; a constant satisfies only the first.

Off-policy, which is the property that matters

The same algorithm, with the agent choosing uniformly at random at every step, never once using what it had learnt:

E E E

N # N

N W W

9 of 9 actions matching, worth +0.7053: the optimal policy. An agent that never acted on its own knowledge learnt exactly what to do.

That is what off-policy means: the policy being learnt about is not the policy being used to act. The mechanism is visible in the update: it takes the maximum over the next state's actions, not the action the agent will actually take, so it evaluates the greedy policy while behaving however it likes.

And the consequence in practice, which is why the property is valuable: Q-learning can learn from logged data, from a human demonstrator, or from an old policy's records. It does not need to be in control of what happens.

SARSA

One symbol changes:

Q-learning : ... + gamma * MAX over a' of Q(s', a')

SARSA : ... + gamma * Q(s', a'), where a' is the action actually taken next

So SARSA learns the value of the policy it is following, exploration and all. The name is the five things its update uses: s, a, r, s', a'.

On the gridLargest value errorActions matchingWorth
Q-learning0.10679 of 9+0.7053
SARSA0.20459 of 9+0.7053

On a forgiving grid they end in much the same place. The difference needs an environment where exploring is dangerous.

The cliff

A six by three corridor. Start bottom left, goal bottom right, and every square between them along the bottom is a fall costing -100 that ends the episode. Every other step costs -1. The floor is not slippery: the danger is entirely the agent's own exploration.

munotes.in533

Q-Learning

Mean reward over the last 500 episodesRoute
Q-learning-19.39rows 0 and 1: along the cliff edge
SARSA-13.81rows 0, 1 and 2: away from the edge

Q-learning scores worse while learning the better policy, and neither is mistaken.

Q-learning's update takes the maximum, so it learns the value of the optimal route assuming no exploration. The optimal route runs along row 1, directly above the cliff. But while it is still exploring, one random step in ten sends it over the edge for -100, so the reward it actually collects is poor.

SARSA's update uses the action it will really take, so the cost of its own exploration is built into the values. A square next to the cliff is genuinely bad for an agent that sometimes steps at random, so SARSA learns a route further from the edge and collects more.

Q-learning learns the optimal policy; SARSA learns the best policy for an agent that explores. Which is wanted depends on the situation:

SituationPrefer
Exploration will be switched off at the endQ-learning
The agent keeps exploring in the real worldSARSA
Falling off the cliff is a real robot falling off a real tableSARSA
Learning from logged data or a demonstratorQ-learning, since SARSA needs its own actions

Where this leads

Everything here stores one number per state and action. The grid has 9 states and 4 actions, so 36 numbers. A board game or a camera image has more states than there are atoms to store them in, and the table is impossible.

The repair is to replace the table with a function approximator that takes the state and returns the action values: a linear model, or a neural network, which is deep Q-learning. Everything in this chapter still applies, and the convergence guarantees do not: with a table Q-learning is proved to converge, and with an approximator it can diverge.

Distinctions

V(s)Q(s, a)
Carries the actionnoyes
To act, needs the modelyesno
Numbers stored here936
Value iterationQ-learning
Needs P and Ryesno
Usesthe sum over next statesthe one state that happened
Source of the averagecomputedaccumulated over visits
Result here+0.7053+0.7053
Q-learningSARSA
Bootstraps frommax over a'the action actually taken
Policyoff-policyon-policy
Learnsthe optimal policythe best policy for an exploring agent
On the cliff-19.39, along the edge-13.81, away from it
Can learn from logged datayesno

What it does not mean

Q-learning does not build a model. It never estimates P(s' given s, a).

munotes.in534

Q-Learning

Matching the optimal policy is not the measure. Two policies matched in 7 of 9 states and were worth +0.6817 and +0.2625.

A constant learning rate does not converge. The estimates bounce for ever, in proportion to alpha.

Off-policy does not mean the behaviour is irrelevant. Every state and action must still be visited, or its value is never learned.

Q-learning's poorer score on the cliff is not a failure. It is the cost of exploring while following an optimal route.

SARSA is not a worse algorithm. It answers a different question, and on a real robot it is usually the one wanted.

The table does not scale. Large problems need function approximation, which loses the convergence guarantee.

Quick revision

  • Q(s, a) is the value of taking a in s and behaving well afterwards. V(s) = max over a of Q(s,a), and the policy is whichever action attains it, with no model.
  • The update: Q(s,a) <- Q(s,a) + alpha [ r + gamma max over a' of Q(s',a') - Q(s,a) ]. The bracket is the temporal difference error.
  • Sampling replaces the sum: the Bellman equation averaged over every next state; this uses the one that happened, and the average accumulates over visits.
  • Measured: after 100,000 episodes the policy is identical to value iteration's and worth +0.7053, with the values still wrong by 0.1067. The policy needs only the order.
  • Judge a policy by what it is worth, not by how many actions match. Two runs matched 7 of 9 and were worth +0.6817 and +0.2625.
  • Constant alpha never converges: error 0.2736 at alpha = 0.50 and 0.0396 at 0.05. To converge, the alphas must sum to infinity with their squares summing to something finite.
  • Off-policy: an agent acting uniformly at random learnt the optimal policy, 9 of 9, worth +0.7053, because the update takes the max rather than the action taken. Hence learning from logged data or a demonstrator.
  • SARSA replaces the max with the action actually taken next, so it is on-policy: s, a, r, s', a'.
  • The cliff: Q-learning -19.39 along the edge, SARSA -13.81 away from it. Q-learning learns the optimal policy; SARSA learns the best policy for an agent that explores.
  • The table is one number per state and action. Large problems replace it with a function approximator, giving deep Q-learning, which loses the convergence guarantee.

Test yourself

1. Write the Q-learning update and name the bracketed term. Q(s,a) becomes Q(s,a) plus alpha times the quantity r + gamma * max over a' of Q(s',a') - Q(s,a). That quantity is the temporal difference error: what the observed step suggests the value should be, minus what was believed.

munotes.in535

Q-Learning

2. Why does Q-learning need no model of the environment? The Bellman equation requires a sum over all next states weighted by their transition probabilities, which needs the model. The update replaces that sum with the single next state that actually occurred, and averages over many visits instead of computing the average, so the transition probabilities are never needed. Storing values for actions rather than states also means the policy can be read off without looking ahead.

3. In the measurement, two runs both matched the optimal policy in 7 of 9 states and were worth +0.6817 and +0.2625. What does that show? That counting matching actions is a poor measure of a policy. Which states disagree matters far more than how many, since an error in a state the agent passes through often or one that leads towards the penalty costs a great deal, while an error in a rarely visited state costs almost nothing.

4. Why do the values keep changing with a constant learning rate, and what condition fixes it? Each update moves the estimate part of the way towards one sampled outcome, so the estimate keeps being pulled around by individual samples and bounces about the true value in proportion to alpha. Exact convergence requires alpha to shrink so that the learning rates sum to infinity, leaving every estimate still movable, while the sum of their squares is finite, so the fluctuation dies away.

5. What does off-policy mean, and what evidence was given for it? That the policy being learnt about is not the one being used to act, because the update bootstraps from the maximum over the next state's actions rather than the action that will be taken. The evidence was a run in which the agent chose uniformly at random at every step and never used what it had learnt, and still recovered the optimal policy in all nine states, worth +0.7053.

6. State the difference between Q-learning and SARSA in one line, and explain the cliff result. Q-learning bootstraps from the maximum over the next actions; SARSA bootstraps from the action it will actually take. On the cliff Q-learning learns the optimal route along the edge and collects -19.39 per episode, because while exploring it sometimes steps off; SARSA builds the cost of its own exploration into the values, learns a route further from the edge, and collects -13.81. Q-learning has found the better policy for an agent that will stop exploring; SARSA the better policy for one that will not.

7. When would you prefer each? Q-learning when exploration will be turned off before the policy is used, and when learning must happen from logged data or a demonstrator's records, which SARSA cannot do because it needs its own action choices. SARSA when the agent will keep exploring in the real world and the mistakes are expensive, such as a physical robot near a drop.

Contents This chapter on its own page

munotes.in536

Chapter Eighty-Two

Ethical Issues in AI Systems

Syllabus topic Module 2, "Ethical issues in AI systems"

In one line

The ethical questions about an AI system are not opinions about the future; they are about measurable harms that particular systems have already done to particular people.

MU's Course Outcome 5 asks a student to "cultivate awareness of ethical considerations and responsible AI practices", and its outcome OC 5 asks the student to assess AI systems from a responsible AI perspective. Assess is the operative word. This block of the syllabus is not a request for views; it is a request for a method.

Why a technical subject ends with this

The rest of this book has been about making a model accurate. Every measure in Evaluating a Model scored a prediction against a truth. Not one of them asks who the prediction is about, what happens to that person afterwards, or whether the person can ask why.

Three facts, each established earlier in this book, make the questions unavoidable:

Earlier chapterThe factWhy it matters here
Evaluating a Modela classifier scoring 0.9700 accuracy was worthlessan aggregate number can hide the whole of the behaviour
Bias and Variancea model fits the data it was givena data set records the world as it was, including its injustices
Ensemble Methods, Bagging and The Random Forest301 trees are not a set of rulesthe model that works best is often the one nobody can read

A taxonomy of harms

A paper asking to "discuss ethical issues in AI" is answered badly by a list of worries and well by a taxonomy with examples. Two cuts are standard and worth both.

The first cut: what kind of harm it is.

Allocative harmRepresentational harm
The systemwithholds or grants somethingdescribes people in a way that demeans or erases
Examplea loan, a job interview, bail, a college placea search that returns degrading results for one group's name
Measurableyes, by outcome ratesharder, and no less real
Fixed bychanging the decision rulechanging the data, the task, or abandoning it

The second cut: where in the pipeline it entered.

StageThe harm that enters there
The questionautomating a decision that should not be automated at all
The dataa sample that does not represent the people it will be used on
The labela proxy that is not the thing wanted: arrests recorded instead of crimes committed
The modelan accuracy optimised on the average, which is the majority
The deploymentuse on a population, or for a purpose, the model was never tested on
The feedbackthe model's own outputs becoming tomorrow's training data

The last row is the one that is missed and it is the most dangerous. The Reinforcement Learning Framework made the same point about an agent generating its own data: a system that decides where to send police generates arrest records in the places it sent them, and those records then justify sending more. The loop is closed and it looks like confirmation.

munotes.in537

Ethical Issues in AI Systems

The measured harms

Three findings, from the three sources on file, so that an answer can cite rather than assert.

Face classification is not equally accurate for everyone

Buolamwini and Gebru, 2018, tested three commercial gender classification services and reported:

FindingFigure
All classifiers perform better on male than female faces8.1 to 20.6 per cent difference in error rate
All classifiers perform better on lighter than darker faces11.8 to 19.2 per cent difference in error rate
All classifiers perform worst on darker female faces20.8 to 34.7 per cent error rate
Two of the three perform best on lighter male faceserror rates of 0.0 and 0.3 per cent
Maximum difference between the best and worst classified groups34.4 per cent

Read the first and last rows together. A system whose error ranges from 0.0 per cent to 34.7 per cent depending on who is in front of it can still be advertised by a single average accuracy, and all three vendors were. The paper also records that none of the three reported performance on existing benchmarks in their documentation, and that one explicitly disclaimed any warranty of accuracy.

The cost of training is not free

Bender and colleagues, 2021, citing Strubell and colleagues' benchmark:

An average human is responsible foran estimated 5 tonnes of CO2 equivalent per year
Training one large Transformer with neural architecture search was estimated to emit284 tonnes of CO2
Training a single BERT base model on GPUs requiredas much energy as a trans-American flight

The paper's own point about these numbers is not that the training should not happen. It is that the risks and the benefits do not accrue to the same people, and it notes the literature on environmental harms falling on populations who are not the ones using the systems.

Undocumented data cannot be held to account

Bender and colleagues name documentation debt: relying on ever larger data sets until they are both undocumented and too large to document afterwards. The consequence they draw is precise and is worth memorising: undocumented training data perpetuates harm without recourse. If nobody can say what is in the data, nobody can say what the model learned, and nobody can be asked to fix it.

The issues, named

A syllabus answer should name these and give one line each. The four that follow this chapter have their own treatment; the rest belong here.

munotes.in538

Ethical Issues in AI Systems

IssueThe question it asks
Bias and discriminationdoes the system work equally well for everyone it is used on? Bias and Fairness in AI Models
Transparencycan anyone find out how it works? Transparency and Explainability
Accountabilitywhen it is wrong, who answers? Accountability and Human Oversight
Generative riskswhat does it produce that is not true, and who is harmed? Hallucination in Generative AI, Deepfakes and Misuse
Privacy and consentwere the people in the training data asked, and can they leave?
Surveillancedoes the system make watching people cheap enough to do by default?
Labourwhose work does it replace, and whose work, often invisible, labelled its data?
Environmental cost284 tonnes for one training run
Concentration of powerwho can afford to train, and therefore to decide?
Dual usea model that detects a disease detects who has it, for an insurer too
Safetywhat is the worst outcome of a wrong answer, and who bears it?
Autonomyis a person still deciding, or merely confirming?

Note that several of these are not about a defect. Dual use, surveillance and concentration of power are consequences of the system working exactly as intended, which is why they are not fixed by better accuracy.

The framework, so an answer has a structure

The NIST AI Risk Management Framework 1.0, published in 2023, is on file and is the most quotable structure for this topic. It names seven characteristics of trustworthy AI:

1valid and reliable
2safe
3secure and resilient
4accountable and transparent
5explainable and interpretable
6privacy-enhanced
7fair, with harmful bias managed

Two remarks from the framework itself are worth carrying, because they are the ones students most often get wrong.

Valid and reliable is the base. The framework shows it as the foundation the others rest on, and accountability and transparency as running through all of them. A system that does not work cannot be made trustworthy by any of the other six.

They trade off against each other. The framework says so directly: highly secure but unfair systems, accurate but opaque systems, and inaccurate but secure and transparent systems are all undesirable, and risk management means balancing them. There is no setting in which all seven are maximised, which is why "responsible AI" is a design problem and not a checkbox.

And the framework's four functions, which are the verbs of the process: govern, map, measure and manage. Governance runs through the other three rather than preceding them.

How to assess a system, which is what OC 5 asks

This is the examinable skill. Given a described system, these are the questions, in order.

munotes.in539

Ethical Issues in AI Systems

QuestionWhat a bad answer looks like
1What decision does it make, about whom, and what happens to them next?"it classifies images"
2Should this decision be automated at all?assuming yes
3Where did the data come from, who is in it, and who is not?"a large public data set"
4What is the label actually recording, and is it the thing wanted?treating a proxy as the truth
5What is the accuracy for each group, not overall?one number
6What are the two kinds of error, and which costs more, to whom?reporting accuracy
7Can the person affected find out why, and contest it?"the model is complex"
8Who is accountable when it is wrong, by name and role?"the system"
9What happens as its outputs become its own future inputs?not considering it
10How will it be monitored after deployment, and what triggers a stop?shipping and leaving

Question 5 is where Evaluating a Model and this chapter meet exactly: a confusion matrix per group is the single most useful artefact in a responsible AI assessment, and it is arithmetic a second-year student can already do.

What it does not mean

Ethics is not the opposite of accuracy. Gender Shades is a measurement of accuracy, group by group.

A high average is not fairness. 0.0 per cent for one group and 34.7 for another averages to something respectable.

These are not future problems. All three findings quoted here are published measurements of deployed systems.

Not every issue is a bug. Surveillance, dual use and concentration of power follow from the system working.

A framework is not a checklist. NIST says its seven characteristics trade off and must be balanced.

"The algorithm decided" is not an account. Somebody chose the question, the data, the label and the threshold.

Awareness is not the outcome asked for. MU asks the student to assess, which means producing an answer about a particular system.

Quick revision

  • MU's outcome is to assess a system from a responsible AI perspective, not to hold opinions.
  • Harms divide into allocative (something is granted or withheld) and representational (people are described demeaningly), and by where they entered: the question, the data, the label, the model, the deployment, the feedback loop.
  • The feedback loop is the dangerous one: a system's outputs become its own training data and look like confirmation.
  • Buolamwini and Gebru, 2018: male against female error difference 8.1 to 20.6 per cent; lighter against darker 11.8 to 19.2; worst group, darker female faces, 20.8 to 34.7 per cent error; best, lighter male faces, 0.0 and 0.3 per cent; maximum gap 34.4 per cent.
  • Bender and colleagues, 2021, citing Strubell: an average human 5 tonnes of CO2 equivalent a year; one large Transformer training run with architecture search an estimated 284 tonnes; one BERT base training run as much energy as a trans-American flight. The risks and benefits do not accrue to the same people.
  • Documentation debt: data both undocumented and too large to document afterwards. Undocumented training data perpetuates harm without recourse.
  • NIST AI RMF 1.0, 2023: seven characteristics, valid and reliable, safe, secure and resilient, accountable and transparent, explainable and interpretable, privacy-enhanced, fair with harmful bias managed; valid and reliable is the base; they trade off. Four functions: govern, map, measure, manage.
  • The assessment questions: what decision about whom; should it be automated; whose data; what is the label really; accuracy per group; which error costs more; can it be contested; who is accountable; what does the feedback loop do; what triggers a stop.
munotes.in540

Ethical Issues in AI Systems

Test yourself

1. Distinguish allocative from representational harm, with an example of each. An allocative harm is a system granting or withholding something of value, such as a loan, a job interview or a college place, unequally. A representational harm is a system describing a group of people in a way that demeans or erases them, such as a search returning degrading results for one group's name. Allocative harms can usually be measured by comparing outcome rates; representational harms are harder to quantify and no less real.

2. Where can bias enter a machine learning pipeline? At the choice of question, by automating a decision that should not be automated; in the data, through a sample unrepresentative of the people it will be used on; in the label, by recording a proxy such as arrests rather than the thing wanted; in the model, by optimising an average that is dominated by the majority; in deployment, by use on a population or purpose never tested; and in the feedback loop, where the system's own outputs become its future training data.

3. Why is the feedback loop the most dangerous stage? Because the system's outputs shape the data that will be used to judge and retrain it, so its mistakes are confirmed rather than corrected. A system that sends attention to certain places generates records in those places, and those records then justify sending more attention, which looks like evidence that the system was right.

4. Summarise the Gender Shades findings and say what they show about reporting accuracy. Three commercial gender classifiers were better on male than female faces by 8.1 to 20.6 per cent in error rate, and better on lighter than darker faces by 11.8 to 19.2 per cent. All performed worst on darker female faces, with error rates of 20.8 to 34.7 per cent, while two performed best on lighter male faces at 0.0 and 0.3 per cent. The largest gap between best and worst classified groups was 34.4 per cent. A single overall accuracy figure can therefore conceal an error rate varying from nothing to a third depending on who is in front of the camera.

munotes.in541

Ethical Issues in AI Systems

5. What is documentation debt and what follows from it? Relying on data sets so large that they are undocumented and can no longer be documented after the fact. It follows that nobody can say what the model learned or why, so no harm traced to the data can be attributed, contested or repaired, which is why the authors write that undocumented training data perpetuates harm without recourse.

6. Name the seven NIST trustworthiness characteristics and state two things the framework says about them. Valid and reliable; safe; secure and resilient; accountable and transparent; explainable and interpretable; privacy-enhanced; and fair with harmful bias managed. The framework treats valid and reliable as the base on which the others rest, so a system that does not work cannot be made trustworthy by the rest, and it states that the characteristics trade off against one another, so managing risk means balancing them rather than maximising all seven.

7. A college proposes to rank scholarship applicants with a model trained on which past applicants graduated. Give five questions you would ask. What exactly is being decided and what happens to a rejected applicant next. Should the decision be automated at all, or should the model only order a list a person reads. Who is in the training data, and which kinds of applicant are absent from it, since past admissions decide who could graduate. Is graduation the thing wanted, or a proxy shaped by who received support after admission. And what is the accuracy separately for each group of applicants, with the two kinds of error distinguished, since rejecting a student who would have succeeded and funding one who does not are not equally costly to the same people.

Contents This chapter on its own page

munotes.in542

Chapter Eighty-Three

Bias and Fairness in AI Models

Syllabus topic Module 2, "Bias and fairness in AI models"

In one line

Bias is not a bug in the algorithm; it is what the algorithm learns when the world the data came from was unequal, and no single definition of fairness can remove it.

MU's outcome OC 5 names bias and fairness together. They are different things: bias is a property of a system's behaviour, and fairness is a criterion someone has chosen to judge it by. The second is where the difficulty is.

Where bias comes from

Six sources, and a paper asking "where does bias enter" wants them separated rather than lumped as "biased data".

SourceWhat it isExample
Historicalthe world was unequal and the data records it faithfullypast hiring favoured one group, so the labels do
Representationsome group is under-sampleda face data set with few darker faces
Measurementthe label is a proxy for the thing wantedarrests recorded instead of offences committed
Aggregationone model for groups that behave differentlya threshold tuned on the majority
Learningthe objective itselfaccuracy is dominated by the largest group
Deploymentuse outside the tested population or purposea model built for one city used in another

Historical bias is the one that cannot be fixed by better data collection, because the data is already correct. It records what happened. Bias and Variance said a model fits the data it was given, and this is the cost of that.

And note that measurement bias is often invisible in the metrics. A model predicting re-arrest with perfect accuracy is a perfect model of policing, not of crime, and every score in Evaluating a Model will look excellent.

The measurement

# Fairness, computed. Three reasonable definitions are applied to one classifier
# and they disagree; then every threshold is tried and none satisfies all three.
# Finally the protected attribute is deleted and the bias survives.
def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(606060)
rnd = lambda: next(gen)                                   # noqa: E731

# 400 scholarship applicants in two groups. The TRUE outcome is whether the
# student would complete the course if funded. The two groups have DIFFERENT
# BASE RATES, which is a fact about the world the data came from and not a
# property of the people: group B's schools prepared them less well.
BASE = {"A": 0.60, "B": 0.30}
SIZE = {"A": 300, "B": 100}
people = []
for g in ("A", "B"):
    for _ in range(SIZE[g]):
        completes = rnd() < BASE[g]
        # the admission score: correlated with the outcome, noisily, and NOT
        # with the group beyond what the outcome already carries.
        score = (0.55 if completes else 0.35) + (rnd() - 0.5) * 0.5
        # two harmless-looking extra facts, both correlated with the group
        coaching = rnd() < (0.70 if g == "A" else 0.20)
        english_medium = rnd() < (0.80 if g == "A" else 0.35)
        people.append({"group": g, "completes": completes, "score": score,
                       "coaching": coaching, "english": english_medium})

def counts(rows, threshold):
    tp = sum(1 for r in rows if r["score"] >= threshold and r["completes"])
    fp = sum(1 for r in rows if r["score"] >= threshold and not r["completes"])
    fn = sum(1 for r in rows if r["score"] < threshold and r["completes"])
    tn = sum(1 for r in rows if r["score"] < threshold and not r["completes"])
    return tp, fp, fn, tn

def measures(rows, threshold):
    tp, fp, fn, tn = counts(rows, threshold)
    n = len(rows)
    return {
        "selected": (tp + fp) / n,                                  # demographic parity
        "tpr": tp / (tp + fn) if tp + fn else 0.0,                  # equal opportunity
        "fpr": fp / (fp + tn) if fp + tn else 0.0,                  # equalised odds
        "precision": tp / (tp + fp) if tp + fp else 0.0,            # predictive parity
        "base": (tp + fn) / n,
        "n": n,
    }

A = [r for r in people if r["group"] == "A"]
B = [r for r in people if r["group"] == "B"]

print("400 SCHOLARSHIP APPLICANTS. the decision is whether to fund; the true")
print("outcome is whether the student would complete the course if funded.")
print("   group | applicants | proportion who would complete")
for g, rows in (("A", A), ("B", B)):
    print("   %5s | %10d | %.4f"
          % (g, len(rows), sum(1 for r in rows if r["completes"]) / len(rows)))
print("   THE BASE RATES DIFFER. that is a fact about the schooling the two")
print("   groups received, recorded in the data. everything below follows from")
print("   it, and NOTHING below can be fixed by choosing a better model.")
print()

print("FOUR DEFINITIONS OF FAIRNESS, each of which someone will defend:")
print("   DEMOGRAPHIC PARITY  the same PROPORTION of each group is funded.")
print("   EQUAL OPPORTUNITY   of those who WOULD complete, the same proportion")
print("                       of each group is funded. (equal true positive rate)")
print("   EQUALISED ODDS      equal true positive rate AND equal false positive")
print("                       rate.")
print("   PREDICTIVE PARITY   of those funded, the same proportion of each group")
print("                       completes. (equal precision)")
print()

T = 0.45
print("ONE CLASSIFIER: fund everyone whose score is at least %.2f." % T)
print("   group | funded | funded of all | TPR (opportunity) | FPR | precision")
for g, rows in (("A", A), ("B", B)):
    m = measures(rows, T)
    tp, fp, fn, tn = counts(rows, T)
    print("   %5s | %6d | %13.4f | %17.4f | %.4f | %9.4f"
          % (g, tp + fp, m["selected"], m["tpr"], m["fpr"], m["precision"]))
ma, mb = measures(A, T), measures(B, T)
print()
print("   IT FAILS DEMOGRAPHIC PARITY: %.4f of group A is funded and %.4f of"
      % (ma["selected"], mb["selected"]))
print("   group B, a gap of %.4f." % abs(ma["selected"] - mb["selected"]))
print("   IT FAILS EQUAL OPPORTUNITY: %.4f against %.4f, a gap of %.4f."
      % (ma["tpr"], mb["tpr"], abs(ma["tpr"] - mb["tpr"])))
print("   IT FAILS PREDICTIVE PARITY: %.4f against %.4f, a gap of %.4f."
      % (ma["precision"], mb["precision"], abs(ma["precision"] - mb["precision"])))
print()

print("SO REPAIR IT. hold group A at %.2f and try EVERY threshold for group B," % T)
print("looking for one that makes all three agree:")
print("   B's cut | B funded | gap in funded | gap in TPR | gap in precision")
best = {}
for i in range(0, 81):
    t = 0.10 + i * 0.01
    mb2 = measures(B, t)
    gaps = {"funded": abs(ma["selected"] - mb2["selected"]),
            "tpr": abs(ma["tpr"] - mb2["tpr"]),
            "precision": abs(ma["precision"] - mb2["precision"])}
    for k, v in gaps.items():
        if k not in best or v < best[k][0]:
            best[k] = (v, t, mb2)
    if i % 8 == 0:
        print("   %7.2f | %8d | %13.4f | %10.4f | %16.4f"
              % (t, sum(1 for r in B if r["score"] >= t),
                 gaps["funded"], gaps["tpr"], gaps["precision"]))
print()
print("   THE BEST THRESHOLD FOR EACH DEFINITION, AND WHAT IT COSTS THE OTHERS:")
print("   aiming at          | B's cut | gap funded | gap TPR | gap precision")
for k in ("funded", "tpr", "precision"):
    v, t, mb2 = best[k]
    print("   %-18s | %7.2f | %10.4f | %7.4f | %13.4f"
          % ({"funded": "demographic parity", "tpr": "equal opportunity",
              "precision": "predictive parity"}[k], t,
             abs(ma["selected"] - mb2["selected"]),
             abs(ma["tpr"] - mb2["tpr"]),
             abs(ma["precision"] - mb2["precision"])))
print()
print("   NO ROW HAS THREE SMALL NUMBERS. equalising any one definition pushes")
print("   the others apart, and the three thresholds are different numbers.")
print()
print("   AND IT IS NOT A FAILURE OF SEARCHING. the arithmetic forbids it.")
print("   write b for a group's base rate, p for precision, t for the true")
print("   positive rate and f for the false positive rate. counting the members")
print("   of the group two ways gives, for every group,")
print("      p = b*t / ( b*t + (1-b)*f )")
print("   so if two groups share p, t and f but differ in b, that identity is")
print("   violated. IF THE BASE RATES DIFFER, EQUAL PRECISION AND EQUALISED ODDS")
print("   CANNOT BOTH HOLD, unless the classifier is perfect. checked on the")
print("   figures above:")
for g, rows, m in (("A", A, ma), ("B", B, mb)):
    b, t, f = m["base"], m["tpr"], m["fpr"]
    implied = b * t / (b * t + (1 - b) * f) if (b * t + (1 - b) * f) else 0.0
    print("      group %s: b=%.4f t=%.4f f=%.4f  ->  p = %.4f, measured %.4f"
          % (g, b, t, f, implied, m["precision"]))
print()

print("DELETING THE GROUP LABEL DOES NOT HELP, and this is the commonest")
print("mistake. remove 'group' from the data and keep the two harmless facts:")
print("whether the applicant had coaching, and whether they studied in English.")
print("   how often each is true, by group:")
for g, rows in (("A", A), ("B", B)):
    print("      group %s: coaching %.4f, english medium %.4f"
          % (g, sum(1 for r in rows if r["coaching"]) / len(rows),
             sum(1 for r in rows if r["english"]) / len(rows)))
print()
print("   now try to RECOVER the group from those two facts alone, with the")
print("   simplest possible rule: for each combination, guess the commoner group.")
table = {}
for r in people:
    key = (r["coaching"], r["english"])
    table.setdefault(key, []).append(r["group"])
right = 0
print("   coaching | english | members | commoner group | guess is right")
for key in sorted(table):
    members = table[key]
    guess = max(("A", "B"), key=lambda g: members.count(g))
    hits = members.count(guess)
    right += hits
    print("   %8s | %7s | %7d | %14s | %d of %d"
          % (key[0], key[1], len(members), guess, hits, len(members)))
majority = max(len(A), len(B)) / len(people)
print("   the rule is right %d times in %d, %.4f, against %.4f for always"
      % (right, len(people), right / len(people), majority))
print("   guessing the larger group.")
print()
print("   THE PROTECTED ATTRIBUTE IS STILL IN THE DATA. it is spread across the")
print("   other columns, and any model that uses them uses it. DELETING A COLUMN")
print("   IS NOT A FAIRNESS INTERVENTION; it only removes the ability to MEASURE")
print("   what the model is doing to each group.")
print()
print("   WHICH GIVES THE ONE RULE WORTH TAKING AWAY: keep the protected")
print("   attribute, do not train on it, and use it to AUDIT. a model that")
print("   cannot be audited by group is not fairer; it is unexaminable.")
munotes.in543

Bias and Fairness in AI Models

400 SCHOLARSHIP APPLICANTS. the decision is whether to fund; the true
outcome is whether the student would complete the course if funded.
   group | applicants | proportion who would complete
       A |        300 | 0.6133
       B |        100 | 0.3100
   THE BASE RATES DIFFER. that is a fact about the schooling the two
   groups received, recorded in the data. everything below follows from
   it, and NOTHING below can be fixed by choosing a better model.

FOUR DEFINITIONS OF FAIRNESS, each of which someone will defend:
   DEMOGRAPHIC PARITY  the same PROPORTION of each group is funded.
   EQUAL OPPORTUNITY   of those who WOULD complete, the same proportion
                       of each group is funded. (equal true positive rate)
   EQUALISED ODDS      equal true positive rate AND equal false positive
                       rate.
   PREDICTIVE PARITY   of those funded, the same proportion of each group
                       completes. (equal precision)

ONE CLASSIFIER: fund everyone whose score is at least 0.45.
   group | funded | funded of all | TPR (opportunity) | FPR | precision
       A |    165 |        0.5500 |            0.7446 | 0.2414 |    0.8303
       B |     36 |        0.3600 |            0.5161 | 0.2899 |    0.4444

   IT FAILS DEMOGRAPHIC PARITY: 0.5500 of group A is funded and 0.3600 of
   group B, a gap of 0.1900.
   IT FAILS EQUAL OPPORTUNITY: 0.7446 against 0.5161, a gap of 0.2284.
   IT FAILS PREDICTIVE PARITY: 0.8303 against 0.4444, a gap of 0.3859.

SO REPAIR IT. hold group A at 0.45 and try EVERY threshold for group B,
looking for one that makes all three agree:
   B's cut | B funded | gap in funded | gap in TPR | gap in precision
      0.10 |      100 |        0.4500 |     0.2554 |           0.5203
      0.18 |       91 |        0.3600 |     0.2554 |           0.4896
      0.26 |       80 |        0.2500 |     0.2554 |           0.4428
      0.34 |       64 |        0.0900 |     0.2232 |           0.3616
      0.42 |       43 |        0.1200 |     0.0671 |           0.3419
      0.50 |       28 |        0.2700 |     0.3252 |           0.3660
      0.58 |       12 |        0.4300 |     0.3897 |           0.0864
      0.66 |        7 |        0.4800 |     0.5188 |           0.1697
      0.74 |        1 |        0.5400 |     0.7123 |           0.1697
      0.82 |        0 |        0.5500 |     0.7446 |           0.8303
      0.90 |        0 |        0.5500 |     0.7446 |           0.8303

   THE BEST THRESHOLD FOR EACH DEFINITION, AND WHAT IT COSTS THE OTHERS:
   aiming at          | B's cut | gap funded | gap TPR | gap precision
   demographic parity |    0.37 |     0.0100 |  0.0941 |        0.3660
   equal opportunity  |    0.41 |     0.0600 |  0.0026 |        0.3609
   predictive parity  |    0.58 |     0.4300 |  0.3897 |        0.0864

   NO ROW HAS THREE SMALL NUMBERS. equalising any one definition pushes
   the others apart, and the three thresholds are different numbers.

   AND IT IS NOT A FAILURE OF SEARCHING. the arithmetic forbids it.
   write b for a group's base rate, p for precision, t for the true
   positive rate and f for the false positive rate. counting the members
   of the group two ways gives, for every group,
      p = b*t / ( b*t + (1-b)*f )
   so if two groups share p, t and f but differ in b, that identity is
   violated. IF THE BASE RATES DIFFER, EQUAL PRECISION AND EQUALISED ODDS
   CANNOT BOTH HOLD, unless the classifier is perfect. checked on the
   figures above:
      group A: b=0.6133 t=0.7446 f=0.2414  ->  p = 0.8303, measured 0.8303
      group B: b=0.3100 t=0.5161 f=0.2899  ->  p = 0.4444, measured 0.4444

DELETING THE GROUP LABEL DOES NOT HELP, and this is the commonest
mistake. remove 'group' from the data and keep the two harmless facts:
whether the applicant had coaching, and whether they studied in English.
   how often each is true, by group:
      group A: coaching 0.7167, english medium 0.7967
      group B: coaching 0.1500, english medium 0.3500

   now try to RECOVER the group from those two facts alone, with the
   simplest possible rule: for each combination, guess the commoner group.
   coaching | english | members | commoner group | guess is right
      False |   False |      70 |              B | 56 of 70
      False |    True |     100 |              A | 71 of 100
       True |   False |      56 |              A | 47 of 56
       True |    True |     174 |              A | 168 of 174
   the rule is right 342 times in 400, 0.8550, against 0.7500 for always
   guessing the larger group.

   THE PROTECTED ATTRIBUTE IS STILL IN THE DATA. it is spread across the
   other columns, and any model that uses them uses it. DELETING A COLUMN
   IS NOT A FAIRNESS INTERVENTION; it only removes the ability to MEASURE
   what the model is doing to each group.

   WHICH GIVES THE ONE RULE WORTH TAKING AWAY: keep the protected
   attribute, do not train on it, and use it to AUDIT. a model that
   cannot be audited by group is not fairer; it is unexaminable.
munotes.in544

Bias and Fairness in AI Models

Four definitions of fairness

Each is reasonable, each has been argued for in court and in print, and they are not the same. Learn all four with their formulae.

munotes.in545

Bias and Fairness in AI Models

DefinitionRequiresIn confusion-matrix terms
Demographic paritythe same proportion of each group is selectedequal (TP + FP) / n
Equal opportunityof those who would succeed, the same proportion is selectedequal true positive rate
Equalised oddsequal true positive rate and false positive rateboth, together
Predictive parityof those selected, the same proportion succeedsequal precision
munotes.in546

Bias and Fairness in AI Models

Two more worth naming: calibration, that a score of 0.7 means a 70 per cent chance in every group; and individual fairness, that similar individuals receive similar decisions, which needs a definition of "similar" and so moves the problem rather than solving it.

munotes.in547

Bias and Fairness in AI Models

One classifier, three failures

Four hundred scholarship applicants. Group A has a completion rate of 0.6133 and group B of 0.3100. The base rates differ, and the program says why that matters before any model is fitted: it is a fact about the schooling the two groups received, recorded faithfully in the data.

Fund everyone scoring at least 0.45:

FundedProportion fundedTrue positive rateFalse positive ratePrecision
A1650.55000.74460.24140.8303
B360.36000.51610.28990.4444

It fails all three: demographic parity by 0.1900, equal opportunity by 0.2284, predictive parity by 0.3859.

munotes.in548

Bias and Fairness in AI Models

So repair it, and watch the repair fail

Hold group A at 0.45 and try every threshold for group B. The best threshold for each definition, with what it costs the others:

Aiming atB's cutGap in proportion fundedGap in TPRGap in precision
demographic parity0.370.01000.09410.3660
equal opportunity0.410.06000.00260.3609
predictive parity0.580.43000.38970.0864

No row has three small numbers, and the three thresholds are three different numbers. Equalising any one definition pushes the others apart. The last row is the starkest: making the two groups' funded students equally likely to succeed means funding 43 per cent fewer of group B in proportion, and failing half the capable ones.

And it is not a failure of searching

The arithmetic forbids it, and this is the examinable core of the chapter. Write b for a group's base rate, p for precision, t for the true positive rate and f for the false positive rate. Counting the group's members two ways gives, for every group:

p = bt / ( bt + (1-b)*f )

The numerator is the selected members who succeed; the denominator adds those selected who do not. So p is determined by b, t and f. If two groups have equal t and equal f but different b, their p must differ. Equalised odds and predictive parity cannot both hold across groups with different base rates, unless the classifier is perfect.

The program checks the identity rather than asserting it:

btfp impliedp measured
A0.61330.74460.24140.83030.8303
B0.31000.51610.28990.44440.4444

This is the impossibility result of fairness in machine learning, and it is worth stating in an answer in exactly this form: with unequal base rates, you must choose which definition to satisfy. There is no classifier and no threshold that satisfies them all.

Which means the question "is this model fair?" has no technical answer. It has a technical answer only once someone has said which fairness is wanted, and that is a decision about values, taken by people who can be held to it.

Deleting the protected attribute does not work

The commonest proposal, and the one to be able to refute. Remove group from the data and keep two harmless-looking facts: whether the applicant had coaching, and whether they studied in English.

CoachingEnglish medium
A0.71670.7967
B0.15000.3500

Now recover the group from those two facts alone, with the simplest possible rule, guessing the commoner group for each combination:

CoachingEnglishMembersGuessRight
nono70B56 of 70
noyes100A71 of 100
yesno56A47 of 56
yesyes174A168 of 174
munotes.in549

Bias and Fairness in AI Models

0.8550 against a 0.7500 baseline for always guessing the larger group. A rule with two bits of input recovers the protected attribute most of the time, and a model with dozens of features will do far better.

The protected attribute is still in the data. It is spread across the other columns as a proxy, and any model using them uses it. Deleting the column is not a fairness intervention. It only removes the ability to measure what the model is doing to each group.

Hence the one rule worth carrying away: keep the protected attribute, do not train on it, and use it to audit. A model that cannot be audited by group is not fairer; it is unexaminable.

What can actually be done

Interventions divide by where they act, and a paper may ask for them.

Pre-processingIn-processingPost-processing
Acts onthe datathe trainingthe decisions
Examplereweighting, resampling under-represented groupsa fairness penalty added to the lossa different threshold per group
Advantagemodel-independentcan trade off preciselyworks on a model you cannot retrain
Difficultychanges what the data saysneeds access to trainingexplicitly uses the protected attribute, which may be unlawful

Note the last cell. A different threshold per group is the most effective post-processing repair and it is the most legally exposed, because it treats people differently by group on its face. The technically simplest answer and the legally simplest answer point in opposite directions.

And two things that are not interventions at all but are usually the most useful:

Report per-group metrics. A confusion matrix for each group, published. Evaluating a Model already gives the arithmetic, and Ethical Issues in AI Systems measured what hiding it cost: a 34.4 per cent gap behind a single advertised accuracy.

Ask whether the base rate difference is the thing to predict. Group B's completion rate is 0.3100 because of the schooling they received. A model predicting completion will encode that faithfully for ever. A scholarship whose purpose is to change that outcome should perhaps not be awarded by predicting it.

Distinctions

BiasFairness
Isa property of the system's behavioura criterion chosen to judge it
Measuredby comparing groupsonly after a definition is chosen
Has one definitionroughlyno, and they conflict
Demographic parityEqual opportunityPredictive parity
Equalisesthe selected ratethe true positive rateprecision
Ignoreswhether they would succeedthose who would not succeedthose never selected
Best B threshold here0.370.410.58
Deleting the attributeKeeping it for audit
Removes the biasno, 0.8550 recoverableno
Allows measurementnoyes
Usually recommendednoyes
munotes.in550

Bias and Fairness in AI Models

What it does not mean

Bias is not a coding error. It is the faithful learning of an unequal record.

Fairness is not one thing. Four definitions here, and no threshold satisfies three of them.

The conflict is not a limitation of the model. It follows from an identity between base rate, precision and the two error rates.

Equal accuracy is not fairness. A model can be equally accurate and select the groups at very different rates.

Removing the protected attribute does not remove the bias. Two binary proxies recovered it at 0.8550.

Per-group thresholds are not obviously permissible. They are the most direct repair and the most legally exposed.

A fair model does not make the decision just. The base rates themselves came from somewhere.

Quick revision

  • Bias is the behaviour; fairness is a chosen criterion. Sources: historical, representation, measurement, aggregation, learning, deployment. Historical bias cannot be collected away.
  • Four definitions: demographic parity (equal selected rate), equal opportunity (equal TPR), equalised odds (equal TPR and FPR), predictive parity (equal precision). Also calibration and individual fairness.
  • Measured on one classifier: A funded 0.5500, TPR 0.7446, precision 0.8303; B funded 0.3600, TPR 0.5161, precision 0.4444. Gaps 0.1900, 0.2284, 0.3859.
  • Every threshold for B was tried. Best for demographic parity 0.37, for equal opportunity 0.41, for predictive parity 0.58. No threshold satisfies all three.
  • The identity p = bt / (bt + (1-b)*f) forces it: with different base rates, equal t and f imply different p. Checked: A implies 0.8303, measured 0.8303; B implies 0.4444, measured 0.4444.
  • "Is this model fair" has no technical answer until someone says which fairness is wanted.
  • Deleting the protected column: two binary proxies recovered the group at 0.8550 against a 0.7500 baseline. Keep it, do not train on it, use it to audit.
  • Interventions: pre-processing (reweight, resample), in-processing (a fairness penalty), post-processing (per-group thresholds, effective and legally exposed). Always report per-group metrics.

Test yourself

1. Name six sources of bias in a machine learning system. Historical bias, where the data faithfully records an unequal world; representation bias, where a group is under-sampled; measurement bias, where the label is a proxy for the thing wanted; aggregation bias, where one model serves groups that behave differently; learning bias, where the objective itself favours the largest group; and deployment bias, where the system is used on a population or for a purpose it was not tested on.

2. Define demographic parity, equal opportunity and predictive parity. Demographic parity requires the same proportion of each group to be selected. Equal opportunity requires that, among those who would in fact succeed, the same proportion of each group is selected, which is equality of the true positive rate. Predictive parity requires that, among those selected, the same proportion of each group succeeds, which is equality of precision.

munotes.in551

Bias and Fairness in AI Models

3. State and justify the impossibility result. For any group, precision is determined by the base rate, the true positive rate and the false positive rate through p = bt / (bt + (1-b)*f), since the numerator counts selected members who succeed and the denominator adds those who do not. If two groups have equal true and false positive rates but different base rates, the formula gives them different precisions. Equalised odds and predictive parity therefore cannot both hold across groups with different base rates unless the classifier makes no errors at all.

4. In the measurement, what happened when a threshold was chosen to equalise each definition in turn? Each was achievable on its own and each broke the others. Equalising the proportion funded needed a cut of 0.37 and left a precision gap of 0.3660; equalising the true positive rate needed 0.41 and left a precision gap of 0.3609; equalising precision needed 0.58 and left a funding gap of 0.4300 and a true positive rate gap of 0.3897. No threshold produced three small gaps.

5. Why does deleting the protected attribute not remove the bias? Because the attribute is correlated with other features, so it can be reconstructed from them and any model using them uses it indirectly. Here a rule with only two binary inputs, coaching and medium of instruction, recovered the group correctly 0.8550 of the time against a baseline of 0.7500. Deleting the column removes the ability to measure the model's behaviour by group without removing the behaviour.

6. What should be done with the protected attribute instead? Keep it in the data, exclude it from the features the model trains on, and use it to audit: compute and publish a confusion matrix and the per-group rates for each group. A model that cannot be examined by group is not fairer, merely unexaminable.

7. Classify the possible interventions and give the difficulty of each. Pre-processing acts on the data, by reweighting or resampling, and is model-independent but changes what the data records. In-processing adds a fairness term to the training objective and allows a precise trade-off but requires access to training. Post-processing adjusts the decisions, most directly by using a different threshold for each group, which works on a model that cannot be retrained but treats people differently by group on its face and is therefore the most legally exposed.

Contents This chapter on its own page

munotes.in552

Chapter Eighty-Four

Transparency and Explainability

Syllabus topic Module 2, "Transparency and explainability"

In one line

Transparency is telling people what the system is; explainability is telling one person why it did what it did to them; and they are different obligations with different remedies.

The two words, kept apart

MU prints them together and they are routinely confused. The distinction is the first thing a paper on this topic is looking for.

TransparencyExplainability
Aboutthe systemone decision
Answerswhat is this, who made it, on what data, how well does it workwhy was I refused
Delivered bydocumentation and disclosurea computation on the case
Audienceregulators, auditors, the publicthe affected person
Available for a deep modelyes, always: it is a choicehard, and always approximate
Costwriting it downengineering, and sometimes accuracy

Transparency is never technically impossible. Whatever the model, somebody can state what data it was trained on, what it is for, and how well it scored on whom. Failing to is a decision, not a limitation. Ethical Issues in AI Systems measured what that decision costs: three vendors published no per-group performance, and behind their advertised accuracy lay a 34.4 per cent gap between the best and worst treated groups.

What transparency actually consists of

Four artefacts, each a real practice with a name, and naming them is worth marks.

ArtefactDocumentsTypical contents
Model cardthe modelwhat it is for, the intended users, out-of-scope uses, per-group performance, known limitations
Datasheetthe data sethow it was collected, who is in it, consent, labelling process, known gaps
System cardthe deployed systemthe model plus the human process around it, the thresholds, the appeal route
Audit logthe decisionswhat was decided, on what inputs, by which version, when

Two things about this list are worth stating in an answer.

It is prose, not mathematics. Every artefact here is written by people and could have been written for any model, however opaque. "The model is too complex to explain" is never an answer to a transparency question, because none of the four asks how the model works inside.

The audit log is what makes anything else enforceable. Without a record of what was decided, on what input, by which version, no later complaint can be investigated. It is also the artefact most often missing, because it costs storage and nobody asks for it until something has gone wrong.

The interpretability trade-off

The trade-off is real and this book has measured both ends of it.

ModelReadable asAccuracy here
A decision treea set of if-then rulesone tree, 0.6657 on the noisy problem of Ensemble Methods, Bagging and The Random Forest
A random forest301 trees, which are not rules0.7450
A linear modela weight per feature, readable by sign and sizedepends
A neural networka matrix of numbers with no meaning individuallyhighest, usually
munotes.in553

Transparency and Explainability

So the forest gained 0.1014 in accuracy and lost the property that a person could read it. That is a genuine trade and not a scandal, but it is a trade somebody must make deliberately, and the right side of it depends on the decision.

The rule worth carrying: the higher the stakes and the more the decision must be contested, the more interpretability is worth paying accuracy for. A film recommendation may be a forest. A decision to refuse a loan, a bail application or a scholarship should be something a person can read, unless there is a strong measured reason otherwise.

Two kinds of interpretability

IntrinsicPost hoc
The model isreadable by construction: a short tree, a linear model, a rule listany model at all
The explanation isthe model itselfa separate thing, built afterwards
Faithfulby definitionnot guaranteed
ExamplesReading, Drawing and Pruning a Decision Tree, linear regressionfeature importance, LIME, SHAP, saliency maps, counterfactuals

Post hoc explanation methods, and what each really says

A paper may ask for the methods by name. Four, with the honest description of each.

Feature importance. How much the model's accuracy falls when one feature's values are shuffled. Ensemble Methods, Bagging and The Random Forest gave exactly this for a forest, using the out-of-bag rows, and noted it is a measurement, unlike the position-in-the-tree heuristic that Reading, Drawing and Pruning a Decision Tree warned against. It is global: it describes the model, not your case.

Local surrogate, of which LIME is the standard example. Fit a simple model, usually linear, to the complex model's behaviour near one case, and report the simple model's coefficients. The explanation is therefore a model of a model, and it is right only where the surrogate fits.

Shapley values, of which SHAP is the standard implementation. Divide the difference between this prediction and the average prediction among the features, using an allocation from cooperative game theory that is the unique one satisfying a set of fairness axioms. It is the best-founded method here and it is expensive, since in principle it considers every subset of features.

Counterfactual explanation. "You would have been approved if your income had been 40,000 rather than 32,000." This is usually the most useful kind for the person affected, because it is actionable: it names something that could change. And it must be checked for feasibility, since "if you were five years younger" explains nothing anyone can act on.

munotes.in554

Transparency and Explainability

What an explanation is worth

An explanation is a model of a model, and it can be wrong. That single sentence is what separates a good answer from a list of tool names.

Four cautions, each of which has bitten real deployments:

Caution
Not faithfulthe surrogate agrees with the model near the case and may disagree elsewhere; two methods can give different explanations of the same decision
Not causalit reports what the model used, not what causes the outcome in the world. Support, Confidence and Lift made the same point about lift
Can be gameda model can be built to score well on the explanation method while behaving otherwise; the explanation is then a marketing artefact
Can persuade falselya plausible explanation raises trust whether or not the decision was right, so a good explanation of a bad model is worse than none

The last row deserves its own emphasis. An explanation makes a decision feel accountable. If the explanation is not faithful, that feeling is manufactured, and the person has been given something that looks like a reason and is not one.

The right to an explanation, briefly and carefully

Data protection law in several places gives a person rights about automated decisions, and the strongest version, in the European Union's General Data Protection Regulation, concerns decisions made solely by automated means with legal or similarly significant effects.

State this carefully in an examination. What such provisions typically guarantee is meaningful information about the logic involved, together with the right to obtain human intervention and to contest the decision. Whether that amounts to a right to an explanation of one particular decision is genuinely disputed among lawyers, and an answer that asserts a settled right has overstated it.

India's Digital Personal Data Protection Act, 2023 governs the handling of personal data, and the practical consequence for a student building a system here is the same in either jurisdiction: know what personal data the model was trained on, be able to say what it is used for, and have a route by which a person can reach a human being.

What to do, in order

Given a system to make transparent, this is the order of work, and it is what an examiner means by "how would you address this".

1Write the model card and datasheet. Cheap, always possible, and the largest single gain.
2Publish per-group performance, not one accuracy.
3Keep an audit log of decisions, inputs and model version.
4Prefer an intrinsically interpretable model where the stakes are high; measure what the accuracy costs before deciding it is too much.
5If a complex model is kept, add counterfactual explanations for the affected person, and feature importance for the auditor.
6Test the explanations: check that the surrogate agrees with the model, and that two methods do not contradict each other.
7Provide a human to appeal to, named by role. Accountability and Human Oversight continues from here.
munotes.in555

Transparency and Explainability

Distinctions

TransparencyExplainability
Scopethe systemone decision
Formdocumentationcomputation
Possible for any modelyesapproximately
Failure isa choicesometimes technical
Global explanationLocal explanation
Describesthe whole modelone case
Examplefeature importanceLIME, SHAP, a counterfactual
Useful toan auditorthe person affected
Intrinsic interpretabilityPost hoc explanation
The explanation isthe modela second model
Faithfulby definitionnot guaranteed
Costpossibly accuracypossibly a false sense of understanding

What it does not mean

Transparency is not explainability. One is documentation about the system, the other a computation about a decision.

"Too complex to explain" is not a defence against a transparency question. None of the four artefacts asks how the model works inside.

Open source is not transparency. Publishing weights without the data, the intended use and the per-group performance documents almost nothing.

An explanation is not the model's reasoning. It is a second model's account of the first.

An explanation is not a cause. It reports what the model used.

Two explanations agreeing is not proof. Two methods can also disagree on the same decision.

A right to an explanation is not settled law. What is typically guaranteed is meaningful information about the logic, human intervention and a route to contest.

Quick revision

  • Transparency is about the system and is documentation; explainability is about one decision and is a computation. Transparency is never technically impossible.
  • Artefacts: model card (purpose, intended users, out-of-scope uses, per-group performance), datasheet (how the data was collected, who is in it, consent), system card (the model plus the human process), audit log (what was decided, on what input, by which version).
  • The trade-off is real: one tree 0.6657 and readable, a forest 0.7450 and not. The higher the stakes, the more interpretability is worth paying for.
  • Intrinsic interpretability is faithful by definition; post hoc explanation is a second model and is not guaranteed faithful.
  • Methods: feature importance (shuffle a feature, measure the fall; global), LIME (a local linear surrogate), SHAP (Shapley values, best founded, expensive), counterfactual (actionable, must be feasible).
  • An explanation is a model of a model and can be wrong. It is not causal, it can be gamed, and a plausible explanation of a bad decision is worse than none.
  • Law: the GDPR concerns decisions made solely by automated means with significant effects, and guarantees meaningful information about the logic, human intervention and the right to contest; whether that is a right to explain one decision is disputed. India's Digital Personal Data Protection Act, 2023 governs personal data.
  • Order of work: model card and datasheet, per-group metrics, audit log, prefer an interpretable model where stakes are high, add counterfactuals and feature importance, test the explanations, provide a named human to appeal to.
munotes.in556

Transparency and Explainability

Test yourself

1. Distinguish transparency from explainability. Transparency concerns the system: what it is for, what data it was trained on, who built it and how well it performs on whom, and it is delivered by documentation. Explainability concerns a single decision and the reason for it, and it is delivered by a computation on that case. Transparency is always possible whatever the model, so its absence is a choice; explainability for a complex model is hard and always approximate.

2. Name four transparency artefacts and say what each documents. A model card documents the model, including its purpose, intended users, uses that are out of scope and its performance broken down by group. A datasheet documents the data set, including how it was collected, who is in it and how it was labelled. A system card documents the deployed system, the model together with the human process, thresholds and appeal route. An audit log records the decisions themselves, with inputs, model version and time, and without it no later complaint can be investigated.

3. Why is "the model is too complex to explain" not an answer to a transparency requirement? Because none of the transparency artefacts asks how the model works inside. What data it was trained on, what it is intended and not intended for, and how accurate it is for each group, are all statable about any model whatever, so failing to state them is a decision and not a technical limitation.

4. Describe the interpretability trade-off with the figures from this book. A single decision tree can be read as a set of rules and scored 0.6657 on the noisy problem used earlier; a random forest of 301 trees scored 0.7450 and cannot be read as rules at all. The gain of 0.1014 in accuracy was paid for with the ability of a person to inspect the decision rule, and which side of that trade is right depends on how high the stakes are and on whether the decision must be contestable.

5. Distinguish intrinsic interpretability from post hoc explanation, and say why the difference matters. An intrinsically interpretable model, such as a short decision tree or a linear model, is its own explanation, so the account is faithful by definition. A post hoc explanation is a separate construction applied to a model that cannot be read, so it is a model of a model and may not match the original's behaviour away from the case examined.

munotes.in557

Transparency and Explainability

6. Name four post hoc explanation methods and what each reports. Feature importance shuffles a feature's values and reports how much accuracy falls, which describes the whole model rather than one case. LIME fits a simple model to the complex model's behaviour near one case and reports its coefficients. SHAP divides the difference between this prediction and the average among the features using Shapley values from cooperative game theory, which is well founded and expensive. A counterfactual explanation names a change to the inputs that would have altered the decision, which is the most useful kind for the person affected provided the change is one they could actually make.

7. Give three reasons for being cautious about an explanation. It may not be faithful, since a surrogate that agrees with the model near one case may disagree elsewhere, and two methods can explain the same decision differently. It is not causal: it reports what the model used, not what brings the outcome about in the world. And it persuades: a plausible explanation increases trust whether or not the decision was correct, so a good explanation attached to a bad model leaves the affected person worse off than no explanation at all.

Contents This chapter on its own page

munotes.in558

Chapter Eighty-Five

Accountability and Human Oversight

Syllabus topic Module 2, "Accountability and human oversight"

In one line

Accountability is the question of who answers when the system is wrong, and human oversight is the arrangement that is supposed to make an answer possible.

The two, and how they depend on the last chapter

The NIST AI Risk Management Framework states the dependency in one line worth quoting: "Trustworthy AI depends upon accountability. Accountability presupposes transparency."

Read that as the argument for the order of these chapters. You cannot hold anyone to account for a decision nobody can inspect. And the framework adds the converse caution: a transparent system is not necessarily accurate, secure, private or fair, but it is difficult to determine whether an opaque system possesses those characteristics at all, and harder still as it changes over time.

The accountability gap

The problem in one paragraph, and a paper asking "who is responsible" wants it in these terms.

A model is trained by one team on data collected by another, bought by a third organisation, configured by a fourth, and used by a clerk who was told to follow it. When it refuses someone wrongly, each participant can truthfully say the fault was not theirs: the researcher published a model with stated limitations; the buyer used it as documented; the clerk followed the process. Nobody lied and nobody is answerable. This is the problem of many hands, and the phrase "the algorithm decided" is the sound it makes.

Two further features make it worse:

The system is probabilistic. It was expected to be wrong sometimes, so any single wrong decision is within specification and points at nobody.

The error is distributed. Bias and Fairness in AI Models measured a model failing one group far more than another, and no individual decision in that pattern looks like a fault. The harm is visible only in aggregate, and responsibility is assigned case by case.

Who can be accountable

A useful answer names the roles rather than saying "the company".

RoleAnswers for
The data collectorwhat is in the data, consent, who is missing from it
The model developerthe intended use, the stated limitations, the per-group performance published
The deployerchoosing this model for this purpose and this population, and the threshold set
The operatorthe individual decision, if a real choice was available
The organisationthe process, the training, the appeal route, the monitoring
The regulatorrequiring the above to exist and be inspectable

Accountability must attach to a named role, not to a system. The practical test is the one an examiner will accept: can you write the job title of the person who has to answer? If not, the arrangement is not accountable however carefully it is described.

munotes.in559

Accountability and Human Oversight

Levels of human oversight

Three levels, in the terminology in common use, and MU's label asks for exactly this.

Human in the loopHuman on the loopHuman in command
The machineproposesactsacts
The humandecides every casemonitors and can intervenesets the policy and can stop the system
Speedslowestfastfast
Suitshigh stakes, low volume: a loan, a diagnosis, bailhigh volume with a monitored exception path: fraud flagsinfrastructure decisions, deployment scope
Main failureautomation biasno time to intervenetoo far from the case to notice

There is a fourth arrangement which is honest to name: no human at all, which is correct for decisions of no consequence and indefensible for decisions of consequence. The interesting question is never "is there a human" but "does the human have the information, the time, the authority and the incentive to disagree?"

The four conditions, which is the examinable part

Oversight that fails does so because one of four things is missing, and naming them turns a vague answer into a specific one.

ConditionWithout it
Informationthe reviewer sees a score and no reason, so cannot judge it
Time200 cases an hour means 18 seconds each, which is not review
Authorityoverriding needs a manager's signature, so nobody overrides
Incentivethe reviewer is measured on throughput, or blamed for overrides that turn out wrong

The fourth is the one designers forget. If agreeing with the machine is safe and disagreeing is risky, the reviewer will agree, and the oversight is a formality however sincere the reviewer.

Automation bias

The specific failure to name, because it is the reason "a human reviews it" is not by itself an answer.

Automation bias is the tendency to accept a machine's output as correct and to stop looking for contrary evidence. It has two forms, and both are worth distinguishing:

Errors of commissionErrors of omission
The reviewerfollows a wrong recommendationfails to act because the machine did not flag anything
Causethe machine said sonothing drew attention to the case
Harder to detectnoyes, since nothing happened

And the diagnostic that costs nothing: measure the override rate. A human who approves 99 per cent of what the machine proposes is not providing oversight, whatever the process document says. Nor is a rate of zero good news; it means the reviewer has stopped being a check.

Three ways to make review real, all measurable:

Show the case, not the scoreso the reviewer can form an independent judgement first
Seed known casesinsert cases with known answers and measure how often the reviewer catches a wrong machine recommendation
Measure and publish the override rate, and treat a very low one as a fault in the system rather than proof that it works
munotes.in560

Accountability and Human Oversight

Governing the system over its life

NIST's four functions are the structure worth reproducing, and the framework is explicit that governance is cross-cutting rather than a first step that finishes: after establishing governance, most users begin with MAP and continue to MEASURE or MANAGE, iterating between them.

FunctionWhat it does
GOVERNcultivates a culture of risk management; sets the processes, documents and structures; connects technical design to the organisation's values; runs throughout
MAPestablishes the context and identifies what risks the system poses, to whom
MEASUREanalyses and tracks those risks with metrics, including per-group performance
MANAGEallocates resources to the risks found, and acts on them

The practical apparatus that these four imply, and which an answer should name:

Model versioningevery decision recorded against the version that made it
An audit loginputs, output, version, time, reviewer
Monitoring for driftthe population changes, and a model tested on last year's applicants is not tested on this year's
Incident reportinga route by which a harm becomes a recorded event rather than a complaint that goes nowhere
Red teamingsomeone paid to make the system fail before a user does
A stop rulethe condition, written in advance, under which the system is switched off
A named ownera role, not a committee

Drift is the one that fails quietly. The Statistical Learning Framework said a model is fitted to a distribution; when the distribution moves, every score in Evaluating a Model was computed on a world that no longer exists, and nothing announces it.

Redress, which is what the person affected actually needs

Accountability inside an organisation is worth little to the person refused. Four things they need, and an answer that lists them is answering the real question:

To know a machine was involved at all
To be told the decision and something meaningful about the reason
To reach a human with the authority to change it
To have the case reconsidered on the merits, not merely rerun

The last is the one usually missing. Rerunning the same model is not an appeal.

Distinctions

AccountabilityOversight
Iswho answers afterwardsthe arrangement during
Attaches toa named rolea process
Can exist without transparencynonominally, and uselessly
Human in the loopHuman on the loop
Decidesevery casethe exceptions
Machine acts firstnoyes
Fails byautomation biasno time to intervene
Errors of commissionErrors of omission
The reviewerfollows a wrong recommendationmisses what was not flagged
Visiblein the recordrarely

What it does not mean

"A human reviews it" is not oversight. Measure the override rate before believing it.

munotes.in561

Accountability and Human Oversight

An override rate of zero is not success. It is evidence the check has stopped working.

Accountability is not the same as blame. It is the prior question of who is obliged to answer.

A system cannot be accountable. Only a person in a named role can be.

Being within specification is not an excuse. A model expected to be wrong sometimes still harmed someone this time.

Rerunning the model is not an appeal. The case must be reconsidered by someone able to decide differently.

Governance is not a launch checklist. NIST places GOVERN across the whole life of the system.

Quick revision

  • NIST: "Trustworthy AI depends upon accountability. Accountability presupposes transparency." An opaque system's other properties cannot be determined at all.
  • The accountability gap, the problem of many hands: everyone acted correctly by their own scope and nobody answers. Worsened because the system is probabilistic and the harm is visible only in aggregate.
  • Roles that can answer: data collector, model developer, deployer, operator, organisation, regulator. The test: can you write the job title?
  • Oversight levels: in the loop (decides every case), on the loop (monitors, intervenes), in command (sets policy, can stop it). The real question is whether the human has information, time, authority and incentive to disagree.
  • Automation bias: accepting the machine's output and ceasing to look. Errors of commission (following a wrong recommendation) and errors of omission (missing what was not flagged, which is harder to detect). Measure the override rate; 99 per cent agreement is not oversight.
  • NIST functions: GOVERN (cross-cutting, throughout), then MAP, MEASURE, MANAGE, iteratively.
  • Apparatus: model versioning, audit log, drift monitoring, incident reporting, red teaming, a written stop rule, a named owner. Drift fails quietly.
  • Redress: to know a machine was involved, to be told something meaningful, to reach a human with authority, and to be reconsidered. Rerunning the model is not an appeal.

Test yourself

1. Why does accountability presuppose transparency? Because nobody can be held to answer for a decision that cannot be inspected. Without a record of what was decided, on what input and by which version, and without a statement of what the system was for and how well it performs, there is nothing against which a claim of fault can be tested; and as NIST notes, an opaque system's accuracy, security, privacy and fairness cannot be determined at all.

2. Describe the accountability gap. A system is built, sold, configured and operated by different parties, each acting correctly within its own scope, so when someone is wrongly refused every participant can truthfully deny fault: the developer published stated limitations, the deployer used the model as documented, the operator followed the process. Nobody lied and nobody answers. The gap is widened because the model was expected to err sometimes, so no single wrong decision is out of specification, and because unfairness is visible only in aggregate while responsibility is assigned case by case.

munotes.in562

Accountability and Human Oversight

3. Distinguish the three levels of human oversight. With a human in the loop the machine proposes and a person decides every case, which suits high-stakes low-volume decisions. With a human on the loop the machine acts and a person monitors and may intervene, which suits high volume with an exception path. With a human in command the machine operates and a person sets the policy and retains the ability to stop it. Their characteristic failures are automation bias, having no time to intervene, and being too far from the individual case to notice.

4. What four conditions must hold for human oversight to be real? The reviewer must have the information needed to form an independent judgement, the time to do so, the authority to override without obstruction, and an incentive structure in which disagreeing is not personally riskier than agreeing. The last is the one most often absent: if agreement is safe and override is punished when it turns out wrong, the reviewer will agree.

5. What is automation bias, and how is it detected? The tendency to accept a machine's output as correct and to stop seeking contrary evidence, either by following a wrong recommendation or by failing to act on a case the machine did not flag, the second being harder to detect because nothing happened. It is detected by measuring the override rate: a reviewer who approves 99 per cent of recommendations is not providing oversight, and it can be tested directly by seeding cases with known answers and counting how often the reviewer catches a wrong recommendation.

6. Give the four NIST functions and say what is distinctive about the first. Govern, map, measure and manage. Govern is not a first step that completes but a cross-cutting one: it establishes the culture, processes and documentation of risk management and connects technical design to the organisation's values, while most users, having established it, begin with map and continue iteratively to measure and manage.

7. What does a person wrongly refused by an automated system actually need? To know that a machine was involved at all; to be told the decision with something meaningful about its reasons; to be able to reach a human being with the authority to change it; and to have the case reconsidered on its merits. Rerunning the same model on the same inputs satisfies none of these and is not an appeal.

Contents This chapter on its own page

munotes.in563

Chapter Eighty-Six

Hallucination in Generative AI

Syllabus topic Module 2, "hallucination"

In one line

A language model is trained to produce text that looks like its training data, and nothing anywhere in that training refers to whether the text is true.

Hallucination is the standard name for a generative model producing output that is fluent, confident and false. The word is a poor one, because it suggests a malfunction. Nothing has malfunctioned, and this chapter's purpose is to show why by building the smallest possible language model and watching it happen.

The measurement

# Why a language model produces confident falsehoods, shown on the smallest
# language model there is. A bigram model is trained on a closed world whose
# facts are written out first, so that TRUE and FALSE are not matters of opinion.
import math

def lcg(seed):
    x = seed
    while True:
        x = (1664525 * x + 1013904223) % (2 ** 32)
        yield x / 2 ** 32

gen = lcg(818181)
rnd = lambda: next(gen)                                   # noqa: E731

# ---- the closed world, stated once and for all -----------------------------
FACTS = [
    "the reading room opens at eight in the morning",
    "the reading room closes at eight in the evening",
    "the reading room is closed on sunday",
    "the reference section is on the second floor",
    "the newspaper section is on the ground floor",
    "a member may borrow four books at a time",
    "a member may keep a book for fourteen days",
    "the fine is two rupees a day",
]

# ---- the training text: the same facts, said several ways ------------------
TEXT = """
the reading room opens at eight in the morning and closes at eight in the
evening . the reading room is closed on sunday . the reading room opens at
eight on monday . the reference section is on the second floor . the
newspaper section is on the ground floor . the reference section is on the
second floor and the newspaper section is on the ground floor . a member may
borrow four books at a time . a member may keep a book for fourteen days . a
member may borrow four books and may keep a book for fourteen days . the fine
is two rupees a day . the fine is two rupees a day after fourteen days . the
reading room closes at eight . the reading room is on the second floor of the
college building . a member may borrow a book from the reference section for
one day . the newspaper section opens at eight in the morning .
"""
WORDS = TEXT.split()

print("A CLOSED WORLD. these eight statements are the whole truth here, and")
print("anything that contradicts them is false. no judgement is required.")
for f in FACTS:
    print("   %s" % f)
print()
print("A TRAINING TEXT of %d words says those facts in several ways." % len(WORDS))
print()

# ---- the model: P(next word | this word) -----------------------------------
after = {}
for a, b in zip(WORDS, WORDS[1:]):
    after.setdefault(a, {})
    after[a][b] = after[a].get(b, 0) + 1
TRIPLES = set(zip(WORDS, WORDS[1:], WORDS[2:]))
PAIRS = set(zip(WORDS, WORDS[1:]))

print("THE MODEL IS A BIGRAM MODEL: for each word, how often each word follows")
print("it. that is ALL it is. it has no representation of a reading room, of a")
print("floor, or of a fact. it has counts of word pairs.")
print()
print("   what the model knows about the word 'section':")
for w, c in sorted(after["section"].items(), key=lambda kv: (-kv[1], kv[0])):
    print("      P(%-8s | section) = %d/%d = %.4f"
          % (w, c, sum(after["section"].values()), c / sum(after["section"].values())))
print()

def logp(sentence):
    """The model's score for a sentence: the sum of the log probabilities of
    each word given the one before it. Unseen pairs are smoothed, exactly as
    the maximum likelihood chapter required, or the score would be -infinity."""
    ws = sentence.split()
    total = 0.0
    V = len(set(WORDS))
    for a, b in zip(ws, ws[1:]):
        counts = after.get(a, {})
        total += math.log((counts.get(b, 0) + 1) / (sum(counts.values()) + V))
    return total

print("NOW THE POINT. score a TRUE sentence and a FALSE one:")
PAIRS_TO_TEST = [
    ("the reference section is on the second floor",
     "the reference section is on the ground floor"),
    ("a member may borrow four books at a time",
     "a member may borrow four books for fourteen days"),
    ("the reading room is closed on sunday",
     "the reading room is closed on monday"),
]
print("   sentence                                            | true? |  score")
for true_s, false_s in PAIRS_TO_TEST:
    for s, ok in ((true_s, "TRUE"), (false_s, "FALSE")):
        print("   %-51s | %5s | %7.3f" % (s, ok, logp(s)))
    d = logp(false_s) - logp(true_s)
    print("      the model prefers the %s one by %.3f."
          % ("FALSE" if d > 0 else "true", abs(d)))
    print()
print("   READ ALL THREE RESULTS TOGETHER, because they are three different")
print("   failures and only one of them looks like one.")
print("      the FIRST pair it gets right. that is luck, not knowledge: the true")
print("         ending happened to be the commoner sequence of words.")
print("      the SECOND pair it gets WRONG, preferring the false sentence by")
print("         0.602. 'for fourteen days' is a more ordinary ending than 'at a")
print("         time', and ordinariness is the only thing being measured.")
print("      the THIRD pair it scores EXACTLY EQUAL, to the last decimal place.")
print("         sunday and monday follow 'on' equally often in the text, so the")
print("         model has no opinion whatever about which day the room is shut.")
print("   IT IS NOT CONFUSED AND IT HAS NOT MADE A MISTAKE. it was never scoring")
print("   truth. it scores how ORDINARY a sequence of words looks, and a false")
print("   sentence made of ordinary phrases scores well by construction.")
print()

def generate(start, n, temperature):
    """Walk the chain. TEMPERATURE reweights the counts: below 1 it sharpens
    towards the commonest continuation, above 1 it flattens towards the rare."""
    out = [start]
    w = start
    for _ in range(n):
        counts = after.get(w)
        if not counts:
            break
        items = sorted(counts.items())
        weights = [c ** (1.0 / temperature) for _, c in items]
        total = sum(weights)
        r = rnd() * total
        acc = 0.0
        for (nxt, _), wt in zip(items, weights):
            acc += wt
            if r <= acc:
                w = nxt
                break
        out.append(w)
    return out

print("GENERATING. start at 'the' and walk the chain 18 words:")
for temp in (0.5, 1.0, 1.6):
    print()
    print("   temperature %.1f" % temp)
    for _ in range(3):
        words = generate("the", 18, temp)
        trips = list(zip(words, words[1:], words[2:]))
        new = sum(1 for t in trips if t not in TRIPLES)
        print("      %s" % " ".join(words))
        print("         %d of %d three-word runs in that sentence NEVER appeared"
              % (new, len(trips)))
        print("         in the training text.")
print()
print("   READ THE COUNTS. every two-word step is one the model saw; a large")
print("   share of the THREE-word runs is new. the model is stitching together")
print("   sequences of forms it has seen, and the result is fluent, confident,")
print("   and frequently states something the training text never said.")
print()
print("   AND THE TEMPERATURE, averaged over 200 sentences each so that the")
print("   three examples above are not the evidence:")
print("      temperature | mean new three-word runs per 17 | as a fraction")
for temp in (0.4, 0.7, 1.0, 1.3, 1.6, 2.0):
    tot = 0
    for _ in range(200):
        ws = generate("the", 18, temp)
        trips = list(zip(ws, ws[1:], ws[2:]))
        tot += sum(1 for t in trips if t not in TRIPLES)
    print("      %11.1f | %31.2f | %.4f"
          % (temp, tot / 200.0, tot / 200.0 / 17.0))
print("   the invention rises with the temperature, steadily and measurably.")
print("   a low temperature repeats the commonest phrases and says little that")
print("   is new; a high one says more and invents more. THE SETTING THAT MAKES")
print("   A MODEL INTERESTING IS THE SETTING THAT MAKES IT WRONG, and there is")
print("   no value of it at which the model begins to check anything.")
print()

print("WHY IT CANNOT BE FIXED BY MAKING THE MODEL BIGGER.")
print("   this model has %d distinct words and %d word pairs. a modern language"
      % (len(set(WORDS)), len(PAIRS)))
print("   model has billions of parameters and a context of thousands of words.")
print("   THE CORE IS THE SAME OBJECT. both are trained to predict the next")
print("   token from the previous ones, and neither has any term in that")
print("   objective referring to whether the result is TRUE. accuracy at")
print("   predicting the next word is not accuracy about the world, and no")
print("   quantity of the first produces the second.")
print("   A LATER TRAINING STAGE CAN HELP AND IS NOT A CHECK EITHER. modern")
print("   systems are further trained on human preferences between answers,")
print("   which reduces obvious nonsense; but what it optimises is what a rater")
print("   APPROVED OF, and a confident, well-written, wrong answer is exactly")
print("   the kind a rater approves of. the check has to come from OUTSIDE the")
print("   model: retrieval from a source, a tool that computes, or a person who")
print("   knows.")
print()
print("   Bender and colleagues, 2021, put the reason precisely: languages are")
print("   systems of signs, that is, pairings of FORM and MEANING, but the")
print("   training data for a language model is only form; it has no access to")
print("   meaning. the paper's name for what the model does is stitching")
print("   together sequences of linguistic forms it has observed, according to")
print("   probabilistic information about how they combine, without reference to")
print("   meaning. THE COUNTS PRINTED ABOVE ARE THAT SENTENCE, MEASURED.")
munotes.in564

Hallucination in Generative AI

A CLOSED WORLD. these eight statements are the whole truth here, and
anything that contradicts them is false. no judgement is required.
   the reading room opens at eight in the morning
   the reading room closes at eight in the evening
   the reading room is closed on sunday
   the reference section is on the second floor
   the newspaper section is on the ground floor
   a member may borrow four books at a time
   a member may keep a book for fourteen days
   the fine is two rupees a day

A TRAINING TEXT of 168 words says those facts in several ways.

THE MODEL IS A BIGRAM MODEL: for each word, how often each word follows
it. that is ALL it is. it has no representation of a reading room, of a
floor, or of a fact. it has counts of word pairs.

   what the model knows about the word 'section':
      P(is       | section) = 4/6 = 0.6667
      P(for      | section) = 1/6 = 0.1667
      P(opens    | section) = 1/6 = 0.1667

NOW THE POINT. score a TRUE sentence and a FALSE one:
   sentence                                            | true? |  score
   the reference section is on the second floor        |  TRUE | -17.267
   the reference section is on the ground floor        | FALSE | -17.821
      the model prefers the true one by 0.554.

   a member may borrow four books at a time            |  TRUE | -22.440
   a member may borrow four books for fourteen days    | FALSE | -21.838
      the model prefers the FALSE one by 0.602.

   the reading room is closed on sunday                |  TRUE | -17.017
   the reading room is closed on monday                | FALSE | -17.017
      the model prefers the true one by 0.000.

   READ ALL THREE RESULTS TOGETHER, because they are three different
   failures and only one of them looks like one.
      the FIRST pair it gets right. that is luck, not knowledge: the true
         ending happened to be the commoner sequence of words.
      the SECOND pair it gets WRONG, preferring the false sentence by
         0.602. 'for fourteen days' is a more ordinary ending than 'at a
         time', and ordinariness is the only thing being measured.
      the THIRD pair it scores EXACTLY EQUAL, to the last decimal place.
         sunday and monday follow 'on' equally often in the text, so the
         model has no opinion whatever about which day the room is shut.
   IT IS NOT CONFUSED AND IT HAS NOT MADE A MISTAKE. it was never scoring
   truth. it scores how ORDINARY a sequence of words looks, and a false
   sentence made of ordinary phrases scores well by construction.

GENERATING. start at 'the' and walk the chain 18 words:

   temperature 0.5
      the newspaper section is on the reading room opens at eight in the second floor . the reading room
         2 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the newspaper section is on sunday . the reading room opens at eight in the newspaper section is on
         2 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the morning . a book from the fine is on the newspaper section is on the reading room is
         6 of 17 three-word runs in that sentence NEVER appeared
         in the training text.

   temperature 1.0
      the reference section for fourteen days . a member may keep a member may borrow four books at eight
         3 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the reference section is on monday . the evening . the fine is closed on sunday . the fine
         3 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the fine is on sunday . the second floor and closes at eight in the college building . the
         6 of 17 three-word runs in that sentence NEVER appeared
         in the training text.

   temperature 1.6
      the fine is closed on monday . a day after fourteen days . a day . the newspaper section
         5 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the reading room opens at a book for fourteen days . a time . the newspaper section opens at
         4 of 17 three-word runs in that sentence NEVER appeared
         in the training text.
      the fine is on the second floor of the reading room is on monday . the ground floor and
         5 of 17 three-word runs in that sentence NEVER appeared
         in the training text.

   READ THE COUNTS. every two-word step is one the model saw; a large
   share of the THREE-word runs is new. the model is stitching together
   sequences of forms it has seen, and the result is fluent, confident,
   and frequently states something the training text never said.

   AND THE TEMPERATURE, averaged over 200 sentences each so that the
   three examples above are not the evidence:
      temperature | mean new three-word runs per 17 | as a fraction
              0.4 |                            2.81 | 0.1656
              0.7 |                            3.38 | 0.1985
              1.0 |                            3.98 | 0.2341
              1.3 |                            4.07 | 0.2391
              1.6 |                            4.21 | 0.2474
              2.0 |                            4.38 | 0.2579
   the invention rises with the temperature, steadily and measurably.
   a low temperature repeats the commonest phrases and says little that
   is new; a high one says more and invents more. THE SETTING THAT MAKES
   A MODEL INTERESTING IS THE SETTING THAT MAKES IT WRONG, and there is
   no value of it at which the model begins to check anything.

WHY IT CANNOT BE FIXED BY MAKING THE MODEL BIGGER.
   this model has 45 distinct words and 79 word pairs. a modern language
   model has billions of parameters and a context of thousands of words.
   THE CORE IS THE SAME OBJECT. both are trained to predict the next
   token from the previous ones, and neither has any term in that
   objective referring to whether the result is TRUE. accuracy at
   predicting the next word is not accuracy about the world, and no
   quantity of the first produces the second.
   A LATER TRAINING STAGE CAN HELP AND IS NOT A CHECK EITHER. modern
   systems are further trained on human preferences between answers,
   which reduces obvious nonsense; but what it optimises is what a rater
   APPROVED OF, and a confident, well-written, wrong answer is exactly
   the kind a rater approves of. the check has to come from OUTSIDE the
   model: retrieval from a source, a tool that computes, or a person who
   knows.

   Bender and colleagues, 2021, put the reason precisely: languages are
   systems of signs, that is, pairings of FORM and MEANING, but the
   training data for a language model is only form; it has no access to
   meaning. the paper's name for what the model does is stitching
   together sequences of linguistic forms it has observed, according to
   probabilistic information about how they combine, without reference to
   meaning. THE COUNTS PRINTED ABOVE ARE THAT SENTENCE, MEASURED.
munotes.in565

Hallucination in Generative AI

The model

A bigram model: for each word, how often each word follows it. Trained on 168 words describing a reading room whose eight facts are written out first, so that true and false are not matters of opinion.

munotes.in566

Hallucination in Generative AI

P(is | section) = 4/6 = 0.6667

P(for | section) = 1/6 = 0.1667

P(opens | section) = 1/6 = 0.1667

munotes.in567

Hallucination in Generative AI

That is all it is. There is no representation of a reading room, of a floor, or of a fact anywhere in it. There are counts of word pairs.

munotes.in568

Hallucination in Generative AI

Three sentence pairs, three different failures

Each pair is one true sentence and one false one, by the stated facts.

munotes.in569

Hallucination in Generative AI

SentenceTrue?Score
the reference section is on the second floorTRUE-17.267
the reference section is on the ground floorFALSE-17.821
a member may borrow four books at a timeTRUE-22.440
a member may borrow four books for fourteen daysFALSE-21.838
the reading room is closed on sundayTRUE-17.017
the reading room is closed on mondayFALSE-17.017

Read all three together, because only one of them looks like a failure.

The first it gets right. That is luck, not knowledge: the true ending happened to be the commoner sequence of words in the text.

The second it gets wrong, preferring the false sentence by 0.602. "for fourteen days" is a more ordinary ending than "at a time", and ordinariness is the only thing being measured.

The third it scores exactly equal, to the last decimal place. sunday and monday follow on equally often, so the model has no opinion whatever about which day the room is shut and will produce either with equal readiness.

It is not confused and it has not made a mistake. It was never scoring truth. It scores how ordinary a sequence of words looks, and a false sentence made of ordinary phrases scores well by construction.

Watching it invent

Generated sentences, every one of them fluent, and among them:

the newspaper section is on sunday . the reading room opens at eight ...

the fine is closed on monday . a day after fourteen days ...

the fine is on the second floor of the reading room is on monday ...

Each is assembled from word pairs the model actually saw. The falsehood appears at the joins. the fine is is in the text; is closed on monday is in the text; "the fine is closed on monday" is not, and is nonsense.

And that is measurable. Counting the three-word runs in each generated sentence that never appeared in the training text, and averaging over 200 sentences:

TemperatureMean new three-word runs per 17As a fraction
0.42.810.1656
0.73.380.1985
1.03.980.2341
1.34.070.2391
1.64.210.2474
2.04.380.2579
munotes.in570

Hallucination in Generative AI

The invention rises steadily with the temperature. A low temperature repeats the commonest phrases and says little that is new; a high one says more and invents more. The setting that makes a model interesting is the setting that makes it wrong, and there is no value of it at which the model begins to check anything.

Why a bigger model does not fix it

This model has 45 distinct words and 79 word pairs. A modern language model has billions of parameters and a context of thousands of words. The core is the same object: both are trained to predict the next token from the previous ones, and neither has any term in that objective referring to whether the output is true.

Be precise about the qualification, because an answer that ignores it is out of date. Modern systems are further trained on human preferences between answers, which does reduce obvious nonsense. But what that stage optimises is what a rater approved of, and a confident, well-written, wrong answer is exactly the kind of answer a rater approves of. It makes the failure rarer and harder to spot, which is not the same as removing it.

Bender and colleagues, 2021, give the reason in the form worth quoting: languages are systems of signs, that is, pairings of form and meaning, but the training data for a language model is only form; it has no access to meaning. Their description of what such a model does is stitching together sequences of linguistic forms it has observed, according to probabilistic information about how they combine, without reference to meaning. The counts printed above are that sentence, measured.

What actually reduces it

Since the check cannot come from inside the model, it must come from outside. Five approaches, with what each really does.

What it doesHonest limit
Retrievalfetch documents and require the answer to be drawn from themthe model may still misread or over-generalise from the fetched text
Toolslet a calculator, a database or a search engine answer the part it canonly covers what a tool can do
Citationrequire a source for each claim, and check the source exists and says itan uncited claim is unaffected; fabricated citations are a known failure
Abstentiontrain or instruct the system to say it does not knowcosts usefulness, and the model's confidence is a poor guide to when to abstain
Human reviewa person checks before it is usedAccountability and Human Oversight: check the override rate, or it is automation bias
munotes.in571

Hallucination in Generative AI

And one that is not a remedy: asking the model whether it is sure. Its stated confidence is text produced by the same process as the answer, so a confidently phrased wrong answer will be confidently defended.

The rule for a student using such a system for study, which is the practical point of this chapter: treat every specific claim, number, citation, section number and date as unverified until checked against a source. The fluent parts are the most dangerous, because fluency is precisely what the model was trained to produce.

Distinctions

A search engineA language model
Returnsdocuments that existtext it composed
Wrong byreturning something irrelevantproducing something that was never true
Checkableopen the pagenothing to open unless retrieval was used
Low temperatureHigh temperature
Outputrepetitive, safevaried, interesting
New three-word runs2.81 of 174.38 of 17
Inventslessmore
Checks anythingnono
FormMeaning
In the training datayesno
What the model optimisesformnothing
Where the check must come fromoutside the model

What it does not mean

Hallucination is not a malfunction. The model did exactly what it was trained to do.

It is not a lie. Lying requires knowing the truth and choosing otherwise.

A confident answer is not a checked answer. Confidence is a property of the text.

A bigger model does not remove it. The objective is unchanged; preference training makes it rarer and harder to detect.

Asking the model if it is sure is not a check. The answer comes from the same process.

A low temperature does not make it truthful. It makes it repetitive, and still invented 2.81 new runs in 17.

Retrieval is not a guarantee. It supplies a source; it does not ensure the source was read correctly.

Quick revision

  • A language model is trained to predict the next token. No term in that objective refers to truth.
  • Measured on a bigram model of a closed world: the true and false sentence pairs score -17.267 / -17.821 (right, by luck), -22.440 / -21.838 ( wrong by 0.602) and -17.017 / -17.017 ( exactly equal, no opinion at all).
  • It scores how ordinary a word sequence looks. A false sentence made of ordinary phrases scores well by construction.
  • Falsehood appears at the joins: every word pair was seen, and "the fine is closed on monday" was not.
  • Measured invention: mean new three-word runs per 17 rises from 2.81 at temperature 0.4 to 4.38 at 2.0. More interesting means more invented, and no setting adds a check.
  • 45 words and 79 pairs against billions of parameters: the core is the same object. Human preference training makes the failure rarer and harder to spot, because it rewards what a rater approved of.
  • Bender and colleagues, 2021: languages pair form and meaning; the training data is only form. The model stitches together sequences of forms without reference to meaning.
  • Remedies, all outside the model: retrieval, tools, citation with the source checked, abstention, human review with the override rate measured. Asking the model whether it is sure is not one.
  • For study: treat every specific claim, number, citation and date as unverified until checked.
munotes.in572

Hallucination in Generative AI

Test yourself

1. Why is hallucination not a malfunction? Because the model is trained to predict the next token from the previous ones, and no term in that objective refers to whether the output is true. Producing fluent text that resembles its training data is exactly what it was optimised to do, so a confident falsehood is a success by the only measure the training applied.

2. In the measurement, what did the three sentence pairs show? Three different failures. The first pair the model scored correctly, but only because the true ending happened to be the commoner word sequence. The second it scored wrongly, preferring the false sentence by 0.602, because "for fourteen days" is a more ordinary ending than "at a time". The third it scored exactly equal, because the two day names follow the preceding word equally often, so the model has no opinion at all about which is correct.

3. Where in a generated sentence does the falsehood appear, and why? At the joins. Every two-word step is one the model observed, so each local fragment looks right, but the combination of fragments was never in the data. "The fine is" and "is closed on monday" both occur; "the fine is closed on monday" does not and is nonsense. Counting three-word runs absent from the training text measures exactly this.

4. What does the temperature do, and what did the measurement show? It reweights the next-word probabilities: low values sharpen towards the commonest continuation and high values flatten towards the rarer ones. Averaged over 200 sentences, the mean number of three-word runs never seen in training rose from 2.81 out of 17 at temperature 0.4 to 4.38 at 2.0. Greater variety and greater invention are the same quantity, and no setting introduces a check on truth.

5. Does a larger model solve the problem? Answer precisely. No. The core objective is unchanged: predict the next token, with nothing referring to truth. Later training on human preferences between answers does reduce obvious nonsense, but it optimises what a rater approved of, and a confident, well-written, wrong answer is the kind a rater approves of, so the failure becomes rarer and harder to detect rather than absent.

munotes.in573

Hallucination in Generative AI

6. State Bender and colleagues' explanation. Languages are systems of signs, that is, pairings of form and meaning, whereas the training data available to a language model is only form; it has no access to meaning. What the model does is stitch together sequences of linguistic forms it has observed according to probabilistic information about how they combine, without reference to meaning.

7. What actually reduces hallucination, and what does not? Measures that bring a check from outside the model: retrieval, so the answer must be drawn from fetched documents; tools such as a calculator or database for the parts they can answer; required citations whose sources are then checked to exist and to say what is claimed; abstention, at some cost in usefulness; and human review with the override rate monitored. Asking the model whether it is confident does not, since its statement of confidence is produced by the same process as the answer it is defending.

Contents This chapter on its own page

munotes.in574

Chapter Eighty-Seven

Deepfakes and Misuse

Syllabus topic Module 2, "deepfakes"

In one line

A deepfake is synthetic media that presents a real person as having said or done something they did not, and the worst damage it does is to make real evidence deniable.

What it is

Synthetic media is any image, audio or video generated or altered by a model. A deepfake is the subset that depicts an identifiable real person. The distinction matters: a generated landscape is synthetic media and harms nobody; a generated video of a named person confessing is a different object entirely.

KindWhat is synthesised
Face swapone person's face on another's recorded performance
Lip sync and reenactmenta real recording driven to match new speech
Voice cloninga person's voice saying new words, from a short sample
Whole-cloth generationan image or video of an event that never occurred
Text impersonationmessages in a person's writing style

The second and third are the ones that matter most in practice, because they need the least source material and are the hardest for an ordinary listener to doubt.

The mechanism, at the level needed to reason about defence

Three families, described only as far as is required to understand why detection is hard.

Generative adversarial networks. Two networks are trained against each other: a generator producing candidates and a discriminator judging whether a sample is real or generated. The generator improves until the discriminator can no longer tell.

Read that definition again, because it contains the whole problem of detection. A detector is a discriminator. Anything that reliably distinguishes generated from real media can be used as the training signal that removes the difference. Detection is therefore not a problem that gets solved; it is an arms race in which the defender's success is the attacker's training data.

Autoencoders. A network compresses a face to a small code and reconstructs it; train one encoder with two decoders and the code from one face can be rendered in the other's appearance.

Diffusion models. Start from noise and remove it step by step towards something that looks like the training distribution, guided by a description. These produce the highest quality current images and require no paired data.

And the fact that decides the social consequences: all three have become cheap. What required a studio became a laboratory, then a workstation, then an application. The technical story is about quality; the social story is entirely about cost, and an answer that discusses only quality has missed why the problem is now urgent.

The harms, in order of how much they are discussed and of how much they matter

These are not the same order, which is the point of setting them out this way.

HarmNote
1Non-consensual intimate imagerythe largest category of deepfake video by volume in every survey of it, and overwhelmingly of women. It is the harm the technology is most used for and the one least discussed in technical courses
2Frauda cloned voice of a relative in distress, or of a superior authorising a payment. Needs seconds of audio and no video at all
3Disinformationa candidate appearing to say something days before a poll, when a correction cannot travel as far as the claim
4Fabricated evidencea recording produced in a dispute, a complaint or a court
5Harassment and extortiontargeted at an individual, frequently a student
6The liar's dividendthe deepest harm, below
munotes.in575

Deepfakes and Misuse

The liar's dividend

The most serious consequence of deepfakes is not that a fake is believed. It is that a real recording can now be denied.

Once everyone knows that convincing fakes exist, anyone caught on a genuine recording has a defence that was not previously available, and it costs nothing to use. The name for the advantage this hands to a person who is actually lying is the liar's dividend, from Chesney and Citron, 2019.

Notice what follows, because it is the part students find surprising: the harm does not require a single deepfake to be made. The mere existence and publicity of the capability is enough to devalue all recorded evidence. Better detection does not undo it either, since the public's doubt is not a technical fact but a social one.

Defences, honestly assessed

Four families, and only one of them is structurally sound.

DefenceHow it worksHonest assessment
Detectiona classifier for artefacts: inconsistent lighting, blinking, compression traces, lip and audio mismatchan arms race by construction, generalises poorly to new generators, and unusable by an ordinary viewer
Watermarkingthe generator embeds a signal in its outputworks for cooperating generators; a model that omits it, or an attacker who re-encodes, defeats it
Provenancesign the media at capture and record every edit, as the C2PA content credentials scheme doesthe only one that is not an arms race: it proves what is real rather than chasing what is fake. Needs adoption by cameras, editors and platforms
Processverify through a second channel: ring back on a known number, agree a family code word, require a second approver for paymentsthe most effective defence available today, and it is not technical at all

The structural insight worth stating in an answer: detection asks "is this fake", which the attacker can train against. Provenance asks "can this be traced to a camera and an unbroken chain of edits", which the attacker cannot forge without the signing key. Proving the real is tractable; proving the fake is not.

munotes.in576

Deepfakes and Misuse

The legal position in India

This changed recently. Check the current text of the rules rather than trusting any printed note, including this one.

What has long applied, under the Information Technology Act, 2000:

ProvisionConcerns
Section 66Cidentity theft, the fraudulent use of another person's electronic signature, password or unique identification feature
Section 66Dcheating by personation using a computer resource, which is the provision that fits a cloned voice or face used to defraud
Section 66Eviolation of privacy by capturing or publishing images of a person's private area without consent

The general criminal law applies alongside it: the Bharatiya Nyaya Sanhita, 2023, which replaced the Indian Penal Code, carries the offences of cheating, forgery, criminal intimidation and defamation, and they are not displaced by the medium being synthetic. The Digital Personal Data Protection Act, 2023 governs the handling of personal data, which includes the images and voice recordings a model is trained on.

And the part that moved. The Information Technology (Intermediary Guidelines and Digital Media Ethics Code) Rules, 2021 place obligations on platforms, and a platform that does not meet them risks its safe harbour under section 79 of the Act. Advisories issued by the Ministry of Electronics and Information Technology in December 2023 and March 2024 told platforms to label synthetic content and to act quickly on takedown requests. Amendments effective 15 November 2025 introduced a defined category of synthetically generated information, with labelling obligations and fixed removal windows, reported as 24 hours for sexual or explicit material and 36 hours for other deepfake misinformation.

Two cautions for an examination answer. Quote section numbers only for the three IT Act provisions above, which are stable. For the rules, say what they require and when they changed, and do not invent a rule number. And note the practical limitation that no statute removes: the harm is done at the speed of sharing, and a takedown after 24 hours is a remedy, not a prevention.

What a student should actually do

The examinable content above is not the useful part for the reader's own life. Six things:

1Verify through a second channel. A request for money, however convincing the voice, is confirmed by ringing back on a number you already had.
2Agree a code word within a family, for exactly this.
3Treat urgency as the warning sign. Every voice-cloning fraud is urgent, because urgency is what prevents the second channel being used.
4Do not answer "is this fake" by looking harder. Current fakes defeat the eye, and the artefacts taught last year are fixed this year.
5Know the route. In India, report through the national cybercrime reporting portal and to the platform, and preserve the original file and the link rather than a screenshot.
6Do not make one, even as a joke. Section 66D does not ask about your intention to amuse, and a college project that impersonates a real person is an offence whatever mark it receives.
munotes.in577

Deepfakes and Misuse

Distinctions

Synthetic mediaDeepfake
Depictsanythingan identifiable real person
Harmful by itselfnofrequently
DetectionProvenance
Asksis this fakecan this be traced to a capture
Against an attackeran arms race: the detector trains the generatornot forgeable without the key
Generalises to a new generatorpoorlyyes, it is indifferent to how the fake was made
Available to an ordinary viewernoyes, as a badge on the file
A fake that is believedThe liar's dividend
Requires a fake to existyesno
Fixed by better detectionpartlyno
Who benefitswhoever made itwhoever is actually guilty

What it does not mean

A deepfake is not merely a fake photograph. The cost of production, not the possibility, is what changed.

Detection is not a solution. A reliable detector is a training signal for the next generator.

Watermarking is not detection. It only works when the generator cooperates.

Quality is not the story. Cost is.

The main harm is not political. By volume it is non-consensual intimate imagery, overwhelmingly of women.

The liar's dividend does not need a deepfake. The publicity of the capability is enough.

A statute is not a prevention. Removal within a day is a remedy after the sharing has happened.

Quick revision

  • Synthetic media is anything generated; a deepfake depicts an identifiable real person. Kinds: face swap, reenactment and lip sync, voice cloning, whole-cloth generation, text impersonation.
  • Mechanisms: GANs (generator against discriminator), autoencoders (one code, two decoders), diffusion (denoise from noise, guided by a description).
  • A detector is a discriminator, so detection is an arms race by construction: the defender's success trains the attacker.
  • Cost, not quality, is the social story.
  • Harms: non-consensual intimate imagery (largest by volume, overwhelmingly of women), fraud by cloned voice, disinformation timed so a correction cannot catch it, fabricated evidence, harassment, and the liar's dividend (Chesney and Citron, 2019), which needs no deepfake at all and is not fixed by detection.
  • Defences: detection (an arms race), watermarking (needs a cooperating generator), provenance such as C2PA ( the only structurally sound one: proving the real, not the fake), and process, which is the best available today and is not technical.
  • India: IT Act, 2000 sections 66C (identity theft), 66D (cheating by personation), 66E (privacy); the Bharatiya Nyaya Sanhita, 2023 for cheating, forgery and defamation; the DPDP Act, 2023 for personal data; the IT Rules, 2021, platform obligations and safe harbour under section 79; MeitY advisories of December 2023 and March 2024; amendments effective 15 November 2025 defining synthetically generated information with labelling and removal windows of 24 and 36 hours. Check the current text.
  • Practice: verify on a second channel, agree a code word, treat urgency as the warning, preserve the original file, report through the national cybercrime portal, and do not make one.
munotes.in578

Deepfakes and Misuse

Test yourself

1. Distinguish synthetic media from a deepfake. Synthetic media is any image, audio or video generated or altered by a model. A deepfake is the subset depicting an identifiable real person as having said or done something they did not, which is what makes it capable of harming a particular individual.

2. Explain why detection is structurally an arms race. A generative adversarial network is trained by pitting a generator against a discriminator that judges real from generated, and the generator improves until the discriminator fails. Any reliable detector is such a discriminator, so it can be used directly as the training signal that removes the differences it relies on. The defender's success therefore becomes the attacker's next improvement.

3. What is the liar's dividend, and why is it the deepest harm? It is the advantage that the known existence of convincing fakes gives to a person caught on a genuine recording, who can now deny it at no cost. It is the deepest harm because it requires no deepfake to be made at all, so better detection cannot undo it: the doubt it exploits is a social fact about what the public believes is possible, not a technical property of any particular file.

4. Compare detection with provenance as defences. Detection asks whether a file is fake, which the attacker can train against and which generalises poorly to generators it has not seen, and it is unusable by an ordinary viewer. Provenance signs media at the moment of capture and records the chain of edits, so it establishes what is real rather than chasing what is false, cannot be forged without the signing key, and is indifferent to how any fake was produced. Its difficulty is adoption by cameras, editing tools and platforms rather than anything technical.

5. Which single defence is most effective today, and why is it not technical? Verification through a second channel: ringing back on a number already known, agreeing a family code word, requiring a second approver for a payment. It works because a cloned voice cannot control the channel you choose to verify on, and because every such fraud relies on urgency precisely to prevent that verification.

munotes.in579

Deepfakes and Misuse

6. Which provisions of the Information Technology Act, 2000 apply to deepfakes? Section 66C on identity theft, section 66D on cheating by personation using a computer resource, which is the provision that fits a cloned voice or face used to defraud, and section 66E on violation of privacy through capturing or publishing images of a person's private area without consent. The general criminal law under the Bharatiya Nyaya Sanhita, 2023 applies alongside them for cheating, forgery and defamation.

7. What do the IT Rules require of platforms, and what is their limitation? They impose obligations on intermediaries whose breach puts the platform's safe harbour under section 79 at risk; advisories in December 2023 and March 2024 required labelling of synthetic content and prompt action on takedown requests, and amendments effective 15 November 2025 defined synthetically generated information with labelling duties and removal windows reported as 24 hours for sexual or explicit material and 36 hours for other deepfake misinformation. Their limitation is that sharing outruns removal: a takedown a day later is a remedy after the harm, not a prevention of it.

Contents This chapter on its own page

munotes.in580

Chapter Eighty-Eight

Using an AI Library Responsibly

Syllabus topic Module 2, "Demo of OpenAI/TensorFlow Tools"

In one line

A library call is one of the algorithms in this book with the arguments hidden, and using it responsibly means knowing which algorithm, what it assumed, and what to check before believing the number it returns.

MU's paired practical, Computer Science Practical 5, sets a demonstration using OpenAI or TensorFlow tools, and the machine learning practicals use scikit-learn throughout. This chapter is about what those calls are doing and what must be checked. It is not a tutorial in any library's syntax, which changes, and which the library's own documentation gives better.

A declaration about this chapter

Every other program in this book was run on three interpreters and its output pasted from the run. The listings here are not. scikit-learn, TensorFlow and the OpenAI client are not installed on the machine this book was checked on, so nothing below could be executed, and no output is claimed for any of it.

Each block is therefore written as a form: the shape of the call, with the parts that matter named. Check the library's current documentation before using any of them, because these interfaces change between versions and a printed line in a book is out of date the moment a release happens.

Every call is a chapter of this book

This table is the chapter. A student who can complete it can read a practical's solution; one who cannot is copying.

The callWhat it actually isChapter
LinearRegressionleast squares by the normal equationsThe First Learner: Fitting a Straight Line
SGDRegressor, SGDClassifiergradient descent, in batchesGradient Descent
Ridge, Lassoleast squares with a penalty on the weightsRegularisation
DecisionTreeClassifierID3 or CART: choose the split with the best information gainBuilding a Decision Tree with ID3
RandomForestClassifierbagging plus a random subset of features per splitEnsemble Methods, Bagging and The Random Forest
AdaBoostClassifierthe reweighting of Boosting and AdaBoost
GaussianNB, MultinomialNBthe independence assumption, with smoothingNaive Bayes
KNeighborsClassifierstore everything, compare at query timek-Nearest Neighbours
SVC(kernel=...)the maximum margin, with the kernel trickThe Kernel Trick
KMeansassign, recentre, repeatClustering and k-means
AgglomerativeClustering(linkage=...)merge the two closest clustersHierarchical Clustering and Judging a Clustering
train_test_split, cross_val_scoreholding data back, and k foldsEvaluating a Model
classification_reportprecision, recall, F1, per classEvaluating a Model
StandardScalerthe scaling that distance-based methods needk-Nearest Neighbours
A Sequential model with Dense layersa feed-forward networkNeural Networks and The Perceptron
loss='categorical_crossentropy', optimizer='adam'the loss and the descent ruleBackpropagation, Gradient Descent
model.fit(..., epochs=..., validation_split=...)training, with a held-out set to watch for overfittingOverfitting and Underfitting

Two entries deserve a second look.

munotes.in581

Using an AI Library Responsibly

SVC(kernel='rbf') is a decision, not a default. The Kernel Trick showed what a kernel does and what it costs. Choosing one without being able to say what shape of boundary it allows is choosing at random.

RandomForestClassifier gives up interpretability. Transparency and Explainability measured the trade: one readable tree at 0.6657 against an unreadable forest at 0.7450. That is a real gain and it is a real loss, and the loss is invisible until someone asks why a person was refused.

The shape of a scikit-learn program

X, y = features, labels                 # X: rows by columns, y: one label per row
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)
scaler.fit(Xtr); Xtr = scaler.transform(Xtr); Xte = scaler.transform(Xte)
model = SomeClassifier(**chosen_hyperparameters)
model.fit(Xtr, ytr)                     # the learning
print(classification_report(yte, model.predict(Xte)))
print(confusion_matrix(yte, model.predict(Xte)))

Four things in that form carry the whole responsibility of the chapter, and every one of them is a line a beginner deletes.

stratify=y. Without it, an unbalanced problem can put almost none of the rare class in the test set, and Evaluating a Model showed what unbalanced data does to an accuracy figure.

random_state=0. Without a fixed seed the split changes every run, so the score changes every run, and a comparison between two models measures the split rather than the models.

scaler.fit(Xtr) and not scaler.fit(X). Fitting the scaler on all the data lets the test set's mean and spread into the training, which is data leakage: the score improves and the model does not. The rule is absolute: anything fitted must be fitted on the training data alone.

classification_report and confusion_matrix rather than score. Evaluating a Model measured a classifier at 0.9700 accuracy that was worthless. A single number is not a result.

The shape of a TensorFlow or Keras program

model = Sequential([Dense(32, activation='relu'), Dense(n_classes, activation='softmax')])
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(Xtr, ytr, epochs=50, validation_split=0.2, verbose=0)
# the two curves in history are the point: training loss falling while
# validation loss rises IS overfitting, seen as it happens
loss, acc = model.evaluate(Xte, yte)

The comment is the content. The validation curve turning upward while the training curve keeps falling is the picture Overfitting and Underfitting drew, and it is the one thing a practical write-up should contain and usually does not.

And the honest note about epochs=50: it is a guess. Early stopping, halting when the validation loss stops improving, is the principled version, and it is one argument to the same call.

The shape of a call to a hosted model

key = os.environ["OPENAI_API_KEY"]      # NEVER written in the source file
reply = client.responses.create(model=..., input=prompt)
# everything in `prompt` has left the machine. treat it as published.
munotes.in582

Using an AI Library Responsibly

Three rules, and the first two are absolute.

The key is a secret. It goes in an environment variable or a secrets manager, never in the source and never in a repository. A key in a public repository is found by automated scanners in minutes and billed to its owner.

The prompt leaves the machine. Anything sent is disclosed to a third party: a classmate's marks, a patient record, a friend's message, an unpublished manuscript. Treat the prompt as published, because for the purposes of the person whose data it was, it is.

The reply is unverified. Hallucination in Generative AI measured why: the model scores how ordinary a sequence of words looks and a false sentence of ordinary phrases scores well. Every specific claim, number, citation and date in a reply must be checked against a source before it is used.

The checks before a result is believed

Ten, in order, and this list is the answer to "how would you validate your practical's result".

CheckWhy
1What is the baseline? The largest class's share, or the simplest ruleEvaluating a Model: 0.9700 was the floor, not the result
2Is the test data genuinely held out, and was nothing fitted on it?data leakage inflates every number
3Are there duplicate rows across the split?the same row in train and test is memorised, not learned
4Does any feature encode the answer?a column recorded after the outcome is a leak
5What is the confusion matrix, and which error costs more?the two errors are not the same error
6What are the scores per group?Bias and Fairness in AI Models
7What is the spread across folds, not just the mean?Evaluating a Model: five folds ran 0.50 to 1.00
8Were the hyperparameters chosen on the test set?then the test set is training data and the score is meaningless
9Does the result survive a different random seed?if not, it is the seed's result
10Is the training score being reported by mistake?it means nothing; the model has seen those rows

Check 8 is the one that quietly ruins student projects. Trying twenty models and reporting the best test score reports the maximum of twenty noisy numbers. Hyperparameters are chosen on a validation set or by cross validation inside the training data, and the test set is touched once, at the end.

Responsibilities that are not about accuracy

Licencea model and a data set each have one, and "available to download" is not a licence to use
Provenance of the datawho is in it, and were they asked
Personal dataIndia's Digital Personal Data Protection Act, 2023 applies to a student project as much as to a company
Attributionsay which library, which version, and which pretrained weights
Reproducibilityrecord the versions and the seed, or the result is not a result
Cost and footprintEthical Issues in AI Systems: one large training run was estimated at 284 tonnes of CO2
Scopea model trained on one population is not evidence about another
munotes.in583

Using an AI Library Responsibly

Distinctions

Calling a libraryUnderstanding the call
Needsthe documentationthe chapter
Producesa numbera number you can defend
Examinablerarelyyes
fit on the training datafit on everything
Scorehonestinflated
Name for the errordata leakage
scoreclassification_report
Returnsone numberprecision, recall, F1, per class
Safe on unbalanced datanoyes

What it does not mean

A library call is not a black box. Every one in the table is an algorithm in this book.

A default is not a choice. A kernel, a depth, a learning rate and a number of epochs are all decisions.

A high score is not a result. Compare it with the baseline first.

Fitting a scaler on all the data is not harmless. It is leakage and it inflates every number afterwards.

Choosing a model on the test set is not evaluation. It makes the test set training data.

An API key in a file is not private. It is found by scanners within minutes of being published.

A prompt is not private either. Treat it as published.

A model's reply is not a source. Check every specific claim against one.

Quick revision

  • Every library call is a chapter of this book. LinearRegression, SGDClassifier, Ridge, DecisionTreeClassifier, RandomForestClassifier, AdaBoostClassifier, GaussianNB, KNeighborsClassifier, SVC, KMeans, AgglomerativeClustering, cross_val_score, StandardScaler, Sequential with Dense.
  • The four lines that carry the responsibility: stratify, random_state, fit the scaler on the training data only, and report a confusion matrix, not a score.
  • Data leakage: anything fitted must be fitted on the training data alone.
  • In Keras, the training and validation curves are the result: validation rising while training falls is overfitting. Early stopping replaces a guessed epoch count.
  • Hosted models: the key is a secret, the prompt leaves the machine and should be treated as published, and the reply is unverified.
  • The ten checks: baseline, genuinely held-out test data, duplicates, a feature encoding the answer, the confusion matrix, per-group scores, the spread across folds, hyperparameters not chosen on the test set, survival of a different seed, and not reporting the training score.
  • Choosing among twenty models by test score reports the maximum of twenty noisy numbers. Tune on a validation set; touch the test set once.
  • Beyond accuracy: licence, data provenance, personal data under the DPDP Act, 2023, attribution, reproducibility (versions and seed), cost, and scope.
munotes.in584

Using an AI Library Responsibly

Test yourself

1. A practical uses RandomForestClassifier. What is it doing, in the terms of this book? Growing many decision trees, each on a bootstrap sample of the rows drawn with replacement and each restricted at every split to a random subset of the features, then combining them by majority vote. The random feature subset makes the trees less alike so that their errors cancel, at the cost of each tree being individually worse and of the whole model no longer being readable as a set of rules.

2. Why must a scaler be fitted on the training data only? Because fitting it on all the data uses the test set's mean and spread to transform the training data, so information from the test set enters the model. That is data leakage: the reported score improves while the model does not, and the improvement disappears on genuinely new data.

3. Name four things in a scikit-learn pipeline a beginner omits and say why each matters. Stratifying the split, without which an unbalanced problem may place almost none of the rare class in the test set; fixing the random seed, without which the score changes every run and comparisons measure the split rather than the model; fitting transformations on the training data alone, without which there is leakage; and reporting a confusion matrix and per-class report rather than a single accuracy, since an accuracy of 0.97 was shown earlier to belong to a worthless classifier.

4. What should a practical write-up show from a Keras training run? The training and validation curves together. Training loss falling while validation loss rises is overfitting, visible as it happens, and it is the one piece of evidence that shows whether the chosen number of epochs was right. Early stopping on the validation loss replaces the guess.

5. Give three rules for calling a hosted model. The API key is a secret and belongs in an environment variable or secrets manager, never in source or a repository, since published keys are found by automated scanners within minutes. Everything in the prompt leaves the machine and should be treated as published, so another person's data must not be sent without their consent. And the reply is unverified text produced by a process that scores how ordinary a word sequence looks, so every specific claim, number, citation and date must be checked against a source.

munotes.in585

Using an AI Library Responsibly

6. Why is reporting the best test score among twenty tried models misleading? Because it reports the maximum of twenty noisy measurements, which is biased upward, and because each comparison used the test set to make a choice, so the test set has become part of the training process. Hyperparameters must be selected on a validation set or by cross validation within the training data, and the test set used once, at the end.

7. List the checks you would make before believing a classification result. Compare it with the baseline given by the largest class or the simplest rule; confirm the test data was genuinely held out and that nothing was fitted on it; look for duplicate rows across the split; check that no feature records the answer or something recorded after it; read the confusion matrix and decide which error costs more; compute the scores separately for each group; report the spread across folds and not only the mean; confirm the hyperparameters were not chosen on the test set; repeat with a different seed; and make sure the number quoted is not the training score.

Contents This chapter on its own page

munotes.in586

Chapter Eighty-Nine

What the Examination Asks, and How to Answer It

Syllabus topic Module 2, "What is AI?", "Introduction of Machine Learning"

In one line

Twelve questions are printed, six are answered, each is worth five marks, and the whole paper lasts one hour.

The pattern, as MU prints it

Read this once and the rest of the chapter is obvious.

TypeTheory. The paired practical, Computer Science Practical 5, is a separate paper with its own marks
Credits and hours2 credits, 15 hours per module, 30 in all
Semester end examination1 hour, 30 marks
Q.1on Module 1: answer any 2 of the following, any 2 out of 4, for 10 marks
Q.2on Module 2: the same
Q.3on Modules 1 and 2: the same
Internal, 20 marksClass Test 1 on Module 1 (10) and Class Test 2 on Module 2 (10), averaged to 10, plus an assignment on each module (5 each), totalling 10

Check the instructions printed on the paper in front of you. A pattern can be revised between the year a book is written and the year it is sat.

What that arithmetic means

Four consequences, and they decide how to revise.

Ten minutes an answer. Sixty minutes, six answers. There is no time to think about what the question means. An answer must begin the moment it is read, which means the material must be held in the shape an answer takes.

Five marks is a short answer, not an essay. Roughly: a definition, the mechanism or formula, one worked thing, and one limitation. Four sentences and a line of arithmetic will score better than a page of general remarks.

Choice is real: 4 offered, 2 required. You may leave half of each question. But the choice is within a question, so a module left unrevised costs 10 marks and cannot be recovered from the other.

Q.3 crosses the modules. A comparison spanning the two is a question that can be set, and it is the question students prepare least. The crossings worth having ready are below.

The two modules, in one table each

Module 1, as printed:

BlockTopics
Foundations and agentswhat is AI, rational agents against human thinking, computational agents, agent and environment interaction, types of environment, agent architectures: simple reflex, model-based, goal-based, utility-based, learning
Problem solving and searchproblem formulation; uninformed: BFS, DFS, uniform cost, IDS; informed: greedy, A*; heuristics: admissibility and consistency; adversarial: minimax and alpha-beta
Knowledge and logicknowledge-based agents, propositional logic and inference, first-order logic, rule-based systems, planning (STRIPS), fuzzy logic and fuzzification
Uncertaintyprobabilistic reasoning, Bayes theorem, conditional independence, Bayesian networks

Module 2, as printed:

BlockTopics
Introductionforms of learning (supervised, unsupervised, reinforcement), parametric against nonparametric, bias and variance, overfitting and regularisation, gradient descent
Supervised modelsclassification against regression, k-NN, decision trees, naive Bayes, SVM, neural networks (single layer, and the concept of deep learning), ensembles and boosting
Probabilistic and latentstatistical learning framework, maximum likelihood, learning with complete data, hidden variables, EM, hidden Markov models
Unsupervised and reinforcementclustering, association rules (Apriori), reinforcement learning framework, MDPs, Q-learning
Responsible AIethical issues, bias and fairness, transparency and explainability, accountability and human oversight, risks in generative AI (hallucination, deepfakes, misuse)
munotes.in587

What the Examination Asks, and How to Answer It

The shape of a five-mark answer

Use it every time and it will not need thinking about on the day.

1The definition, in one sentence, in the syllabus's own words where possible
2The mechanism: the steps, or the formula, written out
3One worked thing: a number, a small table, a two-line example
4One limitation or condition: when it fails, or what it assumes

Step 3 is what separates answers. A marker cannot tell whether a fluent paragraph was understood; a worked number is evidence. Every chapter of this book carries one for exactly this reason.

The formulae to have by heart

Short, and every one has been used in a worked example in this book.

f(n) = g(n) + h(n) A* evaluation

h(n) <= h*(n) for all n the admissibility condition

h(n) <= c(n, n') + h(n') consistency

P(a given b) = P(b given a) * P(a) / P(b) Bayes

entropy = - sum of p * log2(p) and gain = entropy before - weighted after

accuracy = (TP + TN) / n, precision = TP/(TP+FP), recall = TP/(TP+FN)

F1 = 2PR / (P + R) the harmonic mean

p = h / (h + t) the MLE of a coin

alpha = 0.5 * ln((1 - e) / e) AdaBoost's weight

V(s) = R(s) + gamma * sum of P(s' given s, pi(s)) V(s') policy evaluation

V(s) = max over a of sum of P(s' given s,a)[R + gamma V(s')] Bellman optimality

Q(s,a) <- Q(s,a) + alpha[r + gamma max_a' Q(s',a') - Q(s,a)] Q-learning

support, confidence = sup(A and B)/sup(A), lift = conf / sup(B)

silhouette s = (b - a) / max(a, b)

The crossings Q.3 can ask for

Each of these spans the two modules and each is already made somewhere in this book.

CrossingThe point
Bayes theorem against the naive Bayes classifierthe theorem is exact; the classifier adds an independence assumption that is usually false and works anyway
Search against learningsearch is given the goal and finds a path; learning is given examples and finds a rule
Admissibility of a heuristic against the bias of a modelboth are statements about systematic error in one direction
A* against Viterbiboth find a best path by combining partial paths; one uses a heuristic, the other the Markov property
Bayesian networks against hidden Markov modelsan HMM is a Bayesian network unrolled in time
Conditional independence against naive Bayes and EMthe same assumption, used to make a model small, and what breaks when a variable is hidden
Minimax against value iterationboth back values up from the end; one alternates a max and a min, the other maximises expectation
Fuzzy logic against probabilitydegree of membership is not degree of belief
STRIPS against an MDPa plan is a sequence; an MDP's answer is a policy, because actions can go wrong
Rule-based systems against decision treesrules written by a person against rules learnt from data, with the same readability
munotes.in588

What the Examination Asks, and How to Answer It

The twenty most answerable things in this book

Each is a measured result with a number, which makes it a five-mark answer with evidence.

1An accuracy of 0.9700 belonging to a worthless classifier on unbalanced data
2F1 being 0.0000 for that same classifier
3The greedy trap on the district map, and why admissibility prevents it
4Alpha-beta's saving, and why move ordering decides it
5Entropy 0.9403 on the attendance table, and the gain of each split
6Pruning: the training score falls and the test score rises
7Bagging +0.0476 against the random forest's +0.1014 with individually worse trees
8AdaBoost: a single stump 0.8000, the ensemble 1.0000, dipping to 0.7000 at round 2
9The MLE variance running 20 per cent short of a true 144
10A zero count making an outcome impossible, and Laplace smoothing
11EM's log likelihood rising every round, and a symmetric start never moving
12The forward algorithm agreeing with brute force at 0.06084495 while the best path is only 43.7 per cent of it
13Viterbi RRRR against the pointwise RRRN
14k-means: 838 of 2024 starts reaching a worse answer
15k-means scoring 20 of 40 on two bands where single linkage scores 40
16if samosa then tea: confidence 1.0000, lift 1.1111
17Apriori pruning a candidate without counting it
18The optimal policy going away from the goal below the penalty, and the step cost changing the policy
19Q-learning learning the optimal policy while acting completely at random
20The 34.4 per cent gap in Gender Shades, and the fairness impossibility with unequal base rates

How to revise, in the last week

In order, and the order matters.

munotes.in589

What the Examination Asks, and How to Answer It

1Read every chapter's Quick revision box. That alone covers the paper.
2Write the formulae above from memory, twice.
3Work one numerical example per major algorithm by hand: an A* expansion, an information gain, one AdaBoost round, one Bellman update, one forward column.
4Answer the Test yourself questions of the chapters you are least sure of, in writing and against a clock.
5Prepare three crossings from the table above, for Q.3.
6Practise the four-part answer shape on six questions in sixty minutes.

What not to do: rereading. Recognition is not recall, and a chapter that feels familiar is not a chapter you can write about in ten minutes.

In the examination

Read all twelve first.Two minutes spent choosing is worth more than two minutes of writing.
Answer the ones you can work.An answer with a number beats an answer with adjectives.
Draw.A small tree, a grid, a confusion matrix, a network. They are fast and they carry marks.
State the condition."A* is optimal if the heuristic is admissible" is the mark; the sentence without the condition often is not.
Stop at ten minutes.A sixth answer at half marks beats a fifth answer at full marks.
Do not leave a question blank.The definition alone is worth something, and it takes a minute.

What this paper is not

It is not the practical. Computer Science Practical 5 is a separate paper; code is not asked for here, though an algorithm's steps are.

It is not a memory test of library syntax. No mark in this paper depends on remembering a function's arguments.

It is not a test of opinions. The Responsible AI block asks for named harms, named measures and named frameworks.

It is not long-form. Five marks is four sentences and a worked line.

Quick revision

  • 1 hour, 30 marks. Q.1 Module 1, Q.2 Module 2, Q.3 both, each any 2 out of 4 for 10 marks. Twelve printed, six answered, five marks each, ten minutes each. Internal 20: two class tests averaged to 10, plus two assignments totalling 10.
  • The four-part answer: definition, mechanism or formula, one worked thing, one limitation.
  • Half of each question may be left, but a whole module cannot: it is 10 marks that the others cannot replace.
  • Q.3 crosses the modules. Have three crossings ready.
  • Know by heart: f = g + h, admissibility, consistency, Bayes, entropy and gain, accuracy, precision, recall, F1, the coin MLE, AdaBoost's alpha, policy evaluation, Bellman optimality, the Q-learning update, support, confidence, lift, silhouette.
  • Revise by writing, not rereading. Work one numerical example per algorithm.
  • In the hall: read all twelve, choose the workable ones, draw, state the condition, stop at ten minutes, and leave nothing blank.
munotes.in590

What the Examination Asks, and How to Answer It

Test yourself

1. State the pattern of the semester end examination. One hour and 30 marks. Question 1 is set on Module 1, Question 2 on Module 2 and Question 3 across both, and each requires any two of four parts to be answered for ten marks. Twelve parts are therefore printed, six are answered, each is worth five marks, and about ten minutes is available for each.

2. How are the internal 20 marks made up? Two class tests, one on each module and each out of ten, averaged to give ten marks, together with one assignment on each module worth five marks each, giving a further ten.

3. What shape should a five-mark answer take? A definition in one sentence, the mechanism or formula written out, one worked thing such as a number, a small table or a short example, and one limitation or condition. The worked element is what distinguishes an answer that was understood from one that was recognised.

4. Why can half of each question be left but not a whole module? Because the choice is offered within a question, not across questions. Two of four parts may be omitted in each, but Question 1 is set entirely on Module 1 and Question 2 entirely on Module 2, so a module left unrevised costs ten marks that no other question can supply.

5. Give three comparisons that could be set as a Question 3. Bayes theorem against the naive Bayes classifier, the first exact and the second adding an independence assumption that is usually false and works anyway. A hidden Markov model against a Bayesian network, the first being the second unrolled in time. And a STRIPS plan against a Markov decision process, a sequence of actions against a policy, the difference being that an action in an MDP may not do what was intended.

6. Write from memory the formulae for A*, information gain, F1 and the Q-learning update. f(n) = g(n) + h(n). Information gain is the entropy of the set before the split minus the weighted average of the entropies of the parts, entropy being minus the sum of p times log2 p. F1 = 2PR/(P+R), the harmonic mean of precision and recall. And Q(s,a) becomes Q(s,a) + alpha[r + gamma max over a' of Q(s',a') - Q(s,a)].

7. How should the last week be spent? Reading every chapter's revision box, writing the formulae from memory twice, working one numerical example by hand for each major algorithm, answering the Test yourself questions of the least certain chapters in writing and against a clock, preparing three cross-module comparisons for Question 3, and practising six answers in sixty minutes in the four-part shape. Rereading should be avoided: recognising a chapter is not the same as being able to write about it in ten minutes.

Contents This chapter on its own page

munotes.in591

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself, or the past papers, for the same subject.

Issue
Done!