Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
019a6d8
perf: Add special case to `Table.add_rows` to increase performance
Marsmaennchen221 Apr 3, 2024
5471a03
style: apply automated linter fixes
megalinter-bot Apr 3, 2024
0802e0e
perf: change number_of_rows to number_of_columns in `add_rows` as 0 c…
Marsmaennchen221 Apr 3, 2024
a177d97
perf: special case if rows has columns but no rows
Marsmaennchen221 Apr 3, 2024
8450dc6
test: Added test for `Table.add_rows` for "same schema add no rows"
Marsmaennchen221 Apr 3, 2024
bae8e4d
perf: suggested performance upgrades for nn._fnn_layer and nn._model
Marsmaennchen221 Apr 4, 2024
4ae795e
make dataloader shuffle data each epoch
sibre28 Apr 9, 2024
350b771
add learning_rate parameter to fit() function
sibre28 Apr 9, 2024
905f103
raise an Error if test data doesnt match format of train data
sibre28 Apr 9, 2024
7593204
add abstract layer class
sibre28 Apr 9, 2024
f5f291e
make forward return tensor instead of float and change method to buil…
sibre28 Apr 9, 2024
7284c89
remove uncoverable lines from codecov
sibre28 Apr 9, 2024
0572cb4
small change
sibre28 Apr 9, 2024
0eefee7
small change
sibre28 Apr 9, 2024
f5bdf22
add abstract functions
sibre28 Apr 10, 2024
e3543fb
change for linter
sibre28 Apr 10, 2024
41bdd6a
change for linter
sibre28 Apr 10, 2024
1487ea2
change for linter
sibre28 Apr 10, 2024
8df1f26
change for linter
sibre28 Apr 10, 2024
37238db
Merge branch 'main' into 610-improve-fnn-layer-and-model-performance-…
sibre28 Apr 10, 2024
03907fd
style: apply automated linter fixes
megalinter-bot Apr 10, 2024
7f56aa2
style: apply automated linter fixes
megalinter-bot Apr 10, 2024
0923989
change for linter
sibre28 Apr 10, 2024
4c64e53
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 10, 2024
625c0b6
change for linter
sibre28 Apr 10, 2024
5feeff5
style: apply automated linter fixes
megalinter-bot Apr 10, 2024
3c98c23
accumulate epoch and batch counters and loss over all fit-calls
sibre28 Apr 10, 2024
6a05dd6
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 10, 2024
8191fc4
style: apply automated linter fixes
megalinter-bot Apr 10, 2024
908409a
add input_size property to Layer
sibre28 Apr 10, 2024
2e253af
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 10, 2024
846a36d
raise InputSizeError if input size and table size mismatch
sibre28 Apr 10, 2024
c4c0965
style: apply automated linter fixes
megalinter-bot Apr 10, 2024
fe842e8
perf: suggested performance upgrades for dataloader in TaggedTable an…
Marsmaennchen221 Apr 12, 2024
4892d5d
rename FNNLayer to Forward Layer and put it in separate File
sibre28 Apr 13, 2024
d42e44f
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 13, 2024
0ca1ec8
style: apply automated linter fixes
megalinter-bot Apr 13, 2024
d39ada7
remove unnecessary test file
sibre28 Apr 14, 2024
f567310
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 14, 2024
a41c330
Merge remote-tracking branch 'origin/suggested_perf_upgrades_model_an…
sibre28 Apr 14, 2024
8b30b1a
Merge remote-tracking branch 'origin/suggested_perf_upgrades_tagged_t…
sibre28 Apr 14, 2024
bf74b67
merge suggested changes
sibre28 Apr 15, 2024
1d0bfa1
style: apply automated linter fixes
megalinter-bot Apr 15, 2024
f61c687
style: apply automated linter fixes
megalinter-bot Apr 15, 2024
9a6d706
update test to cover into_dataloader_with_classes
sibre28 Apr 15, 2024
3db67cd
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 15, 2024
4100e6d
remove inplace modifications of model and reset loss after every epoch
sibre28 Apr 17, 2024
7ecec5b
adjust loss calculation
sibre28 Apr 17, 2024
7833e05
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
b7da6df
loss_sum
sibre28 Apr 17, 2024
c8040ed
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 17, 2024
2501c4c
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
8ecb9fd
fix bug
sibre28 Apr 17, 2024
cbd69f0
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
8222b5f
fix bug
sibre28 Apr 17, 2024
080fe03
Merge remote-tracking branch 'origin/610-improve-fnn-layer-and-model-…
sibre28 Apr 17, 2024
99ec26c
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
2842732
Merge branch 'main' into 610-improve-fnn-layer-and-model-performance-…
sibre28 Apr 17, 2024
02e2996
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
265e55c
added input and output layer interface
Gerhardsa0 Apr 17, 2024
0ef68dc
Changes by alexg
Gerhardsa0 Apr 17, 2024
c4252dc
Changes by Simon
Gerhardsa0 Apr 17, 2024
c556f72
Merge branch 'main' of https://github.com/Safe-DS/Library into 621-fe…
Marsmaennchen221 Apr 17, 2024
d5015e1
refactor: linter
Marsmaennchen221 Apr 17, 2024
d7d41b2
refactor: codecov
Marsmaennchen221 Apr 17, 2024
d8f2551
refactor: linter
Marsmaennchen221 Apr 17, 2024
2e07146
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
05e0703
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
f4a69de
refactor: lazy imports
Marsmaennchen221 Apr 17, 2024
8e0228c
style: apply automated linter fixes
megalinter-bot Apr 17, 2024
d02f03b
refactor: non global internal model creation
Marsmaennchen221 Apr 17, 2024
631ae38
Merge branch '621-feat-add-input-layer-for-nn-interface' of https://g…
Marsmaennchen221 Apr 17, 2024
ac631d8
feat: Added predict type to `InputConversion`
Marsmaennchen221 Apr 18, 2024
53b2b82
refactor: changed `TypeVar` to match correct classes
Marsmaennchen221 Apr 18, 2024
bea4d1a
style: apply automated linter fixes
megalinter-bot Apr 18, 2024
9719467
added documentation
Gerhardsa0 Apr 18, 2024
3ecc3c7
Linter changes
Gerhardsa0 Apr 18, 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
4 changes: 2 additions & 2 deletions src/safeds/data/tabular/containers/_tagged_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from collections.abc import Callable, Mapping, Sequence
from typing import Any

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

