На этом шаге мы рассмотрим еще один пример использования созданной нейронной сети.
Мы собираемся протестировать нейронную сеть на другом наборе данных, основанном на химическом анализе сортов итальянских вин. Этот набор данных содержит 178 образцов. Механизм работы с ним будет примерно таким же, что и с набором данных об ирисах, но структура CSV-файла немного иная. Вот его фрагмент:
1,14.23,1.71,2.43,15.6,127,2.8,3.06,.28,2.29,5.64,1.04,3.92,1065 1,13.2,1.78,2.14,11.2,100,2.65,2.76,.26,1.28,4.38,1.05,3.4,1050 1,13.16,2.36,2.67,18.6,101,2.8,3.24,.3,2.81,5.68,1.03,3.17,1185 1,14.37,1.95,2.5,16.8,113,3.85,3.49,.24,2.18,7.8,.86,3.45,1480 1,13.24,2.59,2.87,21,118,2.8,2.69,.39,1.82,4.32,1.04,2.93,735
Первым значением в каждой строке всегда будет целое число от 1 до 3, представляющее один из трех сортов, к которым может принадлежать образец. Но обратите внимание на то, сколько здесь еще параметров для классификации. В наборе данных об ирисах было только четыре параметра. В наборе данных о винах их 13.
Наша модель нейронной сети отлично масштабируется, нужно только увеличить количество входных нейронов. Файл wine_test.ру аналогичен iris_test.ру, но в него внесено несколько незначительных изменений, чтобы учесть различия в их структуре.
import csv from typing import List from util import normalize_by_feature_scaling from network import Network from random import shuffle if __name__ == "__main__": wine_parameters: List[List[float]] = [] wine_classifications: List[List[float]] = [] wine_species: List[int] = [] with open('wine.csv', mode='r') as wine_file: wines: List = list(csv.reader(wine_file, quoting=csv.QUOTE_NONNUMERIC)) shuffle(wines) # получаем наши строки данных в случайном порядке for wine in wines: parameters: List[float] = [float(n) for n in wine[1:14]] wine_parameters.append(parameters) species: int = int(wine[0]) if species == 1: wine_classifications.append([1.0, 0.0, 0.0]) elif species == 2: wine_classifications.append([0.0, 1.0, 0.0]) else: wine_classifications.append([0.0, 0.0, 1.0]) wine_species.append(species) normalize_by_feature_scaling(wine_parameters)
Как уже упоминалось, конфигурация слоя в сети для классификации сортов вин требует 13 входных нейронов - по одному для каждого параметра. Кроме того, нужны три выходных нейрона (существует три сорта вина, точно так же, как раньше было три вида ирисов). Интересно, что сеть хорошо работает, когда число нейронов в скрытом слое меньше, чем во входном. Одним из возможных интуитивных объяснений этого является то, что некоторые входные параметры на самом деле не помогают выполнить классификацию и их лучше опустить во время обработки. На самом деле меньшее количество нейронов в скрытом слое работает не совсем так, но это интересное предположение.
wine_network: Network = Network([13, 7, 3], 0.9)
Подчеркнем еще раз: иногда интересно поэкспериментировать с другим количеством скрытых нейронов или с другой скоростью обучения:
def wine_interpret_output(output: List[float]) -> int: if max(output) == output[0]: return 1 elif max(output) == output[1]: return 2 else: return 3
Функция wine_interpret_output() аналогична iris_interpret_output(). Поскольку у нас нет названий сортов вин, просто присваиваем сортам целочисленные номера и используем их в исходном наборе данных.
# обучение на первых 158 образцах вина, повторяется десять раз wine_trainers: List[List[ float ]] = wine_parameters[0:150] wine_trainers_corrects: List[List[float]] = wine_classifications[0:150] for _ in range(10): wine_network.train(wine_trainers, wine_trainers_corrects)
Будем обучать сеть на первых 150 образцах из набора данных, оставляя последние 28 для проверки, и повторим обучение десять раз для каждой выборки, что значительно меньше, чем 50 для набора данных об ирисах. По какой-то причине (возможно, из-за специфических свойств этого набора данных или настроек параметров, таких как скорость обучения и количество скрытых нейронов) этот набор данных требует более короткого обучения для достижения значительной точности, чем набор данных об ирисах.
# тестирование на последних 28 образцах вина в наборе данных wine_testers: List[List[float]] = wine_parameters[150:178] wine_testers_corrects: List[int] = wine_species[150:178] wine_results = wine_network.validate(wine_testers, wine_testers_corrects, wine_interpret_output) print(f"{wine_results[0]} корректно из {wine_results[1]} = {wine_results[2] * 100}%")
Если повезет, то ваша нейронная сеть сможет довольно точно классифицировать 28 образцов:
27 корректно из 28 = 96.42857142857143%
На следующем шаге мы рассмотрим способы повышение скорости работы нейронной сети.