commit 0e7fad6a87cbafd673c300f856cafc0c206173e5 Author: bogdan Date: Sun Jan 19 16:08:54 2025 +0300 Пробы пера diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ba925d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/.idea/ +/.venv/ +__pycache__ +/cifar-10-batches-py/ +/data/ +/cifar-10-python.tar.gz +/cifar10_model.h5 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0df39f2 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +### Dataset source + +- https://www.cs.toronto.edu/%7Ekriz/cifar.html +- https://www.cs.toronto.edu/%7Ekriz/cifar-10-python.tar.gz (c58f30108f718f92721af3b95e74349a) diff --git a/ViT16.py b/ViT16.py new file mode 100644 index 0000000..fbd6cbd --- /dev/null +++ b/ViT16.py @@ -0,0 +1,113 @@ +import torch +import torchvision.transforms as transforms +from torchvision.datasets import CIFAR10 +from torch.utils.data import DataLoader +from transformers import ViTImageProcessor, ViTForImageClassification, ViTFeatureExtractor +import torch.nn.functional as F +from sklearn.metrics import accuracy_score, classification_report +from torch.optim import AdamW +from torch.nn import CrossEntropyLoss +#import os + +#os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True' + +# Загрузка предобученной модели ViT-16 +# model = ViTForImageClassification.from_pretrained('WinKawaks/vit-small-patch16-224') #-in21k') +processor = ViTImageProcessor.from_pretrained('google/vit-base-patch16-224') +model = ViTForImageClassification.from_pretrained('google/vit-base-patch16-224') + +# Изменение количества классов на 10 (для CIFAR-10) +model.classifier = torch.nn.Linear(model.classifier.in_features, 10) + +# Перенос модели на GPU, если доступно +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +# model.to(device) +model.half().to(device) # Load in half precision + +# Преобразования для данных +transform = transforms.Compose([ + transforms.Resize((224, 224)), # ViT-16 ожидает изображения размером 224x224 + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) +]) + +# Загрузка данных +train_dataset = CIFAR10(root='./data', train=True, download=True, transform=transform) +test_dataset = CIFAR10(root='./data', train=False, download=True, transform=transform) + +# train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True) +# test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False) +train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) +test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False) + +# Оптимизатор и функция потерь +optimizer = AdamW(model.parameters(), lr=1e-4) +criterion = CrossEntropyLoss() + +# Дообучение модели +model.train() +num_epochs = 10 + +for epoch in range(num_epochs): + for images, labels in train_loader: + images = images.to(device) + labels = labels.to(device) + + optimizer.zero_grad() + outputs = model(images).logits + loss = criterion(outputs, labels) + loss.backward() + optimizer.step() + + print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item()}') + +# for epoch in range(num_epochs): +# epoch_loss = 0.0 +# for batch_idx, (images, labels) in enumerate(train_loader): +# images = images.to(device) +# labels = labels.to(device) +# +# optimizer.zero_grad() +# outputs = model(images).logits +# loss = criterion(outputs, labels) +# loss.backward() +# optimizer.step() +# +# epoch_loss += loss.item() +# +# # Печать прогресса каждые 10 батчей +# if (batch_idx + 1) % 10 == 0: +# print(f'Epoch {epoch+1}/{num_epochs}, Batch {batch_idx+1}/{len(train_loader)}, Loss: {loss.item()}') +# +# # Печать средней потери за эпоху +# avg_epoch_loss = epoch_loss / len(train_loader) +# print(f'Epoch {epoch+1}/{num_epochs}, Average Loss: {avg_epoch_loss}') + +# Функция для оценки модели +def evaluate_model(model, data_loader, device): + model.eval() + all_preds = [] + all_labels = [] + + with torch.no_grad(): + for images, labels in data_loader: + images = images.to(device) + labels = labels.to(device) + + outputs = model(images).logits + preds = torch.argmax(outputs, dim=1) + + all_preds.extend(preds.cpu().numpy()) + all_labels.extend(labels.cpu().numpy()) + + accuracy = accuracy_score(all_labels, all_preds) + report = classification_report(all_labels, all_preds, target_names=train_dataset.classes) + + return accuracy, report + +# Оценка модели на тестовых данных +accuracy, report = evaluate_model(model, test_loader, device) + +print(f'Test Accuracy: {accuracy:.4f}') +print('Classification Report:') +print(report) diff --git a/cifar10.py b/cifar10.py new file mode 100644 index 0000000..55266b6 --- /dev/null +++ b/cifar10.py @@ -0,0 +1,57 @@ +import tensorflow as tf +from tensorflow.keras import datasets, layers, models +import matplotlib.pyplot as plt + +print("TensorFlow version:", tf.__version__) +print("CUDA runtime version:", tf.sysconfig.get_build_info()['cuda_version']) + +# Load the CIFAR-10 dataset +(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data() + +# Normalize pixel values to be between 0 and 1 +train_images, test_images = train_images / 255.0, test_images / 255.0 + +# Verify the data +class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] + +plt.figure(figsize=(10,10)) +for i in range(25): + plt.subplot(5,5,i+1) + plt.xticks([]) + plt.yticks([]) + plt.grid(False) + plt.imshow(train_images[i]) + plt.xlabel(class_names[train_labels[i][0]]) +plt.show() + +# Build the CNN model +model = models.Sequential() +model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) +model.add(layers.MaxPooling2D((2, 2))) +model.add(layers.Conv2D(64, (3, 3), activation='relu')) +model.add(layers.MaxPooling2D((2, 2))) +model.add(layers.Conv2D(64, (3, 3), activation='relu')) + +model.add(layers.Flatten()) +model.add(layers.Dense(64, activation='relu')) +model.add(layers.Dense(10)) + +# Compile the model +model.compile(optimizer='adam', + loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), + metrics=['accuracy']) + +# Train the model +history = model.fit(train_images, train_labels, epochs=10, + validation_data=(test_images, test_labels)) + +# Evaluate the model +plt.plot(history.history['accuracy'], label='accuracy') +plt.plot(history.history['val_accuracy'], label = 'val_accuracy') +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.ylim([0, 1]) +plt.legend(loc='lower right') + +test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) +print(test_acc) diff --git a/cifar10my.py b/cifar10my.py new file mode 100644 index 0000000..5f3eae5 --- /dev/null +++ b/cifar10my.py @@ -0,0 +1,131 @@ +import os +import pickle +import numpy as np +import urllib.request +import tarfile +import matplotlib.pyplot as plt + +def download_and_extract_cifar10(data_dir='cifar-10-batches-py'): + url = 'https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz' + filename = 'cifar-10-python.tar.gz' + if not os.path.exists(data_dir): + urllib.request.urlretrieve(url, filename) + with tarfile.open(filename, 'r:gz') as tar: + tar.extractall() + return data_dir + +data_dir = download_and_extract_cifar10() + +def load_cifar10(data_dir): + def unpickle(file): + with open(file, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return dict + + train_data = [] + train_labels = [] + for i in range(1, 6): + batch = unpickle(os.path.join(data_dir, 'data_batch_' + str(i))) + train_data.append(batch[b'data']) + train_labels.append(batch[b'labels']) + + train_data = np.concatenate(train_data).reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1) + train_labels = np.concatenate(train_labels) + + test_batch = unpickle(os.path.join(data_dir, 'test_batch')) + test_data = test_batch[b'data'].reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1) + test_labels = np.array(test_batch[b'labels']) + + return train_data, train_labels, test_data, test_labels + +train_data, train_labels, test_data, test_labels = load_cifar10(data_dir) + +# Normalize the data +train_data = train_data / 255.0 +test_data = test_data / 255.0 + +class SimpleNN: + def __init__(self, input_size, hidden_size, output_size): + self.input_size = input_size + self.hidden_size = hidden_size + self.output_size = output_size + + # Initialize weights and biases + self.W1 = np.random.randn(input_size, hidden_size) * 0.01 + self.b1 = np.zeros((1, hidden_size)) + self.W2 = np.random.randn(hidden_size, output_size) * 0.01 + self.b2 = np.zeros((1, output_size)) + + def forward(self, X): + self.Z1 = np.dot(X, self.W1) + self.b1 + self.A1 = np.maximum(0, self.Z1) # ReLU activation + self.Z2 = np.dot(self.A1, self.W2) + self.b2 + self.A2 = np.exp(self.Z2) / np.sum(np.exp(self.Z2), axis=1, keepdims=True) # Softmax activation + return self.A2 + + def backward(self, X, y, output): + m = y.shape[0] + self.dZ2 = output + self.dZ2[range(m), y] -= 1 + self.dW2 = (1 / m) * np.dot(self.A1.T, self.dZ2) + self.db2 = (1 / m) * np.sum(self.dZ2, axis=0, keepdims=True) + self.dA1 = np.dot(self.dZ2, self.W2.T) + self.dZ1 = np.array(self.dA1, copy=True) + self.dZ1[self.Z1 <= 0] = 0 + self.dW1 = (1 / m) * np.dot(X.T, self.dZ1) + self.db1 = (1 / m) * np.sum(self.dZ1, axis=0, keepdims=True) + + def update_parameters(self, learning_rate): + self.W1 -= learning_rate * self.dW1 + self.b1 -= learning_rate * self.db1 + self.W2 -= learning_rate * self.dW2 + self.b2 -= learning_rate * self.db2 + + def compute_loss(self, y, output): + m = y.shape[0] + log_likelihood = -np.log(output[range(m), y]) + loss = np.sum(log_likelihood) / m + return loss + +def train(model, X, y, learning_rate=0.01, epochs=10): + for epoch in range(epochs): + output = model.forward(X) + loss = model.compute_loss(y, output) + model.backward(X, y, output) + model.update_parameters(learning_rate) + if epoch % 1 == 0: + print(f'Epoch {epoch + 1}, Loss: {loss}') + +# Flatten the input data +train_data_flat = train_data.reshape(-1, 32*32*3) +test_data_flat = test_data.reshape(-1, 32*32*3) + +# Initialize the model +model = SimpleNN(input_size=32*32*3, hidden_size=128, output_size=10) + +# Train the model +train(model, train_data_flat, train_labels, learning_rate=0.01, epochs=10) + +def evaluate(model, X, y): + output = model.forward(X) + predictions = np.argmax(output, axis=1) + accuracy = np.mean(predictions == y) + return accuracy + +# Evaluate the model on the test data +accuracy = evaluate(model, test_data_flat, test_labels) +test_data_reshaped = test_data_flat.reshape(-1, 32, 32, 3) + +class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] + +plt.figure(figsize=(10,10)) +for i in range(25): + plt.subplot(5,5,i+1) + plt.xticks([]) + plt.yticks([]) + plt.grid(False) + plt.imshow(test_data_reshaped[i]) + plt.xlabel(class_names[test_labels[i]]) +plt.show() + +print(f'Test Accuracy: {accuracy * 100:.2f}%') diff --git a/cifral10_2.py b/cifral10_2.py new file mode 100644 index 0000000..b9c3f54 --- /dev/null +++ b/cifral10_2.py @@ -0,0 +1,86 @@ +import tensorflow as tf +from tensorflow.keras import layers, models +from tensorflow.keras.preprocessing.image import ImageDataGenerator +import matplotlib.pyplot as plt +import numpy as np +import time + +# Загрузка данных CIFAR-10 +(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data() + +# Нормализация +x_train, x_test = x_train / 255.0, x_test / 255.0 + +# Аугментация +datagen = ImageDataGenerator( + rotation_range=15, + width_shift_range=0.1, + height_shift_range=0.1, + horizontal_flip=True +) +datagen.fit(x_train) + +# Создание модели +model = models.Sequential([ + layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)), + layers.MaxPooling2D((2, 2)), + layers.Conv2D(64, (3, 3), activation='relu'), + layers.MaxPooling2D((2, 2)), + layers.Conv2D(64, (3, 3), activation='relu'), + layers.Flatten(), + layers.Dense(64, activation='relu'), + layers.Dense(10) +]) + +# Компиляция модели +model.compile(optimizer='adam', + loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), + metrics=['accuracy']) + +# Обучение модели +start_time = time.time() +history = model.fit(datagen.flow(x_train, y_train, batch_size=64), + epochs=20, + validation_data=(x_test, y_test)) +end_time = time.time() + +# Время обучения +training_time = end_time - start_time +print(f"Training time: {training_time:.2f} seconds") + +# Оценка модели +test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2) +print(f"Test accuracy: {test_acc:.4f}") + +# Построение графиков +plt.figure(figsize=(12, 4)) + +# График точности +plt.subplot(1, 2, 1) +plt.plot(history.history['accuracy'], label='train accuracy') +plt.plot(history.history['val_accuracy'], label='val accuracy') +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.legend(loc='lower right') +plt.title('Training and Validation Accuracy') + +# График потерь +plt.subplot(1, 2, 2) +plt.plot(history.history['loss'], label='train loss') +plt.plot(history.history['val_loss'], label='val loss') +plt.xlabel('Epoch') +plt.ylabel('Loss') +plt.legend(loc='upper right') +plt.title('Training and Validation Loss') + +plt.show() + +# Документация и комментарии +""" +Этот код загружает данные CIFAR-10, нормализует их, создает и обучает сверточную нейронную сеть. +Используется аугментация данных для улучшения обучения модели. +Модель оценивается на тестовых данных, и строятся графики точности и потерь для анализа обучения. +""" + +# Сохранение модели +model.save('cifar10_model.h5') diff --git a/readme.ipynb b/readme.ipynb new file mode 100644 index 0000000..fdbf189 --- /dev/null +++ b/readme.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Отчет о проделанной работе\n", + "\n", + "## Введение\n", + "\n", + "Задача: Написать нейронную сеть для распознования набора данных Cifral10\n", + "\n", + "## Загрузка и предобработка данных\n", + "\n", + "В качестве набора данных для обучения используется набор данных (Cifral10)[https://www.cs.toronto.edu/%7Ekriz/cifar.html]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Загрузка данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Подготовка данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Нормализация\n", + "x_train, x_test = x_train / 255.0, x_test / 255.0\n", + "\n", + "# Аугментация\n", + "datagen = ImageDataGenerator(\n", + " rotation_range=15,\n", + " width_shift_range=0.1,\n", + " height_shift_range=0.1,\n", + " horizontal_flip=True\n", + ")\n", + "datagen.fit(x_train)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Создание модели\n", + "\n", + "Для решения задачи используется сверточная нейронная сеть (CNN).\n", + "\n", + "### Архитектура модели\n", + "\n", + "1. **Входной слой**:\n", + " - **Тип слоя**: Сверточный слой (Conv2D).\n", + " - **Фильтры**: 32 фильтра.\n", + " - **Размер ядра**: 3x3.\n", + " - **Функция активации**: ReLU (Rectified Linear Unit).\n", + "\n", + "2. **Слой подвыборки (MaxPooling)**:\n", + " - **Тип слоя**: Слой подвыборки (MaxPooling2D).\n", + " - **Размер окна**: 2x2.\n", + " - **Функция**: Уменьшает размерность выходных данных предыдущего слоя вдвое, выбирая максимальное значение в каждом окне 2x2.\n", + "\n", + "3. **Второй сверточный слой**:\n", + " - **Тип слоя**: Сверточный слой (Conv2D).\n", + " - **Фильтры**: 64 фильтра.\n", + " - **Размер ядра**: 3x3.\n", + " - **Функция активации**: ReLU.\n", + "\n", + "4. **Второй слой подвыборки (MaxPooling)**:\n", + " - **Тип слоя**: Слой подвыборки (MaxPooling2D).\n", + " - **Размер окна**: 2x2.\n", + " - **Функция**: Уменьшает размерность выходных данных предыдущего слоя вдвое.\n", + "\n", + "5. **Третий сверточный слой**:\n", + " - **Тип слоя**: Сверточный слой (Conv2D).\n", + " - **Фильтры**: 64 фильтра.\n", + " - **Размер ядра**: 3x3.\n", + " - **Функция активации**: ReLU.\n", + "\n", + "6. **Слой преобразования (Flatten)**:\n", + " - **Тип слоя**: Слой преобразования (Flatten).\n", + " - **Функция**: Преобразует многомерные выходные данные предыдущего слоя в одномерный вектор.\n", + "\n", + "7. **Полносвязный слой (Dense)**:\n", + " - **Тип слоя**: Полносвязный слой (Dense).\n", + " - **Нейроны**: 64 нейрона.\n", + " - **Функция активации**: ReLU.\n", + "\n", + "8. **Выходной слой (Dense)**:\n", + " - **Тип слоя**: Полносвязный слой (Dense).\n", + " - **Нейроны**: 10 нейронов (по одному для каждого класса в CIFAR-10).\n", + " - **Функция активации**: Отсутствует (логиты).\n", + "\n", + "### Объяснение архитектуры\n", + "\n", + "1. **Сверточные слои (Conv2D)**:\n", + " - Сверточные слои используются для извлечения признаков из изображений. Они применяют фильтры к входным данным, чтобы выделить важные характеристики, такие как края, текстуры и формы.\n", + " - В данной архитектуре используются три сверточных слоя с различным количеством фильтров (32, 64, 64), что позволяет модели извлекать все более сложные признаки на каждом уровне.\n", + "\n", + "2. **Слои подвыборки (MaxPooling2D)**:\n", + " - Слои подвыборки уменьшают размерность данных, сохраняя наиболее важные признаки. Это помогает снизить вычислительную сложность и предотвратить переобучение.\n", + " - В данной архитектуре используются два слоя подвыборки, каждый из которых уменьшает размерность данных вдвое.\n", + "\n", + "3. **Слой преобразования (Flatten)**:\n", + " - Слой преобразования преобразует многомерные данные в одномерный вектор, что необходимо для подачи данных в полносвязные слои.\n", + "\n", + "4. **Полносвязные слои (Dense)**:\n", + " - Полносвязные слои используются для классификации извлеченных признаков. Они соединяют все нейроны предыдущего слоя с каждым нейроном текущего слоя.\n", + " - В данной архитектуре используется один полносвязный слой с 64 нейронами и функцией активации ReLU, а также выходной слой с 10 нейронами (по одному для каждого класса)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = models.Sequential([\n", + " layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),\n", + " layers.MaxPooling2D((2, 2)),\n", + " layers.Conv2D(64, (3, 3), activation='relu'),\n", + " layers.MaxPooling2D((2, 2)),\n", + " layers.Conv2D(64, (3, 3), activation='relu'),\n", + " layers.Flatten(),\n", + " layers.Dense(64, activation='relu'),\n", + " layers.Dense(10)\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Компиляция и обучение модели\n", + "\n", + "Предварительно зададим, что будем использовать (оптимизатор)[https://www.tensorflow.org/api_docs/python/tf/keras/optimizers] использующий алгоритм (Adam)[https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam]. [1](https://education.yandex.ru/handbook/ml/article/optimizaciya-v-ml)\n", + "\n", + "В качестве (функции потерь)[https://www.tensorflow.org/api_docs/python/tf/keras/losses] будем использовать функцию (кросс-энтропии)[https://education.yandex.ru/handbook/ml/article/landshaft-funkcii-poter] для эффективного измерения разницы между предсказанными и истинными метками классов хорошо должна подойти (SparseCategoricalCrossentropy)[https://www.tensorflow.org/api_docs/python/tf/keras/losses/SparseCategoricalCrossentropy]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.compile(optimizer='adam',\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['accuracy'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test Accuracy: 0.1000\n", + "Classification Report:\n", + " precision recall f1-score support\n", + "\n", + " airplane 0.10 1.00 0.18 1000\n", + " automobile 0.00 0.00 0.00 1000\n", + " bird 0.00 0.00 0.00 1000\n", + " cat 0.00 0.00 0.00 1000\n", + " deer 0.00 0.00 0.00 1000\n", + " dog 0.00 0.00 0.00 1000\n", + " frog 0.00 0.00 0.00 1000\n", + " horse 0.00 0.00 0.00 1000\n", + " ship 0.00 0.00 0.00 1000\n", + " truck 0.00 0.00 0.00 1000\n", + "\n", + " accuracy 0.10 10000\n", + " macro avg 0.01 0.10 0.02 10000\n", + "weighted avg 0.01 0.10 0.02 10000\n", + "\n", + "---\n", + "\n", + "Test Accuracy: 0.1018\n", + "Classification Report:\n", + " precision recall f1-score support\n", + "\n", + " airplane 0.04 0.01 0.01 1000\n", + " automobile 0.15 0.33 0.21 1000\n", + " bird 0.10 0.07 0.09 1000\n", + " cat 0.11 0.05 0.07 1000\n", + " deer 0.02 0.01 0.01 1000\n", + " dog 0.07 0.07 0.07 1000\n", + " frog 0.25 0.12 0.17 1000\n", + " horse 0.11 0.17 0.14 1000\n", + " ship 0.03 0.06 0.04 1000\n", + " truck 0.16 0.12 0.14 1000\n", + "\n", + " accuracy 0.10 10000\n", + " macro avg 0.11 0.10 0.09 10000\n", + "weighted avg 0.11 0.10 0.09 10000\n", + "\n", + "\n", + "Process finished with exit code 0" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}