Expand Down Expand Up @@ -916,7 +916,7 @@ def _into_dataloader_with_classes(self, batch_size: int, num_of_classes: int) ->
)


def _create_dataset(features: np.array, target: np.array) -> Dataset:
def _create_dataset(features: Tensor, target: Tensor) -> Dataset:
import torch
from torch.utils.data import Dataset

Expand Down
6 changes: 3 additions & 3 deletions src/safeds/exceptions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
DatasetContainsTargetError,
DatasetMissesDataError,
DatasetMissesFeaturesError,
FeatureDataMismatchError,
InputSizeError,
LearningError,
ModelNotFittedError,
NonTimeSeriesError,
PredictionError,
TestTrainDataMismatchError,
UntaggedTableError,
)

Expand Down Expand Up @@ -66,12 +66,12 @@
"DatasetContainsTargetError": "._ml:DatasetContainsTargetError",
"DatasetMissesDataError": "._ml:DatasetMissesDataError",
"DatasetMissesFeaturesError": "._ml:DatasetMissesFeaturesError",
"FeatureDataMismatchError": "._ml:FeatureDataMismatchError",
"InputSizeError": "._ml:InputSizeError",
"LearningError": "._ml:LearningError",
"ModelNotFittedError": "._ml:ModelNotFittedError",
"NonTimeSeriesError": "._ml:NonTimeSeriesError",
"PredictionError": "._ml:PredictionError",
"TestTrainDataMismatchError": "._ml:TestTrainDataMismatchError",
"UntaggedTableError": "._ml:UntaggedTableError",
# Other
"Bound": "._generic:Bound",
Expand Down Expand Up @@ -103,12 +103,12 @@
"DatasetContainsTargetError",
"DatasetMissesDataError",
"DatasetMissesFeaturesError",
"FeatureDataMismatchError",
"InputSizeError",
"LearningError",
"ModelNotFittedError",
"NonTimeSeriesError",
"PredictionError",
"TestTrainDataMismatchError",
"UntaggedTableError",
# Other
"Bound",
Expand Down
6 changes: 3 additions & 3 deletions src/safeds/exceptions/_ml.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ def __init__(self, reason: str):
super().__init__(f"Error occurred while predicting: {reason}")


class TestTrainDataMismatchError(Exception):
"""Raised when the columns of the table passed to the predict method do not match with the feature columns of the training data."""
class FeatureDataMismatchError(Exception):
"""Raised when the columns of the table passed to the predict or fit method do not match with the specified features of the neural network."""

def __init__(self) -> None:
super().__init__(
"The column names in the test table do not match with the feature columns names of the training data.",
"The features in the given table do not match with the specified feature columns names of the neural network.",
)


Expand Down
6 changes: 6 additions & 0 deletions src/safeds/ml/nn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@

if TYPE_CHECKING:
from ._forward_layer import ForwardLayer
from ._input_conversion_table import InputConversionTable
from ._model import NeuralNetworkClassifier, NeuralNetworkRegressor
from ._output_conversion_table import OutputConversionTable

