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

feat: add fnn functionality #529

Merged
merged 78 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
9834636
Add Functionality
sibre28 Jan 10, 2024
a1dc77e
Added Test Files and docstrings for layer and model
sibre28 Jan 18, 2024
3b9f634
Merge branch 'main' into 522-add-fnn-functionality
sibre28 Jan 18, 2024
3386e0d
linter fixes
sibre28 Jan 18, 2024
0ccd6fb
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Jan 18, 2024
f5ae6cc
linter fixes
sibre28 Jan 18, 2024
1c0c3b6
linter fixes
sibre28 Jan 18, 2024
371d1e2
style: apply automated linter fixes
megalinter-bot Jan 18, 2024
752ecbe
add into_dataloader test
sibre28 Jan 22, 2024
a41789d
Add Classification and Regression Model
sibre28 Jan 22, 2024
31d1bae
Change ValueError to OutOfBoundsError and add tests
sibre28 Jan 24, 2024
e88329e
style: apply automated linter fixes
megalinter-bot Jan 24, 2024
b1f3979
style: apply automated linter fixes
megalinter-bot Jan 24, 2024
b74165b
Change ValueError to OutOfBoundsError and add tests in layer as well
sibre28 Jan 24, 2024
5dd2568
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Jan 24, 2024
aa872e4
style: apply automated linter fixes
megalinter-bot Jan 24, 2024
c86d9e3
minor changes
sibre28 Jan 24, 2024
32077c9
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Jan 24, 2024
381c6de
style: apply automated linter fixes
megalinter-bot Jan 24, 2024
4b8b15a
minor changes
sibre28 Jan 25, 2024
aaaafcb
Change Name of PytorchLayer to InternalLayer
sibre28 Jan 30, 2024
15eb8a0
minor changes
sibre28 Jan 30, 2024
5b38df7
reworked predictions method and some other stuff
sibre28 Jan 31, 2024
e568652
changed some more stuff
sibre28 Jan 31, 2024
259fce3
linter fixes
sibre28 Jan 31, 2024
6e387aa
linter fixes
sibre28 Jan 31, 2024
6074594
linter fixes
sibre28 Jan 31, 2024
6306aea
Merge branch 'main' into 522-add-fnn-functionality
sibre28 Feb 4, 2024
e4f783e
add is_fitted() Method
sibre28 Feb 6, 2024
a336485
minor changes
sibre28 Feb 6, 2024
9aee9fe
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Feb 6, 2024
94076d4
style: apply automated linter fixes
megalinter-bot Feb 6, 2024
c4e6bd1
improve codecov and fix a lot of bugs
sibre28 Feb 8, 2024
5ef1425
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Feb 8, 2024
7404d21
minor fixes
sibre28 Feb 8, 2024
87f0fbb
linter fixes
sibre28 Feb 8, 2024
baea7f7
Merge branch 'main' into 522-add-fnn-functionality
sibre28 Feb 8, 2024
7f8f39a
style: apply automated linter fixes
megalinter-bot Feb 8, 2024
c485c68
Remove input_size from layer, (add Callbacks), minor changes
sibre28 Mar 2, 2024
0c4d0ca
linter fixes
sibre28 Mar 2, 2024
eabb9f1
style: apply automated linter fixes
megalinter-bot Mar 2, 2024
98cbf53
test fixes
sibre28 Mar 2, 2024
ec13884
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 2, 2024
536cd0f
codecov
sibre28 Mar 4, 2024
7a0437f
Update src/safeds/data/tabular/containers/_table.py
sibre28 Mar 6, 2024
5bf384d
Apply suggestions from code review
sibre28 Mar 6, 2024
2888028
add running_loss and minor stuff
sibre28 Mar 6, 2024
0bbfe4a
fix
sibre28 Mar 6, 2024
9777889
style: apply automated linter fixes
megalinter-bot Mar 6, 2024
8b31cae
rework stuff and add callbacks with tests
sibre28 Mar 9, 2024
9b4e652
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 9, 2024
e62ac7e
linter
sibre28 Mar 9, 2024
82db404
style: apply automated linter fixes
megalinter-bot Mar 9, 2024
644f790
style: apply automated linter fixes
megalinter-bot Mar 9, 2024
6f4684a
stuff
sibre28 Mar 9, 2024
bc3733c
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 9, 2024
e524e26
Merge branch 'main' into 522-add-fnn-functionality
sibre28 Mar 9, 2024
f711f02
tests
sibre28 Mar 10, 2024
c1d87f0
rename
sibre28 Mar 10, 2024
645c6bf
little fix so models with batch size > 1 work correctly
sibre28 Mar 18, 2024
bc2cc91
style: apply automated linter fixes
megalinter-bot Mar 18, 2024
7063549
style: apply automated linter fixes
megalinter-bot Mar 18, 2024
96fee8f
fix classification models not working properly for multiclass use-cases
sibre28 Mar 18, 2024
5b165a5
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 18, 2024
e2030e2
add testcase for multiclass classification
sibre28 Mar 18, 2024
5e1a800
add testcase for multiclass classification
sibre28 Mar 18, 2024
8aea4b1
small changes
sibre28 Mar 19, 2024
3b47196
Merge branch 'main' into 522-add-fnn-functionality
sibre28 Mar 19, 2024
f7c7af6
style: apply automated linter fixes
megalinter-bot Mar 19, 2024
4f5cf83
small changes
sibre28 Mar 19, 2024
f3c4a59
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 19, 2024
c66a8fd
style: apply automated linter fixes
megalinter-bot Mar 19, 2024
781b191
small changes for codecov
sibre28 Mar 19, 2024
647224e
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 19, 2024
a60d26d
style: apply automated linter fixes
megalinter-bot Mar 19, 2024
8f39fc6
remove lines that cannot be easily covered from codecov inspection
sibre28 Mar 19, 2024
ad4cfd4
Merge remote-tracking branch 'origin/522-add-fnn-functionality' into …
sibre28 Mar 19, 2024
b07bd48
style: apply automated linter fixes
megalinter-bot Mar 19, 2024
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
40 changes: 40 additions & 0 deletions src/safeds/data/tabular/containers/_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
import openpyxl
import pandas as pd
import seaborn as sns
import torch
import xxhash
from pandas import DataFrame
from scipy import stats
from torch.utils.data import DataLoader, Dataset

