Wednesday, July 6, 2022

Number of layers in gradient methods for tuning neural networks

Предложенное ниже носит характер рекомендаций, которые можно попробовать для конкретнных NN. Здесь нет однозначного решения. Keras Tuner часто дает информацию для принятия стартовых решений по гиперпараметрам. 

1) Один из методов,состоит в том, чтобы добавлять слои до тех пор, пока вы не начнете переобучать свой тренировочный набор. Затем вы добавляете отсев или другой метод регуляризации.Идея состоит в том, что, как только ваша сеть перенастроится, вы будете уверены, что она достаточно мощна для вашей задачи. Исключение помогает предотвратить совместную адаптацию функций и, следовательно, избежать переобучения.У вас есть мощная модель, которая вынуждена разумно использовать свою мощь.Количество нейронов в каждом слое не имеет большого значения. Обычно вы помещаете на первый слой немного больше или столько же нейронов, чем входных, и постепенно уменьшаете до последнего слоя.

============================================

2) KerasTuner выводит журналы на экран, включая значения гиперпараметров в каждом испытании, чтобы пользователь мог отслеживать ход выполнения. Однако чтение журналов недостаточно интуитивно понятно, чтобы ощутить влияние гиперпараметров на результаты. 

(.env) boris@boris-All-Series:~/FOREL/KERASTUNER$ cat kerasTuner.py

import numpy as np

import keras_tuner

from tensorflow import keras

from tensorflow.keras import layers

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

# Normalize the pixel values to the range of [0, 1].

x_train = x_train.astype("float32") / 255

x_test = x_test.astype("float32") / 255

# Add the channel dimension to the images.

x_train = np.expand_dims(x_train, -1)

x_test = np.expand_dims(x_test, -1)

# Print the shapes of the data.

print(x_train.shape)

print(y_train.shape)

print(x_test.shape)

print(y_test.shape)


def build_model(hp):

    inputs = keras.Input(shape=(28, 28, 1))

    # Model type can be MLP or CNN.

    model_type = hp.Choice("model_type", ["mlp", "cnn"])

    x = inputs

    if model_type == "mlp":

        x = layers.Flatten()(x)

        # Number of layers of the MLP is a hyperparameter.

        for i in range(hp.Int("mlp_layers", 1, 3)):

            # Number of units of each layer are

            # different hyperparameters with different names.

            output_node = layers.Dense(

                units=hp.Int(f"units_{i}", 32, 128, step=32), activation="relu",

            )(x)

    else:

        # Number of layers of the CNN is also a hyperparameter.

        for i in range(hp.Int("cnn_layers", 1, 3)):

            x = layers.Conv2D(

                hp.Int(f"filters_{i}", 32, 128, step=32),

                kernel_size=(3, 3),

                activation="relu",

            )(x)

            x = layers.MaxPooling2D(pool_size=(2, 2))(x)

        x = layers.Flatten()(x)

    # A hyperparamter for whether to use dropout layer.

    if hp.Boolean("dropout"):

        x = layers.Dropout(0.5)(x)

    # The last layer contains 10 units,

    # which is the same as the number of classes.

    outputs = layers.Dense(units=10, activation="softmax")(x)

    model = keras.Model(inputs=inputs, outputs=outputs)

    # Compile the model.

    model.compile(

      loss="sparse_categorical_crossentropy", metrics=["accuracy"], optimizer="adam",)

    return model

# Initialize the `HyperParameters` and set the values.

hp = keras_tuner.HyperParameters()

hp.values["model_type"] = "cnn"

# Build the model using the `HyperParameters`.

model = build_model(hp)

# Test if the model runs with our data.

model(x_train[:100])

# Print a summary of the model.

model.summary()

# Do the same for MLP model.

hp.values["model_type"] = "mlp"

model = build_model(hp)

model(x_train[:100])

model.summary()






























