Audyt: CATS => R, R=> syntetyczne sieci neuronowe

REF/: https://rpubs.com/staszkiewicz/AI_EX_1_Back_Prop

Cel projektu

Demonstracja działania prostej sieci neuronowej z propagacją wsteczną.

Wprowadzenie

Ten dokument przedstawia prosty przykład sieci neuronowej, który demonstruje działanie propagacji wstecznej. Sieć neuronowa to model obliczeniowy inspirowany budową ludzkiego mózgu, zdolny do uczenia się wzorców z danych. Propagacja wsteczna to algorytm uczenia, który dostosowuje wagi sieci w celu minimalizacji błędu między przewidywaniami a rzeczywistymi wartościami.

Przygotowanie danych

W tej sekcji generujemy dane treningowe. Składają się one z dwóch cech (x1 i x2) oraz zmiennej docelowej (y), która przyjmuje wartość 1, jeśli punkt (x1, x2) znajduje się wewnątrz okręgu o promieniu 0.5, a 0 w przeciwnym razie. Jest to nieliniowy problem, który sieć neuronowa ma rozwiązać.

set.seed(123)
n <- 1000
x <- matrix(runif(n*2, -1, 1), ncol=2)
y <- ifelse(x[,1]^2 + x[,2]^2 < 0.5, 1, 0)  # Okrąg decyzyjny
y_matrix <- matrix(y, ncol = 1)

Defncje funcji

W tej części definiujemy funkcje niezbędne do działania sieci neuronowej:

# Funkcje aktywacji
sigmoid <- function(x) {
  1 / (1 + exp(-x))
}

sigmoid_deriv <- function(x) {
  x * (1 - x)
}

# Inicjalizacja sieci
init_network <- function() {
  list(
    W1 = matrix(rnorm(2*4, 0, 0.1), 2, 4),  # Warstwa ukryta: 2 wejścia -> 4 neurony
    b1 = matrix(rep(0, 4), nrow = 1),
    W2 = matrix(rnorm(4*1, 0, 0.1), 4, 1),  # Warstwa wyjściowa: 4 neurony -> 1 wyjście
    b2 = matrix(rep(0, 1), nrow = 1)
  )
}

# Propagacja wsteczna
train_nn <- function(network, X, y, epochs = 1000, lr = 0.1) {
  loss_history <- numeric(epochs)
  
  for(epoch in 1:epochs) {
    # Propagacja wprzód
    hidden_input <- X %*% network$W1 + matrix(rep(network$b1, nrow(X)), ncol = ncol(network$b1), byrow = TRUE)
    hidden_layer <- sigmoid(hidden_input)
    
    output_input <- hidden_layer %*% network$W2 + matrix(rep(network$b2, nrow(hidden_layer)), ncol = ncol(network$b2), byrow = TRUE)
    output_layer <- sigmoid(output_input)
    
    # Obliczenie straty (MSE)
    loss <- mean((output_layer - y)^2)
    loss_history[epoch] <- loss
    
    # Propagacja wsteczna
    d_output <- (output_layer - y) * sigmoid_deriv(output_layer)
    d_hidden <- (d_output %*% t(network$W2)) * sigmoid_deriv(hidden_layer)
    
    # Aktualizacja wag
    network$W2 <- network$W2 - lr * t(hidden_layer) %*% d_output
    network$b2 <- network$b2 - lr * colSums(d_output)
    network$W1 <- network$W1 - lr * t(X) %*% d_hidden
    network$b1 <- network$b1 - lr * colSums(d_hidden)
    
    if(epoch %% 200 == 0) {
      cat("Epoka:", epoch, " Strata:", loss, "\n")
    }
  }
  
  return(list(network = network, loss = loss_history))
}

Trenowanie modelu

Teraz inicjujemy sieć i trenujemy ją na wygenerowanych danych. Proces treningowy trwa przez zadaną liczbę epok (2000) i aktualizuje wagi sieci w celu minimalizacji straty.

nn <- init_network()
result <- train_nn(nn, x, y, epochs=2000, lr=0.1)
## Epoka: 200  Strata: 0.3951945 
## Epoka: 400  Strata: 0.08709829 
## Epoka: 600  Strata: 0.07555704 
## Epoka: 800  Strata: 0.05678827 
## Epoka: 1000  Strata: 0.04943748 
## Epoka: 1200  Strata: 0.04149414 
## Epoka: 1400  Strata: 0.03368687 
## Epoka: 1600  Strata: 0.03210593 
## Epoka: 1800  Strata: 0.03115282 
## Epoka: 2000  Strata: 0.03033942
trained_nn <- result$network

Wizualizacja wyników

Po treningu wizualizujemy wyniki:

# Krzywa uczenia
plot(result$loss, type = 'l', main = 'Krzywa uczenia', 
     xlab = 'Epoka', ylab = 'Strata', col = 'blue')

