Files
AIM-PIbd-31-Anisin-R-S/lab_12/lab12.ipynb
2025-05-16 23:05:22 +04:00

104 KiB
Raw Blame History

Лабораторная 12

Классификация набора изображений

Датасет: Vehicle Type Recognition (https://www.kaggle.com/datasets/kaggleashwin/vehicle-type-recognition)

In [1]:
import os
os.environ["KERAS_BACKEND"] = "jax"

from keras import backend as K
K.clear_session()

dataset_path = "static/Dataset"

classes = os.listdir(dataset_path)
num_classes = len(classes)

print(f"Всего классов: {num_classes}")
print("Список классов:", classes)
Всего классов: 4
Список классов: ['Bus', 'Car', 'motorcycle', 'Truck']

Предобработка изображений и разделение их на выборки

In [ ]:
import numpy as np
from sklearn.model_selection import train_test_split
from keras.api.utils import to_categorical
from PIL import Image

img_width, img_height = 224, 224
input_shape = (img_width, img_height, 3)  

X = []
y = []

for i, image_class in enumerate(classes):
    class_dir = os.path.join(dataset_path, image_class)
    for img_file in os.listdir(class_dir):
        try:
            img_path = os.path.join(class_dir, img_file)
            img = Image.open(img_path).convert('RGB')
            img = img.resize((img_width, img_height))
            img_array = np.array(img) / 255.0
            X.append(img_array)
            y.append(i)
        except Exception as e:
            print(f"Ошибка при загрузке {img_path}: {e}")

X = np.array(X)
y = np.array(y)

y = to_categorical(y, num_classes=num_classes)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print(f"Размер обучающей выборки: {X_train.shape}")
print(f"Размер тестовой выборки: {X_test.shape}")
print(f"Количество классов: {num_classes}")
c:\Users\User\Desktop\aim\aimvenv\Lib\site-packages\PIL\Image.py:1056: UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images
  warnings.warn(
Размер обучающей выборки: (320, 224, 224, 3)
Размер тестовой выборки: (80, 224, 224, 3)
Количество классов: 4

Проектированию глубокой сверточной нейронной сети

используем AlexNet

In [ ]:
from keras.api.models import Sequential
from keras.api.layers import InputLayer, Conv2D, MaxPooling2D, Dropout, Flatten, Dense, BatchNormalization

alexnet_model = Sequential()

alexnet_model.add(InputLayer(shape=(224, 224, 3)))

alexnet_model.add(Conv2D(96, kernel_size=(11, 11), strides=(4, 4), activation="relu"))
alexnet_model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
alexnet_model.add(BatchNormalization())

alexnet_model.add(Conv2D(256, kernel_size=(5, 5), activation="relu"))
alexnet_model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
alexnet_model.add(BatchNormalization())

alexnet_model.add(Conv2D(256, kernel_size=(3, 3), activation="relu"))

alexnet_model.add(Conv2D(384, kernel_size=(3, 3), activation="relu"))

alexnet_model.add(Conv2D(384, kernel_size=(3, 3), activation="relu"))
alexnet_model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
alexnet_model.add(BatchNormalization())

alexnet_model.add(Flatten())
alexnet_model.add(Dense(4096, activation="tanh"))
alexnet_model.add(Dropout(0.5))

alexnet_model.add(Dense(4096, activation="tanh"))
alexnet_model.add(Dropout(0.5))

alexnet_model.add(Dense(num_classes, activation="softmax"))

alexnet_model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 54, 54, 96)     │        34,944 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 26, 26, 96)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization             │ (None, 26, 26, 96)     │           384 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 22, 22, 256)    │       614,656 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 10, 10, 256)    │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization_1           │ (None, 10, 10, 256)    │         1,024 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_2 (Conv2D)               │ (None, 8, 8, 256)      │       590,080 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_3 (Conv2D)               │ (None, 6, 6, 384)      │       885,120 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_4 (Conv2D)               │ (None, 4, 4, 384)      │     1,327,488 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_2 (MaxPooling2D)  │ (None, 1, 1, 384)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization_2           │ (None, 1, 1, 384)      │         1,536 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten (Flatten)               │ (None, 384)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 4096)           │     1,576,960 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 4096)           │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 4096)           │    16,781,312 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_1 (Dropout)             │ (None, 4096)           │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_2 (Dense)                 │ (None, 4)              │        16,388 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 21,829,892 (83.27 MB)
 Trainable params: 21,828,420 (83.27 MB)
 Non-trainable params: 1,472 (5.75 KB)