Инициализируйте тюнер RandomSearch с 10 испытаниями и используйте точность проверки в качестве метрики для выбора моделей.

(.env) boris@boris-All-Series:~/FOREL/KERASTUNER$ cat kerasTuner1.py
import numpy as np
import keras_tuner
from tensorflow import keras
from tensorflow.keras import layers

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Normalize the pixel values to the range of [0, 1].
x_train = x_train.astype("float32") / 255
x_test = x_test.astype("float32") / 255
# Add the channel dimension to the images.
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
# Print the shapes of the data.
print(x_train.shape)
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)

def build_model(hp):
    inputs = keras.Input(shape=(28, 28, 1))
    # Model type can be MLP or CNN.
    model_type = hp.Choice("model_type", ["mlp", "cnn"])
    x = inputs
    if model_type == "mlp":
        x = layers.Flatten()(x)
        # Number of layers of the MLP is a hyperparameter.
        for i in range(hp.Int("mlp_layers", 1, 3)):
            # Number of units of each layer are
            # different hyperparameters with different names.
            output_node = layers.Dense(
                units=hp.Int(f"units_{i}", 32, 128, step=32), activation="relu",
            )(x)
    else:
        # Number of layers of the CNN is also a hyperparameter.
        for i in range(hp.Int("cnn_layers", 1, 3)):
            x = layers.Conv2D(
                hp.Int(f"filters_{i}", 32, 128, step=32),
                kernel_size=(3, 3),
                activation="relu",
            )(x)
            x = layers.MaxPooling2D(pool_size=(2, 2))(x)
        x = layers.Flatten()(x)

    # A hyperparamter for whether to use dropout layer.
    if hp.Boolean("dropout"):
        x = layers.Dropout(0.5)(x)

    # The last layer contains 10 units,
    # which is the same as the number of classes.
    outputs = layers.Dense(units=10, activation="softmax")(x)
    model = keras.Model(inputs=inputs, outputs=outputs)

    # Compile the model.
    model.compile(
        loss="sparse_categorical_crossentropy", metrics=["accuracy"], optimizer="adam",
    )
    return model

# Initialize the `HyperParameters` and set the values.
hp = keras_tuner.HyperParameters()
hp.values["model_type"] = "cnn"
# Build the model using the `HyperParameters`.
model = build_model(hp)
# Test if the model runs with our data.
model(x_train[:100])
# Print a summary of the model.
model.summary()

# Do the same for MLP model.
hp.values["model_type"] = "mlp"
model = build_model(hp)
model(x_train[:100])
model.summary()


tuner = keras_tuner.RandomSearch(
    build_model,
    max_trials=10,
    # Do not resume the previous search in the same directory.
    overwrite=True,
    objective="val_accuracy",
    # Set a directory to store the intermediate results.
    directory="/tmp/tb",
)

tuner.search(
    x_train,
    y_train,
    validation_split=0.2,
    epochs=2,
    # Use the TensorBoard callback.
    # The logs will be write to "/tmp/tb_logs".
    callbacks=[keras.callbacks.TensorBoard("/tmp/tb_logs")],
)
































Monday, July 4, 2022

Lance-Williams algorithm

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

Как вы объединяете кластеры? В начале, когда все кластеры имеют только по одной точке, это тривиально: вы хотите, чтобы расстояние между точками в одном кластере было небольшим (это называется сцеплением), а расстояние между точками в разных кластерах было больше (это называется разделением); поэтому вы объединяете точки, которые находятся ближе всего друг к другу. 

================================

Есть несколько эвристик, которые мы могли бы использовать:

1.Single Linkage или MIN: в этом случае расстояние между двумя кластерами является минимальным из расстояний между любыми двумя точками, каждая из которых взята из одного из кластеров. Это обрабатывает неэллиптические формы, но чувствительно к шуму и выбросам.

2.Полная связь или МАКС: это похоже на первое, но вместо этого мы рассматриваем максимальное расстояние. Это менее чувствительно к шуму и выбросам, но предпочитает шаровидные формы. 

