ilovetools 0.2.19__tar.gz → 0.2.20__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.
- {ilovetools-0.2.19/ilovetools.egg-info → ilovetools-0.2.20}/PKG-INFO +2 -2
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/__init__.py +2 -2
- ilovetools-0.2.20/ilovetools/ml/rnn.py +498 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20/ilovetools.egg-info}/PKG-INFO +2 -2
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools.egg-info/SOURCES.txt +3 -1
- {ilovetools-0.2.19 → ilovetools-0.2.20}/pyproject.toml +2 -2
- {ilovetools-0.2.19 → ilovetools-0.2.20}/setup.py +2 -2
- ilovetools-0.2.20/tests/test_rnn.py +419 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/LICENSE +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/MANIFEST.in +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/README.md +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ai/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ai/embeddings.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ai/inference.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ai/llm_helpers.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/audio/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/automation/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/automation/file_organizer.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/conversion/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/conversion/config_converter.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/conversion/config_converter_fixed_header.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/data/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/data/feature_engineering.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/data/preprocessing.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/database/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/datetime/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/email/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/email/template_engine.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/files/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/image/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/activations.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/anomaly_detection.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/attention.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/clustering.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/cnn.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/cross_validation.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/dimensionality.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/ensemble.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/feature_selection.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/gradient_descent.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/imbalanced.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/interpretation.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/loss_functions.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/metrics.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/neural_network.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/normalization.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/optimizers.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/pipeline.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/regularization.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/timeseries.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/ml/tuning.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/security/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/security/password_checker.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/text/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/utils/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/utils/cache_system.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/utils/logger.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/utils/rate_limiter.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/utils/retry.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/validation/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/validation/data_validator.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/web/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/web/scraper.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/web/url_shortener.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools.egg-info/dependency_links.txt +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools.egg-info/requires.txt +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools.egg-info/top_level.txt +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/requirements.txt +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/setup.cfg +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/__init__.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_activations.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_attention.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_cnn.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_gradient_descent.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_loss_functions.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_neural_network.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_normalization.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_optimizers.py +0 -0
- {ilovetools-0.2.19 → ilovetools-0.2.20}/tests/test_regularization.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ilovetools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.20
|
|
4
4
|
Summary: A comprehensive Python utility library with modular tools for AI/ML, data processing, and daily programming needs
|
|
5
5
|
Home-page: https://github.com/AliMehdi512/ilovetools
|
|
6
6
|
Author: Ali Mehdi
|
|
@@ -11,7 +11,7 @@ Project-URL: Repository, https://github.com/AliMehdi512/ilovetools
|
|
|
11
11
|
Project-URL: Issues, https://github.com/AliMehdi512/ilovetools/issues
|
|
12
12
|
Project-URL: Bug Reports, https://github.com/AliMehdi512/ilovetools/issues
|
|
13
13
|
Project-URL: Source, https://github.com/AliMehdi512/ilovetools
|
|
14
|
-
Keywords: utilities,tools,ai,ml,data-processing,automation,
|
|
14
|
+
Keywords: utilities,tools,ai,ml,data-processing,automation,rnn,lstm,gru,recurrent-neural-networks,sequence-modeling,nlp
|
|
15
15
|
Classifier: Development Status :: 3 - Alpha
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Recurrent Neural Network Operations
|
|
3
|
+
|
|
4
|
+
This module provides RNN architectures and operations:
|
|
5
|
+
- Basic RNN (Vanilla RNN)
|
|
6
|
+
- LSTM (Long Short-Term Memory)
|
|
7
|
+
- GRU (Gated Recurrent Unit)
|
|
8
|
+
- Bidirectional RNNs
|
|
9
|
+
- Stacked RNNs
|
|
10
|
+
- Sequence-to-Sequence utilities
|
|
11
|
+
|
|
12
|
+
All operations support batched inputs and are optimized for sequence processing.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
from typing import Tuple, Optional, List
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ============================================================================
|
|
20
|
+
# BASIC RNN (VANILLA RNN)
|
|
21
|
+
# ============================================================================
|
|
22
|
+
|
|
23
|
+
def rnn_cell_forward(
|
|
24
|
+
x_t: np.ndarray,
|
|
25
|
+
h_prev: np.ndarray,
|
|
26
|
+
W_xh: np.ndarray,
|
|
27
|
+
W_hh: np.ndarray,
|
|
28
|
+
b_h: np.ndarray
|
|
29
|
+
) -> np.ndarray:
|
|
30
|
+
"""
|
|
31
|
+
Single timestep of basic RNN cell
|
|
32
|
+
|
|
33
|
+
Formula: h_t = tanh(W_xh @ x_t + W_hh @ h_prev + b_h)
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
x_t: Input at timestep t, shape (batch, input_size)
|
|
37
|
+
h_prev: Previous hidden state, shape (batch, hidden_size)
|
|
38
|
+
W_xh: Input-to-hidden weights, shape (input_size, hidden_size)
|
|
39
|
+
W_hh: Hidden-to-hidden weights, shape (hidden_size, hidden_size)
|
|
40
|
+
b_h: Hidden bias, shape (hidden_size,)
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
h_t: New hidden state, shape (batch, hidden_size)
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
>>> x_t = np.random.randn(32, 128) # (batch, input_size)
|
|
47
|
+
>>> h_prev = np.random.randn(32, 256) # (batch, hidden_size)
|
|
48
|
+
>>> W_xh = np.random.randn(128, 256)
|
|
49
|
+
>>> W_hh = np.random.randn(256, 256)
|
|
50
|
+
>>> b_h = np.zeros(256)
|
|
51
|
+
>>> h_t = rnn_cell_forward(x_t, h_prev, W_xh, W_hh, b_h)
|
|
52
|
+
>>> print(h_t.shape) # (32, 256)
|
|
53
|
+
"""
|
|
54
|
+
h_t = np.tanh(np.dot(x_t, W_xh) + np.dot(h_prev, W_hh) + b_h)
|
|
55
|
+
return h_t
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def rnn_forward(
|
|
59
|
+
x: np.ndarray,
|
|
60
|
+
h_0: np.ndarray,
|
|
61
|
+
W_xh: np.ndarray,
|
|
62
|
+
W_hh: np.ndarray,
|
|
63
|
+
b_h: np.ndarray
|
|
64
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
65
|
+
"""
|
|
66
|
+
Forward pass through entire RNN sequence
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
x: Input sequence, shape (batch, seq_len, input_size)
|
|
70
|
+
h_0: Initial hidden state, shape (batch, hidden_size)
|
|
71
|
+
W_xh: Input-to-hidden weights
|
|
72
|
+
W_hh: Hidden-to-hidden weights
|
|
73
|
+
b_h: Hidden bias
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Tuple of (outputs, hidden_states)
|
|
77
|
+
- outputs: shape (batch, seq_len, hidden_size)
|
|
78
|
+
- hidden_states: shape (batch, seq_len, hidden_size)
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
>>> x = np.random.randn(32, 10, 128) # (batch, seq_len, input_size)
|
|
82
|
+
>>> h_0 = np.zeros((32, 256))
|
|
83
|
+
>>> W_xh = np.random.randn(128, 256)
|
|
84
|
+
>>> W_hh = np.random.randn(256, 256)
|
|
85
|
+
>>> b_h = np.zeros(256)
|
|
86
|
+
>>> outputs, hidden_states = rnn_forward(x, h_0, W_xh, W_hh, b_h)
|
|
87
|
+
>>> print(outputs.shape) # (32, 10, 256)
|
|
88
|
+
"""
|
|
89
|
+
batch_size, seq_len, input_size = x.shape
|
|
90
|
+
hidden_size = h_0.shape[1]
|
|
91
|
+
|
|
92
|
+
# Initialize outputs
|
|
93
|
+
outputs = np.zeros((batch_size, seq_len, hidden_size))
|
|
94
|
+
hidden_states = np.zeros((batch_size, seq_len, hidden_size))
|
|
95
|
+
|
|
96
|
+
h_t = h_0
|
|
97
|
+
|
|
98
|
+
# Process sequence
|
|
99
|
+
for t in range(seq_len):
|
|
100
|
+
h_t = rnn_cell_forward(x[:, t, :], h_t, W_xh, W_hh, b_h)
|
|
101
|
+
outputs[:, t, :] = h_t
|
|
102
|
+
hidden_states[:, t, :] = h_t
|
|
103
|
+
|
|
104
|
+
return outputs, hidden_states
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ============================================================================
|
|
108
|
+
# LSTM (LONG SHORT-TERM MEMORY)
|
|
109
|
+
# ============================================================================
|
|
110
|
+
|
|
111
|
+
def lstm_cell_forward(
|
|
112
|
+
x_t: np.ndarray,
|
|
113
|
+
h_prev: np.ndarray,
|
|
114
|
+
c_prev: np.ndarray,
|
|
115
|
+
W_f: np.ndarray,
|
|
116
|
+
W_i: np.ndarray,
|
|
117
|
+
W_c: np.ndarray,
|
|
118
|
+
W_o: np.ndarray,
|
|
119
|
+
b_f: np.ndarray,
|
|
120
|
+
b_i: np.ndarray,
|
|
121
|
+
b_c: np.ndarray,
|
|
122
|
+
b_o: np.ndarray
|
|
123
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
124
|
+
"""
|
|
125
|
+
Single timestep of LSTM cell
|
|
126
|
+
|
|
127
|
+
LSTM has three gates:
|
|
128
|
+
- Forget gate: decides what to forget from cell state
|
|
129
|
+
- Input gate: decides what new information to store
|
|
130
|
+
- Output gate: decides what to output
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
x_t: Input at timestep t, shape (batch, input_size)
|
|
134
|
+
h_prev: Previous hidden state, shape (batch, hidden_size)
|
|
135
|
+
c_prev: Previous cell state, shape (batch, hidden_size)
|
|
136
|
+
W_f, W_i, W_c, W_o: Weight matrices for gates
|
|
137
|
+
b_f, b_i, b_c, b_o: Bias vectors for gates
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Tuple of (h_t, c_t)
|
|
141
|
+
- h_t: New hidden state, shape (batch, hidden_size)
|
|
142
|
+
- c_t: New cell state, shape (batch, hidden_size)
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
>>> x_t = np.random.randn(32, 128)
|
|
146
|
+
>>> h_prev = np.random.randn(32, 256)
|
|
147
|
+
>>> c_prev = np.random.randn(32, 256)
|
|
148
|
+
>>> # Initialize weights...
|
|
149
|
+
>>> h_t, c_t = lstm_cell_forward(x_t, h_prev, c_prev, W_f, W_i, W_c, W_o, b_f, b_i, b_c, b_o)
|
|
150
|
+
>>> print(h_t.shape, c_t.shape) # (32, 256), (32, 256)
|
|
151
|
+
"""
|
|
152
|
+
# Concatenate input and previous hidden state
|
|
153
|
+
concat = np.concatenate([h_prev, x_t], axis=1)
|
|
154
|
+
|
|
155
|
+
# Forget gate
|
|
156
|
+
f_t = sigmoid(np.dot(concat, W_f) + b_f)
|
|
157
|
+
|
|
158
|
+
# Input gate
|
|
159
|
+
i_t = sigmoid(np.dot(concat, W_i) + b_i)
|
|
160
|
+
|
|
161
|
+
# Candidate cell state
|
|
162
|
+
c_tilde = np.tanh(np.dot(concat, W_c) + b_c)
|
|
163
|
+
|
|
164
|
+
# New cell state
|
|
165
|
+
c_t = f_t * c_prev + i_t * c_tilde
|
|
166
|
+
|
|
167
|
+
# Output gate
|
|
168
|
+
o_t = sigmoid(np.dot(concat, W_o) + b_o)
|
|
169
|
+
|
|
170
|
+
# New hidden state
|
|
171
|
+
h_t = o_t * np.tanh(c_t)
|
|
172
|
+
|
|
173
|
+
return h_t, c_t
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def lstm_forward(
|
|
177
|
+
x: np.ndarray,
|
|
178
|
+
h_0: np.ndarray,
|
|
179
|
+
c_0: np.ndarray,
|
|
180
|
+
W_f: np.ndarray,
|
|
181
|
+
W_i: np.ndarray,
|
|
182
|
+
W_c: np.ndarray,
|
|
183
|
+
W_o: np.ndarray,
|
|
184
|
+
b_f: np.ndarray,
|
|
185
|
+
b_i: np.ndarray,
|
|
186
|
+
b_c: np.ndarray,
|
|
187
|
+
b_o: np.ndarray
|
|
188
|
+
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
189
|
+
"""
|
|
190
|
+
Forward pass through entire LSTM sequence
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
x: Input sequence, shape (batch, seq_len, input_size)
|
|
194
|
+
h_0: Initial hidden state, shape (batch, hidden_size)
|
|
195
|
+
c_0: Initial cell state, shape (batch, hidden_size)
|
|
196
|
+
W_f, W_i, W_c, W_o: Weight matrices
|
|
197
|
+
b_f, b_i, b_c, b_o: Bias vectors
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Tuple of (outputs, hidden_states, cell_states)
|
|
201
|
+
- outputs: shape (batch, seq_len, hidden_size)
|
|
202
|
+
- hidden_states: shape (batch, seq_len, hidden_size)
|
|
203
|
+
- cell_states: shape (batch, seq_len, hidden_size)
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
>>> x = np.random.randn(32, 10, 128)
|
|
207
|
+
>>> h_0 = np.zeros((32, 256))
|
|
208
|
+
>>> c_0 = np.zeros((32, 256))
|
|
209
|
+
>>> # Initialize weights...
|
|
210
|
+
>>> outputs, h_states, c_states = lstm_forward(x, h_0, c_0, W_f, W_i, W_c, W_o, b_f, b_i, b_c, b_o)
|
|
211
|
+
>>> print(outputs.shape) # (32, 10, 256)
|
|
212
|
+
"""
|
|
213
|
+
batch_size, seq_len, input_size = x.shape
|
|
214
|
+
hidden_size = h_0.shape[1]
|
|
215
|
+
|
|
216
|
+
# Initialize outputs
|
|
217
|
+
outputs = np.zeros((batch_size, seq_len, hidden_size))
|
|
218
|
+
hidden_states = np.zeros((batch_size, seq_len, hidden_size))
|
|
219
|
+
cell_states = np.zeros((batch_size, seq_len, hidden_size))
|
|
220
|
+
|
|
221
|
+
h_t = h_0
|
|
222
|
+
c_t = c_0
|
|
223
|
+
|
|
224
|
+
# Process sequence
|
|
225
|
+
for t in range(seq_len):
|
|
226
|
+
h_t, c_t = lstm_cell_forward(
|
|
227
|
+
x[:, t, :], h_t, c_t,
|
|
228
|
+
W_f, W_i, W_c, W_o,
|
|
229
|
+
b_f, b_i, b_c, b_o
|
|
230
|
+
)
|
|
231
|
+
outputs[:, t, :] = h_t
|
|
232
|
+
hidden_states[:, t, :] = h_t
|
|
233
|
+
cell_states[:, t, :] = c_t
|
|
234
|
+
|
|
235
|
+
return outputs, hidden_states, cell_states
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ============================================================================
|
|
239
|
+
# GRU (GATED RECURRENT UNIT)
|
|
240
|
+
# ============================================================================
|
|
241
|
+
|
|
242
|
+
def gru_cell_forward(
|
|
243
|
+
x_t: np.ndarray,
|
|
244
|
+
h_prev: np.ndarray,
|
|
245
|
+
W_z: np.ndarray,
|
|
246
|
+
W_r: np.ndarray,
|
|
247
|
+
W_h: np.ndarray,
|
|
248
|
+
b_z: np.ndarray,
|
|
249
|
+
b_r: np.ndarray,
|
|
250
|
+
b_h: np.ndarray
|
|
251
|
+
) -> np.ndarray:
|
|
252
|
+
"""
|
|
253
|
+
Single timestep of GRU cell
|
|
254
|
+
|
|
255
|
+
GRU has two gates:
|
|
256
|
+
- Update gate: decides how much to update
|
|
257
|
+
- Reset gate: decides how much to forget
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
x_t: Input at timestep t, shape (batch, input_size)
|
|
261
|
+
h_prev: Previous hidden state, shape (batch, hidden_size)
|
|
262
|
+
W_z, W_r, W_h: Weight matrices for gates
|
|
263
|
+
b_z, b_r, b_h: Bias vectors for gates
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
h_t: New hidden state, shape (batch, hidden_size)
|
|
267
|
+
|
|
268
|
+
Example:
|
|
269
|
+
>>> x_t = np.random.randn(32, 128)
|
|
270
|
+
>>> h_prev = np.random.randn(32, 256)
|
|
271
|
+
>>> # Initialize weights...
|
|
272
|
+
>>> h_t = gru_cell_forward(x_t, h_prev, W_z, W_r, W_h, b_z, b_r, b_h)
|
|
273
|
+
>>> print(h_t.shape) # (32, 256)
|
|
274
|
+
"""
|
|
275
|
+
# Concatenate input and previous hidden state
|
|
276
|
+
concat = np.concatenate([h_prev, x_t], axis=1)
|
|
277
|
+
|
|
278
|
+
# Update gate
|
|
279
|
+
z_t = sigmoid(np.dot(concat, W_z) + b_z)
|
|
280
|
+
|
|
281
|
+
# Reset gate
|
|
282
|
+
r_t = sigmoid(np.dot(concat, W_r) + b_r)
|
|
283
|
+
|
|
284
|
+
# Candidate hidden state
|
|
285
|
+
concat_reset = np.concatenate([r_t * h_prev, x_t], axis=1)
|
|
286
|
+
h_tilde = np.tanh(np.dot(concat_reset, W_h) + b_h)
|
|
287
|
+
|
|
288
|
+
# New hidden state
|
|
289
|
+
h_t = (1 - z_t) * h_prev + z_t * h_tilde
|
|
290
|
+
|
|
291
|
+
return h_t
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def gru_forward(
|
|
295
|
+
x: np.ndarray,
|
|
296
|
+
h_0: np.ndarray,
|
|
297
|
+
W_z: np.ndarray,
|
|
298
|
+
W_r: np.ndarray,
|
|
299
|
+
W_h: np.ndarray,
|
|
300
|
+
b_z: np.ndarray,
|
|
301
|
+
b_r: np.ndarray,
|
|
302
|
+
b_h: np.ndarray
|
|
303
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
304
|
+
"""
|
|
305
|
+
Forward pass through entire GRU sequence
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
x: Input sequence, shape (batch, seq_len, input_size)
|
|
309
|
+
h_0: Initial hidden state, shape (batch, hidden_size)
|
|
310
|
+
W_z, W_r, W_h: Weight matrices
|
|
311
|
+
b_z, b_r, b_h: Bias vectors
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Tuple of (outputs, hidden_states)
|
|
315
|
+
- outputs: shape (batch, seq_len, hidden_size)
|
|
316
|
+
- hidden_states: shape (batch, seq_len, hidden_size)
|
|
317
|
+
|
|
318
|
+
Example:
|
|
319
|
+
>>> x = np.random.randn(32, 10, 128)
|
|
320
|
+
>>> h_0 = np.zeros((32, 256))
|
|
321
|
+
>>> # Initialize weights...
|
|
322
|
+
>>> outputs, hidden_states = gru_forward(x, h_0, W_z, W_r, W_h, b_z, b_r, b_h)
|
|
323
|
+
>>> print(outputs.shape) # (32, 10, 256)
|
|
324
|
+
"""
|
|
325
|
+
batch_size, seq_len, input_size = x.shape
|
|
326
|
+
hidden_size = h_0.shape[1]
|
|
327
|
+
|
|
328
|
+
# Initialize outputs
|
|
329
|
+
outputs = np.zeros((batch_size, seq_len, hidden_size))
|
|
330
|
+
hidden_states = np.zeros((batch_size, seq_len, hidden_size))
|
|
331
|
+
|
|
332
|
+
h_t = h_0
|
|
333
|
+
|
|
334
|
+
# Process sequence
|
|
335
|
+
for t in range(seq_len):
|
|
336
|
+
h_t = gru_cell_forward(
|
|
337
|
+
x[:, t, :], h_t,
|
|
338
|
+
W_z, W_r, W_h,
|
|
339
|
+
b_z, b_r, b_h
|
|
340
|
+
)
|
|
341
|
+
outputs[:, t, :] = h_t
|
|
342
|
+
hidden_states[:, t, :] = h_t
|
|
343
|
+
|
|
344
|
+
return outputs, hidden_states
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# ============================================================================
|
|
348
|
+
# BIDIRECTIONAL RNN
|
|
349
|
+
# ============================================================================
|
|
350
|
+
|
|
351
|
+
def bidirectional_rnn_forward(
|
|
352
|
+
x: np.ndarray,
|
|
353
|
+
h_0_forward: np.ndarray,
|
|
354
|
+
h_0_backward: np.ndarray,
|
|
355
|
+
W_xh_f: np.ndarray,
|
|
356
|
+
W_hh_f: np.ndarray,
|
|
357
|
+
b_h_f: np.ndarray,
|
|
358
|
+
W_xh_b: np.ndarray,
|
|
359
|
+
W_hh_b: np.ndarray,
|
|
360
|
+
b_h_b: np.ndarray
|
|
361
|
+
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
362
|
+
"""
|
|
363
|
+
Bidirectional RNN forward pass
|
|
364
|
+
|
|
365
|
+
Processes sequence in both forward and backward directions.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
x: Input sequence, shape (batch, seq_len, input_size)
|
|
369
|
+
h_0_forward: Initial forward hidden state
|
|
370
|
+
h_0_backward: Initial backward hidden state
|
|
371
|
+
W_xh_f, W_hh_f, b_h_f: Forward RNN parameters
|
|
372
|
+
W_xh_b, W_hh_b, b_h_b: Backward RNN parameters
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Tuple of (outputs, forward_states, backward_states)
|
|
376
|
+
- outputs: Concatenated forward and backward, shape (batch, seq_len, 2*hidden_size)
|
|
377
|
+
|
|
378
|
+
Example:
|
|
379
|
+
>>> x = np.random.randn(32, 10, 128)
|
|
380
|
+
>>> h_0_f = np.zeros((32, 256))
|
|
381
|
+
>>> h_0_b = np.zeros((32, 256))
|
|
382
|
+
>>> # Initialize weights...
|
|
383
|
+
>>> outputs, h_f, h_b = bidirectional_rnn_forward(x, h_0_f, h_0_b, W_xh_f, W_hh_f, b_h_f, W_xh_b, W_hh_b, b_h_b)
|
|
384
|
+
>>> print(outputs.shape) # (32, 10, 512)
|
|
385
|
+
"""
|
|
386
|
+
# Forward pass
|
|
387
|
+
forward_outputs, forward_states = rnn_forward(
|
|
388
|
+
x, h_0_forward, W_xh_f, W_hh_f, b_h_f
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# Backward pass (reverse sequence)
|
|
392
|
+
x_reversed = np.flip(x, axis=1)
|
|
393
|
+
backward_outputs, backward_states = rnn_forward(
|
|
394
|
+
x_reversed, h_0_backward, W_xh_b, W_hh_b, b_h_b
|
|
395
|
+
)
|
|
396
|
+
backward_outputs = np.flip(backward_outputs, axis=1)
|
|
397
|
+
backward_states = np.flip(backward_states, axis=1)
|
|
398
|
+
|
|
399
|
+
# Concatenate forward and backward
|
|
400
|
+
outputs = np.concatenate([forward_outputs, backward_outputs], axis=2)
|
|
401
|
+
|
|
402
|
+
return outputs, forward_states, backward_states
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
# ============================================================================
|
|
406
|
+
# UTILITY FUNCTIONS
|
|
407
|
+
# ============================================================================
|
|
408
|
+
|
|
409
|
+
def sigmoid(x: np.ndarray) -> np.ndarray:
|
|
410
|
+
"""
|
|
411
|
+
Sigmoid activation function
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
x: Input array
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
Sigmoid of input
|
|
418
|
+
"""
|
|
419
|
+
return 1 / (1 + np.exp(-np.clip(x, -500, 500)))
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def initialize_rnn_weights(
|
|
423
|
+
input_size: int,
|
|
424
|
+
hidden_size: int,
|
|
425
|
+
cell_type: str = 'rnn'
|
|
426
|
+
) -> dict:
|
|
427
|
+
"""
|
|
428
|
+
Initialize RNN weights
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
input_size: Size of input features
|
|
432
|
+
hidden_size: Size of hidden state
|
|
433
|
+
cell_type: Type of RNN cell ('rnn', 'lstm', 'gru')
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
Dictionary of initialized weights
|
|
437
|
+
|
|
438
|
+
Example:
|
|
439
|
+
>>> weights = initialize_rnn_weights(128, 256, cell_type='lstm')
|
|
440
|
+
>>> print(weights.keys())
|
|
441
|
+
"""
|
|
442
|
+
weights = {}
|
|
443
|
+
|
|
444
|
+
if cell_type == 'rnn':
|
|
445
|
+
weights['W_xh'] = np.random.randn(input_size, hidden_size) * 0.01
|
|
446
|
+
weights['W_hh'] = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
447
|
+
weights['b_h'] = np.zeros(hidden_size)
|
|
448
|
+
|
|
449
|
+
elif cell_type == 'lstm':
|
|
450
|
+
concat_size = hidden_size + input_size
|
|
451
|
+
weights['W_f'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
452
|
+
weights['W_i'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
453
|
+
weights['W_c'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
454
|
+
weights['W_o'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
455
|
+
weights['b_f'] = np.zeros(hidden_size)
|
|
456
|
+
weights['b_i'] = np.zeros(hidden_size)
|
|
457
|
+
weights['b_c'] = np.zeros(hidden_size)
|
|
458
|
+
weights['b_o'] = np.zeros(hidden_size)
|
|
459
|
+
|
|
460
|
+
elif cell_type == 'gru':
|
|
461
|
+
concat_size = hidden_size + input_size
|
|
462
|
+
weights['W_z'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
463
|
+
weights['W_r'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
464
|
+
weights['W_h'] = np.random.randn(concat_size, hidden_size) * 0.01
|
|
465
|
+
weights['b_z'] = np.zeros(hidden_size)
|
|
466
|
+
weights['b_r'] = np.zeros(hidden_size)
|
|
467
|
+
weights['b_h'] = np.zeros(hidden_size)
|
|
468
|
+
|
|
469
|
+
return weights
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def clip_gradients(gradients: np.ndarray, max_norm: float = 5.0) -> np.ndarray:
|
|
473
|
+
"""
|
|
474
|
+
Clip gradients to prevent exploding gradients
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
gradients: Gradient array
|
|
478
|
+
max_norm: Maximum gradient norm
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
Clipped gradients
|
|
482
|
+
|
|
483
|
+
Example:
|
|
484
|
+
>>> grads = np.random.randn(100, 100) * 10
|
|
485
|
+
>>> clipped = clip_gradients(grads, max_norm=5.0)
|
|
486
|
+
>>> print(np.linalg.norm(clipped)) # <= 5.0
|
|
487
|
+
"""
|
|
488
|
+
norm = np.linalg.norm(gradients)
|
|
489
|
+
if norm > max_norm:
|
|
490
|
+
gradients = gradients * (max_norm / norm)
|
|
491
|
+
return gradients
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
# Aliases for convenience
|
|
495
|
+
vanilla_rnn = rnn_forward
|
|
496
|
+
lstm = lstm_forward
|
|
497
|
+
gru = gru_forward
|
|
498
|
+
bidirectional_rnn = bidirectional_rnn_forward
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ilovetools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.20
|
|
4
4
|
Summary: A comprehensive Python utility library with modular tools for AI/ML, data processing, and daily programming needs
|
|
5
5
|
Home-page: https://github.com/AliMehdi512/ilovetools
|
|
6
6
|
Author: Ali Mehdi
|
|
@@ -11,7 +11,7 @@ Project-URL: Repository, https://github.com/AliMehdi512/ilovetools
|
|
|
11
11
|
Project-URL: Issues, https://github.com/AliMehdi512/ilovetools/issues
|
|
12
12
|
Project-URL: Bug Reports, https://github.com/AliMehdi512/ilovetools/issues
|
|
13
13
|
Project-URL: Source, https://github.com/AliMehdi512/ilovetools
|
|
14
|
-
Keywords: utilities,tools,ai,ml,data-processing,automation,
|
|
14
|
+
Keywords: utilities,tools,ai,ml,data-processing,automation,rnn,lstm,gru,recurrent-neural-networks,sequence-modeling,nlp
|
|
15
15
|
Classifier: Development Status :: 3 - Alpha
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -49,6 +49,7 @@ ilovetools/ml/normalization.py
|
|
|
49
49
|
ilovetools/ml/optimizers.py
|
|
50
50
|
ilovetools/ml/pipeline.py
|
|
51
51
|
ilovetools/ml/regularization.py
|
|
52
|
+
ilovetools/ml/rnn.py
|
|
52
53
|
ilovetools/ml/timeseries.py
|
|
53
54
|
ilovetools/ml/tuning.py
|
|
54
55
|
ilovetools/security/__init__.py
|
|
@@ -73,4 +74,5 @@ tests/test_loss_functions.py
|
|
|
73
74
|
tests/test_neural_network.py
|
|
74
75
|
tests/test_normalization.py
|
|
75
76
|
tests/test_optimizers.py
|
|
76
|
-
tests/test_regularization.py
|
|
77
|
+
tests/test_regularization.py
|
|
78
|
+
tests/test_rnn.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ilovetools"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.20"
|
|
8
8
|
description = "A comprehensive Python utility library with modular tools for AI/ML, data processing, and daily programming needs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -12,7 +12,7 @@ license = "MIT"
|
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "Ali Mehdi", email = "ali.mehdi.dev579@gmail.com"}
|
|
14
14
|
]
|
|
15
|
-
keywords = ["utilities", "tools", "ai", "ml", "data-processing", "automation", "
|
|
15
|
+
keywords = ["utilities", "tools", "ai", "ml", "data-processing", "automation", "rnn", "lstm", "gru", "recurrent-neural-networks", "sequence-modeling", "nlp"]
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 3 - Alpha",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="ilovetools",
|
|
8
|
-
version="0.2.
|
|
8
|
+
version="0.2.20",
|
|
9
9
|
author="Ali Mehdi",
|
|
10
10
|
author_email="ali.mehdi.dev579@gmail.com",
|
|
11
11
|
description="A comprehensive Python utility library with modular tools for AI/ML, data processing, and daily programming needs",
|
|
@@ -57,7 +57,7 @@ setup(
|
|
|
57
57
|
"soundfile>=0.12.0",
|
|
58
58
|
],
|
|
59
59
|
},
|
|
60
|
-
keywords="utilities, tools, ai, ml, data-processing, automation, python-library, neural-networks,
|
|
60
|
+
keywords="utilities, tools, ai, ml, data-processing, automation, python-library, neural-networks, rnn, lstm, gru, recurrent-neural-networks, sequence-modeling, nlp",
|
|
61
61
|
project_urls={
|
|
62
62
|
"Bug Reports": "https://github.com/AliMehdi512/ilovetools/issues",
|
|
63
63
|
"Source": "https://github.com/AliMehdi512/ilovetools",
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for RNN operations module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
# Add parent directory to path
|
|
10
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
11
|
+
|
|
12
|
+
from ilovetools.ml.rnn import (
|
|
13
|
+
# Basic RNN
|
|
14
|
+
rnn_cell_forward,
|
|
15
|
+
rnn_forward,
|
|
16
|
+
# LSTM
|
|
17
|
+
lstm_cell_forward,
|
|
18
|
+
lstm_forward,
|
|
19
|
+
# GRU
|
|
20
|
+
gru_cell_forward,
|
|
21
|
+
gru_forward,
|
|
22
|
+
# Bidirectional
|
|
23
|
+
bidirectional_rnn_forward,
|
|
24
|
+
# Utilities
|
|
25
|
+
sigmoid,
|
|
26
|
+
initialize_rnn_weights,
|
|
27
|
+
clip_gradients,
|
|
28
|
+
# Aliases
|
|
29
|
+
vanilla_rnn,
|
|
30
|
+
lstm,
|
|
31
|
+
gru,
|
|
32
|
+
bidirectional_rnn,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_rnn_cell_forward():
|
|
37
|
+
"""Test basic RNN cell forward pass"""
|
|
38
|
+
print("Testing rnn_cell_forward...")
|
|
39
|
+
|
|
40
|
+
batch_size = 32
|
|
41
|
+
input_size = 128
|
|
42
|
+
hidden_size = 256
|
|
43
|
+
|
|
44
|
+
x_t = np.random.randn(batch_size, input_size)
|
|
45
|
+
h_prev = np.random.randn(batch_size, hidden_size)
|
|
46
|
+
W_xh = np.random.randn(input_size, hidden_size) * 0.01
|
|
47
|
+
W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
48
|
+
b_h = np.zeros(hidden_size)
|
|
49
|
+
|
|
50
|
+
h_t = rnn_cell_forward(x_t, h_prev, W_xh, W_hh, b_h)
|
|
51
|
+
|
|
52
|
+
assert h_t.shape == (batch_size, hidden_size), "Output shape incorrect"
|
|
53
|
+
assert np.all(np.abs(h_t) <= 1.0), "tanh output should be in [-1, 1]"
|
|
54
|
+
|
|
55
|
+
print("✓ rnn_cell_forward passed")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_rnn_forward():
|
|
59
|
+
"""Test basic RNN forward pass"""
|
|
60
|
+
print("Testing rnn_forward...")
|
|
61
|
+
|
|
62
|
+
batch_size = 32
|
|
63
|
+
seq_len = 10
|
|
64
|
+
input_size = 128
|
|
65
|
+
hidden_size = 256
|
|
66
|
+
|
|
67
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
68
|
+
h_0 = np.zeros((batch_size, hidden_size))
|
|
69
|
+
W_xh = np.random.randn(input_size, hidden_size) * 0.01
|
|
70
|
+
W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
71
|
+
b_h = np.zeros(hidden_size)
|
|
72
|
+
|
|
73
|
+
outputs, hidden_states = rnn_forward(x, h_0, W_xh, W_hh, b_h)
|
|
74
|
+
|
|
75
|
+
assert outputs.shape == (batch_size, seq_len, hidden_size), "Outputs shape incorrect"
|
|
76
|
+
assert hidden_states.shape == (batch_size, seq_len, hidden_size), "Hidden states shape incorrect"
|
|
77
|
+
|
|
78
|
+
print("✓ rnn_forward passed")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_lstm_cell_forward():
|
|
82
|
+
"""Test LSTM cell forward pass"""
|
|
83
|
+
print("Testing lstm_cell_forward...")
|
|
84
|
+
|
|
85
|
+
batch_size = 32
|
|
86
|
+
input_size = 128
|
|
87
|
+
hidden_size = 256
|
|
88
|
+
|
|
89
|
+
x_t = np.random.randn(batch_size, input_size)
|
|
90
|
+
h_prev = np.random.randn(batch_size, hidden_size)
|
|
91
|
+
c_prev = np.random.randn(batch_size, hidden_size)
|
|
92
|
+
|
|
93
|
+
# Initialize weights
|
|
94
|
+
concat_size = hidden_size + input_size
|
|
95
|
+
W_f = np.random.randn(concat_size, hidden_size) * 0.01
|
|
96
|
+
W_i = np.random.randn(concat_size, hidden_size) * 0.01
|
|
97
|
+
W_c = np.random.randn(concat_size, hidden_size) * 0.01
|
|
98
|
+
W_o = np.random.randn(concat_size, hidden_size) * 0.01
|
|
99
|
+
b_f = np.zeros(hidden_size)
|
|
100
|
+
b_i = np.zeros(hidden_size)
|
|
101
|
+
b_c = np.zeros(hidden_size)
|
|
102
|
+
b_o = np.zeros(hidden_size)
|
|
103
|
+
|
|
104
|
+
h_t, c_t = lstm_cell_forward(x_t, h_prev, c_prev, W_f, W_i, W_c, W_o, b_f, b_i, b_c, b_o)
|
|
105
|
+
|
|
106
|
+
assert h_t.shape == (batch_size, hidden_size), "Hidden state shape incorrect"
|
|
107
|
+
assert c_t.shape == (batch_size, hidden_size), "Cell state shape incorrect"
|
|
108
|
+
|
|
109
|
+
print("✓ lstm_cell_forward passed")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_lstm_forward():
|
|
113
|
+
"""Test LSTM forward pass"""
|
|
114
|
+
print("Testing lstm_forward...")
|
|
115
|
+
|
|
116
|
+
batch_size = 32
|
|
117
|
+
seq_len = 10
|
|
118
|
+
input_size = 128
|
|
119
|
+
hidden_size = 256
|
|
120
|
+
|
|
121
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
122
|
+
h_0 = np.zeros((batch_size, hidden_size))
|
|
123
|
+
c_0 = np.zeros((batch_size, hidden_size))
|
|
124
|
+
|
|
125
|
+
# Initialize weights
|
|
126
|
+
concat_size = hidden_size + input_size
|
|
127
|
+
W_f = np.random.randn(concat_size, hidden_size) * 0.01
|
|
128
|
+
W_i = np.random.randn(concat_size, hidden_size) * 0.01
|
|
129
|
+
W_c = np.random.randn(concat_size, hidden_size) * 0.01
|
|
130
|
+
W_o = np.random.randn(concat_size, hidden_size) * 0.01
|
|
131
|
+
b_f = np.zeros(hidden_size)
|
|
132
|
+
b_i = np.zeros(hidden_size)
|
|
133
|
+
b_c = np.zeros(hidden_size)
|
|
134
|
+
b_o = np.zeros(hidden_size)
|
|
135
|
+
|
|
136
|
+
outputs, hidden_states, cell_states = lstm_forward(
|
|
137
|
+
x, h_0, c_0, W_f, W_i, W_c, W_o, b_f, b_i, b_c, b_o
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
assert outputs.shape == (batch_size, seq_len, hidden_size), "Outputs shape incorrect"
|
|
141
|
+
assert hidden_states.shape == (batch_size, seq_len, hidden_size), "Hidden states shape incorrect"
|
|
142
|
+
assert cell_states.shape == (batch_size, seq_len, hidden_size), "Cell states shape incorrect"
|
|
143
|
+
|
|
144
|
+
print("✓ lstm_forward passed")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_gru_cell_forward():
|
|
148
|
+
"""Test GRU cell forward pass"""
|
|
149
|
+
print("Testing gru_cell_forward...")
|
|
150
|
+
|
|
151
|
+
batch_size = 32
|
|
152
|
+
input_size = 128
|
|
153
|
+
hidden_size = 256
|
|
154
|
+
|
|
155
|
+
x_t = np.random.randn(batch_size, input_size)
|
|
156
|
+
h_prev = np.random.randn(batch_size, hidden_size)
|
|
157
|
+
|
|
158
|
+
# Initialize weights
|
|
159
|
+
concat_size = hidden_size + input_size
|
|
160
|
+
W_z = np.random.randn(concat_size, hidden_size) * 0.01
|
|
161
|
+
W_r = np.random.randn(concat_size, hidden_size) * 0.01
|
|
162
|
+
W_h = np.random.randn(concat_size, hidden_size) * 0.01
|
|
163
|
+
b_z = np.zeros(hidden_size)
|
|
164
|
+
b_r = np.zeros(hidden_size)
|
|
165
|
+
b_h = np.zeros(hidden_size)
|
|
166
|
+
|
|
167
|
+
h_t = gru_cell_forward(x_t, h_prev, W_z, W_r, W_h, b_z, b_r, b_h)
|
|
168
|
+
|
|
169
|
+
assert h_t.shape == (batch_size, hidden_size), "Hidden state shape incorrect"
|
|
170
|
+
|
|
171
|
+
print("✓ gru_cell_forward passed")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_gru_forward():
|
|
175
|
+
"""Test GRU forward pass"""
|
|
176
|
+
print("Testing gru_forward...")
|
|
177
|
+
|
|
178
|
+
batch_size = 32
|
|
179
|
+
seq_len = 10
|
|
180
|
+
input_size = 128
|
|
181
|
+
hidden_size = 256
|
|
182
|
+
|
|
183
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
184
|
+
h_0 = np.zeros((batch_size, hidden_size))
|
|
185
|
+
|
|
186
|
+
# Initialize weights
|
|
187
|
+
concat_size = hidden_size + input_size
|
|
188
|
+
W_z = np.random.randn(concat_size, hidden_size) * 0.01
|
|
189
|
+
W_r = np.random.randn(concat_size, hidden_size) * 0.01
|
|
190
|
+
W_h = np.random.randn(concat_size, hidden_size) * 0.01
|
|
191
|
+
b_z = np.zeros(hidden_size)
|
|
192
|
+
b_r = np.zeros(hidden_size)
|
|
193
|
+
b_h = np.zeros(hidden_size)
|
|
194
|
+
|
|
195
|
+
outputs, hidden_states = gru_forward(x, h_0, W_z, W_r, W_h, b_z, b_r, b_h)
|
|
196
|
+
|
|
197
|
+
assert outputs.shape == (batch_size, seq_len, hidden_size), "Outputs shape incorrect"
|
|
198
|
+
assert hidden_states.shape == (batch_size, seq_len, hidden_size), "Hidden states shape incorrect"
|
|
199
|
+
|
|
200
|
+
print("✓ gru_forward passed")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_bidirectional_rnn_forward():
|
|
204
|
+
"""Test bidirectional RNN forward pass"""
|
|
205
|
+
print("Testing bidirectional_rnn_forward...")
|
|
206
|
+
|
|
207
|
+
batch_size = 32
|
|
208
|
+
seq_len = 10
|
|
209
|
+
input_size = 128
|
|
210
|
+
hidden_size = 256
|
|
211
|
+
|
|
212
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
213
|
+
h_0_f = np.zeros((batch_size, hidden_size))
|
|
214
|
+
h_0_b = np.zeros((batch_size, hidden_size))
|
|
215
|
+
|
|
216
|
+
# Initialize weights for forward and backward
|
|
217
|
+
W_xh_f = np.random.randn(input_size, hidden_size) * 0.01
|
|
218
|
+
W_hh_f = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
219
|
+
b_h_f = np.zeros(hidden_size)
|
|
220
|
+
|
|
221
|
+
W_xh_b = np.random.randn(input_size, hidden_size) * 0.01
|
|
222
|
+
W_hh_b = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
223
|
+
b_h_b = np.zeros(hidden_size)
|
|
224
|
+
|
|
225
|
+
outputs, forward_states, backward_states = bidirectional_rnn_forward(
|
|
226
|
+
x, h_0_f, h_0_b, W_xh_f, W_hh_f, b_h_f, W_xh_b, W_hh_b, b_h_b
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Output should be concatenation of forward and backward (2 * hidden_size)
|
|
230
|
+
assert outputs.shape == (batch_size, seq_len, 2 * hidden_size), "Outputs shape incorrect"
|
|
231
|
+
assert forward_states.shape == (batch_size, seq_len, hidden_size), "Forward states shape incorrect"
|
|
232
|
+
assert backward_states.shape == (batch_size, seq_len, hidden_size), "Backward states shape incorrect"
|
|
233
|
+
|
|
234
|
+
print("✓ bidirectional_rnn_forward passed")
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def test_sigmoid():
|
|
238
|
+
"""Test sigmoid function"""
|
|
239
|
+
print("Testing sigmoid...")
|
|
240
|
+
|
|
241
|
+
x = np.array([-1000, -1, 0, 1, 1000])
|
|
242
|
+
result = sigmoid(x)
|
|
243
|
+
|
|
244
|
+
assert np.all(result >= 0) and np.all(result <= 1), "Sigmoid should be in [0, 1]"
|
|
245
|
+
assert np.isclose(result[2], 0.5), "Sigmoid(0) should be 0.5"
|
|
246
|
+
|
|
247
|
+
print("✓ sigmoid passed")
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def test_initialize_rnn_weights():
|
|
251
|
+
"""Test RNN weight initialization"""
|
|
252
|
+
print("Testing initialize_rnn_weights...")
|
|
253
|
+
|
|
254
|
+
input_size = 128
|
|
255
|
+
hidden_size = 256
|
|
256
|
+
|
|
257
|
+
# Test RNN weights
|
|
258
|
+
weights_rnn = initialize_rnn_weights(input_size, hidden_size, cell_type='rnn')
|
|
259
|
+
assert 'W_xh' in weights_rnn, "RNN weights should have W_xh"
|
|
260
|
+
assert 'W_hh' in weights_rnn, "RNN weights should have W_hh"
|
|
261
|
+
assert 'b_h' in weights_rnn, "RNN weights should have b_h"
|
|
262
|
+
|
|
263
|
+
# Test LSTM weights
|
|
264
|
+
weights_lstm = initialize_rnn_weights(input_size, hidden_size, cell_type='lstm')
|
|
265
|
+
assert 'W_f' in weights_lstm, "LSTM weights should have W_f"
|
|
266
|
+
assert 'W_i' in weights_lstm, "LSTM weights should have W_i"
|
|
267
|
+
assert 'W_c' in weights_lstm, "LSTM weights should have W_c"
|
|
268
|
+
assert 'W_o' in weights_lstm, "LSTM weights should have W_o"
|
|
269
|
+
|
|
270
|
+
# Test GRU weights
|
|
271
|
+
weights_gru = initialize_rnn_weights(input_size, hidden_size, cell_type='gru')
|
|
272
|
+
assert 'W_z' in weights_gru, "GRU weights should have W_z"
|
|
273
|
+
assert 'W_r' in weights_gru, "GRU weights should have W_r"
|
|
274
|
+
assert 'W_h' in weights_gru, "GRU weights should have W_h"
|
|
275
|
+
|
|
276
|
+
print("✓ initialize_rnn_weights passed")
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def test_clip_gradients():
|
|
280
|
+
"""Test gradient clipping"""
|
|
281
|
+
print("Testing clip_gradients...")
|
|
282
|
+
|
|
283
|
+
# Create large gradients
|
|
284
|
+
grads = np.random.randn(100, 100) * 10
|
|
285
|
+
|
|
286
|
+
# Clip to max norm 5.0
|
|
287
|
+
clipped = clip_gradients(grads, max_norm=5.0)
|
|
288
|
+
|
|
289
|
+
norm = np.linalg.norm(clipped)
|
|
290
|
+
assert norm <= 5.0, "Clipped gradient norm should be <= max_norm"
|
|
291
|
+
|
|
292
|
+
# Test with small gradients (should not clip)
|
|
293
|
+
small_grads = np.random.randn(10, 10) * 0.1
|
|
294
|
+
clipped_small = clip_gradients(small_grads, max_norm=5.0)
|
|
295
|
+
assert np.allclose(small_grads, clipped_small), "Small gradients should not be clipped"
|
|
296
|
+
|
|
297
|
+
print("✓ clip_gradients passed")
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def test_aliases():
|
|
301
|
+
"""Test function aliases"""
|
|
302
|
+
print("Testing aliases...")
|
|
303
|
+
|
|
304
|
+
batch_size = 8
|
|
305
|
+
seq_len = 5
|
|
306
|
+
input_size = 64
|
|
307
|
+
hidden_size = 128
|
|
308
|
+
|
|
309
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
310
|
+
h_0 = np.zeros((batch_size, hidden_size))
|
|
311
|
+
|
|
312
|
+
# Test vanilla_rnn alias
|
|
313
|
+
W_xh = np.random.randn(input_size, hidden_size) * 0.01
|
|
314
|
+
W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
315
|
+
b_h = np.zeros(hidden_size)
|
|
316
|
+
|
|
317
|
+
out1, h1 = vanilla_rnn(x, h_0, W_xh, W_hh, b_h)
|
|
318
|
+
out2, h2 = rnn_forward(x, h_0, W_xh, W_hh, b_h)
|
|
319
|
+
assert np.allclose(out1, out2), "vanilla_rnn alias should work"
|
|
320
|
+
|
|
321
|
+
print("✓ aliases passed")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def test_rnn_sequence_processing():
|
|
325
|
+
"""Test that RNN processes sequences correctly"""
|
|
326
|
+
print("Testing RNN sequence processing...")
|
|
327
|
+
|
|
328
|
+
batch_size = 4
|
|
329
|
+
seq_len = 5
|
|
330
|
+
input_size = 32
|
|
331
|
+
hidden_size = 64
|
|
332
|
+
|
|
333
|
+
x = np.random.randn(batch_size, seq_len, input_size)
|
|
334
|
+
h_0 = np.zeros((batch_size, hidden_size))
|
|
335
|
+
W_xh = np.random.randn(input_size, hidden_size) * 0.01
|
|
336
|
+
W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
|
|
337
|
+
b_h = np.zeros(hidden_size)
|
|
338
|
+
|
|
339
|
+
outputs, hidden_states = rnn_forward(x, h_0, W_xh, W_hh, b_h)
|
|
340
|
+
|
|
341
|
+
# Check that each timestep depends on previous
|
|
342
|
+
# (outputs should be different at each timestep)
|
|
343
|
+
assert not np.allclose(outputs[:, 0, :], outputs[:, 1, :]), "Outputs should differ across timesteps"
|
|
344
|
+
|
|
345
|
+
print("✓ RNN sequence processing passed")
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def test_lstm_gates():
|
|
349
|
+
"""Test that LSTM gates work correctly"""
|
|
350
|
+
print("Testing LSTM gates...")
|
|
351
|
+
|
|
352
|
+
batch_size = 4
|
|
353
|
+
input_size = 32
|
|
354
|
+
hidden_size = 64
|
|
355
|
+
|
|
356
|
+
x_t = np.random.randn(batch_size, input_size)
|
|
357
|
+
h_prev = np.random.randn(batch_size, hidden_size)
|
|
358
|
+
c_prev = np.random.randn(batch_size, hidden_size)
|
|
359
|
+
|
|
360
|
+
# Initialize weights
|
|
361
|
+
concat_size = hidden_size + input_size
|
|
362
|
+
W_f = np.random.randn(concat_size, hidden_size) * 0.01
|
|
363
|
+
W_i = np.random.randn(concat_size, hidden_size) * 0.01
|
|
364
|
+
W_c = np.random.randn(concat_size, hidden_size) * 0.01
|
|
365
|
+
W_o = np.random.randn(concat_size, hidden_size) * 0.01
|
|
366
|
+
b_f = np.zeros(hidden_size)
|
|
367
|
+
b_i = np.zeros(hidden_size)
|
|
368
|
+
b_c = np.zeros(hidden_size)
|
|
369
|
+
b_o = np.zeros(hidden_size)
|
|
370
|
+
|
|
371
|
+
h_t, c_t = lstm_cell_forward(x_t, h_prev, c_prev, W_f, W_i, W_c, W_o, b_f, b_i, b_c, b_o)
|
|
372
|
+
|
|
373
|
+
# Cell state should be updated
|
|
374
|
+
assert not np.allclose(c_t, c_prev), "Cell state should be updated"
|
|
375
|
+
|
|
376
|
+
# Hidden state should be different from previous
|
|
377
|
+
assert not np.allclose(h_t, h_prev), "Hidden state should be updated"
|
|
378
|
+
|
|
379
|
+
print("✓ LSTM gates passed")
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def run_all_tests():
|
|
383
|
+
"""Run all tests"""
|
|
384
|
+
print("\n" + "="*60)
|
|
385
|
+
print("RNN OPERATIONS MODULE TESTS")
|
|
386
|
+
print("="*60 + "\n")
|
|
387
|
+
|
|
388
|
+
# Basic RNN tests
|
|
389
|
+
test_rnn_cell_forward()
|
|
390
|
+
test_rnn_forward()
|
|
391
|
+
test_rnn_sequence_processing()
|
|
392
|
+
|
|
393
|
+
# LSTM tests
|
|
394
|
+
test_lstm_cell_forward()
|
|
395
|
+
test_lstm_forward()
|
|
396
|
+
test_lstm_gates()
|
|
397
|
+
|
|
398
|
+
# GRU tests
|
|
399
|
+
test_gru_cell_forward()
|
|
400
|
+
test_gru_forward()
|
|
401
|
+
|
|
402
|
+
# Bidirectional tests
|
|
403
|
+
test_bidirectional_rnn_forward()
|
|
404
|
+
|
|
405
|
+
# Utility tests
|
|
406
|
+
test_sigmoid()
|
|
407
|
+
test_initialize_rnn_weights()
|
|
408
|
+
test_clip_gradients()
|
|
409
|
+
|
|
410
|
+
# Aliases
|
|
411
|
+
test_aliases()
|
|
412
|
+
|
|
413
|
+
print("\n" + "="*60)
|
|
414
|
+
print("ALL TESTS PASSED! ✓")
|
|
415
|
+
print("="*60 + "\n")
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
if __name__ == "__main__":
|
|
419
|
+
run_all_tests()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ilovetools-0.2.19 → ilovetools-0.2.20}/ilovetools/conversion/config_converter_fixed_header.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|