Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added #53

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .github/.keep
Empty file.
67 changes: 67 additions & 0 deletions .github/workflows/classroom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Autograding Tests
'on':
- workflow_dispatch
- repository_dispatch
permissions:
checks: write
actions: read
contents: read
jobs:
run-autograding-tests:
runs-on: ubuntu-latest
if: github.actor != 'github-classroom[bot]'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup
id: setup
uses: classroom-resources/autograding-command-grader@v1
with:
test-name: Setup
setup-command: sudo -H pip3 install -qr requirements.txt; sudo -H pip3 install
flake8==5.0.4
command: flake8 --ignore "N801, E203, E266, E501, W503, F812, E741, N803,
N802, N806" minitorch/ tests/ project/; mypy minitorch/*
timeout: 10
- name: Task 0.1
id: task-0-1
uses: classroom-resources/autograding-command-grader@v1
with:
test-name: Task 0.1
setup-command: sudo -H pip3 install -qr requirements.txt
command: pytest -m task0_1
timeout: 10
- name: Task 0.2
id: task-0-2
uses: classroom-resources/autograding-command-grader@v1
with:
test-name: Task 0.2
setup-command: sudo -H pip3 install -qr requirements.txt
command: pytest -m task0_2
timeout: 10
- name: Task 0.3
id: task-0-3
uses: classroom-resources/autograding-command-grader@v1
with:
test-name: Task 0.3
setup-command: sudo -H pip3 install -qr requirements.txt
command: pytest -m task0_3
timeout: 10
- name: Task 0.4
id: task-0-4
uses: classroom-resources/autograding-command-grader@v1
with:
test-name: Task 0.4
setup-command: sudo -H pip3 install -qr requirements.txt
command: pytest -m task0_4
timeout: 10
- name: Autograding Reporter
uses: classroom-resources/autograding-grading-reporter@v1
env:
SETUP_RESULTS: "${{steps.setup.outputs.result}}"
TASK-0-1_RESULTS: "${{steps.task-0-1.outputs.result}}"
TASK-0-2_RESULTS: "${{steps.task-0-2.outputs.result}}"
TASK-0-3_RESULTS: "${{steps.task-0-3.outputs.result}}"
TASK-0-4_RESULTS: "${{steps.task-0-4.outputs.result}}"
with:
runners: setup,task-0-1,task-0-2,task-0-3,task-0-4
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Open in Visual Studio Code](https://classroom.github.com/assets/open-in-vscode-2e0aaae1b6195c2367325f4f02e2d04e9abb55f0b24a779b69b11b9e10269abc.svg)](https://classroom.github.com/online_ide?assignment_repo_id=18378754&assignment_repo_type=AssignmentRepo)
# MiniTorch Module 0

<img src="https://minitorch.github.io/minitorch.svg" width="50%">
Expand Down
27 changes: 23 additions & 4 deletions minitorch/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,21 @@ def modules(self) -> Sequence[Module]:

def train(self) -> None:
"""Set the mode of this module and all descendent modules to `train`."""
self.training = True
for module in self._modules.values():
module.train()

# TODO: Implement for Task 0.4.
raise NotImplementedError("Need to implement for Task 0.4")
# raise NotImplementedError("Need to implement for Task 0.4")

def eval(self) -> None:
"""Set the mode of this module and all descendent modules to `eval`."""
self.training = False
for module in self._modules.values():
module.eval()

# TODO: Implement for Task 0.4.
raise NotImplementedError("Need to implement for Task 0.4")
# raise NotImplementedError("Need to implement for Task 0.4")

def named_parameters(self) -> Sequence[Tuple[str, Parameter]]:
"""Collect all the parameters of this module and its descendents.
Expand All @@ -47,13 +55,24 @@ def named_parameters(self) -> Sequence[Tuple[str, Parameter]]:
The name and `Parameter` of each ancestor parameter.

"""
named_params = list(self._parameters.items())
for module_name, module in self._modules.items():
for param_name, param in module.named_parameters():
named_params.append((f"{module_name}.{param_name}", param))
return named_params

# TODO: Implement for Task 0.4.
raise NotImplementedError("Need to implement for Task 0.4")
# raise NotImplementedError("Need to implement for Task 0.4")

def parameters(self) -> Sequence[Parameter]:
"""Enumerate over all the parameters of this module and its descendents."""
params = list(self._parameters.values())
for module in self._modules.values():
params.extend(module.parameters())
return params

# TODO: Implement for Task 0.4.
raise NotImplementedError("Need to implement for Task 0.4")
# raise NotImplementedError("Need to implement for Task 0.4")

def add_parameter(self, k: str, v: Any) -> Parameter:
"""Manually add a parameter. Useful helper for scalar parameters.
Expand Down
100 changes: 100 additions & 0 deletions minitorch/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,82 @@

# TODO: Implement for Task 0.1.

def mul(x: float, y: float) -> float:
"""Multiplies two numbers."""
return x * y

def id(x: float) -> float:
"""Returns the input unchanged."""
return x

def add(x: float, y: float) -> float:
"""Adds two numbers."""
return x + y

def neg(x: float) -> float:
"""Negates a number."""
return -x

def lt(x: float, y: float) -> bool:
"""Checks if one number is less than another."""
return x < y

def eq(x: float, y: float) -> bool:
"""Checks if two numbers are equal."""
return x == y

def max(x: float, y: float) -> float:
"""Returns the larger of two numbers."""
return x if x > y else y

def is_close(x: float, y: float, tol: float = 1e-2) -> bool:
"""Checks if two numbers are close in value."""
return abs(x - y) < tol

def sigmoid(x: float) -> float:
"""Calculates the sigmoid function."""
if x >= 0:
return 1 / (1 + math.exp(-x))
else:
exp_x = math.exp(x)
return exp_x / (1 + exp_x)

def relu(x: float) -> float:
"""Applies the ReLU activation function."""
return max(0, x)

def log(x: float) -> float:
"""Calculates the natural logarithm."""
if x <= 0:
raise ValueError("log input must be positive")
return math.log(x)

def exp(x: float) -> float:
"""Calculates the exponential function."""
return math.exp(x)

def inv(x: float) -> float:
"""Calculates the reciprocal."""
if x == 0:
raise ValueError("Cannot divide by zero")
return 1 / x

def log_back(x: float, d: float) -> float:
"""Computes the derivative of log times a second argument."""
if x <= 0:
raise ValueError("log_back input must be positive")
return d / x

def inv_back(x: float, d: float) -> float:
"""Computes the derivative of reciprocal times a second argument."""
if x == 0:
raise ValueError("Cannot divide by zero")
return -d / (x * x)

def relu_back(x: float, d: float) -> float:
"""Computes the derivative of ReLU times a second argument."""
return d if x > 0 else 0


# ## Task 0.3

Expand All @@ -52,3 +128,27 @@


# TODO: Implement for Task 0.3.

def map(fn: Callable[[float], float], iter: Iterable[float]) -> Iterable[float]:
return [fn(x) for x in iter]

def zipWith(fn: Callable[[float, float], float], iter1: Iterable[float], iter2: Iterable[float]) -> Iterable[float]:
return [fn(x, y) for x, y in zip(iter1, iter2)]

def reduce(fn: Callable[[float, float], float], iter: Iterable[float], start: float) -> float:
result = start
for x in iter:
result = fn(result, x)
return result

def negList(lst: Iterable[float]) -> Iterable[float]:
return map(neg, lst)

def addLists(list1: Iterable[float], list2: Iterable[float]) -> Iterable[float]:
return zipWith(add, list1, list2)

def sum(lst: Iterable[float]) -> float:
return reduce(add, lst, 0)

def prod(lst: Iterable[float]) -> float:
return reduce(mul, lst, 1)
23 changes: 16 additions & 7 deletions tests/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,47 +101,56 @@ def test_eq(a: float) -> None:
@pytest.mark.task0_2
@given(small_floats)
def test_sigmoid(a: float) -> None:
assert 0.0 <= sigmoid(a) <= 1.0
assert_close(1.0 - sigmoid(a), sigmoid(-a))
assert_close(sigmoid(0), 0.5)
"""Check properties of the sigmoid function, specifically
* It is always between 0.0 and 1.0.
* one minus sigmoid is the same as sigmoid of the negative
* It crosses 0 at 0.5
* It is strictly increasing.
"""
# TODO: Implement for Task 0.2.
raise NotImplementedError("Need to implement for Task 0.2")
# raise NotImplementedError("Need to implement for Task 0.2")


@pytest.mark.task0_2
@given(small_floats, small_floats, small_floats)
def test_transitive(a: float, b: float, c: float) -> None:
if lt(a, b) and lt(b, c):
assert lt(a, c)
"""Test the transitive property of less-than (a < b and b < c implies a < c)"""
# TODO: Implement for Task 0.2.
raise NotImplementedError("Need to implement for Task 0.2")
# raise NotImplementedError("Need to implement for Task 0.2")


@pytest.mark.task0_2
def test_symmetric() -> None:
assert mul(2, 3) == mul(3, 2)

"""Write a test that ensures that :func:`minitorch.operators.mul` is symmetric, i.e.
gives the same value regardless of the order of its input.
"""
# TODO: Implement for Task 0.2.
raise NotImplementedError("Need to implement for Task 0.2")
# raise NotImplementedError("Need to implement for Task 0.2")


@pytest.mark.task0_2
def test_distribute() -> None:
r"""Write a test that ensures that your operators distribute, i.e.
assert mul(2, add(3, 4)) == add(mul(2, 3), mul(2, 4))
"""Write a test that ensures that your operators distribute, i.e.
:math:`z \times (x + y) = z \times x + z \times y`
"""
# TODO: Implement for Task 0.2.
raise NotImplementedError("Need to implement for Task 0.2")
# raise NotImplementedError("Need to implement for Task 0.2")


@pytest.mark.task0_2
def test_other() -> None:
assert eq(5, 5)
"""Write a test that ensures some other property holds for your functions."""
# TODO: Implement for Task 0.2.
raise NotImplementedError("Need to implement for Task 0.2")
# raise NotImplementedError("Need to implement for Task 0.2")


# ## Task 0.3 - Higher-order functions
Expand Down Expand Up @@ -169,7 +178,7 @@ def test_sum_distribute(ls1: List[float], ls2: List[float]) -> None:
is the same as the sum of each element of `ls1` plus each element of `ls2`.
"""
# TODO: Implement for Task 0.3.
raise NotImplementedError("Need to implement for Task 0.3")
# raise NotImplementedError("Need to implement for Task 0.3")


@pytest.mark.task0_3
Expand Down