3.Среднее по группе: здесь вы берете среднее расстояние между всеми возможными парами точек, по одной точке из каждого кластера.

4.Метод Ward: в методе Ward вы объединяете кластеры, которые приводят к минимальной дисперсии внутри кластера. 

Другой способ сформулировать это так: вы объединяете кластеры, которые приводят к минимальному увеличению квадрата ошибки.

Алгоритм принадлежит к семейству Ланса-Вильямса, если расстояние d_{(ij)k} может быть рекурсивно вычислено как




При этом мы имеем матрицу







===================================

Выбираем метрику расстояния для измерения расстояния между двумя группами. 

1) Используя метод Ward , в этом методе  вы объединяете кластеры, которые приводят к минимальной дисперсии внутри кластера. Смотри аргументацию (4)

2) На каждой итерации мы объединяем два кластера с наименьшей средней связью в один. Повторяем последний шаг, пока у нас не будет один большой кластер, содержащий все точки данных.

(.env) boris@boris-All-Series:~/AgglomerClustering$ cat CreditCard.py

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

from sklearn.decomposition import PCA

from sklearn.cluster import AgglomerativeClustering

from sklearn.preprocessing import StandardScaler, normalize

from sklearn.metrics import silhouette_score

import scipy.cluster.hierarchy as shc


X = pd.read_csv('CC_GENERAL.csv')

# Dropping the CUST_ID column from the data

X = X.drop('CUST_ID', axis = 1)

# Handling the missing values

X.fillna(method ='ffill', inplace = True)

# Scaling the data so that all the features become comparable

scaler = StandardScaler()

X_scaled = scaler.fit_transform(X)

# Normalizing the data so that the data approximately

# follows a Gaussian distribution

X_normalized = normalize(X_scaled)

# Converting the numpy array into a pandas DataFrame

X_normalized = pd.DataFrame(X_normalized)

pca = PCA(n_components = 2)

X_principal = pca.fit_transform(X_normalized)

X_principal = pd.DataFrame(X_principal)

X_principal.columns = ['P1', 'P2']

plt.figure(figsize =(8, 8))

plt.title('Visualising the data')

Dendrogram = shc.dendrogram((shc.linkage(X_principal, method ='ward')))

plt.show()






























Изменения последних строк кода

plt.figure(figsize =(8, 8))
plt.title('Visualising the data')
Dendrogram = shc.dendrogram((shc.linkage(X_principal, method ='ward')))

ac5 = AgglomerativeClustering(n_clusters = 5)
 
plt.figure(figsize =(6, 6))
plt.scatter(X_principal['P1'], X_principal['P2'],
            c = ac5.fit_predict(X_principal), cmap ='rainbow')
plt.show()















Использование метода средней связи, где расстояние между двумя кластерами — это среднее расстояние между точками данных в одном кластере и точками данных в другом.
На каждой итерации мы объединяем два кластера с наименьшей средней связью в один.
Повторяйте вышеуказанный шаг, пока у нас не будет один большой кластер, содержащий все точки данных. Плюсы:
Нет необходимости указывать количество кластеров. У вас есть возможность выбрать самые красивые кластеры.Этот алгоритм не чувствителен к выбору метрики расстояния.

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()






























Friday, July 1, 2022

How the self-organizing map of Kohonen works

 Созданная в 1982 году финским профессором и исследователем доктором Теуво Кохоненом, самоорганизующаяся карта представляет собой модель обучения без учителя, предназначенную для приложений, в которых важно поддерживать топологию между входными и выходными пространствами. Примечательной характеристикой этого алгоритма является то, что входные векторы, которые близки — похожи — в многомерном пространстве, также сопоставляются с соседними узлами в 2D-пространстве. По сути, это метод уменьшения размерности, поскольку он отображает входные данные большой размерности в низкое (обычно двумерное) дискретное представление и сохраняет основную структуру своего входного пространства.Ценной деталью является то, что все обучение происходит без присмотра, т. е. узлы самоорганизуются. Их также называют картами признаков, так как они, по сути, переобучают признаки входных данных и просто группируются в соответствии со сходством между собой. Это имеет прагматическое значение для визуализации сложных или больших объемов многомерных данных и представления отношений между ними в низком, обычно двумерном поле, чтобы увидеть, имеют ли данные немаркированные данные какую-либо структуру.

























