aino 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
aino-1.0.0/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ playground/
2
+ test/
@@ -0,0 +1,10 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Ignored default folder with query files
5
+ /queries/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
9
+ # Editor-based HTTP Client requests
10
+ /httpRequests/
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
+ </content>
7
+ <orderEntry type="jdk" jdkName="uv (aino)" jdkType="Python SDK" />
8
+ <orderEntry type="sourceFolder" forTests="false" />
9
+ </component>
10
+ </module>
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="uv (aino)" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="uv (aino)" project-jdk-type="Python SDK" />
7
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/aino.iml" filepath="$PROJECT_DIR$/.idea/aino.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,172 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="ChangeListManager">
7
+ <list default="true" id="8e9c724b-7d0c-402b-bdef-157a458f6352" name="Changes" comment="" />
8
+ <option name="SHOW_DIALOG" value="false" />
9
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
10
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
11
+ <option name="LAST_RESOLUTION" value="IGNORE" />
12
+ </component>
13
+ <component name="FileTemplateManagerImpl">
14
+ <option name="RECENT_TEMPLATES">
15
+ <list>
16
+ <option value="gitignore" />
17
+ <option value="Python Script" />
18
+ <option value="Jupyter Notebook" />
19
+ </list>
20
+ </option>
21
+ </component>
22
+ <component name="Git.Settings">
23
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
24
+ </component>
25
+ <component name="McpProjectServerCommands">
26
+ <commands />
27
+ <urls />
28
+ </component>
29
+ <component name="ProblemsViewState">
30
+ <option name="selectedTabId" value="CurrentFile" />
31
+ </component>
32
+ <component name="ProjectColorInfo">{
33
+ &quot;associatedIndex&quot;: 1
34
+ }</component>
35
+ <component name="ProjectId" id="39gpcKMThkj1lJGsICnna3MYcgT" />
36
+ <component name="ProjectViewState">
37
+ <option name="hideEmptyMiddlePackages" value="true" />
38
+ <option name="showLibraryContents" value="true" />
39
+ </component>
40
+ <component name="PropertiesComponent">{
41
+ &quot;keyToString&quot;: {
42
+ &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
43
+ &quot;Python.XOR.executor&quot;: &quot;Run&quot;,
44
+ &quot;Python.main.executor&quot;: &quot;Run&quot;,
45
+ &quot;Python.model.executor&quot;: &quot;Run&quot;,
46
+ &quot;Python.neural_network.executor&quot;: &quot;Run&quot;,
47
+ &quot;Python.test.executor&quot;: &quot;Run&quot;,
48
+ &quot;RunOnceActivity.MCP Project settings loaded&quot;: &quot;true&quot;,
49
+ &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
50
+ &quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
51
+ &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
52
+ &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
53
+ &quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
54
+ &quot;ai.playground.ignore.import.keys.banner.in.settings&quot;: &quot;true&quot;,
55
+ &quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;,
56
+ &quot;git-widget-placeholder&quot;: &quot;master&quot;,
57
+ &quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
58
+ &quot;last_opened_file_path&quot;: &quot;/home/arufa/Downloads&quot;,
59
+ &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
60
+ &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
61
+ &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
62
+ &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
63
+ &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
64
+ &quot;settings.editor.selected.configurable&quot;: &quot;preferences.keymap&quot;,
65
+ &quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
66
+ &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
67
+ },
68
+ &quot;keyToStringList&quot;: {
69
+ &quot;com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File&quot;: [
70
+ &quot;Markdown&quot;
71
+ ]
72
+ }
73
+ }</component>
74
+ <component name="RecentsManager">
75
+ <key name="MoveFile.RECENT_KEYS">
76
+ <recent name="$PROJECT_DIR$/aino" />
77
+ <recent name="$PROJECT_DIR$/test" />
78
+ </key>
79
+ </component>
80
+ <component name="RunAnythingCache">
81
+ <option name="myCommands">
82
+ <command value="ls" />
83
+ <command value="git add /" />
84
+ <command value="git add ." />
85
+ <command value="git commit -m 'write docs, and change print output to english'" />
86
+ <command value="uv add pytest" />
87
+ <command value="uv add --dev pyttest" />
88
+ <command value="uv run python -m -v pytest test/test.py" />
89
+ <command value="uv add pandas" />
90
+ <command value="uv add --dev matplotlib" />
91
+ <command value="tree" />
92
+ </option>
93
+ </component>
94
+ <component name="RunManager">
95
+ <configuration name="perceptron" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
96
+ <module name="aino" />
97
+ <option name="ENV_FILES" value="" />
98
+ <option name="INTERPRETER_OPTIONS" value="" />
99
+ <option name="PARENT_ENVS" value="true" />
100
+ <envs>
101
+ <env name="PYTHONUNBUFFERED" value="1" />
102
+ </envs>
103
+ <option name="SDK_HOME" value="" />
104
+ <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
105
+ <option name="IS_MODULE_SDK" value="true" />
106
+ <option name="ADD_CONTENT_ROOTS" value="true" />
107
+ <option name="ADD_SOURCE_ROOTS" value="true" />
108
+ <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
109
+ <option name="RUN_TOOL" value="" />
110
+ <option name="SCRIPT_NAME" value="$PROJECT_DIR$/aino/perceptron.py" />
111
+ <option name="PARAMETERS" value="" />
112
+ <option name="SHOW_COMMAND_LINE" value="false" />
113
+ <option name="EMULATE_TERMINAL" value="false" />
114
+ <option name="MODULE_MODE" value="false" />
115
+ <option name="REDIRECT_INPUT" value="false" />
116
+ <option name="INPUT_FILE" value="" />
117
+ <method v="2" />
118
+ </configuration>
119
+ <recent_temporary>
120
+ <list>
121
+ <item itemvalue="Python.perceptron" />
122
+ </list>
123
+ </recent_temporary>
124
+ </component>
125
+ <component name="SharedIndexes">
126
+ <attachedChunks>
127
+ <set>
128
+ <option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-PY-253.30387.173" />
129
+ <option value="bundled-python-sdk-4762d8aabb82-6d6dccd035ac-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-253.30387.173" />
130
+ </set>
131
+ </attachedChunks>
132
+ </component>
133
+ <component name="TaskManager">
134
+ <task active="true" id="Default" summary="Default task">
135
+ <changelist id="8e9c724b-7d0c-402b-bdef-157a458f6352" name="Changes" comment="" />
136
+ <created>1771127645826</created>
137
+ <option name="number" value="Default" />
138
+ <option name="presentableId" value="Default" />
139
+ <updated>1771127645826</updated>
140
+ <workItem from="1771127646959" duration="10873000" />
141
+ <workItem from="1771202138897" duration="6979000" />
142
+ <workItem from="1771217752619" duration="7182000" />
143
+ <workItem from="1771231495826" duration="2606000" />
144
+ <workItem from="1771246086108" duration="10692000" />
145
+ <workItem from="1771308120288" duration="441000" />
146
+ <workItem from="1771308576340" duration="9943000" />
147
+ <workItem from="1771335396524" duration="642000" />
148
+ </task>
149
+ <servers />
150
+ </component>
151
+ <component name="TypeScriptGeneratedFilesManager">
152
+ <option name="version" value="3" />
153
+ </component>
154
+ <component name="Vcs.Log.Tabs.Properties">
155
+ <option name="TAB_STATES">
156
+ <map>
157
+ <entry key="MAIN">
158
+ <value>
159
+ <State />
160
+ </value>
161
+ </entry>
162
+ </map>
163
+ </option>
164
+ </component>
165
+ <component name="com.intellij.coverage.CoverageDataManagerImpl">
166
+ <SUITE FILE_PATH="coverage/aino$model.coverage" NAME="model Coverage Results" MODIFIED="1771142913313" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
167
+ <SUITE FILE_PATH="coverage/aino$test.coverage" NAME="test Coverage Results" MODIFIED="1771306492592" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
168
+ <SUITE FILE_PATH="coverage/aino$XOR.coverage" NAME="XOR Coverage Results" MODIFIED="1771222407469" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test" />
169
+ <SUITE FILE_PATH="coverage/aino$main.coverage" NAME="main Coverage Results" MODIFIED="1771141365029" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
170
+ <SUITE FILE_PATH="coverage/aino$neural_network.coverage" NAME="neural_network Coverage Results" MODIFIED="1771204224176" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
171
+ </component>
172
+ </project>
aino-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: aino
3
+ Version: 1.0.0
4
+ Summary: AINO Is Neural Operation: A lightweight, educational neural network library.
5
+ Author-email: Arufa <radityaalfarisi6@gmail.com>
6
+ License: MIT
7
+ Keywords: educational,machine-learning,neural-network,numpy,perceptron
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: numpy>=1.21.0
13
+ Description-Content-Type: text/markdown
14
+
15
+ # AINO (Aino is Neural Operation)
16
+ ![AINO Banner](assets/aino.png)
17
+
18
+ > **"Aino is Neural Operation."** > A custom-built Deep Learning framework built from scratch using pure Python and NumPy.
19
+
20
+ ---
21
+
22
+ ## 🌟 Inspiration
23
+
24
+ This project was born out of curiosity after watching this inspiring video:
25
+ [**MIT Introduction to Deep Learning | 6.S191**](https://youtu.be/alfdI7S6wCY?si=MPqH4F2EiP3U67t-)
26
+
27
+ I didn't want to just "import tensorflow" and call it a day. I wanted to see **directly** how the magic happens under the hood. I wanted to feel the weight of the matrices, understand the flow of the gradients, and build the brain neuron by neuron.
28
+
29
+ ## The Tech Stack
30
+
31
+ So, I built AINO using **only NumPy**.
32
+
33
+ * **No Black Boxes:** Every Forward Pass and Backpropagation step is manually calculated.
34
+ * **Modular Design:** Built with Object-Oriented Programming (Perceptron -> Layer -> NeuralNetwork).
35
+ * **Custom File Format:** Saves and loads trained models using the custom `.dit` format.
36
+
37
+ ## Features
38
+
39
+ * **Flexible Architecture:** Define any number of layers and neurons (e.g., `[3, 20, 10, 1]`).
40
+ * **Activation Functions:** Supports `Sigmoid`, `ReLU`, `Tanh`, and more soon.
41
+ * **Tasks:** Capable of both **Classification** (e.g., Iris Dataset) and **Regression** (e.g., Rocket Trajectory Prediction).
42
+ * **Training Engine:** Includes `.fit()` and `.predict()` methods similar to Scikit-Learn.
43
+
44
+ ## 🧠 What I Learned
45
+
46
+ Building AINO from the ground up gave me insights that high-level libraries often hide:
47
+
48
+ 1. **Object-Oriented Neural Architecture:**
49
+ Instead of abstract tensors, I built the network hierarchically. I learned how a **Neural Network** manages **Layers**, and how a **Layer** orchestrates individual **Perceptrons**. This OOP approach helped me visualize exactly how data flows through the structure.
50
+
51
+ 2. **The Calculus of Backpropagation:**
52
+ I implemented the **Chain Rule** manually. By coding the `backward()` method in `Layer` and `update_weight()` in `Perceptron`, I understood how error gradients propagate from the output back to the input, and how weights ($w$) and biases ($b$) are adjusted using the learning rate ($n$).
53
+
54
+ 3. **Activation Functions & Derivatives:**
55
+ I manually coded the mathematical formulas for **Sigmoid**, **Tanh**, and **ReLU**, along with their specific derivatives needed for the gradient descent step. I learned why ReLU is crucial for preventing vanishing gradients in deeper networks.
56
+
57
+ 4. **NumPy Vectorization:**
58
+ Handling matrix multiplication (`np.dot`) and shape alignment was challenging. I learned how to efficiently process inputs and weights as vectors rather than looping through every single value.
59
+
60
+ 5. **Model Serialization (The `.dit` Format):**
61
+ I learned how to persist state. By implementing the `save()` and `load()` methods, I figured out how to extract weights/configs from objects, store them in a binary format (`.npz`), and reconstruct the exact object architecture from that file later.
62
+ ## 💻 Usage Example
63
+
64
+ ```python
65
+ import aino
66
+
67
+ model = aino.NeuralNetwork([2, 3, 1], activation_type='sigmoid')
68
+ model.fit(X_train, y_train, epochs=100, n=0.1)
69
+ model.predict(X_test)
70
+ model.save('aino.dit')
71
+
72
+ ```
73
+
74
+ Built with ❤️ use Python and Numpy.
75
+
aino-1.0.0/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # AINO (Aino is Neural Operation)
2
+ ![AINO Banner](assets/aino.png)
3
+
4
+ > **"Aino is Neural Operation."** > A custom-built Deep Learning framework built from scratch using pure Python and NumPy.
5
+
6
+ ---
7
+
8
+ ## 🌟 Inspiration
9
+
10
+ This project was born out of curiosity after watching this inspiring video:
11
+ [**MIT Introduction to Deep Learning | 6.S191**](https://youtu.be/alfdI7S6wCY?si=MPqH4F2EiP3U67t-)
12
+
13
+ I didn't want to just "import tensorflow" and call it a day. I wanted to see **directly** how the magic happens under the hood. I wanted to feel the weight of the matrices, understand the flow of the gradients, and build the brain neuron by neuron.
14
+
15
+ ## The Tech Stack
16
+
17
+ So, I built AINO using **only NumPy**.
18
+
19
+ * **No Black Boxes:** Every Forward Pass and Backpropagation step is manually calculated.
20
+ * **Modular Design:** Built with Object-Oriented Programming (Perceptron -> Layer -> NeuralNetwork).
21
+ * **Custom File Format:** Saves and loads trained models using the custom `.dit` format.
22
+
23
+ ## Features
24
+
25
+ * **Flexible Architecture:** Define any number of layers and neurons (e.g., `[3, 20, 10, 1]`).
26
+ * **Activation Functions:** Supports `Sigmoid`, `ReLU`, `Tanh`, and more soon.
27
+ * **Tasks:** Capable of both **Classification** (e.g., Iris Dataset) and **Regression** (e.g., Rocket Trajectory Prediction).
28
+ * **Training Engine:** Includes `.fit()` and `.predict()` methods similar to Scikit-Learn.
29
+
30
+ ## 🧠 What I Learned
31
+
32
+ Building AINO from the ground up gave me insights that high-level libraries often hide:
33
+
34
+ 1. **Object-Oriented Neural Architecture:**
35
+ Instead of abstract tensors, I built the network hierarchically. I learned how a **Neural Network** manages **Layers**, and how a **Layer** orchestrates individual **Perceptrons**. This OOP approach helped me visualize exactly how data flows through the structure.
36
+
37
+ 2. **The Calculus of Backpropagation:**
38
+ I implemented the **Chain Rule** manually. By coding the `backward()` method in `Layer` and `update_weight()` in `Perceptron`, I understood how error gradients propagate from the output back to the input, and how weights ($w$) and biases ($b$) are adjusted using the learning rate ($n$).
39
+
40
+ 3. **Activation Functions & Derivatives:**
41
+ I manually coded the mathematical formulas for **Sigmoid**, **Tanh**, and **ReLU**, along with their specific derivatives needed for the gradient descent step. I learned why ReLU is crucial for preventing vanishing gradients in deeper networks.
42
+
43
+ 4. **NumPy Vectorization:**
44
+ Handling matrix multiplication (`np.dot`) and shape alignment was challenging. I learned how to efficiently process inputs and weights as vectors rather than looping through every single value.
45
+
46
+ 5. **Model Serialization (The `.dit` Format):**
47
+ I learned how to persist state. By implementing the `save()` and `load()` methods, I figured out how to extract weights/configs from objects, store them in a binary format (`.npz`), and reconstruct the exact object architecture from that file later.
48
+ ## 💻 Usage Example
49
+
50
+ ```python
51
+ import aino
52
+
53
+ model = aino.NeuralNetwork([2, 3, 1], activation_type='sigmoid')
54
+ model.fit(X_train, y_train, epochs=100, n=0.1)
55
+ model.predict(X_test)
56
+ model.save('aino.dit')
57
+
58
+ ```
59
+
60
+ Built with ❤️ use Python and Numpy.
61
+
@@ -0,0 +1,5 @@
1
+ from .model import NeuralNetwork
2
+ from .layer import Layer
3
+ from .perceptron import Perceptron
4
+
5
+ __all__ = ["NeuralNetwork", "Layer", "Perceptron"]
@@ -0,0 +1,82 @@
1
+ import numpy as np
2
+ from .perceptron import Perceptron
3
+ from typing import List, Union, Optional
4
+
5
+ class Layer:
6
+ """
7
+ Represents a single layer in a multi-layer perceptron (MLP).
8
+
9
+ A layer consists of a collection of Perceptron objects that all receive
10
+ the same input vector and produce a combined output vector.
11
+ """
12
+
13
+ def __init__(self, input_dim: int, amount: Optional[int] = None, activation_type: str = 'relu'):
14
+ """
15
+ Initializes the Layer and populates it with Perceptrons.
16
+
17
+ Args:
18
+ input_dim (int): The number of inputs each perceptron receives.
19
+ amount (int, optional): Number of neurons in this layer. Defaults to 10.
20
+ activation_type (str): The activation function to use for all neurons in the layer.
21
+ """
22
+ self.activation_type: str = activation_type if activation_type is not None else 'relu'
23
+ self.amount: int = amount if amount is not None else 10
24
+ self.layer: List[Perceptron] = []
25
+ self.input_dim: int = input_dim
26
+
27
+ # Initialize the neurons
28
+ self.add_perceptron(self.amount)
29
+
30
+ def add_perceptron(self, amount: int) -> None:
31
+ """
32
+ Instantiates and adds Perceptron units to the layer.
33
+
34
+ Args:
35
+ amount (int): The number of Perceptrons to create and add.
36
+ """
37
+ for _ in range(amount):
38
+ p = Perceptron(dim=self.input_dim, activation_type=self.activation_type)
39
+ self.layer.append(p)
40
+
41
+ def forward(self, x: Union[np.ndarray, List[float]]) -> np.ndarray:
42
+ """
43
+ Passes the input through every perceptron in the layer.
44
+
45
+ Args:
46
+ x (Union[np.ndarray, List[float]]): The input vector from the previous layer or data.
47
+
48
+ Returns:
49
+ np.ndarray: A vector of activated outputs, one from each neuron.
50
+ """
51
+ Y = []
52
+ for perceptron in self.layer:
53
+ Y.append(perceptron.forward(x))
54
+ return np.array(Y)
55
+
56
+ def backward(self, error: np.ndarray, n: float) -> np.ndarray:
57
+ """
58
+ Performs backpropagation for the layer.
59
+
60
+ Calculates the error gradient for each neuron, updates their weights,
61
+ and aggregates the error to be passed to the preceding layer.
62
+
63
+ Args:
64
+ error (np.ndarray): The error vector from the subsequent layer (gradient of loss).
65
+ n (float): The learning rate.
66
+
67
+ Returns:
68
+ np.ndarray: The accumulated error vector for the previous layer.
69
+ """
70
+ error_for_back = np.zeros(self.input_dim)
71
+
72
+ for i in range(len(self.layer)):
73
+ perceptron = self.layer[i]
74
+ perceptron_error = error[i]
75
+
76
+ D = perceptron_error * perceptron.get_derivative()
77
+
78
+ error_for_back += D * perceptron.w
79
+
80
+ perceptron.update_weight(n, D)
81
+
82
+ return error_for_back
@@ -0,0 +1,170 @@
1
+ from typing import List, Union, Optional
2
+ import numpy as np
3
+ from .layer import Layer
4
+
5
+ class NeuralNetwork:
6
+ """
7
+ A Multi-Layer Perceptron (MLP) manager that chains Layer objects.
8
+
9
+ This class orchestrates the training (fit), inference (predict),
10
+ and persistence (save/load) of the neural network weights.
11
+ """
12
+
13
+ def __init__(self, layer_config: List[int], activation_type: str = 'relu'):
14
+ """
15
+ Initializes the network architecture.
16
+
17
+ Args:
18
+ layer_config (List[int]): List defining neurons per layer (e.g., [3, 10, 2]).
19
+ activation_type (str): Nonlinearity to use throughout the network.
20
+ """
21
+ self.config: List[int] = layer_config
22
+ self.activation_type: str = activation_type if activation_type is not None else 'relu'
23
+ self.layers: List[Layer] = []
24
+
25
+ for i in range(len(layer_config) - 1):
26
+ i_dim = layer_config[i]
27
+ neuron_count = layer_config[i + 1]
28
+
29
+ new_layer = Layer(i_dim, neuron_count, activation_type=self.activation_type)
30
+ self.layers.append(new_layer)
31
+
32
+ def _forward(self, x: np.ndarray) -> np.ndarray:
33
+ """
34
+ Internal method to propagate input through all layers.
35
+
36
+ Args:
37
+ x (np.ndarray): Input vector.
38
+
39
+ Returns:
40
+ np.ndarray: The final output vector from the last layer.
41
+ """
42
+ current_input = x
43
+ for layer in self.layers:
44
+ current_input = layer.forward(current_input)
45
+ return current_input
46
+
47
+ def _backprop(self, pred: np.ndarray, target: np.ndarray, n: float = 0.1) -> None:
48
+ """
49
+ Internal method to calculate gradients and update weights.
50
+
51
+ Args:
52
+ pred (np.ndarray): The output from the forward pass.
53
+ target (np.ndarray): The expected ground-truth values.
54
+ n (float): Learning rate.
55
+ """
56
+ # Initial error derivative (dLoss/dOutput) for Mean Squared Error
57
+ error = target - pred
58
+ for layer in reversed(self.layers):
59
+ error = layer.backward(error, n)
60
+
61
+ def predict(self, X: Union[np.ndarray, List[List[float]]]) -> np.ndarray:
62
+ """
63
+ Generates predictions for a batch of inputs.
64
+
65
+ Args:
66
+ X (Union[np.ndarray, List[List[float]]]): A 2D array of input samples.
67
+
68
+ Returns:
69
+ np.ndarray: A 2D array of predictions.
70
+ """
71
+ X = np.array(X)
72
+ results = []
73
+
74
+ for i in range(len(X)):
75
+ output = self._forward(X[i])
76
+ results.append(output)
77
+
78
+ return np.array(results)
79
+
80
+ def fit(self, X: np.ndarray, y: np.ndarray, epochs: int = 1000, n: float = 0.1, verbose: bool = False) -> None:
81
+ """
82
+ Trains the model using Stochastic Gradient Descent.
83
+
84
+ Args:
85
+ X (np.ndarray): Training features.
86
+ y (np.ndarray): Training labels.
87
+ epochs (int): Number of iterations over the dataset.
88
+ n (float): Learning rate.
89
+ verbose (bool): If True, prints loss progress every 10%.
90
+ """
91
+ X = np.array(X)
92
+ y = np.array(y)
93
+
94
+ print(f"Start training AINO model over {epochs} epoch...")
95
+
96
+ for epoch in range(epochs):
97
+ total_error = 0
98
+ for i in range(len(X)):
99
+ pred = self._forward(X[i])
100
+ total_error += np.mean((y[i] - pred) ** 2)
101
+ self._backprop(pred, y[i], n)
102
+
103
+ if verbose and (epoch % (max(1, epochs // 10)) == 0):
104
+ avg_loss = total_error / len(X)
105
+ print(f"Epoch {epoch}, Loss: {avg_loss:.6f}")
106
+
107
+ print("Training is done!")
108
+
109
+ def save(self, filename: str = "model.dit") -> None:
110
+ """
111
+ Serializes model weights, biases, and config to a .dit file (NPZ format).
112
+
113
+ Args:
114
+ filename (str): Name of the file to save.
115
+ """
116
+ if not filename.endswith(".dit"):
117
+ filename += ".dit"
118
+
119
+ data = {
120
+ 'config': np.array(self.config),
121
+ 'activation': np.array(self.activation_type)
122
+ }
123
+
124
+ for i, layer in enumerate(self.layers):
125
+ w_layer = np.array([p.w for p in layer.layer])
126
+ b_layer = np.array([p.b for p in layer.layer])
127
+ data[f"layer_{i}_w"] = w_layer
128
+ data[f"layer_{i}_b"] = b_layer
129
+
130
+ with open(filename, 'wb') as f:
131
+ np.savez(f, **data)
132
+
133
+ print(f"succesfully save model to '{filename}'")
134
+
135
+ @staticmethod
136
+ def load(filename: str) -> Optional['NeuralNetwork']:
137
+ """
138
+ Reconstructs a NeuralNetwork from a saved .dit file.
139
+
140
+ Args:
141
+ filename (str): Path to the .dit file.
142
+
143
+ Returns:
144
+ Optional[NeuralNetwork]: The restored model, or None if loading fails.
145
+ """
146
+ if not filename.endswith(".dit"):
147
+ print(f"Warning: '{filename}' isnt a .dit model...")
148
+
149
+ try:
150
+ with open(filename, 'rb') as f:
151
+ data = np.load(f, allow_pickle=True)
152
+ config = data['config'].tolist()
153
+ activation = str(data['activation'])
154
+
155
+ print(f"Architecture: {config}, Non-linearity: {activation}")
156
+ model_baru = NeuralNetwork(config, activation_type=activation)
157
+
158
+ for i, layer in enumerate(model_baru.layers):
159
+ w_layer = data[f"layer_{i}_w"]
160
+ b_layer = data[f"layer_{i}_b"]
161
+ for j, perceptron in enumerate(layer.layer):
162
+ perceptron.w = w_layer[j]
163
+ perceptron.b = b_layer[j]
164
+
165
+ print("AINO model ready")
166
+ return model_baru
167
+
168
+ except Exception as e:
169
+ print(f"Error when try to load model: {e}")
170
+ return None