apipkg.initpkg(
__name__,
{
"ForwardLayer": "._forward_layer:ForwardLayer",
"InputConversionTable": "._input_conversion_table:InputConversionTable",
"OutputConversionTable": "._output_conversion_table:OutputConversionTable",
"NeuralNetworkClassifier": "._model:NeuralNetworkClassifier",
"NeuralNetworkRegressor": "._model:NeuralNetworkRegressor",
},
)

__all__ = [
"ForwardLayer",
"InputConversionTable",
"OutputConversionTable",
"NeuralNetworkClassifier",
"NeuralNetworkRegressor",
]
50 changes: 30 additions & 20 deletions src/safeds/ml/nn/_forward_layer.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
from torch import Tensor, nn
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from torch import Tensor, nn

from safeds.exceptions import ClosedBound, OutOfBoundsError
from safeds.ml.nn._layer import Layer
from safeds.ml.nn._layer import _Layer


def _create_internal_model(input_size: int, output_size: int, activation_function: str) -> nn.Module:
from torch import nn

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)

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: Tensor) -> Tensor:
return self._fn(self._layer(x))

def forward(self, x: Tensor) -> Tensor:
return self._fn(self._layer(x))
return _InternalLayer(input_size, output_size, activation_function)


class ForwardLayer(Layer):
class ForwardLayer(_Layer):
def __init__(self, output_size: int, input_size: int | None = None):
"""
Create a FNN Layer.
Expand All @@ -47,8 +57,8 @@ def __init__(self, output_size: int, input_size: int | None = None):
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)
def _get_internal_layer(self, activation_function: str) -> nn.Module:
return _create_internal_model(self._input_size, self._output_size, activation_function)

@property
def input_size(self) -> int:
Expand Down
37 changes: 37 additions & 0 deletions src/safeds/ml/nn/_input_conversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Generic, TypeVar

if TYPE_CHECKING:
from torch.utils.data import DataLoader

from safeds.data.tabular.containers import Table, TaggedTable, TimeSeries

FT = TypeVar("FT", TaggedTable, TimeSeries)
PT = TypeVar("PT", Table, TimeSeries)


class _InputConversion(Generic[FT, PT], ABC):
"""The input conversion for a neural network, defines the input parameters for the neural network."""

@property
@abstractmethod
def _data_size(self) -> int:
pass # pragma: no cover

@abstractmethod
def _data_conversion_fit(self, input_data: FT, batch_size: int, num_of_classes: int = 1) -> DataLoader:
pass # pragma: no cover

@abstractmethod
def _data_conversion_predict(self, input_data: PT, batch_size: int) -> DataLoader:
pass # pragma: no cover

@abstractmethod
def _is_fit_data_valid(self, input_data: FT) -> bool:
pass # pragma: no cover

@abstractmethod
def _is_predict_data_valid(self, input_data: PT) -> bool:
pass # pragma: no cover
46 changes: 46 additions & 0 deletions src/safeds/ml/nn/_input_conversion_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from torch.utils.data import DataLoader

from safeds.data.tabular.containers import Table, TaggedTable
from safeds.ml.nn._input_conversion import _InputConversion


class InputConversionTable(_InputConversion[TaggedTable, Table]):
"""The input conversion for a neural network, defines the input parameters for the neural network."""

def __init__(self, feature_names: list[str], target_name: str) -> None:
"""
Define the input parameters for the neural network in the input conversion.

Parameters
----------
feature_names
The names of the features for the input table, used as features for the training.
target_name
The name of the target for the input table, used as target for the training.
"""
self._feature_names = feature_names
self._target_name = target_name

@property
def _data_size(self) -> int:
return len(self._feature_names)

def _data_conversion_fit(self, input_data: TaggedTable, batch_size: int, num_of_classes: int = 1) -> DataLoader:
return input_data._into_dataloader_with_classes(
batch_size,
num_of_classes,
)

def _data_conversion_predict(self, input_data: Table, batch_size: int) -> DataLoader:
return input_data._into_dataloader(batch_size)

def _is_fit_data_valid(self, input_data: TaggedTable) -> bool:
return (sorted(input_data.features.column_names)).__eq__(sorted(self._feature_names))

def _is_predict_data_valid(self, input_data: Table) -> bool:
return (sorted(input_data.column_names)).__eq__(sorted(self._feature_names))
8 changes: 6 additions & 2 deletions src/safeds/ml/nn/_layer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

from torch import nn
if TYPE_CHECKING:
from torch import nn


class Layer(ABC):
class _Layer(ABC):
@abstractmethod
def __init__(self) -> None:
pass # pragma: no cover
Expand Down
Loading