Make sure you check the syllabus for the due date. Please use the notations adopted in class.
Instructions. Submit code (Jupyter notebook encouraged) plus a short report with tables and plots. Libraries (numpy, sklearn, matplotlib) are allowed for data handling, plotting, and basic math; the core of any "from scratch" problem must be your own.
Requirements.
Model/hyperparameter selection. Wherever a problem asks you to choose among kernels, hyperparameters, or a dimension (Problem 1's kernel grid, Problem 3's kernel + regularization, Problem 5's T), split off a validation set and pick using validation performance only. Report the test-set number once, for the configuration you already chose — never pick a configuration by looking at test performance.
Datasets. Links are relative to ../../data/.... Used here: Spambase, polluted Spambase, the Digits dataset (images / HAAR features), the WAVE set (waveX, waveY) and CRESCENT set (crescentX, crescentY), and the 2-D TwoSpirals (used in Problems 2 and 5, binary, label ∈ {−1,+1}) / ThreeCircles (Problem 5 only — despite the shared 2-D-points file format, this is a balanced 3-class dataset, label ∈ {−1,0,+1}, chance ≈ 33%, not 50%) sets.
Starter code. For each problem where a library counterpart exists, the starter notebook gives you the full data/eval pipeline and asks you to fill in two things: a short library-call baseline (a quick sanity-check number, using a well-known library function) and the from-scratch algorithm steps, evaluated the same way — your from-scratch number should land on or near the library one. The one exception is Problem 1, which is the library problem — it has no from-scratch counterpart to compare against (that's Problem 2). Answers to the (THEORY) problems may be written directly in the notebook (e.g. a markdown cell) rather than a separate document, as long as they include any equation, plot, or illustration the answer depends on — not prose alone.
Use an SVM library of your choice (e.g. LIBSVM, scikit-learn). Try several kernels, including polynomial and RBF; report results.
Library calls: sklearn.svm.SVC, sklearn.multiclass.OneVsRestClassifier (this problem is library-only by design — there's no from-scratch counterpart required here; see PROBLEM 2 for the from-scratch SVM).
Implement your own SVM solver using the Simplified SMO algorithm: see the CS229 Simplified SMO notes — iterate over all αi, and whenever αi violates the KKT conditions pick a random αj among the rest and jointly optimize the pair. (The full Platt SMO algorithm — writeup here — adds an error cache and pair-selection heuristics for speed; that fuller version is optional below, not required.) Write your solver so it only ever looks at a precomputed kernel (Gram) matrix, never raw features directly — that way the same code works for any kernel.
Note: the "stop once a fixed number of sweeps pass with no change" stopping rule in the Simplified SMO notes is not guaranteed to trigger on noisy, non-separable data. Cap the total number of sweeps (e.g. 300) so your run time stays bounded regardless of whether that rule ever fires — without a cap this can run for a very long time.
[optional] Run the same solver on Spambase or ThreeCircles; implement the full Platt SMO heuristics (error cache, entire-set/non-bound alternation, second-choice pair selection) instead of the simplified version; run it on Digits via a multiclass wrapper.
Library calls: sklearn.svm.SVC (linear and RBF kernels), matching Problem 1's library baseline.
Implement a kernel ridge regression wrapper with fit(X, y) and predict(X); the initializer selects the kernel (linear, polynomial, RBF) and its hyperparameters (regularization λ solved as α = (K + λI)-1y). The kernel evaluation may use a library, but the rest must be from scratch. Check your implementation against a library baseline (e.g. sklearn.kernel_ridge.KernelRidge) at the same kernel/hyperparameters.
Library calls: sklearn.kernel_ridge.KernelRidge.
Using the polluted Spambase dataset (original points, many extra junk / duplicated features):
Library calls: sklearn.decomposition.PCA, sklearn.linear_model.LogisticRegression.
Datasets: 1000 2-D points each — TwoSpirals (binary, chance ≈ 50%) and ThreeCircles (a balanced 3-class dataset despite the shared file format, chance ≈ 33%). Report chance level alongside accuracy so the two datasets' numbers aren't compared as if both were binary.
Library calls: sklearn.decomposition.KernelPCA, sklearn.linear_model.LogisticRegression.
Fit your PROBLEM 3 kernel ridge regression on WAVE or CRESCENT with an RBF kernel at a very small bandwidth vs. a much larger bandwidth. With a very small bandwidth, the fitted curve passes almost exactly through every training point, with wild oscillations between them; with a larger bandwidth, it looks like a smooth curve that doesn't hit every point exactly, but tracks the overall trend.
In a short written answer, explain this pattern, and propose how to choose the bandwidth properly (i.e., not by eye and not by minimizing training error).
Your PROBLEM 1 one-vs-rest multiclass SVM wrapper trains one binary SVM per class and predicts using whichever classifier gives the most confident "positive" score. For most test points this works fine, but for points near the boundary between three or more classes, it is possible for all the binary classifiers to output a negative ("not this class") decision, leaving no clear winner — or, conversely, for multiple classifiers to claim the point positively.
In a short written answer, explain why one-vs-rest can produce this kind of ambiguous region, and propose whether switching to a one-vs-one (all-pairs) voting scheme would fix it.
Instead of a library SVM, run your own Problem 2 SMO solver on the Digits dataset. Digits has 10 classes and your SMO is a binary classifier, so you need a multiclass wrapper on top of it — choose one of:
Digits is learnable enough that you can subsample the training set (e.g. 10–20% per class) to keep runtime down — but evaluate on the full test set.
Problem 2 uses the CS229 Simplified SMO algorithm (random second-variable selection, no error cache). Extra credit for implementing the full Platt SMO heuristics instead, following the Platt SMO paper:
Reference implementations already exist in this course's materials (6_SVM_kernels/code_HW6/bingyu/SVM/SVM.py, SMO.java) if you want to check your work against them — but implement your own rather than copying them.
Same problem as Problem 2, but instead of SMO, solve the SVM dual directly with a general-purpose quadratic-programming solver (e.g. cvxopt.solvers.qp in Python, or an equivalent in Matlab/Java/C). Compare the resulting α's and accuracy against your SMO solution.
Consider the following 6 points in 2-D, for two classes:
class 0: (1,1) (2,2) (2,0)
class 1: (0,0) (1,0) (0,1)
a) Plot these 6 points, construct the optimal hyperplane by inspection and intuition (give
W, b) and calculate the margin.
b) Which points are support vectors?
c) [Extra credit] Construct the hyperplane by solving the dual optimization problem using
the Lagrangian. Compare with part (a).
Explain why 0 ≤ α ≤ C/m is a constraint in the dual optimization with slack variables (hint: read the Burges SVM tutorial first). Distinguish three cases, and explain each in terms of the classification and the constraints: a) α = 0; b) 0 < α < C/m; c) α = C/m. This has been discussed in class and in the SVM notes; a detailed, rigorous explanation is expected, not just a restatement of the three cases.
What is the VC dimension of an SVM with a linear kernel?
Problem 4 rescues polluted Spambase with PCA. Run LDA instead of PCA before the downstream logistic regression classifier — you can use a library LDA implementation (e.g. sklearn.discriminant_analysis.LinearDiscriminantAnalysis). Compare accuracy against Problem 4's PCA result.
Pick a problem from DHS (Duda, Hart & Stork, Pattern Classification) chapter 5 (linear discriminant functions / SVMs) that isn't already covered above, and solve it. If you're not sure which one to pick, ask.
t-SNE isn't a kernel method, but it rhymes with this HW's PCA/KPCA problems: another way to turn high-dimensional data into something a 2-D plot (or a simple downstream classifier) can actually work with — and unlike PCA, it's built specifically to preserve local neighborhood structure, at the cost of not being a linear projection at all.
Part A (library). Run a library t-SNE (e.g. sklearn.manifold.TSNE) on MNIST and/or 20 Newsgroups, project to 2 or 3 dimensions, and scatter-plot the points colored by label. Try a few perplexity values (e.g. 5, 20, 100) and see how the picture changes. Here's what a good result looks like — each color is a different digit/newsgroup, and they should separate into fairly clean clusters:

Part B (from scratch, harder). Implement t-SNE yourself. We're deliberately not giving you code here — go read Laurens van der Maaten's own t-SNE page (the original author; it has the paper, reference implementations in several languages, and FAQ) and work from that. At a high level, the algorithm is:
Run your implementation on MNIST (or a manageable subsample of it) and compare your scatter plot against Part A's library result.
Library calls: sklearn.manifold.TSNE (Part A only — Part B is the from-scratch counterpart).