Обучение модели

In [4]:
from keras.api.callbacks import EarlyStopping

alexnet_model.compile(
    loss="categorical_crossentropy",
    optimizer="adam",
    metrics=["accuracy"]
)

early_stop = EarlyStopping(monitor='val_accuracy', patience=10, restore_best_weights=True)
alexnet_model.fit(
    x=X_train, 
    y=y_train,
    epochs=100,
    validation_data=(X_test, y_test),
    callbacks=[early_stop]
)
Epoch 1/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 11s 935ms/step - accuracy: 0.3209 - loss: 5.4267 - val_accuracy: 0.2500 - val_loss: 9.1606
Epoch 2/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 8s 700ms/step - accuracy: 0.3936 - loss: 7.7186 - val_accuracy: 0.2500 - val_loss: 10.6578
Epoch 3/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 696ms/step - accuracy: 0.3039 - loss: 7.0676 - val_accuracy: 0.2500 - val_loss: 2.7710
Epoch 4/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 702ms/step - accuracy: 0.3167 - loss: 2.5632 - val_accuracy: 0.2500 - val_loss: 1.7581
Epoch 5/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 693ms/step - accuracy: 0.2744 - loss: 2.0231 - val_accuracy: 0.2625 - val_loss: 1.7923
Epoch 6/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 693ms/step - accuracy: 0.2843 - loss: 1.9969 - val_accuracy: 0.2500 - val_loss: 1.6605
Epoch 7/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 694ms/step - accuracy: 0.2986 - loss: 1.8363 - val_accuracy: 0.2500 - val_loss: 1.4946
Epoch 8/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 695ms/step - accuracy: 0.3106 - loss: 1.8001 - val_accuracy: 0.2750 - val_loss: 1.6487
Epoch 9/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 683ms/step - accuracy: 0.3362 - loss: 1.7756 - val_accuracy: 0.2625 - val_loss: 1.4614
Epoch 10/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 696ms/step - accuracy: 0.2665 - loss: 1.9055 - val_accuracy: 0.2500 - val_loss: 1.9306
Epoch 11/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 684ms/step - accuracy: 0.3043 - loss: 1.9743 - val_accuracy: 0.2125 - val_loss: 2.4484
Epoch 12/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 683ms/step - accuracy: 0.3049 - loss: 1.9582 - val_accuracy: 0.2625 - val_loss: 1.4873
Epoch 13/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 691ms/step - accuracy: 0.4019 - loss: 1.6694 - val_accuracy: 0.2875 - val_loss: 1.9368
Epoch 14/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 697ms/step - accuracy: 0.4397 - loss: 1.5109 - val_accuracy: 0.2625 - val_loss: 2.7897
Epoch 15/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 689ms/step - accuracy: 0.3716 - loss: 1.7504 - val_accuracy: 0.4125 - val_loss: 1.5172
Epoch 16/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 697ms/step - accuracy: 0.4378 - loss: 1.5575 - val_accuracy: 0.3250 - val_loss: 1.8495
Epoch 17/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 700ms/step - accuracy: 0.4742 - loss: 1.5302 - val_accuracy: 0.3000 - val_loss: 2.0239
Epoch 18/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 687ms/step - accuracy: 0.4646 - loss: 1.3401 - val_accuracy: 0.3250 - val_loss: 1.5780
Epoch 19/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 700ms/step - accuracy: 0.4993 - loss: 1.3897 - val_accuracy: 0.2750 - val_loss: 1.9663
Epoch 20/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 704ms/step - accuracy: 0.5081 - loss: 1.5911 - val_accuracy: 0.2250 - val_loss: 2.3920
Epoch 21/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 690ms/step - accuracy: 0.4561 - loss: 1.4729 - val_accuracy: 0.3125 - val_loss: 2.1290
Epoch 22/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 689ms/step - accuracy: 0.5576 - loss: 1.4146 - val_accuracy: 0.2500 - val_loss: 1.8015
Epoch 23/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 688ms/step - accuracy: 0.4931 - loss: 1.2931 - val_accuracy: 0.2500 - val_loss: 2.0941
Epoch 24/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 685ms/step - accuracy: 0.5758 - loss: 1.1323 - val_accuracy: 0.3625 - val_loss: 1.7523
Epoch 25/100
10/10 ━━━━━━━━━━━━━━━━━━━━ 7s 685ms/step - accuracy: 0.5046 - loss: 1.2337 - val_accuracy: 0.3750 - val_loss: 1.8958
Out[4]:
<keras.src.callbacks.history.History at 0x17d1a971880>