Самоорганизующаяся карта (SOM) отличается от типичных ИНС как своей архитектурой, так и алгоритмическими свойствами. Во-первых, его структура состоит из однослойной линейной 2D-сетки нейронов, а не из серии слоев. Все узлы в этой сетке подключены непосредственно к входному вектору, но не друг к другу, что означает, что узлы не знают значений своих соседей и только обновляют вес своих соединений в зависимости от заданных входов. Сама сетка представляет собой карту, которая самоорганизуется на каждой итерации в зависимости от ввода входных данных. Таким образом, после кластеризации каждый узел имеет свою координату (i,j), что позволяет вычислить евклидово расстояние между двумя узлами с помощью теоремы Пифагора.
Кроме того, самоорганизующаяся карта использует конкурентное обучение, а не обучение с исправлением ошибок, чтобы скорректировать свой вес. Это означает, что каждая итерация активируется только одним узлом, в котором свойства включения вектора включают нейронную сеть, поскольку все обнаруживаются за право реакции на ввод.
Выбранный узел — Best Matching Unit (BMU) — выбирается в соответствие с подобием между текущими входными значениями и всеми комплектами в сетке.Узел с наименьшей евклидовой разностью между входным вектором и всеми узлами выбирается вместе с соседними узлами в определенных пределах радиуса, их положение было немного скорректировано, чтобы соответствовать входному вектору.
Проходя через все узлы, присутствующие в сетке, вся сетка в конечном итоге полностью соответствует набору входных данных, с похожими узлами, сгруппированными в одной области, и разнородными, разделенными.

















=============================
Переменные
t — текущая итерация
n - предел итераций, т.е. общее количество итераций, которые может пройти сеть.
λ - постоянная времени, используемая для уменьшения радиуса и скорости обучения.
i - координата строки сетки узлов
j - координата столбца сетки узлов
d - расстояние между узлом и BMU
w - весовой вектор
w_ij(t) — вес связи между узлами i,j в сетке и экземпляром входного вектора на итерации t
x - входной вектор
x(t) — экземпляр входного вектора на итерации t
α(t) — скорость обучения, уменьшающаяся со временем в интервале [0,1], чтобы обеспечить сходимость сети.
β_ij(t) — функция соседства, монотонно убывающая и представляющая узел i, расстояние j от BMU и влияние, которое он оказывает на обучение на шаге t.
σ(t) — радиус функции соседства, который определяет, насколько далеко проверяются соседние узлы в двумерной сетке при обновлении векторов. Со временем она постепенно снижается.
=========================
Алгоритм
1. Инициализировать вес каждого узла w_ij случайным значением
2. Выберите случайный входной вектор x_k
3. Повторите пункты 4 и 5 для всех узлов на карте:
4. Вычислите евклидово расстояние между входным вектором x(t) и весовым вектором w_ij, связанным с первым узлом, где t, i, j = 0.
5. Отследите узел, который дает наименьшее расстояние t.
6. Найдите общий Best Matching Unit (BMU), т.е. узел с наименьшим расстоянием от всех рассчитанных.
7. Определить топологическую окрестность βij(t) ее радиус σ(t) БМУ в карте Кохонена
8. Повторите для всех узлов в окрестности BMU: обновите весовой вектор w_ij первого узла в окрестности BMU, добавив долю разницы между входным вектором x(t) и весом w(t) нейрона.
9. Повторяйте всю эту итерацию до достижения выбранного предела итерации t=n
Шаг 1 — это фаза инициализации, а шаги 2–9 — фаза обучения.
===========================
Формулы
Обновление и изменение переменных выполняется по следующим формулам:
Веса в окрестности обновляются как:







