class, __init__ and self — why Keras and PyTorch code looks like that
Do this before Course 2's Keras labs. Goal: class, __init__ and self stop being noise, because Keras and (especially) PyTorch code is built out of them.
You've already been using objects for a whole course without the word:
model = LogisticRegression() # make an object from the blueprint
model.fit(X, y) # objects carry methods…
model.coef_ # …and data of their own
LogisticRegression is a class — a blueprint. model is an object (an instance) built from it. The object owns data (its coefficients) and methods that use that data (fit, predict). That's the entire concept: a bundle of data plus the functions that belong to it.
Broadcast version: the class is the camera model spec sheet; each camera body on the shelf is an instance. Same buttons (methods), each body has its own settings and hours (data).
class Clip:
def __init__(self, name, fps):
self.name = name
self.fps = fps
self.markers = []
def add_marker(self, seconds):
self.markers.append(seconds)
def describe(self):
return f"{self.name} @ {self.fps}fps, {len(self.markers)} markers"
Decode:
class Clip: — new blueprint named Clip.__init__ — the setup routine. Runs automatically when you build one: Clip("A014", 29.97). The weird underscores mark it as a special method Python calls for you.self is "this particular object". Every method's first parameter. self.name = name means "store name on THIS clip". You never pass self yourself — Python fills it in: c.add_marker(4.2) secretly runs add_marker(c, 4.2).self.markers = [] — each clip gets its OWN empty list. Two clips, two separate marker lists.c = Clip("A014C022", 29.97) # __init__ runs here
c.add_marker(4.2)
c.add_marker(11.0)
print(c.describe()) # A014C022 @ 29.97fps, 2 markers
Run this in the Code Lab. Then make a second clip and confirm its marker list is independent — that's self doing its job.
c.add_marker(4.2), what is self inside the method?__init__ never need to be called by you?One more idea and Keras/PyTorch code opens up:
class TimecodedClip(Clip): # ← "based on Clip"
def __init__(self, name, fps, start_tc):
super().__init__(name, fps) # run the parent's setup first
self.start_tc = start_tc
class TimecodedClip(Clip) — everything a Clip has, plus extras. super().__init__(...) says "parent, do your setup" before adding your own. Forget that call and the parent's setup never runs — half your object is missing.
Now read actual course code from Course 4/5:
class Net(nn.Module): # my network is BASED ON nn.Module
def __init__(self, D_in, H, D_out):
super().__init__() # let PyTorch do its setup — MANDATORY
self.linear1 = nn.Linear(D_in, H) # store layers on THIS network
self.linear2 = nn.Linear(H, D_out)
def forward(self, x): # what happens when data flows through
x = torch.sigmoid(self.linear1(x))
return self.linear2(x)
Every line is a pattern you now own: a blueprint based on PyTorch's base class; setup that first defers to the parent, then stores two layer-objects on self; a method that uses them. The certificate's notes said "custom model: subclass nn.Module" — this is all that ever meant.
Keras' Sequential style hides the class, but the moment you meet callbacks, custom layers, or PyTorch, this is the shape.
super().__init__() is missing in a PyTorch model? (The notes' Course 4 pages rely on this.)self.linear1 = nn.Linear(D_in, H) — is nn.Linear a class or a function? How is self.linear1 like self.markers from the Clip example?model = Sequential()
model.add(Dense(50, activation='relu', input_shape=(8,)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
history = model.fit(X, y, epochs=100)
Sequential() — build an object from a blueprint. Dense(50, ...) — build a layer object; model.add(...) stores it inside the model. Objects containing objects.model.compile(...), model.fit(...) — methods, configured with keyword arguments.history = model.fit(...) — fit returns an object too (the training history). history.history['loss'] — that's a dict living on an object. You can decode that chain now: object → attribute (a dict) → key.Nothing in these five lines is syntax you haven't now met.
__init__ = setup, runs at creation; ClassName(...) builds and returns an instanceself = this object — auto-filled first parameter; self.x = ... stores data on the instanceclass Child(Parent) = everything the parent has, plus; super().__init__() runs the parent's setup and is mandatory in PyTorch models.fit() even returns oneself refers to right there