Advertisement
mirosh111000

Застосування нейронної мережi Кохонена з фiксованою структурою для кластеризацiї об’єктiв(pr10)

Nov 25th, 2024
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.43 KB | None | 0 0
  1. import numpy as np
  2. import tensorflow as tf
  3. import matplotlib.pyplot as plt
  4. import datetime as dt
  5. import os
  6. import pandas as pd
  7. from IPython.display import clear_output
  8. import numpy as np
  9. from sklearn.preprocessing import MinMaxScaler
  10. from imblearn.under_sampling import RandomUnderSampler
  11. import seaborn as sns
  12.  
  13.  
  14. class KohonenNetwork:
  15.     def __init__(self, M, N, eta_0=0.5, s_c=1, max_epochs=20, epsilon=0.001, input_range=(0, 1)):
  16.         """
  17.        M: Кількість вхідних елементів (розмірність кожного об'єкта)
  18.        N: Кількість нейронів (кількість кластерів)
  19.        eta_0: Початковий крок навчання
  20.        max_epochs: Максимальна кількість епох
  21.        epsilon: Поріг для зупинки за зміною ваг
  22.        input_range: Інтервал значень вхідних даних
  23.        """
  24.         self.M = M
  25.         self.N = N
  26.         self.eta_0 = eta_0
  27.         self.s_c = s_c
  28.         self.max_epochs = max_epochs
  29.         self.epsilon = epsilon
  30.         self.input_range = input_range
  31.         self.weights = self.initialize_weights()
  32.  
  33.     def initialize_weights(self):
  34.  
  35.         if self.input_range == (-1, 1):
  36.             return np.random.uniform(-1/np.sqrt(self.M), 1/np.sqrt(self.M), (self.N, self.M))
  37.         elif self.input_range == (0, 1):
  38.             return np.random.uniform(1/2 - 1/np.sqrt(self.M), 1/2 + 1/np.sqrt(self.M), (self.N, self.M))
  39.         else:
  40.             raise ValueError("Unsupported input range")
  41.  
  42.     def linear_learning_rate(self, s):
  43.         if s == 0:
  44.             return self.eta_0
  45.         return self.eta_0 / s
  46.  
  47.     def exponential_learning_rate(self, s):
  48.         return self.eta_0 * np.exp(-(s - 1) / self.s_c)
  49.  
  50.     def calculate_euclidean_distances(self, data_point):
  51.         return np.linalg.norm(self.weights - data_point, axis=1)
  52.  
  53.     def update_weights(self, winner_idx, data_point, learning_rate):
  54.         self.weights[winner_idx] += learning_rate * (data_point - self.weights[winner_idx])
  55.  
  56.     def get_labels(self, data):
  57.         clusters = []
  58.         for data_point in data:
  59.             distances = self.calculate_euclidean_distances(data_point)
  60.             winner_idx = np.argmin(distances)
  61.             clusters.append(winner_idx)
  62.         return np.array(clusters)
  63.  
  64.     def train(self, data, lr_type='exp'):
  65.         """
  66.        lr_type: ['lin', 'exp']
  67.        """
  68.         weight_changes = []
  69.         start_time = dt.datetime.now()
  70.         for epoch in range(1, self.max_epochs + 1):
  71.             if lr_type == 'lin':
  72.                 learning_rate = self.linear_learning_rate(epoch)
  73.             elif lr_type == 'exp':
  74.                 learning_rate = self.exponential_learning_rate(epoch)
  75.             epoch_weight_change = 0
  76.             prev_weights = np.copy(self.weights)
  77.            
  78.             for data_point in data:
  79.                 distances = self.calculate_euclidean_distances(data_point)
  80.                 winner_idx = np.argmin(distances)
  81.                 self.update_weights(winner_idx, data_point, learning_rate)
  82.  
  83.             epoch_weight_change = np.linalg.norm(self.weights - prev_weights)
  84.             weight_changes.append(epoch_weight_change)
  85.  
  86.             if epoch_weight_change < self.epsilon:
  87.                 print(f"Зупинка: зміна ваг < {self.epsilon} на епохі {epoch}")
  88.                 break
  89.  
  90.             prcnt = (epoch)/self.max_epochs * 100
  91.             print(f'№{epoch}/{self.max_epochs} - {round(prcnt, 2)}% | total time: {dt.datetime.now() - start_time} | time remaining: {(dt.datetime.now() - start_time) / prcnt * (100 - prcnt)} | end time: {dt.datetime.now() + (dt.datetime.now() - start_time) / prcnt * (100 - prcnt)}', end='\r')
  92.             os.system('cls' if os.name == 'nt' else 'clear')
  93.  
  94.         return self.get_labels(data), weight_changes
  95.  
  96.     def visualize_cluster_centers(self, image_shape=(28, 28)):
  97.         num_clusters = self.weights.shape[0]
  98.         plt.figure(figsize=(7, 5))
  99.         for i in range(num_clusters):
  100.             plt.subplot(int(np.ceil(np.sqrt(num_clusters))), int(np.ceil(np.sqrt(num_clusters))), i + 1)
  101.             plt.imshow(self.weights[i].reshape(image_shape), cmap="gray_r")
  102.             plt.title(f"Кластер {i + 1}")
  103.             plt.axis("off")
  104.         plt.tight_layout()
  105.         plt.show()
  106.  
  107.     def plot_weight_changes(self, weight_changes):
  108.         plt.figure(figsize=(7, 5))
  109.         plt.plot(range(1, len(weight_changes) + 1), weight_changes, marker='o', label="Зміна ваг")
  110.         plt.title("Залежність зміни ваг від епохи навчання")
  111.         plt.xlabel("Епоха")
  112.         plt.ylabel("Норма зміни ваг")
  113.         plt.grid(True)
  114.         plt.legend()
  115.         plt.show()
  116.  
  117.  
  118.  
  119.  
  120. (X_train, y_train), (X_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
  121.  
  122.  
  123. print(f"x_train shape: {X_train.shape}, y_train shape: {y_train.shape}")
  124. print(f"x_test shape: {X_test.shape}, y_test shape: {y_test.shape}")
  125.  
  126. class_names = [
  127.     "Футболка/Топ", "Штани", "Светр", "Сукня", "Куртка",
  128.     "Сандалі", "Сорочка", "Кросівки", "Сумка", "Чоботи"
  129. ]
  130.  
  131. example_images = [X_train[np.where(y_train == cls)[0][0]] for cls in unique_classes]
  132.  
  133. fig, axes = plt.subplots(2, 5, figsize=(7, 5))
  134. axes = axes.flatten()
  135. for i, ax in enumerate(axes):
  136.     ax.imshow(example_images[i], cmap="gray_r")
  137.     ax.set_title(class_names[i], fontsize=10)
  138.     ax.axis("off")
  139. plt.tight_layout()
  140. plt.show()
  141.  
  142.  
  143. scaler = MinMaxScaler(feature_range=(0, 1))
  144. x_train = scaler.fit_transform(X_train.reshape(X_train.shape[0], -1))
  145. x_test = scaler.transform(X_test.reshape(X_test.shape[0], -1))
  146.  
  147. x_train, y_train = RandomUnderSampler().fit_resample(x_train, y_train)
  148. x_test, y_test = RandomUnderSampler().fit_resample(x_test, y_test)
  149.  
  150. indices = np.random.permutation(len(x_train))
  151. x_train = x_train[indices]
  152. y_train = y_train[indices]
  153.  
  154. print(f"x_train shape: {x_train.shape}, y_train shape: {y_train.shape}")
  155. print(f"x_test shape: {x_test.shape}, y_test shape: {y_test.shape}")
  156.  
  157.  
  158. M = x_train.shape[1]  
  159. N = 10
  160.  
  161. model = KohonenNetwork(M=M, N=N, eta_0=0.5, s_c=1, max_epochs=20, epsilon=0.001, input_range=(0, 1))
  162. y_preds, weight_changes = model.train(x_train, lr_type='exp')
  163.  
  164. model.plot_weight_changes(weight_changes)
  165. model.visualize_cluster_centers()
  166.  
  167.  
  168. class_dict = {
  169.     0: "Футболка/Топ", 1: "Штани", 2: "Светр", 3: "Сукня", 4: "Куртка",
  170.     5: "Сандалі", 6:"Сорочка", 7: "Кросівки", 8: "Сумка", 9: "Чоботи"
  171. }
  172.  
  173. df = pd.DataFrame(y_train, columns=['label'])
  174. df['class'] = df['label'].apply(lambda x: class_dict[x])
  175. df = df[['class', 'label']]
  176. df['cluster'] = y_preds
  177.  
  178.  
  179. plt.figure(figsize=(13, 10))
  180. for i in np.unique(y_train):
  181.     df_sub = df[df['label'] == i]['cluster'].value_counts()
  182.     _ = df_sub.copy()
  183.     for idx in range(len(np.unique(y_preds))):
  184.         _.loc[idx] = 0
  185.     for idx in df_sub.index:
  186.         _.loc[idx] = df_sub.loc[idx]
  187.     df_sub = _.copy() / df_sub.sum() * 100
  188.     plt.subplot(int(np.ceil(np.sqrt(len(np.unique(y_train))))), int(np.ceil(np.sqrt(len(np.unique(y_train))))), i + 1)
  189.     plt.ylabel('Frequency [%]')
  190.     plt.xlabel('Cluster number')
  191.     plt.title(f"{class_dict[i]}")
  192.     sns.barplot(df_sub, color='green')
  193.     plt.ylim(0, 100)
  194. plt.tight_layout()
  195. plt.show()
  196.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement