Лаб. работа “Нейросети и глубокое обучение”
Введение в нейросети и глубокое обучение
Глубокое обучение (Deep Learning) — это подраздел машинного обучения, основанный на искусственных нейронных сетях с множеством скрытых слоев. Глубокие нейросети способны автоматически извлекать сложные признаки из данных и достигать высокой точности в задачах распознавания, классификации и прогнозирования.
Основные типы нейронных сетей:
- Полносвязные сети (Fully Connected) — каждый нейрон связан со всеми нейронами следующего слоя
- Сверточные сети (CNN) — для обработки изображений и видео
- Рекуррентные сети (RNN, LSTM) — для обработки последовательностей
- Автоэнкодеры — для сжатия и генерации данных
- Генеративно-состязательные сети (GAN) — для генерации реалистичных данных
- Трансформеры — для обработки естественного языка
Теоретические основы нейронных сетей
Структура нейрона
Искусственный нейрон — базовая единица нейронной сети, которая:
- Получает входные сигналы (входные данные)
- Умножает их на веса (весовые коэффициенты)
- Суммирует взвешенные входы
- Применяет функцию активации
- Выдает выходной сигнал
Формула: \[ y = f(\sum_{i=1}^{n} w_i \cdot x_i + b) \]
где: - \(x_i\) — входные значения - \(w_i\) — веса - \(b\) — смещение (bias) - \(f\) — функция активации
Функции активации
1. Sigmoid: \[ \sigma(x) = \frac{1}{1 + e^{-x}} \]
2. ReLU (Rectified Linear Unit): \[ ReLU(x) = max(0, x) \]
3. Tanh: \[ tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} \]
4. Softmax (для многоклассовой классификации): \[ softmax(x_i) = \frac{e^{x_i}}{\sum_{j=1}^{n} e^{x_j}} \]
Обучение нейронных сетей
Алгоритм обратного распространения ошибки (Backpropagation):
- Прямое распространение (forward pass) — вычисление выхода
- Вычисление ошибки (loss calculation)
- Обратное распространение (backward pass) — вычисление градиентов
- Обновление весов (weight update)
Функции потерь:
- MSE (Mean Squared Error) — для регрессии
- Cross-Entropy — для классификации
- Binary Cross-Entropy — для бинарной классификации
Простая нейронная сеть с нуля
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification, load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report
import seaborn as sns
# Активационные функции
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
def relu(x):
return np.maximum(0, x)
def relu_derivative(x):
return (x > 0).astype(float)
# Класс простой нейронной сети
class SimpleNeuralNetwork:
def __init__(self, input_size, hidden_size, output_size, learning_rate=0.01):
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
self.learning_rate = learning_rate
# Инициализация весов случайными значениями
self.W1 = np.random.randn(self.input_size, self.hidden_size) * 0.1
self.b1 = np.zeros((1, self.hidden_size))
self.W2 = np.random.randn(self.hidden_size, self.output_size) * 0.1
self.b2 = np.zeros((1, self.output_size))
def forward(self, X):
"""Прямое распространение"""
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = relu(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = sigmoid(self.z2)
return self.a2
def backward(self, X, y):
"""Обратное распространение"""
m = X.shape[0]
# Вычисление градиентов
dz2 = self.a2 - y
dW2 = np.dot(self.a1.T, dz2) / m
db2 = np.sum(dz2, axis=0, keepdims=True) / m
da1 = np.dot(dz2, self.W2.T)
dz1 = da1 * relu_derivative(self.a1)
dW1 = np.dot(X.T, dz1) / m
db1 = np.sum(dz1, axis=0, keepdims=True) / m
# Обновление весов
self.W2 -= self.learning_rate * dW2
self.b2 -= self.learning_rate * db2
self.W1 -= self.learning_rate * dW1
self.b1 -= self.learning_rate * db1
def train(self, X, y, epochs=1000, verbose=True):
"""Обучение сети"""
losses = []
for epoch in range(epochs):
# Прямое распространение
output = self.forward(X)
# Вычисление ошибки
loss = np.mean((y - output) ** 2)
losses.append(loss)
# Обратное распространение
self.backward(X, y)
if verbose and epoch % 100 == 0:
print(f'Epoch {epoch}, Loss: {loss:.6f}')
return losses
def predict(self, X):
"""Предсказание"""
output = self.forward(X)
return (output > 0.5).astype(int)
def predict_proba(self, X):
"""Предсказание с вероятностями"""
return self.forward(X)
# Создание синтетического датасета для бинарной классификации
X, y = make_classification(n_samples=1000, n_features=10, n_classes=2,
n_redundant=0, n_informative=10, random_state=42)
# Нормализация данных
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y.reshape(-1, 1),
test_size=0.3, random_state=42)
print("=== Простая нейронная сеть ===")
print(f"Размер обучающей выборки: {X_train.shape}")
print(f"Размер тестовой выборки: {X_test.shape}")
# Создание и обучение сети
nn = SimpleNeuralNetwork(input_size=10, hidden_size=20, output_size=1, learning_rate=0.1)
losses = nn.train(X_train, y_train, epochs=1000, verbose=True)
# Предсказание на тестовых данных
y_pred = nn.predict(X_test)
y_pred_proba = nn.predict_proba(X_test)
# Оценка качества
accuracy = accuracy_score(y_test, y_pred)
print(f"\nAccuracy: {accuracy:.3f}")
print("\nClassification Report:")
print(classification_report(y_test, y_pred))
# Визуализация обучения
plt.figure(figsize=(12, 5))
# График потерь
plt.subplot(1, 2, 1)
plt.plot(losses)
plt.title('График потерь при обучении')
plt.xlabel('Эпоха')
plt.ylabel('Потери (MSE)')
plt.grid(True, alpha=0.3)
# Распределение вероятностей
plt.subplot(1, 2, 2)
plt.hist(y_pred_proba[y_test.flatten() == 0], alpha=0.5, label='Класс 0', bins=30)
plt.hist(y_pred_proba[y_test.flatten() == 1], alpha=0.5, label='Класс 1', bins=30)
plt.title('Распределение предсказанных вероятностей')
plt.xlabel('Вероятность')
plt.ylabel('Частота')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()Сверточные нейронные сети (CNN)
# Импорт TensorFlow и Keras
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist, cifar10
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
# Загрузка датасета MNIST
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print("=== Датасет MNIST ===")
print(f"Размер обучающей выборки: {x_train.shape}")
print(f"Размер тестовой выборки: {x_test.shape}")
print(f"Количество классов: {len(np.unique(y_train))}")
# Визуализация примеров из датасета
fig, axes = plt.subplots(2, 5, figsize=(15, 6))
for i in range(10):
row = i // 5
col = i % 5
axes[row, col].imshow(x_train[i], cmap='gray')
axes[row, col].set_title(f'Label: {y_train[i]}')
axes[row, col].axis('off')
plt.suptitle('Примеры изображений из датасета MNIST')
plt.tight_layout()
plt.show()
# Предобработка данных
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32') / 255
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1).astype('float32') / 255
# Преобразование меток в one-hot encoding
y_train_categorical = to_categorical(y_train, 10)
y_test_categorical = to_categorical(y_test, 10)
print(f"\nПосле предобработки:")
print(f"x_train shape: {x_train.shape}")
print(f"y_train shape: {y_train_categorical.shape}")Создание CNN архитектуры
# Создание модели CNN
def create_cnn_model(input_shape=(28, 28, 1), num_classes=10):
model = Sequential([
# Первый сверточный слой
Conv2D(32, (3, 3), activation='relu', input_shape=input_shape),
MaxPooling2D((2, 2)),
# Второй сверточный слой
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
# Третий сверточный слой
Conv2D(64, (3, 3), activation='relu'),
# Полносвязные слои
Flatten(),
Dense(64, activation='relu'),
Dropout(0.5),
Dense(num_classes, activation='softmax')
])
return model
# Создание и компиляция модели
cnn_model = create_cnn_model()
cnn_model.compile(optimizer=Adam(learning_rate=0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# Вывод архитектуры модели
print("=== Архитектура CNN модели ===")
cnn_model.summary()
# Настройка callbacks
early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=0.00001)
# Обучение модели
print("\n=== Обучение CNN модели ===")
history = cnn_model.fit(x_train, y_train_categorical,
batch_size=128,
epochs=20,
validation_split=0.2,
callbacks=[early_stopping, reduce_lr],
verbose=1)Анализ результатов обучения
# Оценка модели на тестовых данных
test_loss, test_accuracy = cnn_model.evaluate(x_test, y_test_categorical, verbose=0)
print(f"\nTest accuracy: {test_accuracy:.4f}")
print(f"Test loss: {test_loss:.4f}")
# Визуализация истории обучения
fig, axes = plt.subplots(1, 2, figsize=(15, 5))
# График точности
axes[0].plot(history.history['accuracy'], label='Training Accuracy')
axes[0].plot(history.history['val_accuracy'], label='Validation Accuracy')
axes[0].set_title('Точность модели во время обучения')
axes[0].set_xlabel('Эпоха')
axes[0].set_ylabel('Точность')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# График потерь
axes[1].plot(history.history['loss'], label='Training Loss')
axes[1].plot(history.history['val_loss'], label='Validation Loss')
axes[1].set_title('Потери модели во время обучения')
axes[1].set_xlabel('Эпоха')
axes[1].set_ylabel('Потери')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Предсказание на тестовых данных
y_pred_proba = cnn_model.predict(x_test)
y_pred = np.argmax(y_pred_proba, axis=1)
# Визуализация предсказаний
fig, axes = plt.subplots(3, 5, figsize=(15, 9))
for i in range(15):
row = i // 5
col = i % 5
axes[row, col].imshow(x_test[i].reshape(28, 28), cmap='gray')
axes[row, col].set_title(f'True: {y_test[i]}\nPred: {y_pred[i]}')
axes[row, col].axis('off')
plt.suptitle('Результаты предсказания CNN модели')
plt.tight_layout()
plt.show()Рекуррентные нейронные сети (RNN)
# Импорт для работы с последовательностями
from tensorflow.keras.layers import SimpleRNN, LSTM, GRU, Embedding
from tensorflow.keras.preprocessing.sequence import pad_sequences
from sklearn.preprocessing import LabelEncoder
import string
# Создание датасета для временных рядов
def create_time_series_data(n_samples=1000, seq_length=50):
"""Создание синтетических временных рядов"""
time_series_data = []
labels = []
for i in range(n_samples):
# Создание синусоидального сигнала с шумом
frequency = np.random.uniform(0.1, 0.5)
amplitude = np.random.uniform(0.5, 2.0)
phase = np.random.uniform(0, 2 * np.pi)
noise = np.random.normal(0, 0.1, seq_length)
signal = amplitude * np.sin(2 * np.pi * frequency * np.arange(seq_length) + phase) + noise
# Создание метки на основе частоты
if frequency < 0.2:
label = 0 # Низкая частота
elif frequency < 0.35:
label = 1 # Средняя частота
else:
label = 2 # Высокая частота
time_series_data.append(signal)
labels.append(label)
return np.array(time_series_data), np.array(labels)
# Создание временных рядов
X_time, y_time = create_time_series_data(n_samples=1000, seq_length=50)
# Нормализация
X_time = (X_time - X_time.mean(axis=1, keepdims=True)) / X_time.std(axis=1, keepdims=True)
# Разделение на обучающую и тестовую выборки
X_train_time, X_test_time, y_train_time, y_test_time = train_test_split(
X_time, y_time, test_size=0.3, random_state=42, stratify=y_time)
# Преобразование в нужную форму для RNN (samples, timesteps, features)
X_train_time = X_train_time.reshape(X_train_time.shape[0], X_train_time.shape[1], 1)
X_test_time = X_test_time.reshape(X_test_time.shape[0], X_test_time.shape[1], 1)
# Преобразование меток в one-hot encoding
y_train_time_cat = to_categorical(y_train_time, 3)
y_test_time_cat = to_categorical(y_test_time, 3)
print("=== Датасет временных рядов ===")
print(f"Размер обучающей выборки: {X_train_time.shape}")
print(f"Размер тестовой выборки: {X_test_time.shape}")
print(f"Количество классов: {len(np.unique(y_time))}")
# Визуализация примеров временных рядов
fig, axes = plt.subplots(3, 3, figsize=(15, 9))
for class_id in range(3):
class_indices = np.where(y_time == class_id)[0][:3]
for i, idx in enumerate(class_indices):
axes[class_id, i].plot(X_time[idx])
axes[class_id, i].set_title(f'Класс {class_id} - Пример {i+1}')
axes[class_id, i].set_xlabel('Время')
axes[class_id, i].set_ylabel('Значение')
axes[class_id, i].grid(True, alpha=0.3)
plt.suptitle('Примеры временных рядов для каждого класса')
plt.tight_layout()
plt.show()Создание RNN модели
# Создание RNN модели для классификации временных рядов
def create_rnn_model(input_shape=(50, 1), num_classes=3, rnn_type='LSTM'):
model = Sequential()
if rnn_type == 'SimpleRNN':
model.add(SimpleRNN(64, input_shape=input_shape, return_sequences=True))
model.add(SimpleRNN(32))
elif rnn_type == 'LSTM':
model.add(LSTM(64, input_shape=input_shape, return_sequences=True))
model.add(LSTM(32))
elif rnn_type == 'GRU':
model.add(GRU(64, input_shape=input_shape, return_sequences=True))
model.add(GRU(32))
model.add(Dense(16, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(num_classes, activation='softmax'))
return model
# Сравнение различных типов RNN
rnn_types = ['SimpleRNN', 'LSTM', 'GRU']
rnn_results = {}
for rnn_type in rnn_types:
print(f"\n=== Обучение {rnn_type} модели ===")
# Создание модели
rnn_model = create_rnn_model(rnn_type=rnn_type)
rnn_model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
# Обучение
rnn_history = rnn_model.fit(X_train_time, y_train_time_cat,
batch_size=32,
epochs=50,
validation_split=0.2,
verbose=0)
# Оценка на тестовых данных
test_loss, test_accuracy = rnn_model.evaluate(X_test_time, y_test_time_cat, verbose=0)
rnn_results[rnn_type] = {
'model': rnn_model,
'history': rnn_history,
'accuracy': test_accuracy,
'loss': test_loss
}
print(f"{rnn_type} Test Accuracy: {test_accuracy:.4f}")
# Сравнение результатов
rnn_names = list(rnn_results.keys())
rnn_accuracies = [rnn_results[name]['accuracy'] for name in rnn_names]
plt.figure(figsize=(10, 6))
bars = plt.bar(rnn_names, rnn_accuracies, color=['lightblue', 'lightgreen', 'lightcoral'])
plt.title('Сравнение точности различных типов RNN')
plt.xlabel('Тип RNN')
plt.ylabel('Точность')
plt.ylim(0, 1)
for bar, acc in zip(bars, rnn_accuracies):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01,
f'{acc:.3f}', ha='center', va='bottom')
plt.grid(True, alpha=0.3)
plt.show()Предобученные модели и Transfer Learning
# Использование предобученной модели VGG16
from tensorflow.keras.applications import VGG16, ResNet50, MobileNetV2
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# Загрузка предобученной модели VGG16 без верхних слоев
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# Заморозка слоев предобученной модели
for layer in base_model.layers:
layer.trainable = False
# Создание новой модели на основе предобученной
def create_transfer_learning_model(base_model, num_classes=10):
model = Sequential([
base_model,
layers.GlobalAveragePooling2D(),
layers.Dense(256, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
return model
# Создание модели
transfer_model = create_transfer_learning_model(base_model, num_classes=10)
transfer_model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
print("=== Архитектура модели с Transfer Learning ===")
transfer_model.summary()Самостоятельные задания
Задание 1: Сравнение архитектур нейронных сетей
Цель: Исследовать влияние архитектуры нейронной сети на качество классификации.
Задачи: 1. Реализуйте несколько архитектур CNN для датасета CIFAR-10: - Простая CNN (2-3 сверточных слоя) - Глубокая CNN (5+ сверточных слоев) - CNN с Batch Normalization и Dropout - CNN с различными функциями активации (ReLU, LeakyReLU, ELU) 2. Сравните точность и скорость обучения различных архитектур 3. Проанализируйте влияние размера фильтров и количества фильтров 4. Исследуйте влияние размера пакета (batch size) на качество обучения 5. Сравните результаты с предобученными моделями (Transfer Learning)
Формат отчета: - Таблица сравнения архитектур и их характеристик - Графики обучения (потери и точность) для каждой архитектуры - Анализ переобучения и недообучения - Рекомендации по выбору архитектуры - Визуализация признаков, извлекаемых сетью
Задание 2: Создание системы рекомендаций на основе нейронных сетей
Цель: Разработать систему рекомендаций фильмов с использованием нейронных сетей.
Задачи: 1. Используйте датасет MovieLens или создайте синтетический датасет 2. Реализуйте матричную факторизацию с помощью нейронных сетей 3. Создайте эмбединги для пользователей и фильмов 4. Обучите нейронную сеть для предсказания рейтингов 5. Сравните результаты с традиционными методами (SVD, k-NN) 6. Реализуйте гибридную систему (контентная + коллаборативная фильтрация)
Дополнительные задачи: - Добавьте дополнительные признаки (возраст, жанр, время суток) - Реализуйте систему объяснений рекомендаций - Сравните различные функции потерь (MSE, Cross-Entropy, BPR) - Реализуйте систему онлайн-обучения
Формат отчета: - Описание датасета и предобработки - Архитектура нейронной сети и параметры обучения - Метрики качества (RMSE, MAE, Precision@K, Recall@K) - Примеры рекомендаций и их объяснений - Сравнение с другими методами
Задание 3: Создание генеративной модели (VAE или GAN)
Цель: Реализовать генеративную модель для создания новых изображений.
Задачи: 1. Реализуйте Variational Autoencoder (VAE) для генерации изображений цифр MNIST 2. Или реализуйте простой GAN для генерации изображений 3. Сравните качество генерации при различных размерах латентного пространства 4. Визуализируйте латентное пространство и интерполяцию между изображениями 5. Оцените разнообразие сгенерированных изображений 6. Проанализируйте проблемы обучения (mode collapse, нестабильность)
Дополнительные задачи: - Реализуйте Conditional GAN для управляемой генерации - Сравните DCGAN, WGAN и другие архитектуры - Реализуйте систему оценки качества генерации (Inception Score, FID) - Создайте интерактивный интерфейс для генерации
Формат отчета: - Архитектура генеративной модели и параметры обучения - Визуализация сгенерированных изображений - Анализ латентного пространства - Проблемы, возникшие при обучении, и способы их решения - Сравнение с другими генеративными моделями
Задание 4: Создание системы прогнозирования временных рядов
Цель: Разработать систему прогнозирования временных рядов с использованием LSTM.
Задачи: 1. Используйте реальные данные (ценные бумаги, погода, продажи) или создайте синтетический датасет 2. Реализуйте несколько архитектур: - Простой LSTM - Stacked LSTM - Bidirectional LSTM - LSTM с вниманием (Attention) 3. Сравните производительность различных архитектур 4. Исследуйте влияние длины последовательности на качество прогноза 5. Реализуйте многошаговое прогнозирование 6. Сравните с традиционными методами (ARIMA, Prophet)
Дополнительные задачи: - Добавьте экзогенные переменные в модель - Реализуйте ансамбль моделей - Создайте систему онлайн-обучения - Реализуйте систему раннего предупреждения об аномалиях
Формат отчета: - Описание датасета и предобработки временных рядов - Архитектура LSTM моделей и параметры обучения - Метрики качества прогноза (RMSE, MAE, MAPE) - Визуализация прогнозов и фактических значений - Сравнение с другими методами прогнозирования
Задание 5: Оптимизация и ускорение нейронных сетей
Цель: Исследовать методы оптимизации и ускорения нейронных сетей.
Задачи: 1. Сравните различные оптимизаторы (SGD, Adam, RMSprop, AdaGrad) 2. Исследуйте влияние learning rate и learning rate scheduling 3. Реализуйте градиентный клиппинг и его влияние на обучение 4. Сравните batch normalization и layer normalization 5. Исследуйте методы регуляризации (Dropout, L1/L2, Early Stopping) 6. Реализуйте систему автоматического подбора гиперпараметров
Дополнительные задачи: - Реализуйте knowledge distillation (перенос знаний от большой модели к маленькой) - Сравните float32 и float16 обучение - Исследуйте влияние архитектуры на скорость инференса - Реализуйте систему квантизации моделей
Формат отчета: - Сравнение различных оптимизаторов и их характеристик - Графики сходимости для различных настроек - Таблица оптимальных гиперпараметров - Анализ вычислительной эффективности - Рекомендации по оптимизации нейронных сетей
Контрольные вопросы
- Какие существуют основные типы нейронных сетей и для каких задач они применяются?
- Что такое функция активации и какие существуют основные типы функций активации?
- Как работает алгоритм обратного распространения ошибки?
- В чем различие между полносвязными, сверточными и рекуррентными сетями?
- Что такое переобучение и какие существуют методы борьбы с ним?
- Какие метрики используются для оценки качества нейронных сетей в различных задачах?
- Что такое transfer learning и когда его следует применять?
- Какие существуют методы оптимизации обучения нейронных сетей?
- В чем преимущества и недостатки различных оптимизаторов (SGD, Adam, RMSprop)?
- Как выбрать архитектуру нейронной сети для конкретной задачи?
Рекомендации по выполнению работы
- Начинайте с простых моделей и постепенно увеличивайте сложность
- Используйте GPU для ускорения обучения (если доступно)
- Сохраняйте модели после обучения для последующего использования
- Визуализируйте результаты — графики помогают понять поведение модели
- Экспериментируйте с гиперпараметрами но делайте это систематически
- Используйте callbacks для мониторинга и улучшения обучения
- Проверяйте переобучение с помощью валидационной выборки
- Документируйте эксперименты для воспроизводимости результатов