from safeds.data.image.containers import Image
from safeds.data.tabular.typing import ColumnType, Schema
Expand Down Expand Up @@ -2392,3 +2394,41 @@ def __dataframe__(self, nan_as_null: bool = False, allow_copy: bool = True): #
data_copy = self._data.reset_index(drop=True)
data_copy.columns = self.column_names
return data_copy.__dataframe__(nan_as_null, allow_copy)

def _into_dataloader(self, batch_size: int) -> DataLoader:
"""
Return a Dataloader for the data stored in this table, used for training neural networks.

The original table is not modified.

Parameters
----------
batch_size
The size of data batches that should be loaded at one time.

Returns
-------
result :
The DataLoader.

"""
features = self.to_rows()
all_rows = []
for row in features:
new_item = []
for column_name in row:
new_item.append(row.get_value(column_name))
all_rows.append(new_item.copy())
return DataLoader(dataset=_CustomDataset(np.array(all_rows)), batch_size=batch_size)


class _CustomDataset(Dataset):
def __init__(self, features: np.array):
self.X = torch.from_numpy(features.astype(np.float32))
self.len = self.X.shape[0]

def __getitem__(self, item: int) -> torch.Tensor:
return self.X[item]

def __len__(self) -> int:
return self.len
46 changes: 45 additions & 1 deletion src/safeds/data/tabular/containers/_tagged_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import sys
from typing import TYPE_CHECKING

import numpy as np
import torch
import xxhash
from torch.utils.data import DataLoader, Dataset

