Sunday, July 3, 2022

Self-Organizing Maps

Самоорганизующаяся карта была впервые представлена Теуво Кохоненом в 1982 году и также иногда известна как карта Кохонена. Это особый тип искусственной нейронной сети, которая строит карту обучающих данных. Карта обычно представляет собой двумерную прямоугольную сетку весов, но может быть расширена до трехмерной модели или модели большего размера. Также возможны другие структуры сетки, такие как шестиугольные сетки.

SOM в основном используется для визуализации данных и предоставляет краткую визуальную сводку по обучающим экземплярам. В двумерной прямоугольной сетке каждая ячейка представлена весовым вектором. Для обученного SOM каждый вес ячейки представляет собой сводку нескольких обучающих примеров. Ячейки, находящиеся в непосредственной близости друг от друга, имеют одинаковые веса, и подобные примеры могут быть сопоставлены с ячейками, находящимися в небольшом соседстве друг с другом.

(.env) boris@boris-All-Series:~/KOHONEN$ cat stackFinalSOM.py

import numpy as np

import matplotlib.pyplot as plt


def find_BMU(SOM,x):

    distSq = (np.square(SOM - x)).sum(axis=2)

    return np.unravel_index(np.argmin(distSq, axis=None), distSq.shape)

    

# Update the weights of the SOM cells when given a single training example

# and the model parameters along with BMU coordinates as a tuple

def update_weights(SOM, train_ex, learn_rate, radius_sq, 

                   BMU_coord, step=3):

    g, h = BMU_coord

    #if radius is close to zero then only BMU is changed

    if radius_sq < 1e-3:

        SOM[g,h,:] += learn_rate * (train_ex - SOM[g,h,:])

        return SOM

    # Change all cells in a small neighborhood of BMU

    for i in range(max(0, g-step), min(SOM.shape[0], g+step)):

        for j in range(max(0, h-step), min(SOM.shape[1], h+step)):

            dist_sq = np.square(i - g) + np.square(j - h)

            dist_func = np.exp(-dist_sq / 2 / radius_sq)

            SOM[i,j,:] += learn_rate * dist_func * (train_ex - SOM[i,j,:])   

    return SOM    


# Main routine for training an SOM. It requires an initialized SOM grid

# or a partially trained grid as parameter

def train_SOM(SOM, train_data, learn_rate = .1, radius_sq = 1, 

             lr_decay = .1, radius_decay = .1, epochs = 10):    

    learn_rate_0 = learn_rate

    radius_0 = radius_sq

    for epoch in np.arange(0, epochs):

        rand.shuffle(train_data)      

        for train_ex in train_data:

            g, h = find_BMU(SOM, train_ex)

            SOM = update_weights(SOM, train_ex, 

                                 learn_rate, radius_sq, (g,h))

        # Update learning rate and radius

        learn_rate = learn_rate_0 * np.exp(-epoch * lr_decay)

        radius_sq = radius_0 * np.exp(-epoch * radius_decay)            

    return SOM


# Dimensions of the SOM grid

m = 10

n = 10

# Number of training examples

n_x = 3000

rand = np.random.RandomState(0)

# Initialize the training data

train_data = rand.randint(0, 255, (n_x, 3))

# Initialize the SOM randomly

SOM = rand.randint(0, 255, (m, n, 3)).astype(float)


fig, ax = plt.subplots(

    nrows=3, ncols=3, figsize=(15, 15), 

    subplot_kw=dict(xticks=[], yticks=[]))


# Initialize the SOM randomly to the same state


for learn_rate, i in zip([0.001, 0.5, 0.99], [0, 1, 2]):

    for radius_sq, j in zip([0.01, 1, 10], [0, 1, 2]):

        rand = np.random.RandomState(0)

        SOM = rand.randint(0, 255, (m, n, 3)).astype(float)        

        SOM = train_SOM(SOM, train_data, epochs = 5,

                        learn_rate = learn_rate, 

                        radius_sq = radius_sq)

        ax[i][j].imshow(SOM.astype(int))

        ax[i][j].title.set_text('$\eta$ = ' + str(learn_rate) + 

                                ', $\sigma^2$ = ' + str(radius_sq))

plt.show()






























No comments:

Post a Comment