Лаб. 4 НС
.docxМОСКОВСКИЙ ИНСТИТУТ ЭЛЕКТРОННОЙ ТЕХНИКИ
Институт системной и программной инженерии и информационных технологий (Институт СПИНТех)
Лабораторная работа № 4
Распознавание цифр с использованием набора данных MNIST.
Выполнил:
Фамилия И.О. гр. ???-??
Проверил преподаватель:
проф., д.ф.-м. н. Рычагов М.Н.
Москва, 2026
Задание
Код:
import torch import torchvision import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.utils.data import DataLoader, random_split from torchvision.transforms import ToTensor from sklearn.metrics import confusion_matrix, accuracy_score import cv2 import numpy as np import matplotlib.pyplot as plt # Загрузка данных train_data = torchvision.datasets.MNIST( root='./data', train=True, transform=ToTensor(), download=True) test_data = torchvision.datasets.MNIST( root='./data', train=False, transform=ToTensor(), download=True) # Разделение train_data, val_data = random_split(train_data, [50000, 10000]) train_loader = DataLoader(train_data, batch_size=64, shuffle=True) val_loader = DataLoader(val_data, batch_size=64, shuffle=False) test_loader = DataLoader(test_data, batch_size=64, shuffle=False) # Модель class MLP(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(28*28, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = x.view(-1, 28*28) x = F.relu(self.fc1(x)) x = F.softmax(self.fc2(x), dim=1) return x model = MLP() # Обучение optimizer = optim.SGD(model.parameters(), lr=0.01) def train_epoch(model, data_loader, optimizer, loss_fn): model.train() for X, Y in data_loader: optimizer.zero_grad() preds = model(X) loss = loss_fn(preds, Y) loss.backward() optimizer.step() def evaluate_model(model, data_loader, loss_fn): model.eval() total_loss = 0 with torch.no_grad(): for X, Y in data_loader: preds = model(X) loss = loss_fn(preds, Y) total_loss += loss.item() return total_loss / len(data_loader) num_epochs = 20 loss_fn = nn.CrossEntropyLoss() print("=== Обучение ===") for epoch in range(num_epochs): train_epoch(model, train_loader, optimizer, loss_fn) val_loss = evaluate_model(model, val_loader, loss_fn) print(f"Epoch {epoch+1}, Validation Loss: {val_loss:.4f}") # Оценка def predict(model, loader): model.eval() all_preds = [] with torch.no_grad(): for X, _ in loader: preds = model(X) _, labels = torch.max(preds, 1) all_preds.extend(labels.numpy()) return all_preds Y_pred = predict(model, test_loader) accuracy = accuracy_score(test_data.targets.numpy(), Y_pred) cm = confusion_matrix(test_data.targets.numpy(), Y_pred) print("\n=== Оценка модели ===") print(f"Точность: {accuracy:.4f}") print("Матрица ошибок:") print(cm) # Визуализация MNIST def visualize_predictions(images, labels, preds, num_samples=10): idxs = np.random.choice(len(images), size=num_samples, replace=False) fig, axes = plt.subplots(1, num_samples, figsize=(15, 3)) for i, ax in zip(idxs, axes): ax.imshow(images[i].numpy().squeeze(), cmap='gray') ax.set_title(f"{preds[i]} (true: {labels[i]})") ax.axis('off') plt.show() test_images, test_labels = next(iter(test_loader)) model.eval() all_preds = [] with torch.no_grad(): for X in test_images: preds = model(X) _, pred_labels = torch.max(preds, 1) all_preds.extend(pred_labels.numpy()) visualize_predictions(test_images, test_labels.numpy(), all_preds) # Обработка своего фото print("\n=== Обработка своего изображения ===") IMAGE_PATH = "digit8.jpg" image = cv2.imread(IMAGE_PATH) if image is None: print("Ошибка: файл не найден!") exit() image = cv2.resize(image, (28, 28)) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, image = cv2.threshold(image, 130, 255, cv2.THRESH_BINARY) image = 255 - image image = image / 255.0 image_tensor = torch.Tensor(image).unsqueeze(0) # Предсказание model.eval() with torch.no_grad(): preds = model(image_tensor) preds_np = preds.numpy() predicted_digit = np.argmax(preds_np) print(f"\nПредсказанная цифра: {predicted_digit}") print("Вероятности по классам:") print(preds_np) # Визуализация своего изображения plt.imshow(image, cmap='gray') plt.title(f"Predicted: {predicted_digit}") plt.axis('off') plt.show()
Вывод:
=== Обучение ===
Epoch 1, Validation Loss: 2.2771
Epoch 2, Validation Loss: 2.2021
Epoch 3, Validation Loss: 2.0582
Epoch 4, Validation Loss: 1.8947
Epoch 5, Validation Loss: 1.7952
Epoch 6, Validation Loss: 1.7433
Epoch 7, Validation Loss: 1.7136
Epoch 8, Validation Loss: 1.6943
Epoch 9, Validation Loss: 1.6766
Epoch 10, Validation Loss: 1.6493
Epoch 11, Validation Loss: 1.6336
Epoch 12, Validation Loss: 1.6221
Epoch 13, Validation Loss: 1.6134
Epoch 14, Validation Loss: 1.6062
Epoch 15, Validation Loss: 1.6004
Epoch 16, Validation Loss: 1.5961
Epoch 17, Validation Loss: 1.5917
Epoch 18, Validation Loss: 1.5883
Epoch 19, Validation Loss: 1.5852
Epoch 20, Validation Loss: 1.5824
=== Оценка модели ===
Точность: 0.9052
Матрица ошибок:
[[ 961 0 4 2 0 3 7 1 2 0]
[ 0 1106 2 5 0 0 5 2 15 0]
[ 15 2 896 12 16 1 19 27 37 7]
[ 3 0 23 903 1 29 3 19 21 8]
[ 1 3 5 1 909 1 16 2 7 37]
[ 23 5 9 51 24 694 20 12 48 6]
[ 19 3 5 0 8 16 902 0 5 0]
[ 7 18 30 1 10 0 0 933 5 24]
[ 5 8 10 17 10 27 16 12 860 9]
[ 11 6 3 9 40 16 1 24 11 888]]
=== Обработка своего изображения ===
Предсказанная цифра: 8
Вероятности по классам:
[[1.8234140e-07 4.0024570e-01 3.1284061e-03 6.1859825e-04 5.2933267e-04
7.8969274e-04 1.5507266e-02 1.1065605e-04 5.6783831e-01 1.1231836e-02]]
Рисунок 1. Распознавание рукописных цифр обученной нейронной сетью
Рисунок 2. Визуализация результата предварительной предобработки фотографии: бинарное изображение
Рисунок 3. Исходная фотография
Комментарий:
Модель показала точность ~0.90. Обученная модель была применена к изображению рукописной цифры после предварительной обработки (изменение размера, бинаризация, инверсия, нормализация). Модель выдала вероятности принадлежности изображения к каждому классу. Максимальная вероятность соответствует предсказанному классу.