from safeds.data.tabular.containers import Column, Row, Table
from safeds.exceptions import (
Expand Down Expand Up @@ -190,7 +193,9 @@ def __hash__(self) -> int:
hash : int
The hash value.
"""
return xxhash.xxh3_64(hash(self.target).to_bytes(8) + hash(self.features).to_bytes(8) + Table.__hash__(self).to_bytes(8)).intdigest()
return xxhash.xxh3_64(
hash(self.target).to_bytes(8) + hash(self.features).to_bytes(8) + Table.__hash__(self).to_bytes(8),
).intdigest()

def __sizeof__(self) -> int:
"""
Expand Down Expand Up @@ -871,3 +876,42 @@ def transform_column(self, name: str, transformer: Callable[[Row], Any]) -> Tagg
target_name=self.target.name,
feature_names=self.features.column_names,
)

def _into_dataloader(self, batch_size: int) -> DataLoader:
"""
Return a Dataloader for the data stored in this table, used for training neural networks.

The original table is not modified.

Parameters
----------
batch_size
The size of data batches that should be loaded at one time.

Returns
-------
result :
The DataLoader.

"""
feature_rows = self.features.to_rows()
all_rows = []
for row in feature_rows:
new_item = []
for column_name in row:
new_item.append(row.get_value(column_name))
all_rows.append(new_item.copy())
return DataLoader(dataset=_CustomDataset(np.array(all_rows), np.array(self.target)), batch_size=batch_size)


class _CustomDataset(Dataset):
def __init__(self, features: np.array, target: np.array):
self.X = torch.from_numpy(features.astype(np.float32))
self.Y = torch.from_numpy(target.astype(np.float32))
self.len = self.X.shape[0]

def __getitem__(self, item: int) -> tuple[torch.Tensor, torch.Tensor]:
return self.X[item], self.Y[item].unsqueeze(-1)

def __len__(self) -> int:
return self.len
10 changes: 10 additions & 0 deletions src/safeds/ml/nn/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Classes for classification tasks."""

from ._fnn_layer import FNNLayer
from ._model import ClassificationNeuralNetwork, RegressionNeuralNetwork

__all__ = [
"FNNLayer",
"ClassificationNeuralNetwork",
"RegressionNeuralNetwork",
]
67 changes: 67 additions & 0 deletions src/safeds/ml/nn/_fnn_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from torch import nn

from safeds.exceptions import ClosedBound, OutOfBoundsError


class _InternalLayer(nn.Module):
def __init__(self, input_size: int, output_size: int, activation_function: str):
super().__init__()
self._layer = nn.Linear(input_size, output_size)
match activation_function:
case "sigmoid":
self._fn = nn.Sigmoid()
case "relu":
self._fn = nn.ReLU()
case "softmax":
self._fn = nn.Softmax()
case _:
raise ValueError("Unknown Activation Function: " + activation_function)

def forward(self, x: float) -> float:
return self._fn(self._layer(x))


class FNNLayer:
def __init__(self, output_size: int, input_size: int | None = None):
"""
Create a FNN Layer.

Parameters
----------
input_size
The number of neurons in the previous layer
output_size
The number of neurons in this layer

Raises
------
ValueError
If input_size < 1
If output_size < 1

"""
if input_size is not None:
self._set_input_size(input_size=input_size)
if output_size < 1:
raise OutOfBoundsError(actual=output_size, name="output_size", lower_bound=ClosedBound(1))
self._output_size = output_size

def _get_internal_layer(self, activation_function: str) -> _InternalLayer:
return _InternalLayer(self._input_size, self._output_size, activation_function)

@property
def output_size(self) -> int:
"""
Get the output_size of this layer.

Returns
-------
result :
The Number of Neurons in this layer.
"""
return self._output_size

def _set_input_size(self, input_size: int) -> None:
if input_size < 1:
raise OutOfBoundsError(actual=input_size, name="input_size", lower_bound=ClosedBound(1))
self._input_size = input_size
Loading