fix hw3#9
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates Homework 3’s marimo/PyTorch training notebook content to better match the original course notebook (Fixes #7), mainly by expanding and revising the instructional markdown and refreshing the saved marimo session metadata.
Changes:
- Expanded/rewrote HW3 narrative instructions for linear models, SGD, DataLoader iteration, and NN extensions.
- Added a
requires-pythonheader constraint to the HW3 script. - Updated the marimo session JSON (including a
marimo_versionbump and clearing prior stored outputs).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
homework/hw3/hw3.py |
Updates the HW3 written instructions and adds a Python version requirement line. |
homework/hw3/__marimo__/session/hw3.py.json |
Refreshes marimo session metadata, including a marimo version bump and output clearing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+65
to
+67
| In this homework, we'll start to build and train machine learning models (both a linear model a neural network) using PyTorch. While a lot of the code you will develop here corresponds to existing implementations in the PyTorch `nn` module, you will implement almost everything from scratch in these assignments, rather than use pre-built layers. Specifically you will use only the `Module`, and `Parameter` classes from PyTorch (later assignments will also use `ModuleList` and `Buffer`), and everything else should be implemented just with the calls included in the base `torch` library. | ||
|
|
||
| 1. A `Linear` layer as a `Module` subclass | ||
| 2. A `CrossEntropyLoss` module | ||
| 3. A `SGD` optimizer | ||
| 4. A `DataLoader` class | ||
| 5. An `epoch` function that runs one pass over the data | ||
| ***Important:*** **To be very explicit, you solutions in this, and all later problem sets, should _not_ use any classes or functions from within the `torch.nn` module, nor function calls from the `torch.nn.functional` module. You should only use calls available in the base `torch.` module.** |
Comment on lines
+98
to
+99
| - All PyTorch layers are implemented as a subclasses of the `Module` class. This class implements a few things: 1) it lets you instatiate layers as class instances, and apply these layers to inputs or intermediate units in the network; 2) it encapsulates the parameters of that layer (e.g., the weights that you will be training), and recursively tracks parameters of any module included in the class. | ||
| - The `Parameter` class is a simple wrapper you can provide apply to a tensor within that class, such that the layer will track these parameters (in any layer that includes it), and compute gradients of the parameters by default. |
| For the linear layer in particular: | ||
|
|
||
| The forward pass should compute the matrix multiplication $X W^T$ where $X$ is the input and $W$ is the weight matrix. Note that this should work for inputs of arbitrary batch dimensions (e.g., both 2D inputs of shape `(batch, in_dim)` and 3D inputs of shape `(batch1, batch2, in_dim)` should be supported). You can use the `@` operator for matrix multiplication, which handles broadcasting automatically. | ||
| - You should store the weights is a `.weight` Parameter in the class, which should be an `out_dim x in_dim` dimensional tensor. You should initialize with the $\sqrt{2/\text{in\_dim}}$ scaling of random Gaussian weights that we discussed in class. |
| - In `zero_grad()`, you should set each parameter's `.grad` to `None`. | ||
| ### Stochastic Gradient Descent | ||
|
|
||
| Next, you'll implement stochastic gradient descent as a class similar to the analogous class in the PyTorch. This is not at `Module` class, and in fact rather than subclass the analogous `Optimizer` class in PyTorch, we'll just define the class directly, and use a similar interface to what PyTorch uses in its optimizers. |
| Implement these operations in the class below. There are a few pitfalls to keep in mind: | ||
|
|
||
| - In your `__init__` function, you should explicitly call `list()` on the `parameters` input to store it in your class. This is because the `model.parameters()` function returns a Python generator, an object that can be iterated over _one_ time to return all its elements. So if you only store the passed `parameters` variable and then try to iterate over it during your `zero_grad` or `step` functions, you will only iterate over the parameters one time, and thereafter there won't be any elements to iterate over. | ||
| - You need to compute the updates to the parameters within a `torch.no_grad()` block, as shown below. The reason for this is that otherwise, the gradient update will happen _within a automatic differentiation loop itself_, i.e., you will be computing the gradient of the entire chain of parameter updates you perform with gradient descent. There are actually some very cool reasons why it's often useful to differentiate through an entire parameter update, but that is definitely not what we want here. |
Comment on lines
+300
to
+303
| ### to iterate over the dataset | ||
| for X,y in loader: | ||
| ### X,y contain each sequential sequential from X_full,y_full | ||
| ``` |
Comment on lines
+376
to
+379
| Finally, let's implement a routine that actually runs an epoch of optimization on a given dataset. It's convenient (though we'll change this a bit when we do LLM training, since that it typically run single-epoch) to implement an `epoch()` function that carries out a single pass over the data, because this can be used both perform one epoch of optimization on the training set _and_ to compute test loss/error on a held out test set (making sure we don't actually run the optimization then). | ||
|
|
||
| Implement the function below. This function takes three arguments a model, a loader, a loss, and an (optional) optimizer. An example usage would be: | ||
| ```python |
Comment on lines
+388
to
+391
| - Iterate over all minibatches in the data loader | ||
| - For each minibatch, compute the model's predicted outputs and the loss between the predicted and desired outputs. | ||
| - If `opt` is not none, update the model parameters using the optimization | ||
| - Over the entire data loader, capture a running total of the total loss and total error over all samples, then return the average loss and average error. |
Comment on lines
3
to
6
| "metadata": { | ||
| "marimo_version": "0.20.4", | ||
| "marimo_version": "0.23.14", | ||
| "script_metadata_hash": "845cb5ce3dcb38df36e3eb032b046444" | ||
| }, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR brings the content in hw3 in line with the original course notebook. Fixes #7