Оценка качества

In [5]:
def evaluate_model(model, X_test, y_test):
    loss, accuracy = model.evaluate(X_test, y_test)
    print(f"Loss на тестовой выборке: {loss:.4f}")
    print(f"Accuracy на тестовой выборке: {accuracy:.4f}")

evaluate_model(alexnet_model, X_test, y_test)
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 122ms/step - accuracy: 0.4289 - loss: 1.5600
Loss на тестовой выборке: 1.5172
Accuracy на тестовой выборке: 0.4125

Качество модели - 41.25% это хуже чем в 9 ЛР, но лучше чем в 11 ЛР

Классификация текстов

In [6]:
import spacy

sp = spacy.load("ru_core_news_lg")

Загрузка текстов из файлов в датафрейм

In [7]:
import pandas as pd
from docx import Document

def read_docx(file_path):
    doc = Document(file_path)
    full_text = []
    for paragraph in doc.paragraphs:
        full_text.append(paragraph.text)
    return "\n".join(full_text)

def load_docs(dataset_path):
    df = pd.DataFrame(columns=["doc", "text"])
    for file_path in os.listdir(dataset_path):
        if file_path.startswith("~$"):
            continue
        text = read_docx(dataset_path + file_path)
        df.loc[len(df.index)] = [file_path, text]
    return df

df = load_docs("static/text/")
df["type"] = df.apply(lambda row: 0 if str(row["doc"]).startswith("tz_") else 1, axis=1)
df.sort_values(by=["doc"], inplace=True)

display(df.head(), df.tail())
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
doc text type
0 tz_01.docx 2.2 Техническое задание\n2.2.1 Общие сведения\... 0
1 tz_02.docx 2.2 Техническое задание\n2.2.1 Общие сведения\... 0
2 tz_03.docx 2.2. Техническое задание\nОбщие сведения:\nВ д... 0
3 tz_04.docx Техническое задание\n2.2.1 Общие сведения\nИнт... 0
4 tz_05.docx 2.2 Техническое задание\n2.2.1 Общие сведения.... 0
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
doc text type
36 Этапы разработки проекта2.docx Этапы разработки проекта: заключительные стади... 1
37 Этапы разработки проекта3.docx Этапы разработки проекта: определение стратеги... 1
38 Этапы разработки проекта4.docx Этапы разработки проекта: реализация, тестиров... 1
39 Этапы разработки проекта5.docx Этапы разработки проекта: стратегия и анализ\n... 1
40 Язык манипуляции данными.docx 2.1.3. Язык манипуляции данными (ЯМД)\nЯзык ма... 1

Предобработка текста

In [8]:
from gensim.models.phrases import Phraser, Phrases

def prep_text(text):
    doc = sp(text)
    lower_sents = []
    for sent in doc.sents:
        lower_sents.append([word.lemma_.lower() for word in sent if not word.is_punct and not word.is_stop and not word.is_space])
    lower_bigram = Phraser(Phrases(lower_sents))
    clean_sents = []
    for sent in lower_sents:
        clean_sents.append(lower_bigram[sent])
    return clean_sents