# Granica decyzyjna
library(ggplot2)

# Tworzenie siatki punktów
grid_size <- 100
x1_seq <- seq(-1, 1, length.out = grid_size)
x2_seq <- seq(-1, 1, length.out = grid_size)
grid <- expand.grid(x1 = x1_seq, x2 = x2_seq)

# Predykcja dla siatki
grid_matrix <- as.matrix(grid)
hidden_input_grid <- grid_matrix %*% trained_nn$W1 + matrix(rep(trained_nn$b1, nrow(grid_matrix)), ncol = ncol(trained_nn$b1), byrow = TRUE)
hidden_layer_grid <- sigmoid(hidden_input_grid)
output_input_grid <- hidden_layer_grid %*% trained_nn$W2 + matrix(rep(trained_nn$b2, nrow(hidden_layer_grid)), ncol = ncol(trained_nn$b2), byrow = TRUE)
grid$pred <- sigmoid(output_input_grid)

# Wykres
ggplot(grid) +
  geom_raster(aes(x = x1, y = x2, fill = pred)) +
  geom_contour(aes(x = x1, y = x2, z = pred), breaks = 0.5, color = 'red', linewidth = 1) +
  geom_point(data = data.frame(x = x[,1], y = x[,2], class = as.factor(y)), 
             aes(x = x, y = y, color = class), alpha = 0.5) +
  scale_fill_viridis_c(name = "Predykcja") +
  scale_color_manual(values = c("0" = "blue", "1" = "yellow")) +
  labs(title = 'Granica decyzyjna sieci neuronowej',
       subtitle = 'Czerwona linia pokazuje granicę decyzyjną (0.5)') +
  theme_minimal() +
  coord_fixed()

Testowanie modeu

Oceniamy dokładność modelu na danych treningowych. Obliczamy, jaki procent przykładów został poprawnie sklasyfikowany, oraz przedstawiamy macierz pomyłek, która pokazuje, ile przykładów każdej klasy zostało poprawnie i błędnie sklasyfikowanych.

# Przewidywania na danych treningowych
hidden_layer_test <- sigmoid(x %*% trained_nn$W1 + matrix(rep(trained_nn$b1, nrow(x)), ncol = ncol(trained_nn$b1), byrow = TRUE))
predictions <- sigmoid(hidden_layer_test %*% trained_nn$W2 + matrix(rep(trained_nn$b2, nrow(hidden_layer_test)), ncol = ncol(trained_nn$b2), byrow = TRUE))
predicted_classes <- ifelse(predictions > 0.5, 1, 0)

# Dokładność
accuracy <- mean(predicted_classes == y)
cat("Dokładność klasyfikacji:", round(accuracy * 100, 2), "%\n")
## Dokładność klasyfikacji: 94.9 %
# Macierz pomyłek
confusion_matrix <- table(Prawdziwe = y, Przewidziane = predicted_classes)
print("Macierz pomyłek:")
## [1] "Macierz pomyłek:"
print(confusion_matrix)
##          Przewidziane
## Prawdziwe   0   1
##         0 599   0
##         1  51 350

Podsumowanie

Podsumowujemy działanie sieci neuronowej. Podajemy ostateczną wartość straty, architekturę sieci oraz użyte algorytmy.

cat("Ostateczna strata:", round(result$loss[length(result$loss)], 4), "\n")
## Ostateczna strata: 0.0303
cat("Architektura sieci: 2 -> 4 -> 1\n")
## Architektura sieci: 2 -> 4 -> 1
cat("Funkcja aktywacji: Sigmoid\n")
## Funkcja aktywacji: Sigmoid
cat("Algorytm uczenia: Propagacja wsteczna\n")
## Algorytm uczenia: Propagacja wsteczna

Wnioski Sieć neuronowa nauczyła się nieliniowego wzorca (okręgu) za pomocą propagacji wstecznej. Krzywa uczenia pokazuje, że strata systematycznie maleje, a granica decyzyjna jest zbliżona do prawdziwego okręgu. Dokładność klasyfikacji jest wysoka, co potwierdza skuteczność modelu.

Sieć poprawnie nauczyła się nieliniowego wzorca (okręgu) korzystając z: - Funkcji sigmoidalnej jako aktywacji - Algorytmu propagacji wstecznej - Gradient descent do aktualizacji wag

Tech. op.:

Ten kod: 1. Tworzy sieć neuronową z jedną warstwą ukrytą 2. Używa sigmoid jako funkcji aktywacji 3. Implementuje pełną propagację wsteczną 4. Wizualizuje wyniki za pomocą ggplot2 5. Jest napisany czysto w R bez zewnętrznych bibliotek 6. Działa efektywnie w RStudio 7. Może być bezpośrednio uruchomiony w R Markdown