2323class RBM :
2424 def __init__ (
2525 self ,
26- n_visible ,
27- n_hidden ,
28- learning_rate = 0.01 ,
29- k = 1 ,
30- epochs = 10 ,
31- batch_size = 64 ,
32- mode = "bernoulli" ,
33- ):
26+ n_visible : int ,
27+ n_hidden : int ,
28+ learning_rate : float = 0.01 ,
29+ k : int = 1 ,
30+ epochs : int = 10 ,
31+ batch_size : int = 64 ,
32+ mode : str = "bernoulli" ,
33+ ) -> None :
3434 """
3535 Initialize an RBM (Restricted Boltzmann Machine).
3636
@@ -58,7 +58,7 @@ def __init__(
5858 self .hidden_bias = np .zeros (n_hidden )
5959 self .visible_bias = np .zeros (n_visible )
6060
61- def sigmoid (self , x ) :
61+ def sigmoid (self , x : np . ndarray ) -> np . ndarray :
6262 """
6363 Compute the sigmoid activation function element-wise.
6464
@@ -67,10 +67,19 @@ def sigmoid(self, x):
6767
6868 Returns:
6969 np.ndarray: Sigmoid output of input.
70+
71+ >>> rbm = RBM(3, 2)
72+ >>> import numpy as np
73+ >>> np.allclose(
74+ ... dbn.sigmoid(np.array([0, 1])),
75+ ... np.array([0.5, 1/(1+np.exp(-1))])
76+ ... )
77+ True
78+
7079 """
7180 return 1.0 / (1.0 + np .exp (- x ))
7281
73- def sample_prob (self , probs ) :
82+ def sample_prob (self , probs : np . ndarray ) -> np . ndarray :
7483 """
7584 Sample binary states from given probabilities.
7685
@@ -79,10 +88,18 @@ def sample_prob(self, probs):
7988
8089 Returns:
8190 np.ndarray: Binary sampled values.
91+
92+ >>> rbm = RBM(3, 2)
93+ >>> probs = np.array([0., 1.])
94+ >>> result = rbm.sample_prob(probs)
95+ >>> set(result).issubset({0., 1.})
96+ True
8297 """
8398 return (self .rng .random (probs .shape ) < probs ).astype (float )
8499
85- def sample_hidden_given_visible (self , v ):
100+ def sample_hidden_given_visible (
101+ self , v : np .ndarray
102+ ) -> tuple [np .ndarray , np .ndarray ]:
86103 """
87104 Sample hidden units conditioned on visible units.
88105
@@ -96,7 +113,9 @@ def sample_hidden_given_visible(self, v):
96113 hid_samples = self .sample_prob (hid_probs )
97114 return hid_probs , hid_samples
98115
99- def sample_visible_given_hidden (self , h ):
116+ def sample_visible_given_hidden (
117+ self , h : np .ndarray
118+ ) -> tuple [np .ndarray , np .ndarray ]:
100119 """
101120 Sample visible units conditioned on hidden units.
102121
@@ -110,7 +129,7 @@ def sample_visible_given_hidden(self, h):
110129 vis_samples = self .sample_prob (vis_probs )
111130 return vis_probs , vis_samples
112131
113- def contrastive_divergence (self , v0 ) :
132+ def contrastive_divergence (self , v0 : np . ndarray ) -> float :
114133 """
115134 Perform Contrastive Divergence (CD-k) for a single batch.
116135
@@ -139,12 +158,16 @@ def contrastive_divergence(self, v0):
139158 loss = np .mean ((v0 - vk ) ** 2 )
140159 return loss
141160
142- def train (self , data ) :
161+ def train (self , data : np . ndarray ) -> None :
143162 """
144163 Train the RBM on the entire dataset.
145164
146165 Args:
147166 data (np.ndarray): Training dataset matrix.
167+
168+ >>> rbm = RBM(6, 3, epochs=1, batch_size=2)
169+ >>> data = np.random.randint(0, 2, (4, 6)).astype(float)
170+ >>> rbm.train(data) # runs without error
148171 """
149172 n_samples = data .shape [0 ]
150173 for epoch in range (self .epochs ):
@@ -160,16 +183,24 @@ def train(self, data):
160183
161184
162185class DeepBeliefNetwork :
163- def __init__ (self , input_size , layers , mode = "bernoulli" , k = 5 , save_path = None ):
186+ def __init__ (
187+ self ,
188+ input_size : int ,
189+ layers : list [int ],
190+ mode : str = "bernoulli" ,
191+ k : int = 5 ,
192+ save_path : str | None = None ,
193+ ) -> None :
164194 """
165195 Initialize a Deep Belief Network (DBN) with multiple RBM layers.
166196
167197 Args:
168198 input_size (int): Number of features in input layer.
169- layers (list): List of hidden layer unit counts.
199+ layers (list): list of hidden layer unit counts.
170200 mode (str): Sampling mode ('bernoulli' or 'gaussian').
171201 k (int): Number of sampling steps in generate_input_for_layer.
172- save_path (str): Path for saving trained model parameters (optional).
202+ save_path (str, optional): Path for saving trained model parameters.
203+
173204 """
174205 self .input_size = input_size
175206 self .layers = layers
@@ -178,7 +209,7 @@ def __init__(self, input_size, layers, mode="bernoulli", k=5, save_path=None):
178209 self .save_path = save_path
179210 self .layer_params = [{"W" : None , "hb" : None , "vb" : None } for _ in layers ]
180211
181- def sigmoid (self , x ) :
212+ def sigmoid (self , x : np . ndarray ) -> np . ndarray :
182213 """
183214 Compute sigmoid activation function.
184215
@@ -187,10 +218,19 @@ def sigmoid(self, x):
187218
188219 Returns:
189220 np.ndarray: Sigmoid of input.
221+
222+ >>> dbn = DeepBeliefNetwork(4, [3])
223+ >>> import numpy as np
224+ >>> np.allclose(
225+ ... dbn.sigmoid(np.array([0, 1])),
226+ ... np.array([0.5, 1/(1+np.exp(-1))])
227+ ... )
228+ True
229+
190230 """
191231 return 1.0 / (1.0 + np .exp (- x ))
192232
193- def sample_prob (self , probs ) :
233+ def sample_prob (self , probs : np . ndarray ) -> np . ndarray :
194234 """
195235 Sample binary states from probabilities.
196236
@@ -203,7 +243,9 @@ def sample_prob(self, probs):
203243 rng = np .random .default_rng ()
204244 return (rng .random (probs .shape ) < probs ).astype (float )
205245
206- def sample_h (self , x , w , hb ):
246+ def sample_h (
247+ self , x : np .ndarray , w : np .ndarray , hb : np .ndarray
248+ ) -> tuple [np .ndarray , np .ndarray ]:
207249 """
208250 Sample hidden units given visible units for a DBN layer.
209251
@@ -219,7 +261,9 @@ def sample_h(self, x, w, hb):
219261 samples = self .sample_prob (probs )
220262 return probs , samples
221263
222- def sample_v (self , y , w , vb ):
264+ def sample_v (
265+ self , y : np .ndarray , w : np .ndarray , vb : np .ndarray
266+ ) -> tuple [np .ndarray , np .ndarray ]:
223267 """
224268 Sample visible units given hidden units for a DBN layer.
225269
@@ -235,7 +279,7 @@ def sample_v(self, y, w, vb):
235279 samples = self .sample_prob (probs )
236280 return probs , samples
237281
238- def generate_input_for_layer (self , layer_index , x ) :
282+ def generate_input_for_layer (self , layer_index : int , x : np . ndarray ) -> np . ndarray :
239283 """
240284 Generate input for a particular DBN layer by sampling and averaging.
241285
@@ -258,7 +302,7 @@ def generate_input_for_layer(self, layer_index, x):
258302 samples .append (x_dash )
259303 return np .mean (np .stack (samples , axis = 0 ), axis = 0 )
260304
261- def train_dbn (self , x ) :
305+ def train_dbn (self , x : np . ndarray ) -> None :
262306 """
263307 Layer-wise train the DBN using RBMs.
264308
@@ -277,7 +321,7 @@ def train_dbn(self, x):
277321 self .layer_params [idx ]["vb" ] = rbm .visible_bias
278322 print (f"Finished training layer { idx + 1 } /{ len (self .layers )} " )
279323
280- def reconstruct (self , x ) :
324+ def reconstruct (self , x : np . ndarray ) -> tuple [ np . ndarray , np . ndarray , float ] :
281325 """
282326 Reconstruct input through forward and backward Gibbs sampling.
283327
0 commit comments