Первое уравнение говорит нам, что новый обновленный вес w_ij (t + 1) для узла i, j равен сумме старого веса w_ij(t) и доли разницы между старым весом и входным вектором x( т). Другими словами, весовой вектор «перемещается» ближе к входному вектору. Еще один важный элемент, который следует отметить, заключается в том, что обновленный вес будет пропорционален двумерному расстоянию между узлами в радиусе соседства и BMU.
Кроме того, то же уравнение 3.1 не учитывает влияние обучения, пропорциональное расстоянию узла от BMU. Обновленный вес должен учитывать тот факт, что эффект обучения близок к нулю на окраинах района, поскольку объем обучения должен уменьшаться с расстоянием. Следовательно, второе уравнение добавляет дополнительный фактор функции соседства βij(t) и является более точным углубленным уравнением.

















Радиус и скорость обучения одинаково и экспоненциально затухают со временем.








Влияние функции соседства β_i(t) рассчитывается по формуле:








Евклидово расстояние между весовым вектором каждого узла и текущим входным экземпляром вычисляется по формуле Пифагора.












BMU выбирается из всех рассчитанных расстояний узла как тот, у которого наименьшее значение.













Generator to print even numbers (yield in Python)

(.env) boris@boris-All-Series:~/VOTING/ADABOOST$ cat EvenGenerator.py

# Python3 code to demonstrate

# yield keyword

# generator to print even numbers

def print_even(test_list):

    for i in test_list:

        if i % 2 == 0:

            yield i

# initializing list

test_list = [1, 4, 5, 6, 7]

# printing initial list

print("The original list is : " + str(test_list))

# printing even numbers

print("The even numbers in list are : ", end=" ")

for j in print_even(test_list):

    print(j, end=" ")

print("\n")

(.env) boris@boris-All-Series:~/VOTING/ADABOOST$ python3 EvenGenerator.py

The original list is : [1, 4, 5, 6, 7]

The even numbers in list are :  4 6














(.env) boris@boris-All-Series:~/VOTING/ADABOOST$ cat EvenGenerator1.py

def mygenerator(n):

   for i in range(1, n, 2):

      yield i**3

for i in mygenerator(10):

    print(i)

(.env) boris@boris-All-Series:~/VOTING/ADABOOST$ python3 EvenGenerator1.py

1

27

125

343

729



















How to generate all permutations of a list

Смотри https://docs.python.org/3/library/itertools.html#itertools.permutations

 (.env) boris@boris-All-Series:~/VOTING/ADABOOST$ cat permutationsList3.py

import itertools

def permutations(iterable, r=None):

    pool = tuple(iterable)

    n = len(pool)

    r = n if r is None else r

    if r > n:

        return

    indices = list(range(n))

    cycles = list(range(n, n-r, -1))

    yield tuple(pool[i] for i in indices[:r])

    while n:

        for i in reversed(range(r)):

            cycles[i] -= 1

            if cycles[i] == 0:

                indices[i:] = indices[i+1:] + indices[i:i+1]

                cycles[i] = n - i

            else:

                j = cycles[i]

                indices[i], indices[-j] = indices[-j], indices[i]

                yield tuple(pool[i] for i in indices[:r])

                break

        else:

            return

original = ['X','Y','Z']

perm_list = list(permutations(original,r=None))

print(perm_list) 

(.env) boris@boris-All-Series:~/VOTING/ADABOOST$ python3 permutationsList3.py

[('X', 'Y', 'Z'), ('X', 'Z', 'Y'), ('Y', 'X', 'Z'), ('Y', 'Z', 'X'), ('Z', 'X', 'Y'), ('Z', 'Y', 'X')]