Загрузка данных


# =========================
# Практическая работа: Reuters
# Многоклассовая классификация новостных лент
# =========================

import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import reuters
from tensorflow.keras import models, layers
from tensorflow.keras.utils import to_categorical
import copy

# -------------------------
# 1. Загрузка данных
# -------------------------
print("1. Загрузка набора данных Reuters...\n")

(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)

print("Количество обучающих примеров:", len(train_data))
print("Количество тестовых примеров:", len(test_data))
print("Пример последовательности train_data[10]:")
print(train_data[10])
print("Метка train_labels[10]:", train_labels[10])

# -------------------------
# 2. Декодирование новости
# -------------------------
print("\n2. Декодирование одной новости...\n")

word_index = reuters.get_word_index()
reverse_word_index = {value: key for key, value in word_index.items()}

decoded_newswire = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
print("Декодированная новость train_data[0]:\n")
print(decoded_newswire[:1500], "...\n")  # выводим часть текста, чтобы не был слишком длинный вывод

# -------------------------
# 3. Подготовка данных
# -------------------------
print("3. Подготовка данных...\n")

def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results

x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)

def to_one_hot(labels, dimension=46):
    results = np.zeros((len(labels), dimension))
    for i, label in enumerate(labels):
        results[i, label] = 1.
    return results

# Вариант вручную
one_hot_train_labels_manual = to_one_hot(train_labels)
one_hot_test_labels_manual = to_one_hot(test_labels)

# Вариант через keras
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)

print("Форма x_train:", x_train.shape)
print("Форма x_test:", x_test.shape)
print("Форма one_hot_train_labels:", one_hot_train_labels.shape)
print("Форма one_hot_test_labels:", one_hot_test_labels.shape)

# -------------------------
# 4. Конструирование сети
# -------------------------
print("\n4. Создание модели...\n")

model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

model.summary()

# -------------------------
# 5. Выделение валидации
# -------------------------
print("\n5. Деление на обучающую и валидационную выборки...\n")

x_val = x_train[:1000]
partial_x_train = x_train[1000:]

y_val = one_hot_train_labels[:1000]
partial_y_train = one_hot_train_labels[1000:]

print("partial_x_train:", partial_x_train.shape)
print("x_val:", x_val.shape)

# -------------------------
# 6. Обучение модели
# -------------------------
print("\n6. Обучение модели...\n")

history = model.fit(
    partial_x_train,
    partial_y_train,
    epochs=20,
    batch_size=512,
    validation_data=(x_val, y_val),
    verbose=1
)

# -------------------------
# 7. Графики ошибки
# -------------------------
print("\n7. Построение графиков...\n")

loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)

plt.figure(figsize=(10, 5))
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

# -------------------------
# 8. Графики точности
# -------------------------
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

plt.figure(figsize=(10, 5))
plt.plot(epochs, acc, 'bo', label='Training accuracy')
plt.plot(epochs, val_acc, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.grid(True)
plt.show()

# -------------------------
# 9. Повторное обучение на оптимальном количестве эпох
# -------------------------
print("\n8. Повторное обучение модели (оптимально 9 эпох)...\n")

model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

model.fit(
    partial_x_train,
    partial_y_train,
    epochs=9,
    batch_size=512,
    validation_data=(x_val, y_val),
    verbose=1
)

results = model.evaluate(x_test, one_hot_test_labels, verbose=0)
print("\nРезультаты на тестовой выборке:")
print("Loss =", results[0])
print("Accuracy =", results[1])

# -------------------------
# 10. Сравнение со случайной базовой точностью
# -------------------------
print("\n9. Случайная базовая точность...\n")

test_labels_copy = copy.copy(test_labels)
np.random.shuffle(test_labels_copy)
hits_array = np.array(test_labels) == np.array(test_labels_copy)
random_accuracy = float(np.sum(hits_array)) / len(test_labels)

print("Случайная базовая точность:", random_accuracy)

# -------------------------
# 11. Предсказания на новых данных
# -------------------------
print("\n10. Предсказания модели...\n")

predictions = model.predict(x_test, verbose=0)

print("Форма predictions[0]:", predictions[0].shape)
print("Сумма вероятностей predictions[0]:", np.sum(predictions[0]))
print("Предсказанный класс для первой новости:", np.argmax(predictions[0]))
print("Настоящий класс для первой новости:", test_labels[0])

# -------------------------
# 12. Другой способ обработки меток и потерь
# -------------------------
print("\n11. Альтернативный вариант: sparse_categorical_crossentropy...\n")

y_train = np.array(train_labels)
y_test = np.array(test_labels)

model_sparse = models.Sequential()
model_sparse.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model_sparse.add(layers.Dense(64, activation='relu'))
model_sparse.add(layers.Dense(46, activation='softmax'))

model_sparse.compile(optimizer='rmsprop',
                     loss='sparse_categorical_crossentropy',
                     metrics=['accuracy'])

model_sparse.fit(
    partial_x_train,
    y_train[1000:],
    epochs=9,
    batch_size=512,
    validation_data=(x_val, y_train[:1000]),
    verbose=1
)

sparse_results = model_sparse.evaluate(x_test, y_test, verbose=0)
print("\nРезультаты sparse-модели:")
print("Loss =", sparse_results[0])
print("Accuracy =", sparse_results[1])

# -------------------------
# 13. Важность размера промежуточных слоев
# -------------------------
print("\n12. Эксперимент с маленьким промежуточным слоем (4 нейрона)...\n")

model_small = models.Sequential()
model_small.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model_small.add(layers.Dense(4, activation='relu'))
model_small.add(layers.Dense(46, activation='softmax'))

model_small.compile(optimizer='rmsprop',
                    loss='categorical_crossentropy',
                    metrics=['accuracy'])

history_small = model_small.fit(
    partial_x_train,
    partial_y_train,
    epochs=20,
    batch_size=128,
    validation_data=(x_val, y_val),
    verbose=1
)

small_results = model_small.evaluate(x_test, one_hot_test_labels, verbose=0)
print("\nРезультаты модели с маленьким скрытым слоем:")
print("Loss =", small_results[0])
print("Accuracy =", small_results[1])

# -------------------------
# 14. Итог
# -------------------------
print("\n=========================")
print("ИТОГ:")
print("=========================")
print("1. Набор Reuters успешно загружен.")
print("2. Данные векторизованы.")
print("3. Построена сеть для многоклассовой классификации.")
print("4. Выполнено обучение, проверка, предсказание.")
print("5. Проверен альтернативный способ с sparse_categorical_crossentropy.")
print("6. Проведен эксперимент с маленьким скрытым слоем.")
print("=========================")