2. Perceptron
Activity: Understanding Perceptrons and Their Limitations
This activity is designed to test your skills in Perceptrons and their limitations.
The thread running through the activity is separability: you will train the same perceptron on two datasets β one the algorithm can solve, one it cannot β and the interesting part is not that the second one fails, but how it fails.
Technical rules (they apply to the whole activity)
- Fix the random seed β
rng = np.random.default_rng(42)β and use the samerngthroughout the report. Results that cannot be reproduced score no points; - Every plot must have a title, axis labels, and a class legend;
- Allowed libraries:
numpy,pandas,matplotlib/seaborn. The perceptron itself β the activation, the prediction, the update rule and the training loop β MUST BE WRITTEN BY YOU.scikit-learn(or any other library) may not supply the model: noPerceptron, noSGDClassifier, nofit. Using one voids the implementation criterion and the exercise that depends on it; - Whenever the statement asks for a number (weights, bias, epochs, accuracy), report the number in the text β not only in the code output;
- Organize the report with one heading per exercise and one subheading per item (
Exercise 1,A,B, β¦), in the same order as the statement, and number the figures as indicated. The last section of the report must be the Results summary described at the end of this page.
Exercise 1
Separable Data: the case the perceptron was designed for
A β Generate the data
Generate two classes of 2D points, 1000 samples per class, from multivariate normal distributions:
- Class 0: Mean \(= [1.5, 1.5]\), Covariance \(= [[0.5, 0], [0, 0.5]]\)
- Class 1: Mean \(= [5, 5]\), Covariance \(= [[0.5, 0], [0, 0.5]]\)
The means are far apart relative to the spread, so the two clouds are linearly separable with at most a handful of exceptions.
Produce Figure 1: a scatter plot of the 2000 points, one color per class.
B β Implement the perceptron
Write a single-layer perceptron from scratch. This same implementation is reused in Exercise 2 β write it once, as a function or a class.
-
Prediction. \(\hat{y} = \text{step}(\mathbf{w} \cdot \mathbf{x} + b)\), where \(\text{step}(z) = 1\) if \(z \geq 0\) and \(0\) otherwise.
-
Update rule. For each sample \((\mathbf{x}, y)\), compute \(\hat{y}\) and apply
\[ \mathbf{w} \leftarrow \mathbf{w} + \eta \, (y - \hat{y}) \, \mathbf{x}, \qquad b \leftarrow b + \eta \, (y - \hat{y}) \]with \(y, \hat{y} \in \{0, 1\}\). The error \((y - \hat{y})\) is \(0\) on a correct prediction β so correctly classified samples produce no update β and \(+1\) or \(-1\) on the two kinds of mistake.
Why not \(\mathbf{w} \leftarrow \mathbf{w} + \eta \, y \, \mathbf{x}\)?
You will find that form in many textbooks. It belongs to the convention where labels are \(-1\) and \(+1\). With the \(0/1\) labels used here it would never update on Class 0, and the perceptron could never correct a false positive. Match the rule to your labels.
-
Initialization. Draw \(\mathbf{w}\) from
rng.normal(0, 0.01, size=2)and set \(b = 0\). Do not start from \(\mathbf{w} = \mathbf{0}\) β item D asks you to reason about the learning rate, and from an all-zero start the learning rate provably changes nothing (it only rescales \(\mathbf{w}\), leaving the decision boundary and the epoch count identical). -
Learning rate. \(\eta = 0.01\).
-
Stopping. Train until a full pass over the dataset produces no update, or for a maximum of 100 epochs, whichever comes first. Record the accuracy on the full dataset after every epoch.
C β Train and measure
- Train the model and report the final \(\mathbf{w}\), the final \(b\), the number of epochs, and the final accuracy.
- Produce Figure 2: the decision boundary \(\mathbf{w} \cdot \mathbf{x} + b = 0\) drawn over the data points, with any misclassified points marked differently.
- Produce Figure 3: accuracy \(\times\) epoch.
D β Analysis
- Why does separable data converge quickly? Connect your answer to the update rule: what happens to the number of updates per epoch as training progresses?
- Re-run the training with \(\eta = 1.0\), changing nothing else. Report the epoch count and the final accuracy, and compare the direction of \(\mathbf{w}\) (that is, \(\mathbf{w} / \lVert \mathbf{w} \rVert\)) against the \(\eta = 0.01\) run. Both runs should reach 100%, but by different boundaries β explain what \(\eta\) controls, given that every update adds \(\eta \, \mathbf{x}\) to weights that started at a magnitude of about \(0.01\).
- Now argue what would have happened from \(\mathbf{w} = \mathbf{0}\), \(b = 0\). Show algebraically that running the whole training twice, with \(\eta_1\) and \(\eta_2\), produces weights that differ only by the constant factor \(\eta_2 / \eta_1\) β so the decision boundary and the epoch count are identical and \(\eta\) has no effect at all. This is why item B forbids the zero start.
Exercise 2
Overlapping Data: the case the perceptron cannot solve
A β Generate the data
Generate two classes of 2D points, 1000 samples per class:
- Class 0: Mean \(= [3, 3]\), Covariance \(= [[1.5, 0], [0, 1.5]]\)
- Class 1: Mean \(= [4, 4]\), Covariance \(= [[1.5, 0], [0, 1.5]]\)
The means are now close together and the spread is three times larger, so the clouds overlap heavily and no straight line separates them.
Produce Figure 4: a scatter plot of the 2000 points, one color per class.
B β Train, keeping the best weights
Reuse the implementation from Exercise 1, unchanged, with the same \(\eta = 0.01\) and the same 100-epoch cap. Because the data is not separable the training loop will never stop updating, so you will track two sets of weights:
- the final weights β whatever the loop happens to hold after the last epoch;
- the pocket weights β the best-so-far: every time an update produces a higher accuracy on the full dataset than any previously seen, copy \((\mathbf{w}, b)\) into your "pocket" and keep it. This is the pocket algorithm, and the copy is the only thing you add to the loop.
Report, for both sets of weights: \(\mathbf{w}\), \(b\), and the accuracy.
What to expect
The two numbers will be far apart, and the final-iterate accuracy will look broken β somewhere near 50%, which is what you would get by guessing. That is the correct result, not a bug in your code. Item D asks you to explain it.
C β Figures
- Produce Figure 5: both decision boundaries β final and pocket β drawn over the data points, with misclassified points marked.
- Produce Figure 6: two curves against epoch β the accuracy of the current weights, and the best-so-far (pocket) accuracy.
D β Analysis
- The best straight line for this data scores about 73%. Your pocket weights should land close to that; your final weights should not. Explain the gap. Where does the final boundary sit relative to the data cloud, and why does the training loop leave it there? Hint: compare how far \(b\) moves per mistake against how far \(\mathbf{w}\) moves, given that \(\lVert \mathbf{x} \rVert \approx 5\) for this data.
- Compare Figure 3 with Figure 6. In Exercise 1 the accuracy curve settles; here it does not. What does the perceptron convergence theorem guarantee, and which of its assumptions does this dataset violate?
- Does adding more epochs fix it? Does a smaller \(\eta\)? Justify your answer from the update rule rather than by trial and error.
Results summary
Close the report with this table, filled in:
| # | Quantity | Value |
|---|---|---|
| 1 | Exercise 1 β final \(\mathbf{w}\) and \(b\) | |
| 2 | Exercise 1 β epochs to convergence | |
| 3 | Exercise 1 β final accuracy | |
| 4 | Exercise 1 β epochs and final accuracy with \(\eta = 1.0\) | |
| 5 | Exercise 2 β final \(\mathbf{w}\) and \(b\) | |
| 6 | Exercise 2 β accuracy of the final weights | |
| 7 | Exercise 2 β accuracy of the pocket weights | |
| 8 | Exercise 2 β epoch at which the pocket best occurred |
Evaluation Criteria
The deliverable for this activity is a report that includes:
- A brief description of your implementation approach and any challenges faced.
- The code for the perceptron and for the data generation, commented.
- Figures 1 to 6, numbered as requested.
- Your answers to the analysis questions in items D.
- The Results summary table.
Important Notes:
-
The deliverable is a GitHub Pages site backed by a public repository β see Submission Format for the required layout, front matter and checklist;
-
There is a strict no-plagiarism policy. Any form of plagiarism will result in a zero grade for the activity and may lead to further disciplinary action under the university's academic integrity policies;
-
The deadline for each activity is not extended β NO EXCEPTIONS will be made for late submissions.
-
AI collaboration is allowed, but each student MUST UNDERSTAND and be able to explain every part of the submitted code and analysis. Any use of AI tools must be properly cited. ORAL EXAMS may be conducted.
-
All deliverables for individual activities should be submitted through the course platform insper.blackboard.com.
Grading Criteria:
Each row is worth the points indicated, awarded in full, partially (half), or not at all: in full when the item is complete and correct; partially when it is implemented but missing the requested analysis, or when the analysis lacks the numerical result that supports it; zero when absent or incorrect.
The accuracy value itself is not graded β Exercise 2 is supposed to score badly. What is graded is the method, the figures, and reporting honestly what you got.
Exercise 1 β Separable data (4 points):
| Points | Criterion | What earns full credit |
|---|---|---|
| 0.5 | Data generation (A) | Correct parameters, 1000 samples per class, fixed seed, readable Figure 1. |
| 2.0 | Implementation (B) | Perceptron written from scratch, with the \(\{0,1\}\) error-driven update rule, non-zero initialization, and the stopping condition as specified. No third-party model. |
| 1.0 | Training and figures (C) | Final \(\mathbf{w}\), \(b\), epochs and accuracy reported in the text; Figures 2 and 3 correct and labeled. |
| 0.5 | Analysis (D) | Explains convergence from the update rule; reports both \(\eta\) runs with their boundary directions; and shows algebraically that from a zero start \(\eta\) would only rescale \(\mathbf{w}\), leaving the boundary and the epoch count unchanged. |
Exercise 2 β Overlapping data (4 points):
| Points | Criterion | What earns full credit |
|---|---|---|
| 0.5 | Data generation (A) | Correct parameters, 1000 samples per class, fixed seed, readable Figure 4. |
| 1.0 | Training with the pocket (B) | The Exercise 1 implementation reused unchanged, plus best-so-far tracking; both weight sets and both accuracies reported. |
| 1.0 | Figures (C) | Figure 5 with both boundaries and misclassified points marked; Figure 6 with both curves. |
| 1.5 | Analysis (D) | Explains the gap between the final and pocket accuracy from the update rule and the position of the boundary; identifies the assumption the convergence theorem needs and this dataset breaks; argues correctly that neither more epochs nor a smaller \(\eta\) fixes it. |
Report (2 points):
| Points | Criterion | What earns full credit |
|---|---|---|
| 1.0 | Organization | One heading per exercise and per item, in statement order; figures numbered as requested; code commented. |
| 1.0 | Results summary and reproducibility | The summary table filled in, and the reported numbers reproducible from the stated seed. |