knitr::opts_chunk$set( echo = TRUE, fig.align = "center", fig.height = 4.5, fig.width = 8, message = FALSE, warning = FALSE, cache = TRUE ) # funkcja dla wygody nlapply <- function(X, FUN, ...) sapply(X, FUN, ..., simplify = FALSE, USE.NAMES = TRUE) # ziarno losowosci set.seed(1998)
Potwierdzam samodzielność powyższej pracy oraz niekorzystanie przeze mnie z niedozwolonych źródeł. Dominik Rafacz
library(MIOwAD) # pakiet z sieciami library(dplyr) # transformacja danych library(stringi) # transformacja danych library(ggplot2) # wykresy library(patchwork) # laczenie wykresow
X_2d <- read.csv("../data/kohonen/hexagon.csv") X_3d <- read.csv("../data/kohonen/cube.csv") X_mnist <- read.csv("../data/kohonen/mnist_train.csv", header = FALSE) X_mnist <- cbind(number = X_mnist[, 1], X_mnist[ , -1]/255) X_mnist <- do.call(cbind, lapply(X_mnist, function(col) if(sum(col) == 0) NULL else col)) X_uci <- cbind( class = read.csv("../data/kohonen/ucihar_y_train.txt", header = FALSE)[[1]], do.call(rbind, lapply(readLines("../data/kohonen/ucihar_X_train.txt"), function(row) as.numeric(stri_split_regex(row, " +", omit_empty = TRUE)[[1]])) ))
Cel: zbudowanie dwuwymiarowych sieci Kohonena i dopasowanie ich do danych 2d i 3d
Wykonamy eksperyment, dopasowując sieci Kohonena do danych ze zbioru 2d i 3d. Będziemy dopasowywać sieci o rozmiarze 10 x 10, korzystając z dwóch możliwych funkcji sąsiedztwa -- funkcji gaussowskiej i tzw. meksykańskiego kapelusza, a także z pięciu możliwych wartości parametru skali.
ngh_funs <- c( "gauss" = gauss, "mexican_hat" = mexican_hat ) scale_par <- c( `0.1` = 0.1, `0.5` = 0.5, `1` = 1, `5` = 5, `10` = 10 ) # trenujemy sieci dla zbioru 2d dla każdej funkcji dla każdego parametru nets <- list(lab7 = list()) nets[["lab7"]][["2d"]] <- nlapply(ngh_funs, function(fun) nlapply(scale_par, function(par) kohonen_network(X_2d[, 1:2], 10, 10, lambda = 10, ngh_fun = fun, scale = par) ))
# trenujemy sieci dla zbioru 3d dla każdej funkcji dla każdego parametru nets[["lab7"]][["3d"]] <- nlapply(ngh_funs, function(fun) nlapply(scale_par, function(par) kohonen_network(X_3d[, 1:3], 10, 10, lambda = 10, ngh_fun = fun, scale = par) ))
Teraz wygenerujemy wykresy do wizualizacji efektów treningu.
plots <- list(lab7 = list()) plots[["lab7"]][["2d"]] <- nlapply(names(ngh_funs), function(fun) nlapply(names(scale_par), function(par) plot_kohonen(generate_net_plot_data(nets[["lab7"]][["2d"]][[fun]][[par]]), X_2d) + ggtitle("Siec Kohonena", paste0("funkcja: ", fun, ", skala: ", par)) )) plots[["lab7"]][["3d"]] <- nlapply(names(ngh_funs), function(fun) nlapply(names(scale_par), function(par) { dat <- generate_net_plot_data(nets[["lab7"]][["3d"]][[fun]][[par]]) p_xy <- plot_kohonen(dat, X_3d, inp_dims_plot = c(1, 2), inp_class = 4) p_zy <- plot_kohonen(dat, X_3d, inp_dims_plot = c(3, 2), inp_class = 4) p_xz <- plot_kohonen(dat, X_3d, inp_dims_plot = c(1, 3), inp_class = 4) (p_xy + p_zy) / (p_xz + plot_spacer()) }))
Przyjrzyjmy się teraz samym wykresom.
plots[["lab7"]][["2d"]][["gauss"]][["0.1"]] + plots[["lab7"]][["2d"]][["gauss"]][["0.5"]] + plots[["lab7"]][["2d"]][["gauss"]][["1"]] + plots[["lab7"]][["2d"]][["gauss"]][["5"]] + plots[["lab7"]][["2d"]][["gauss"]][["10"]] plots[["lab7"]][["2d"]][["mexican_hat"]][["0.1"]] + plots[["lab7"]][["2d"]][["mexican_hat"]][["0.5"]] + plots[["lab7"]][["2d"]][["mexican_hat"]][["1"]] + plots[["lab7"]][["2d"]][["mexican_hat"]][["5"]] + plots[["lab7"]][["2d"]][["mexican_hat"]][["10"]]
Na pierwszym zestawie wykresów widzimy sieci dopasowane do zbioru z użyciem funckji gaussowskiej z róznym parametrem skali, na drugim funckji meksykańskiej z tymi samymi parametrami. Możemy zauważyć:
Możemy zauważyć, że na dopasowaniach dla najlepszej liczby parametrów neurony klastrują się podobnie do klastrów danych.
plots[["lab7"]][["3d"]][["gauss"]][["0.1"]] plots[["lab7"]][["3d"]][["gauss"]][["0.5"]] plots[["lab7"]][["3d"]][["gauss"]][["1"]] plots[["lab7"]][["3d"]][["gauss"]][["5"]] plots[["lab7"]][["3d"]][["gauss"]][["10"]] plots[["lab7"]][["3d"]][["mexican_hat"]][["0.1"]] plots[["lab7"]][["3d"]][["mexican_hat"]][["0.5"]] plots[["lab7"]][["3d"]][["mexican_hat"]][["1"]] plots[["lab7"]][["3d"]][["mexican_hat"]][["5"]] plots[["lab7"]][["3d"]][["mexican_hat"]][["10"]]
Tutaj każdy wykres to tak naprawdę zestaw trzech wykresów, prezentujących rzuty przestrzeni wejściowej na poszczególne płaszczyzny wyznaczone przez pary osi. Wykresy nie są aż tak czytelne (trudniej zobaczyć strukturę sieci), ale możemy wyciągnąć podobne wnioski jak w przypadku sieci 2d.
Cel: implementacja heksagonalnych sieci Kohonena i porównanie ich dopasowania do danych z sieciami kwadratwoymi
W tym laboratorium zaimplementowałem możliwość wyboru heksagonalnej topologii sieci. Wykonałem eksperyment, dopasowując sieci Kohonena do danych ze zbioru MNIST oraz ze zbioru UCI HAR. Do każdego z tych zbiorów dopasowałem po cztery sieci, wykorzystując wszystkie kombinacje topologii (kwadratowa lub sześciokątna) i funkcji sąsiedzwa (gaussowska oraz minus druga pochodna funkcji gaussowskiej).
topologies = c("square", "hex") # dodatkowy parametr odpowiedzialny za topologie sieci nets[["lab8"]] <- list(mnist = list(), uci = list()) nets[["lab8"]][["mnist"]] <- nlapply(names(ngh_funs), function(fun) { nlapply(topologies, function(topology) kohonen_network(X_mnist[, -1], N = 17, M = 16, lambda = 10, ngh_fun = ngh_funs[[fun]], scale = if (fun == "gauss") 0.6 else 5, topology = topology, verbose = FALSE)) }) nets[["lab8"]][["uci"]] <- nlapply(names(ngh_funs), function(fun) { nlapply(topologies, function(topology) kohonen_network(X_uci[, -1], N = 11, M = 12, lambda = 10, ngh_fun = ngh_funs[[fun]], scale = if (fun == "gauss") 0.8 else 4, topology = topology, verbose = FALSE)) })
plots[["lab8"]] <- list() plots[["lab8"]][["mnist"]] <- nlapply(names(ngh_funs), function(fun) nlapply(topologies, function(topology) plot_kohonen_w_pca(nets[["lab8"]][["mnist"]][[fun]][[topology]], X_mnist, inp_class = 1) )) plots[["lab8"]][["uci"]] <- nlapply(names(ngh_funs), function(fun) nlapply(topologies, function(topology) plot_kohonen_w_pca(nets[["lab8"]][["uci"]][[fun]][[topology]], X_uci, inp_class = 1) ))
plots[["lab8"]][["mnist"]][["gauss"]][["square"]] plots[["lab8"]][["mnist"]][["gauss"]][["hex"]] plots[["lab8"]][["mnist"]][["mexican_hat"]][["square"]] plots[["lab8"]][["mnist"]][["mexican_hat"]][["hex"]] plots[["lab8"]][["uci"]][["gauss"]][["square"]] plots[["lab8"]][["uci"]][["gauss"]][["hex"]] plots[["lab8"]][["uci"]][["mexican_hat"]][["square"]] plots[["lab8"]][["uci"]][["mexican_hat"]][["hex"]]
Jak widzimy na wizualizacjach, funkcja sąsiedztwa "mexican hat" nie sprawdza się najlepiej -- neurony blisko obserwacji "przestrzeliwują", ate trochę dalej są odpychane, co skutkuje w bardzo chaotycznym ich rozmieszczeniu na obu zbiorach danych, niezależnie od topologii sieci.
Jeśli chodzi o gaussowską funckję sąsiedztwa, sprawuje się ona zdecydowanie lepiej. Jeżeli chodzi o porównanie topologii kwadratóœ i sześciokątów, sześciokąty dopasowują się do danych nieco lepiej, gdyż mają więcej swobody.
Na wizualizacjach możemy wyodrębnić pewne skupiska neuronów, ale trudno dostrzec wyraźne klastry, głównie dlatego, że same dane również trudno zwizualizować w ten sposób.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.