df["prep_text"] = df.apply(lambda row: prep_text(row["text"]), axis=1)
display(df.head(), df.tail())
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
doc text type prep_text
0 tz_01.docx 2.2 Техническое задание\n2.2.1 Общие сведения\... 0 [[2.2, технический, задание, 2.2.1, общий, све...
1 tz_02.docx 2.2 Техническое задание\n2.2.1 Общие сведения\... 0 [[2.2, технический, задание, 2.2.1, общий, све...
2 tz_03.docx 2.2. Техническое задание\nОбщие сведения:\nВ д... 0 [[2.2], [технический, задание, общий, сведение...
3 tz_04.docx Техническое задание\n2.2.1 Общие сведения\nИнт... 0 [[технический, задание, 2.2.1, общий, сведение...
4 tz_05.docx 2.2 Техническое задание\n2.2.1 Общие сведения.... 0 [[2.2, технический, задание, 2.2.1, общий, све...
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
doc text type prep_text
36 Этапы разработки проекта2.docx Этапы разработки проекта: заключительные стади... 1 [[этап, разработка, проект, заключительные, ст...
37 Этапы разработки проекта3.docx Этапы разработки проекта: определение стратеги... 1 [[этап, разработка, проект, определение, страт...
38 Этапы разработки проекта4.docx Этапы разработки проекта: реализация, тестиров... 1 [[этап_разработка, проект, реализация, тестиро...
39 Этапы разработки проекта5.docx Этапы разработки проекта: стратегия и анализ\n... 1 [[этап, разработка_проект, стратегия, анализ, ...
40 Язык манипуляции данными.docx 2.1.3. Язык манипуляции данными (ЯМД)\nЯзык ма... 1 [[2.1.3], [язык, манипуляция, данными, ямд, яз...

Векторизация текстовых данных

In [9]:
from gensim.models.word2vec import Word2Vec

word2vec = Word2Vec(
    sentences=df["prep_text"].explode().tolist(),
    vector_size=64,
    sg=1,
    window=10,
    epochs=5,
    min_count=10,
    workers=4,
    seed=9,
)
In [10]:
word_to_id = word2vec.wv.key_to_index
word_to_id = {'pad': 0, **{k: v+1 for k, v in word2vec.wv.key_to_index.items()}}
list(word_to_id.items())[:20]
Out[10]:
[('pad', 0),
 ('система', 1),
 ('работа', 2),
 ('требование', 3),
 ('база', 4),
 ('пользователь', 5),
 ('разработка', 6),
 ('модель', 7),
 ('информация', 8),
 ('субд', 9),
 ('этап', 10),
 ('ошибка', 11),
 ('являться', 12),
 ('функция', 13),
 ('таблица', 14),
 ('средство', 15),
 ('проект', 16),
 ('сервер', 17),
 ('процесс', 18),
 ('документ', 19)]

Преобразуем тексты в списки индексов

In [11]:
def text_to_ids(sentences, word_to_id):
    flat_words = [word for sent in sentences for word in sent]
    return [word_to_id.get(word, 0) for word in flat_words]

df["ids"] = df["prep_text"].apply(lambda doc: text_to_ids(doc, word_to_id))

padding и truncating

In [12]:
from keras.api.preprocessing.sequence import pad_sequences

max_length = 1500
X = pad_sequences(df["ids"].tolist(), maxlen=max_length, padding="pre", truncating="pre", value=0)

Тренировочная и тестовая выборки

In [13]:
from sklearn.model_selection import train_test_split

y = df["type"].values

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
X_train
Out[13]:
array([[  0,   0,   0, ..., 134, 108, 148],
       [ 29,   0,   0, ...,   0,   0, 294],
       [  0,   0,   0, ..., 134, 108, 148],
       ...,
       [  0,  45, 251, ...,   0, 225,  30],
       [  0,   0,   0, ..., 219,   0,   0],
       [  0,   0,   0, ..., 194, 134,   5]])
In [14]:
y_train
Out[14]:
array([0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1,
       0, 1, 1, 1, 0, 1, 0, 1, 0, 0], dtype=int64)

Архитектура глубокой полносвязанной сети

In [15]:
from keras.api.layers import Embedding

vocab_size = len(word_to_id)

model = Sequential()
model.add(InputLayer(shape=(max_length,), dtype="int32"))

model.add(Embedding(input_dim=vocab_size, output_dim=64))

model.add(Flatten())

model.add(Dense(64, activation="relu"))
model.add(Dropout(0.5))

model.add(Dense(1, activation="sigmoid"))

model.summary()
Model: "sequential_1"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ embedding (Embedding)           │ (None, 1500, 64)       │        66,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten_1 (Flatten)             │ (None, 96000)          │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_3 (Dense)                 │ (None, 64)             │     6,144,064 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_2 (Dropout)             │ (None, 64)             │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_4 (Dense)                 │ (None, 1)              │            65 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 6,210,625 (23.69 MB)
 Trainable params: 6,210,625 (23.69 MB)
 Non-trainable params: 0 (0.00 B)

Обучение модели

In [16]:
model.compile(
    loss="binary_crossentropy",
    optimizer="adam",
    metrics=["accuracy"],
)

model.fit(
    X_train,
    y_train,
    batch_size=128,
    epochs=5,
    validation_data=(X_test, y_test)
)
Epoch 1/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 605ms/step - accuracy: 0.3750 - loss: 0.7053 - val_accuracy: 0.4444 - val_loss: 0.8328
Epoch 2/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 359ms/step - accuracy: 0.6562 - loss: 0.5666 - val_accuracy: 0.7778 - val_loss: 0.5512
Epoch 3/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.8125 - loss: 0.3735 - val_accuracy: 0.7778 - val_loss: 0.5157
Epoch 4/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 47ms/step - accuracy: 0.9375 - loss: 0.1711 - val_accuracy: 0.7778 - val_loss: 0.5147
Epoch 5/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 47ms/step - accuracy: 0.9062 - loss: 0.2508 - val_accuracy: 0.7778 - val_loss: 0.5128
Out[16]:
<keras.src.callbacks.history.History at 0x17d91372480>

Оценка качества

In [17]:
evaluate_model(model, X_test, y_test)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 16ms/step - accuracy: 0.7778 - loss: 0.5128
Loss на тестовой выборке: 0.5128
Accuracy на тестовой выборке: 0.7778

Сверточная сеть

In [18]:
from keras.api.layers import SpatialDropout1D, Conv1D, GlobalMaxPooling1D

conv_model = Sequential()
conv_model.add(InputLayer(shape=(max_length,), dtype="int32"))

conv_model.add(Embedding(input_dim=vocab_size, output_dim=64))

conv_model.add(SpatialDropout1D(0.2))

conv_model.add(Conv1D(filters=256, kernel_size=3, activation="relu"))
conv_model.add(GlobalMaxPooling1D())

conv_model.add(Dense(256, activation="relu"))
conv_model.add(Dropout(0.3))  

conv_model.add(Dense(1, activation="sigmoid"))

conv_model.summary()
Model: "sequential_2"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ embedding_1 (Embedding)         │ (None, 1500, 64)       │        66,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ spatial_dropout1d               │ (None, 1500, 64)       │             0 │
│ (SpatialDropout1D)              │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv1d (Conv1D)                 │ (None, 1498, 256)      │        49,408 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_max_pooling1d            │ (None, 256)            │             0 │
│ (GlobalMaxPooling1D)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_5 (Dense)                 │ (None, 256)            │        65,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_3 (Dropout)             │ (None, 256)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_6 (Dense)                 │ (None, 1)              │           257 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 181,953 (710.75 KB)
 Trainable params: 181,953 (710.75 KB)
 Non-trainable params: 0 (0.00 B)

Обучение модели

In [19]:
conv_model.compile(
    loss="binary_crossentropy",
    optimizer="adam",
    metrics=["accuracy"],
)

conv_model.fit(
    X_train,
    y_train,
    batch_size=128,
    epochs=5,
    validation_data=(X_test, y_test)
)
Epoch 1/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 1s/step - accuracy: 0.5938 - loss: 0.6891 - val_accuracy: 0.4444 - val_loss: 0.6881
Epoch 2/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 656ms/step - accuracy: 0.5938 - loss: 0.6901 - val_accuracy: 1.0000 - val_loss: 0.6837
Epoch 3/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 187ms/step - accuracy: 0.6250 - loss: 0.6826 - val_accuracy: 1.0000 - val_loss: 0.6792
Epoch 4/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 125ms/step - accuracy: 0.7188 - loss: 0.6766 - val_accuracy: 0.8889 - val_loss: 0.6733
Epoch 5/5
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 156ms/step - accuracy: 0.6875 - loss: 0.6777 - val_accuracy: 1.0000 - val_loss: 0.6678
Out[19]:
<keras.src.callbacks.history.History at 0x17d9148b3e0>

Оценка качества

In [20]:
evaluate_model(conv_model, X_test, y_test)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 39ms/step - accuracy: 1.0000 - loss: 0.6678
Loss на тестовой выборке: 0.6678
Accuracy на тестовой выборке: 1.0000

Рекуррентная сеть

In [21]:
from keras.api.layers import SimpleRNN

rnn_model = Sequential()
rnn_model.add(InputLayer(shape=(max_length,), dtype="int32"))

rnn_model.add(Embedding(input_dim=vocab_size, output_dim=64))

rnn_model.add(SpatialDropout1D(0.2))

rnn_model.add(SimpleRNN(128, dropout=0.2, recurrent_dropout=0.2))

rnn_model.add(Dense(1, activation="sigmoid"))

rnn_model.summary()
Model: "sequential_3"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ embedding_2 (Embedding)         │ (None, 1500, 64)       │        66,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ spatial_dropout1d_1             │ (None, 1500, 64)       │             0 │
│ (SpatialDropout1D)              │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ simple_rnn (SimpleRNN)          │ (None, 128)            │        24,704 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_7 (Dense)                 │ (None, 1)              │           129 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 91,329 (356.75 KB)
 Trainable params: 91,329 (356.75 KB)
 Non-trainable params: 0 (0.00 B)

Обучение модели

In [22]:
rnn_model.compile(
    loss="binary_crossentropy",
    optimizer="adam",
    metrics=["accuracy"],
)

early_stop = EarlyStopping(monitor='val_accuracy', patience=10, restore_best_weights=True)
rnn_model.fit(
    X_train,
    y_train,
    batch_size=128,
    epochs=40,
    validation_data=(X_test, y_test),
    callbacks=[early_stop]
)
Epoch 1/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 1s/step - accuracy: 0.5000 - loss: 0.7441 - val_accuracy: 0.8889 - val_loss: 0.6012
Epoch 2/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 797ms/step - accuracy: 0.5312 - loss: 0.7488 - val_accuracy: 0.8889 - val_loss: 0.6016
Epoch 3/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5000 - loss: 0.7157 - val_accuracy: 0.8889 - val_loss: 0.6043
Epoch 4/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.6250 - loss: 0.6322 - val_accuracy: 0.8889 - val_loss: 0.6083
Epoch 5/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 234ms/step - accuracy: 0.5000 - loss: 0.6860 - val_accuracy: 0.8889 - val_loss: 0.6114
Epoch 6/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.4062 - loss: 0.7382 - val_accuracy: 0.8889 - val_loss: 0.6095
Epoch 7/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5938 - loss: 0.6835 - val_accuracy: 0.8889 - val_loss: 0.6095
Epoch 8/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5312 - loss: 0.7079 - val_accuracy: 0.8889 - val_loss: 0.6057
Epoch 9/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 234ms/step - accuracy: 0.5000 - loss: 0.6995 - val_accuracy: 1.0000 - val_loss: 0.6025
Epoch 10/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.4688 - loss: 0.7459 - val_accuracy: 0.8889 - val_loss: 0.6156
Epoch 11/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5938 - loss: 0.7364 - val_accuracy: 1.0000 - val_loss: 0.5995
Epoch 12/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.7188 - loss: 0.6552 - val_accuracy: 0.8889 - val_loss: 0.6118
Epoch 13/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5938 - loss: 0.6433 - val_accuracy: 1.0000 - val_loss: 0.6036
Epoch 14/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5625 - loss: 0.7378 - val_accuracy: 1.0000 - val_loss: 0.6088
Epoch 15/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5938 - loss: 0.6532 - val_accuracy: 1.0000 - val_loss: 0.6128
Epoch 16/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5938 - loss: 0.6827 - val_accuracy: 0.8889 - val_loss: 0.6190
Epoch 17/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5312 - loss: 0.7088 - val_accuracy: 0.8889 - val_loss: 0.6045
Epoch 18/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.5625 - loss: 0.6746 - val_accuracy: 0.7778 - val_loss: 0.6072
Epoch 19/40
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 219ms/step - accuracy: 0.4375 - loss: 0.7517 - val_accuracy: 0.7778 - val_loss: 0.6159
Out[22]:
<keras.src.callbacks.history.History at 0x17d071bf2f0>

Оценка качества

In [23]:
evaluate_model(rnn_model, X_test, y_test)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 144ms/step - accuracy: 1.0000 - loss: 0.6025
Loss на тестовой выборке: 0.6025
Accuracy на тестовой выборке: 1.0000

Лучший результат - полносвязанная сеть - 77,78%

Сверточная сеть - 66,78%

Рекуррентная сеть - 60,25%