From 176ed663c1251037dd94397287921e9316fe4c09 Mon Sep 17 00:00:00 2001
From: romanamo <r-schoene@gmx.net>
Date: Thu, 9 May 2024 01:12:49 +0200
Subject: [PATCH] finalized code + cleanup

---
 uebungen/uebung3.py | 86 ++++++++++++++++++++++++++-------------------
 1 file changed, 49 insertions(+), 37 deletions(-)

diff --git a/uebungen/uebung3.py b/uebungen/uebung3.py
index 5aa1627..f65dd85 100644
--- a/uebungen/uebung3.py
+++ b/uebungen/uebung3.py
@@ -1,5 +1,3 @@
-from typing import Tuple
-
 import numpy as np
 import pandas as pd
 import matplotlib.pyplot as plt
@@ -7,95 +5,109 @@ import matplotlib.pyplot as plt
 
 def load_data():
     df_orig_train = pd.read_csv('mnist_test_final.csv')
-    df_digits = df_orig_train.drop('label',axis=1)
+    df_digits = df_orig_train.drop('label', axis=1)
 
     return df_digits.to_numpy()
 
+
 mnist = load_data()
 
+
 def sigmoid(x):
     return 1.0 / (1.0 + np.exp(-x))  # Sigmoidfunktion
 
+
 class RBM:
 
-    def __init__(self, visible_size: int, hidden_size: int, learnrate: float=0.1) -> None:
+    def __init__(self, visible_size: int, hidden_size: int, learnrate: float = 0.1, epochs=20):
+        """__init__ Initializes a newly created Ristricted Bolzmann Machine.
+
+        Args:
+            visible_size (int): amount of neurons inside the visible layer
+            hidden_size (int): amount of neurons inside the hidden layer
+            learnrate (float, optional): learnrate eta in [0;1]. Defaults to 0.1.
+            epochs (int, optional): training epochs. Defaults to 20.
+        """
         self.learnrate = learnrate
         self.visible_size = visible_size
         self.hidden_size = hidden_size
-        self.k = 2
-        self.epochs = 10
+        self.epochs = epochs
 
         self.reset()
 
-    def reset(self) -> None:
+    def reset(self):
+        # initialize/reset learnable attributes
         self.weights = np.random.randn(self.visible_size, self.hidden_size)
         self.visible_bias = np.zeros(self.visible_size) * 0.1
         self.hidden_bias = np.zeros(self.hidden_size) * 0.1
 
     def activate(self, v0):
         return sigmoid(np.matmul(v0.T, self.weights) + self.hidden_bias)
-        
+
     def reactivate(self, h0):
         return sigmoid(np.matmul(self.weights, h0.T) + self.visible_bias)
-    
+
     def contrastive_divergence(self, v0, h0, v1, h1):
+        # calculate gradients
         postive_gradient = np.outer(v0, h0)
         negative_gradient = np.outer(v1, h0)
 
+        # Adjust weights by delta
         self.weights += self.learnrate * (postive_gradient - negative_gradient)
 
-        return self.weights
-        
+        # Adjust biases by delta
+        self.visible_bias += self.learnrate * (v0 - v1)
+        self.hidden_bias += self.learnrate * (h0 - h1)
+
     def train(self, v0):
         for _ in range(self.epochs):
-            h0 = self.activate(v0) # Aktivieren versteckter Schicht
-            v1 = self.reactivate(h0) # Reaktivieren sichtbarer Schicht
+            # activate hidden layer
+            h0 = self.activate(v0)
+
+            # reactivate visible layer 
+            v1 = self.reactivate(h0)
+            
+            #activate next hidden layer
             h1 = self.activate(v1)
 
+            # Adjust weights
             self.contrastive_divergence(v0, h0, v1, h1)
-            
-            self.visible_bias += self.learnrate * (v0 - v1)
-            self.hidden_bias += self.learnrate * (h0 - h1)
 
-
-        return h0, v1
-
-    def run(self, v0 : np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
-        """run Runs the Restricted Boltzmann machine on some input vector v0.
-
-        Args:
-            v0 (np.ndarray): 1-dimensional Input vector
-
-        Returns:
-            Tuple[np.ndarray, np.ndarray]: (hidden activation, visible reactivation)
-        """
+    def run(self, v0):
+        # activate hidden layer
         h0 = self.activate(v0)
         v1 = self.reactivate(h0)
 
         return h0, v1
 
+rbm = RBM(28**2, 256, 0.1, epochs=3)
 
 def validate(idx):
-
+    #flatten and normalize mnist data
     test = mnist[idx].flatten()/255
+
+    # train bolzmann machine and run
     rbm.train(test)
     (hid, out) = rbm.run(test)
 
-    return (hid.reshape((5, 5)), out.reshape((28,28)))
+    return (hid.reshape((16, 16)), out.reshape((28, 28)))
 
-
-rbm = RBM(28**2, 25, 0.1)
-
-rows, columns = (4,4)
+# plot results
+rows, columns = (4, 6)
 fig = plt.figure(figsize=(10, 7))
+
 for i in range((rows * columns)):
     if i % 2 == 0:
         (hid, out) = validate(i)
-        fig.add_subplot(rows, columns, i+1) 
+
+        # hidden layer
+        fig.add_subplot(rows, columns, i+1)
         plt.imshow(hid, cmap='gray')
-        fig.add_subplot(rows, columns,  i+2) 
+        plt.axis('off')
+
+        # visible layer
+        fig.add_subplot(rows, columns,  i+2)
         plt.imshow(out, cmap='gray')
         plt.axis('off')
 
 plt.show()
-