Last active
May 22, 2024 14:33
-
-
Save lebrice/d83e55d5397de98071fa443dd1d21164 to your computer and use it in GitHub Desktop.
Interview Question
This file contains 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
from __future__ import annotations | |
class Value: | |
""" stores a single scalar value and its gradient """ | |
def __init__(self, data, _parents: tuple[Value, ...]=(), _op=''): | |
self.data = data | |
self.grad = 0 | |
# internal variables used for autograd graph construction | |
self._backward = lambda: None | |
self._prev = set(_parents) | |
self._op = _op # the op that produced this node, for graphviz / debugging / etc | |
def __add__(self, other): | |
""" Example. Can be left in to help the interviewee get the idea. """ | |
other = other if isinstance(other, Value) else Value(other) | |
out = Value(self.data + other.data, (self, other), '+') | |
def _backward(): | |
self.grad += out.grad | |
other.grad += out.grad | |
out._backward = _backward | |
return out | |
def __mul__(self, other): | |
raise NotImplementedError("TODO") | |
def __pow__(self, other): | |
raise NotImplementedError("TODO") | |
def relu(self): | |
raise NotImplementedError("TODO") | |
def backward(self): | |
# topological order all of the children in the graph | |
topo = [] | |
visited = set() | |
def build_topo(v): | |
raise NotImplementedError("TODO") | |
build_topo(self) | |
# go one variable at a time and apply the chain rule to get its gradient | |
raise NotImplementedError("TODO") | |
def __neg__(self): # -self | |
return self * -1 | |
def __radd__(self, other): # other + self | |
return self + other | |
def __sub__(self, other): # self - other | |
return self + (-other) | |
def __rsub__(self, other): # other - self | |
return other + (-self) | |
def __rmul__(self, other): # other * self | |
return self * other | |
def __truediv__(self, other): # self / other | |
return self * other**-1 | |
def __rtruediv__(self, other): # other / self | |
return other * self**-1 | |
def __repr__(self): | |
return f"Value(data={self.data}, grad={self.grad})" | |
import random | |
class Module: | |
def zero_grad(self): | |
for p in self.parameters(): | |
p.grad = 0 | |
def parameters(self): | |
return [] | |
class Neuron(Module): | |
def __init__(self, nin, nonlin=True): | |
self.w = [Value(random.uniform(-1,1)) for _ in range(nin)] | |
self.b = Value(0) | |
self.nonlin = nonlin | |
def __call__(self, x): | |
raise NotImplementedError("TODO") | |
def parameters(self): | |
return self.w + [self.b] | |
def __repr__(self): | |
return f"{'ReLU' if self.nonlin else 'Linear'}Neuron({len(self.w)})" | |
class Layer(Module): | |
def __init__(self, nin: int, nout: int, **kwargs): | |
self.neurons = [Neuron(nin, **kwargs) for _ in range(nout)] | |
def __call__(self, x): | |
raise NotImplementedError("TODO") | |
def parameters(self): | |
return [p for n in self.neurons for p in n.parameters()] | |
def __repr__(self): | |
return f"Layer of [{', '.join(str(n) for n in self.neurons)}]" | |
class MLP(Module): | |
def __init__(self, nin: int, nouts: list[int]): | |
sz = [nin] + nouts | |
self.layers = [Layer(sz[i], sz[i+1], nonlin=i!=len(nouts)-1) for i in range(len(nouts))] | |
def __call__(self, x): | |
for layer in self.layers: | |
x = layer(x) | |
return x | |
def parameters(self): | |
return [p for layer in self.layers for p in layer.parameters()] | |
def __repr__(self): | |
return f"MLP of [{', '.join(str(layer) for layer in self.layers)}]" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment